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:
Marc-André Bombeck committed 2026-06-19 22:20:31 +02:00
1 parent b3fea2ef59
commit 1f4ba5939d
1000 files changed
+12130 -8385

No files matched your search

+15 -11
View File
@@ -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",
+1 -4
View File
@@ -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"),
},
},
},
+2 -4
View File
@@ -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": {
+8 -2
View File
@@ -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",
),
},
},
},
+1 -5
View File
@@ -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({
+5 -7
View File
@@ -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({
+144 -145
View File
@@ -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,
},
},
},
};
+10 -3
View File
@@ -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",
),
},
},
},
+9 -7
View File
@@ -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(
+3 -1
View File
@@ -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()
+7 -3
View File
@@ -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
+2 -2
View File
@@ -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: {