mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-10 05:12:14 +00:00
style: apply prettier across the tree
One-shot prettier pass so the new format:check gate starts from a clean baseline. Formatting only — no behaviour change. Generator-owned and vendored artifacts stay untouched via .prettierignore.
This commit is contained in:
1 parent
b3fea2ef59
commit
1f4ba5939d
1000 files changed
+12130
-8385
No files matched your search
@@ -62,7 +62,7 @@ export const coachReminderSuggestionPaths: NonNullable<
|
||||
tags: ["Insights"],
|
||||
summary: "Act on a Coach cadence suggestion",
|
||||
description:
|
||||
"v1.18.1 — accept / dismiss / stop a Coach-proposed measurement cadence. Coach-gated (`requireModuleEnabled(\"coach\")`); a disabled surface 403s. `accept` resolves the cadence from the closed server-side catalog and creates a `MeasurementReminder` with `origin: COACH` (201), or returns 200 with `duplicate: true` when a live COACH reminder for that metric already exists — idempotent against a re-tapped or stale card, with a partial unique index as the structural backstop. Per-user rate-limited (429 on excess). Auth via cookie or Bearer; the owner is narrowed from the session.",
|
||||
'v1.18.1 — accept / dismiss / stop a Coach-proposed measurement cadence. Coach-gated (`requireModuleEnabled("coach")`); a disabled surface 403s. `accept` resolves the cadence from the closed server-side catalog and creates a `MeasurementReminder` with `origin: COACH` (201), or returns 200 with `duplicate: true` when a live COACH reminder for that metric already exists — idempotent against a re-tapped or stale card, with a partial unique index as the structural backstop. Per-user rate-limited (429 on excess). Auth via cookie or Bearer; the owner is narrowed from the session.',
|
||||
requestBody: {
|
||||
required: true,
|
||||
content: {
|
||||
@@ -261,7 +261,9 @@ const coachProvenanceSchema = z
|
||||
counts: z
|
||||
.record(z.string(), z.number().int())
|
||||
.optional()
|
||||
.describe("Per-metric sample-count summary; absent on an empty snapshot."),
|
||||
.describe(
|
||||
"Per-metric sample-count summary; absent on an empty snapshot.",
|
||||
),
|
||||
keyValues: z
|
||||
.array(
|
||||
z.object({
|
||||
@@ -302,7 +304,9 @@ const coachMessageSchema = z
|
||||
promptVersion: z
|
||||
.string()
|
||||
.nullable()
|
||||
.describe("Coach prompt version that produced the reply; null for user turns."),
|
||||
.describe(
|
||||
"Coach prompt version that produced the reply; null for user turns.",
|
||||
),
|
||||
})
|
||||
.meta({
|
||||
id: "CoachMessage",
|
||||
@@ -315,8 +319,8 @@ const coachConversationSchema = z
|
||||
id: z.string(),
|
||||
title: z.string().describe("Title summarised from the first user message."),
|
||||
createdAt: z.iso.datetime({ offset: true }),
|
||||
updatedAt: z
|
||||
.iso.datetime({ offset: true })
|
||||
updatedAt: z.iso
|
||||
.datetime({ offset: true })
|
||||
.describe("Bumped on every appended message; the rail orders by this."),
|
||||
messageCount: z.number().int(),
|
||||
})
|
||||
@@ -384,7 +388,7 @@ export const coachPaths: NonNullable<ZodOpenApiObject["paths"]> = {
|
||||
tags: ["Insights"],
|
||||
summary: "List the caller's Coach conversations",
|
||||
description:
|
||||
"v1.18.0 — cursor-paginated list of the caller's Coach conversations for the history rail, most-recent activity first. Metadata only (id, title, timestamps, message count); message bodies are not decrypted here. `limit` defaults to 20, capped at 50; pass the returned `nextCursor` back as `cursor` for the next page (null at the end). Coach-gated (`requireAssistantSurface(\"coach\")`); a disabled surface 403s. Auth via cookie or Bearer; the owner is narrowed from the session.",
|
||||
'v1.18.0 — cursor-paginated list of the caller\'s Coach conversations for the history rail, most-recent activity first. Metadata only (id, title, timestamps, message count); message bodies are not decrypted here. `limit` defaults to 20, capped at 50; pass the returned `nextCursor` back as `cursor` for the next page (null at the end). Coach-gated (`requireAssistantSurface("coach")`); a disabled surface 403s. Auth via cookie or Bearer; the owner is narrowed from the session.',
|
||||
parameters: [
|
||||
{
|
||||
name: "cursor",
|
||||
@@ -650,7 +654,7 @@ export const coachPaths: NonNullable<ZodOpenApiObject["paths"]> = {
|
||||
tags: ["Insights"],
|
||||
summary: "Whether an unopened Coach message is waiting",
|
||||
description:
|
||||
"v1.18.6 (CCH-03) — server-authoritative unread signal for the Coach FAB. `unread` is true when the caller's newest Coach ASSISTANT message (a proactive nudge or any reply) is newer than `User.coachLastSeenAt`; a user who has never opened the Coach reads an existing nudge as unread exactly once. `nudgedAt` carries that newest assistant-message timestamp (null when none exists) so the client can key a local seen-mirror on a stable value. Coach-gated (`requireAssistantSurface(\"coach\")`); a disabled surface 403s. Auth via cookie or Bearer; the owner is narrowed from the session.",
|
||||
'v1.18.6 (CCH-03) — server-authoritative unread signal for the Coach FAB. `unread` is true when the caller\'s newest Coach ASSISTANT message (a proactive nudge or any reply) is newer than `User.coachLastSeenAt`; a user who has never opened the Coach reads an existing nudge as unread exactly once. `nudgedAt` carries that newest assistant-message timestamp (null when none exists) so the client can key a local seen-mirror on a stable value. Coach-gated (`requireAssistantSurface("coach")`); a disabled surface 403s. Auth via cookie or Bearer; the owner is narrowed from the session.',
|
||||
responses: {
|
||||
"200": {
|
||||
description: "The current unread state.",
|
||||
@@ -658,8 +662,8 @@ export const coachPaths: NonNullable<ZodOpenApiObject["paths"]> = {
|
||||
"application/json": {
|
||||
schema: dataEnvelope(
|
||||
z.object({
|
||||
nudgedAt: z
|
||||
.iso.datetime({ offset: true })
|
||||
nudgedAt: z.iso
|
||||
.datetime({ offset: true })
|
||||
.nullable()
|
||||
.describe(
|
||||
"Timestamp of the newest Coach assistant message; null when none exists.",
|
||||
@@ -692,8 +696,8 @@ export const coachPaths: NonNullable<ZodOpenApiObject["paths"]> = {
|
||||
"application/json": {
|
||||
schema: dataEnvelope(
|
||||
z.object({
|
||||
seenAt: z
|
||||
.iso.datetime({ offset: true })
|
||||
seenAt: z.iso
|
||||
.datetime({ offset: true })
|
||||
.describe("The server-minted open timestamp."),
|
||||
}),
|
||||
"CoachSeenResponse",
|
||||
|
||||
@@ -190,10 +190,7 @@ export const healthRecordPaths: NonNullable<ZodOpenApiObject["paths"]> = {
|
||||
"Passphrase accepted; short-lived token-scoped unlock cookie set.",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: dataEnvelope(
|
||||
shareLinkUnlockResponse,
|
||||
"ShareLinkUnlock",
|
||||
),
|
||||
schema: dataEnvelope(shareLinkUnlockResponse, "ShareLinkUnlock"),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -228,9 +228,7 @@ const illnessCorrelationResponse = z
|
||||
historyDays: z.number().int(),
|
||||
missing: z.array(z.string()),
|
||||
}),
|
||||
confidence: z
|
||||
.object({ score: z.number(), band: z.string() })
|
||||
.nullable(),
|
||||
confidence: z.object({ score: z.number(), band: z.string() }).nullable(),
|
||||
provenance: z.object({
|
||||
inputs: z.array(z.string()),
|
||||
source: z.string(),
|
||||
@@ -515,7 +513,7 @@ export const illnessPaths: NonNullable<ZodOpenApiObject["paths"]> = {
|
||||
tags: ["Illness"],
|
||||
summary: "Per-episode retrospective correlation (v1.18.1)",
|
||||
description:
|
||||
"Returns the coverage-gated `Derived<T>` correlation for one episode: the pre-onset anomaly scan, the nadir, per-vital physiological returns, the headline recovery-gap, and any red flags. The findings derive from the user's OWN baseline (median ± MAD) over a contamination-guarded window — never a population constant. `status:\"insufficient\"` carries coverage + a reason. Retrospective ONLY — never a predictor or diagnoser. Owner-scoped + module-gated.",
|
||||
'Returns the coverage-gated `Derived<T>` correlation for one episode: the pre-onset anomaly scan, the nadir, per-vital physiological returns, the headline recovery-gap, and any red flags. The findings derive from the user\'s OWN baseline (median ± MAD) over a contamination-guarded window — never a population constant. `status:"insufficient"` carries coverage + a reason. Retrospective ONLY — never a predictor or diagnoser. Owner-scoped + module-gated.',
|
||||
requestParams: { path: z.object({ id: z.string() }) },
|
||||
responses: {
|
||||
"200": {
|
||||
|
||||
@@ -34,7 +34,10 @@ const csvImportResponse = z
|
||||
inserted: z.number().int(),
|
||||
updated: z.number().int(),
|
||||
skipped: z.number().int(),
|
||||
total: z.number().int().describe("Total data rows parsed (excludes header)."),
|
||||
total: z
|
||||
.number()
|
||||
.int()
|
||||
.describe("Total data rows parsed (excludes header)."),
|
||||
dryRun: z.boolean(),
|
||||
rows: z.array(csvImportRowResult),
|
||||
})
|
||||
@@ -78,7 +81,10 @@ export const importPaths: NonNullable<ZodOpenApiObject["paths"]> = {
|
||||
description: "Per-row import outcome.",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: dataEnvelope(csvImportResponse, "CsvImportResponseEnvelope"),
|
||||
schema: dataEnvelope(
|
||||
csvImportResponse,
|
||||
"CsvImportResponseEnvelope",
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -14,11 +14,7 @@ import {
|
||||
VITALS_BASELINE_TYPES,
|
||||
} from "@/lib/insights/derived/registry";
|
||||
import { ANALYTICS_RANGES } from "@/lib/analytics/range-delta";
|
||||
import {
|
||||
consentRequiredResponse,
|
||||
dataEnvelope,
|
||||
stdResponses,
|
||||
} from "./shared";
|
||||
import { consentRequiredResponse, dataEnvelope, stdResponses } from "./shared";
|
||||
|
||||
const insightsComprehensiveResponse = z
|
||||
.object({
|
||||
|
||||
@@ -36,13 +36,11 @@ listLabResultsSchema.meta({
|
||||
"Query params for the lab-result list: optional `analyte` (exact) + `panel` filters, an inclusive `from`/`to` date range, and `limit` (≤ 500) / `offset` pagination. Defaults to `takenAt` DESC.",
|
||||
});
|
||||
|
||||
const rangeStatusEnum = z
|
||||
.enum(["in-range", "below", "above", "unknown"])
|
||||
.meta({
|
||||
id: "LabReferenceRangeStatus",
|
||||
description:
|
||||
"Server-computed, NEUTRAL reference-range verdict. `unknown` when the lab reported no usable bounds. Inclusive bounds: a value on the limit reads in-range. The badge that renders this must stay calm and informative — not an alarming red.",
|
||||
});
|
||||
const rangeStatusEnum = z.enum(["in-range", "below", "above", "unknown"]).meta({
|
||||
id: "LabReferenceRangeStatus",
|
||||
description:
|
||||
"Server-computed, NEUTRAL reference-range verdict. `unknown` when the lab reported no usable bounds. Inclusive bounds: a value on the limit reads in-range. The badge that renders this must stay calm and informative — not an alarming red.",
|
||||
});
|
||||
|
||||
const labResultRow = z
|
||||
.object({
|
||||
|
||||
@@ -23,176 +23,175 @@ const reminderNotFound = {
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const measurementReminderPaths: NonNullable<
|
||||
ZodOpenApiObject["paths"]
|
||||
> = {
|
||||
"/api/measurement-reminders": {
|
||||
get: {
|
||||
tags: ["MeasurementReminders"],
|
||||
summary: "List Vorsorge reminders (v1.17.1)",
|
||||
description:
|
||||
"Returns the owner's live (non-tombstoned) Vorsorge reminders, sorted by server-computed nextDueAt ascending (nulls last). Each row carries the canonical nextDueAt the client renders without recomputing.",
|
||||
responses: {
|
||||
"200": {
|
||||
description: "The owner's measurement reminders.",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: dataEnvelope(
|
||||
z.array(measurementReminderDto),
|
||||
"MeasurementReminderListEnvelope",
|
||||
),
|
||||
export const measurementReminderPaths: NonNullable<ZodOpenApiObject["paths"]> =
|
||||
{
|
||||
"/api/measurement-reminders": {
|
||||
get: {
|
||||
tags: ["MeasurementReminders"],
|
||||
summary: "List Vorsorge reminders (v1.17.1)",
|
||||
description:
|
||||
"Returns the owner's live (non-tombstoned) Vorsorge reminders, sorted by server-computed nextDueAt ascending (nulls last). Each row carries the canonical nextDueAt the client renders without recomputing.",
|
||||
responses: {
|
||||
"200": {
|
||||
description: "The owner's measurement reminders.",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: dataEnvelope(
|
||||
z.array(measurementReminderDto),
|
||||
"MeasurementReminderListEnvelope",
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
...stdResponses,
|
||||
},
|
||||
},
|
||||
post: {
|
||||
tags: ["MeasurementReminders"],
|
||||
summary: "Create a Vorsorge reminder (v1.17.1)",
|
||||
description:
|
||||
"Creates a reminder and computes its server-authoritative nextDueAt. Exactly one of intervalDays (rolling) or rrule (RFC-5545) is required. Wrapped in withIdempotency. 201 on insert.",
|
||||
requestBody: {
|
||||
required: true,
|
||||
content: {
|
||||
"application/json": { schema: createMeasurementReminderSchema },
|
||||
...stdResponses,
|
||||
},
|
||||
},
|
||||
responses: {
|
||||
"201": {
|
||||
description: "Reminder created.",
|
||||
post: {
|
||||
tags: ["MeasurementReminders"],
|
||||
summary: "Create a Vorsorge reminder (v1.17.1)",
|
||||
description:
|
||||
"Creates a reminder and computes its server-authoritative nextDueAt. Exactly one of intervalDays (rolling) or rrule (RFC-5545) is required. Wrapped in withIdempotency. 201 on insert.",
|
||||
requestBody: {
|
||||
required: true,
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: dataEnvelope(
|
||||
measurementReminderDto,
|
||||
"MeasurementReminderCreatedEnvelope",
|
||||
),
|
||||
},
|
||||
"application/json": { schema: createMeasurementReminderSchema },
|
||||
},
|
||||
},
|
||||
...stdResponses,
|
||||
},
|
||||
},
|
||||
},
|
||||
"/api/measurement-reminders/{id}": {
|
||||
get: {
|
||||
tags: ["MeasurementReminders"],
|
||||
summary: "Read a single Vorsorge reminder (v1.17.1)",
|
||||
description: "Owner-scoped; a cross-user or tombstoned id 404s.",
|
||||
requestParams: { path: z.object({ id: z.string() }) },
|
||||
responses: {
|
||||
"200": {
|
||||
description: "The reminder.",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: dataEnvelope(
|
||||
measurementReminderDto,
|
||||
"MeasurementReminderEnvelope",
|
||||
),
|
||||
responses: {
|
||||
"201": {
|
||||
description: "Reminder created.",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: dataEnvelope(
|
||||
measurementReminderDto,
|
||||
"MeasurementReminderCreatedEnvelope",
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
...stdResponses,
|
||||
},
|
||||
...reminderNotFound,
|
||||
...stdResponses,
|
||||
},
|
||||
},
|
||||
patch: {
|
||||
tags: ["MeasurementReminders"],
|
||||
summary: "Edit a Vorsorge reminder (v1.17.1)",
|
||||
description:
|
||||
"Partial edit; omitted fields are left untouched. nextDueAt is recomputed server-side after the cadence merge. Owner-scoped.",
|
||||
requestParams: { path: z.object({ id: z.string() }) },
|
||||
requestBody: {
|
||||
required: true,
|
||||
content: {
|
||||
"application/json": { schema: updateMeasurementReminderSchema },
|
||||
},
|
||||
},
|
||||
responses: {
|
||||
"200": {
|
||||
description: "Reminder updated.",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: dataEnvelope(
|
||||
measurementReminderDto,
|
||||
"MeasurementReminderPatchEnvelope",
|
||||
),
|
||||
"/api/measurement-reminders/{id}": {
|
||||
get: {
|
||||
tags: ["MeasurementReminders"],
|
||||
summary: "Read a single Vorsorge reminder (v1.17.1)",
|
||||
description: "Owner-scoped; a cross-user or tombstoned id 404s.",
|
||||
requestParams: { path: z.object({ id: z.string() }) },
|
||||
responses: {
|
||||
"200": {
|
||||
description: "The reminder.",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: dataEnvelope(
|
||||
measurementReminderDto,
|
||||
"MeasurementReminderEnvelope",
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
...reminderNotFound,
|
||||
...stdResponses,
|
||||
},
|
||||
...reminderNotFound,
|
||||
...stdResponses,
|
||||
},
|
||||
},
|
||||
delete: {
|
||||
tags: ["MeasurementReminders"],
|
||||
summary: "Soft-delete a Vorsorge reminder (v1.17.1)",
|
||||
description: "Sets deletedAt (tombstone). Idempotent. Owner-scoped.",
|
||||
requestParams: { path: z.object({ id: z.string() }) },
|
||||
responses: {
|
||||
"200": {
|
||||
description: "Soft-deleted.",
|
||||
patch: {
|
||||
tags: ["MeasurementReminders"],
|
||||
summary: "Edit a Vorsorge reminder (v1.17.1)",
|
||||
description:
|
||||
"Partial edit; omitted fields are left untouched. nextDueAt is recomputed server-side after the cadence merge. Owner-scoped.",
|
||||
requestParams: { path: z.object({ id: z.string() }) },
|
||||
requestBody: {
|
||||
required: true,
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: dataEnvelope(
|
||||
z.object({ deleted: z.boolean() }),
|
||||
"MeasurementReminderDeleteEnvelope",
|
||||
),
|
||||
},
|
||||
"application/json": { schema: updateMeasurementReminderSchema },
|
||||
},
|
||||
},
|
||||
...reminderNotFound,
|
||||
...stdResponses,
|
||||
},
|
||||
},
|
||||
},
|
||||
"/api/measurement-reminders/{id}/satisfy": {
|
||||
post: {
|
||||
tags: ["MeasurementReminders"],
|
||||
summary: "Mark a Vorsorge reminder done (v1.17.1)",
|
||||
description:
|
||||
"Manual 'Erledigt': stamps lastSatisfiedAt = now and recomputes nextDueAt past now. Free-text reminders resolve only through this path; typed reminders also auto-resolve in the cron when a matching reading lands.",
|
||||
requestParams: { path: z.object({ id: z.string() }) },
|
||||
responses: {
|
||||
"200": {
|
||||
description: "Reminder satisfied; next-due re-anchored.",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: dataEnvelope(
|
||||
measurementReminderDto,
|
||||
"MeasurementReminderSatisfyEnvelope",
|
||||
),
|
||||
responses: {
|
||||
"200": {
|
||||
description: "Reminder updated.",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: dataEnvelope(
|
||||
measurementReminderDto,
|
||||
"MeasurementReminderPatchEnvelope",
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
...reminderNotFound,
|
||||
...stdResponses,
|
||||
},
|
||||
...reminderNotFound,
|
||||
...stdResponses,
|
||||
},
|
||||
},
|
||||
},
|
||||
"/api/measurement-reminders/{id}/complete": {
|
||||
post: {
|
||||
tags: ["MeasurementReminders"],
|
||||
summary: "Complete a Vorsorge reminder (v1.18.6)",
|
||||
description:
|
||||
"Explicit user-action completion (iOS #23): the app marks a reminder done server-side instead of only dismissing it locally. Routes through the same satisfaction primitive as the cron auto-resolve — stamps lastSatisfiedAt = now, re-anchors nextDueAt, fires no notification. Idempotent: completing an already-completed / auto-satisfied reminder returns 200 with completed=false. Owner-scoped.",
|
||||
requestParams: { path: z.object({ id: z.string() }) },
|
||||
responses: {
|
||||
"200": {
|
||||
description:
|
||||
"Completion applied (completed=true) or already-satisfied no-op (completed=false); reminder carries the canonical post-completion DTO.",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: dataEnvelope(
|
||||
measurementReminderCompletionDto,
|
||||
"MeasurementReminderCompleteEnvelope",
|
||||
),
|
||||
delete: {
|
||||
tags: ["MeasurementReminders"],
|
||||
summary: "Soft-delete a Vorsorge reminder (v1.17.1)",
|
||||
description: "Sets deletedAt (tombstone). Idempotent. Owner-scoped.",
|
||||
requestParams: { path: z.object({ id: z.string() }) },
|
||||
responses: {
|
||||
"200": {
|
||||
description: "Soft-deleted.",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: dataEnvelope(
|
||||
z.object({ deleted: z.boolean() }),
|
||||
"MeasurementReminderDeleteEnvelope",
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
...reminderNotFound,
|
||||
...stdResponses,
|
||||
},
|
||||
...reminderNotFound,
|
||||
...stdResponses,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
"/api/measurement-reminders/{id}/satisfy": {
|
||||
post: {
|
||||
tags: ["MeasurementReminders"],
|
||||
summary: "Mark a Vorsorge reminder done (v1.17.1)",
|
||||
description:
|
||||
"Manual 'Erledigt': stamps lastSatisfiedAt = now and recomputes nextDueAt past now. Free-text reminders resolve only through this path; typed reminders also auto-resolve in the cron when a matching reading lands.",
|
||||
requestParams: { path: z.object({ id: z.string() }) },
|
||||
responses: {
|
||||
"200": {
|
||||
description: "Reminder satisfied; next-due re-anchored.",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: dataEnvelope(
|
||||
measurementReminderDto,
|
||||
"MeasurementReminderSatisfyEnvelope",
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
...reminderNotFound,
|
||||
...stdResponses,
|
||||
},
|
||||
},
|
||||
},
|
||||
"/api/measurement-reminders/{id}/complete": {
|
||||
post: {
|
||||
tags: ["MeasurementReminders"],
|
||||
summary: "Complete a Vorsorge reminder (v1.18.6)",
|
||||
description:
|
||||
"Explicit user-action completion (iOS #23): the app marks a reminder done server-side instead of only dismissing it locally. Routes through the same satisfaction primitive as the cron auto-resolve — stamps lastSatisfiedAt = now, re-anchors nextDueAt, fires no notification. Idempotent: completing an already-completed / auto-satisfied reminder returns 200 with completed=false. Owner-scoped.",
|
||||
requestParams: { path: z.object({ id: z.string() }) },
|
||||
responses: {
|
||||
"200": {
|
||||
description:
|
||||
"Completion applied (completed=true) or already-satisfied no-op (completed=false); reminder carries the canonical post-completion DTO.",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: dataEnvelope(
|
||||
measurementReminderCompletionDto,
|
||||
"MeasurementReminderCompleteEnvelope",
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
...reminderNotFound,
|
||||
...stdResponses,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -254,7 +254,9 @@ const sleepDebtResource = z.object({
|
||||
.number()
|
||||
.int()
|
||||
.nonnegative()
|
||||
.describe("Nights still needed before the debt is asserted (0 when ready)."),
|
||||
.describe(
|
||||
"Nights still needed before the debt is asserted (0 when ready).",
|
||||
),
|
||||
});
|
||||
|
||||
const chronotypeBandEnum = z.enum([
|
||||
@@ -350,7 +352,9 @@ const seriesQuerySchema = z.object({
|
||||
});
|
||||
|
||||
const seriesPointSchema = z.object({
|
||||
id: z.string().describe("Measurement row id, or `sleep:<wake-day>` for a sleep night."),
|
||||
id: z
|
||||
.string()
|
||||
.describe("Measurement row id, or `sleep:<wake-day>` for a sleep night."),
|
||||
at: z.iso.datetime({ offset: true }).describe("Point timestamp (ISO-8601)."),
|
||||
value: z.number().describe("Primary value in the top-level `unit`."),
|
||||
secondary: z
|
||||
@@ -475,7 +479,10 @@ export const measurementPaths: NonNullable<ZodOpenApiObject["paths"]> = {
|
||||
description: "Resolved series.",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: dataEnvelope(seriesResponse, "GetMeasurementsSeriesResponse"),
|
||||
schema: dataEnvelope(
|
||||
seriesResponse,
|
||||
"GetMeasurementsSeriesResponse",
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -298,13 +298,13 @@ const medicationInventoryItemResource = z
|
||||
.number()
|
||||
.nullable()
|
||||
.describe(
|
||||
"Units the container shipped with (tablets / ampoules / puffs; 1–1000). v1.16.12 — fractional, so a split-pill remainder reads cleanly. Dose-derived readouts divide by the medication's `unitsPerDose`. v1.18.3 (iOS#31) — NULL when the unit count is unknown (a corrupt or legacy row); the client renders \"unknown\", never a fabricated 0.",
|
||||
'Units the container shipped with (tablets / ampoules / puffs; 1–1000). v1.16.12 — fractional, so a split-pill remainder reads cleanly. Dose-derived readouts divide by the medication\'s `unitsPerDose`. v1.18.3 (iOS#31) — NULL when the unit count is unknown (a corrupt or legacy row); the client renders "unknown", never a fabricated 0.',
|
||||
),
|
||||
unitsRemaining: z
|
||||
.number()
|
||||
.nullable()
|
||||
.describe(
|
||||
"Units left in the container. v1.16.12 — fractional (a ½-tablet dose leaves 29.5 of 30). Decremented by the intake consumption hook (FEFO with spillover across containers); refunded when a taken dose is skipped, edited away, or deleted. v1.18.3 (iOS#31) — NULL when the count is unknown (a corrupt or legacy row); the client renders \"unknown\", never a fabricated 0 it could decrement into negatives.",
|
||||
'Units left in the container. v1.16.12 — fractional (a ½-tablet dose leaves 29.5 of 30). Decremented by the intake consumption hook (FEFO with spillover across containers); refunded when a taken dose is skipped, edited away, or deleted. v1.18.3 (iOS#31) — NULL when the count is unknown (a corrupt or legacy row); the client renders "unknown", never a fabricated 0 it could decrement into negatives.',
|
||||
),
|
||||
firstUseAt: z.iso
|
||||
.datetime({ offset: true })
|
||||
@@ -627,7 +627,9 @@ const scheduleRevisionEntrySummary = z
|
||||
dose: z.string().nullable(),
|
||||
scheduleType: z
|
||||
.string()
|
||||
.describe("Schedule-type discriminator of the archived row (SCHEDULED / PRN / CYCLIC)."),
|
||||
.describe(
|
||||
"Schedule-type discriminator of the archived row (SCHEDULED / PRN / CYCLIC).",
|
||||
),
|
||||
})
|
||||
.meta({
|
||||
id: "ScheduleRevisionEntry",
|
||||
@@ -638,12 +640,12 @@ const scheduleRevisionEntrySummary = z
|
||||
const scheduleRevisionResource = z
|
||||
.object({
|
||||
id: z.string(),
|
||||
validFrom: z.iso
|
||||
.datetime()
|
||||
.describe("Inclusive start instant of the era."),
|
||||
validFrom: z.iso.datetime().describe("Inclusive start instant of the era."),
|
||||
validUntil: z.iso
|
||||
.datetime()
|
||||
.describe("Exclusive end instant of the era — the moment the next plan took over."),
|
||||
.describe(
|
||||
"Exclusive end instant of the era — the moment the next plan took over.",
|
||||
),
|
||||
source: z
|
||||
.enum(["ARCHIVED", "MANUAL"])
|
||||
.describe(
|
||||
|
||||
@@ -85,7 +85,9 @@ const moodTagDto = z
|
||||
archived: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe("Custom tags only, present when `include` contains `archived`."),
|
||||
.describe(
|
||||
"Custom tags only, present when `include` contains `archived`.",
|
||||
),
|
||||
usageCount: z
|
||||
.number()
|
||||
.int()
|
||||
|
||||
@@ -36,7 +36,9 @@ const tourUpdateRequest = z
|
||||
.describe("Informational — distinguishes reaching the end from a skip."),
|
||||
progress: tourProgressResource
|
||||
.optional()
|
||||
.describe("Mid-tour resume checkpoint. May arrive alone or with `completed`."),
|
||||
.describe(
|
||||
"Mid-tour resume checkpoint. May arrive alone or with `completed`.",
|
||||
),
|
||||
})
|
||||
.meta({
|
||||
id: "TourUpdateRequest",
|
||||
@@ -51,7 +53,8 @@ const tourUpdateResponse = z
|
||||
})
|
||||
.meta({
|
||||
id: "TourUpdateResponse",
|
||||
description: "The persisted completion flag and resume point after the write.",
|
||||
description:
|
||||
"The persisted completion flag and resume point after the write.",
|
||||
});
|
||||
|
||||
const disclaimerAckRequest = z
|
||||
@@ -66,7 +69,8 @@ const disclaimerAckRequest = z
|
||||
})
|
||||
.meta({
|
||||
id: "DisclaimerAckRequest",
|
||||
description: "Acknowledge the one-time medical disclaimer shown at onboarding.",
|
||||
description:
|
||||
"Acknowledge the one-time medical disclaimer shown at onboarding.",
|
||||
});
|
||||
|
||||
const disclaimerAckResponse = z
|
||||
|
||||
@@ -102,7 +102,7 @@ const notificationPrefsResolved = z
|
||||
deliveryDefault: z
|
||||
.enum(["server", "client"])
|
||||
.describe(
|
||||
"Roaming user-level delivery default. \"client\" implies clientManaged: true.",
|
||||
'Roaming user-level delivery default. "client" implies clientManaged: true.',
|
||||
),
|
||||
lowStockRunwayDays: z
|
||||
.number()
|
||||
@@ -731,7 +731,7 @@ export const profilePaths: NonNullable<ZodOpenApiObject["paths"]> = {
|
||||
tags: ["Notifications"],
|
||||
summary: "Update per-user notification preferences",
|
||||
description:
|
||||
"Deep-merges the supplied partial shape over the persisted row — a PATCH touching only one category leaves the siblings intact. Always returns the fully-resolved next state so clients can hard-set their optimistic update. `medication.clientManaged: true` (or `deliveryDefault: \"client\"`) suppresses server-side MEDICATION_REMINDER APNs; `medication.lowStockRunwayDays` (1–60, nullable, default 7) tunes the low-stock alert — null switches it off. Rate-limit 60/min per user.",
|
||||
'Deep-merges the supplied partial shape over the persisted row — a PATCH touching only one category leaves the siblings intact. Always returns the fully-resolved next state so clients can hard-set their optimistic update. `medication.clientManaged: true` (or `deliveryDefault: "client"`) suppresses server-side MEDICATION_REMINDER APNs; `medication.lowStockRunwayDays` (1–60, nullable, default 7) tunes the low-stock alert — null switches it off. Rate-limit 60/min per user.',
|
||||
requestBody: {
|
||||
required: true,
|
||||
content: {
|
||||
|
||||
Reference in new issue
Block a user