/** * OpenAPI route table — thin aggregation index. * * The route table is split into domain modules under this directory; * this index assembles them into the single `openApiPaths` object the * registry consumes. The spread order below is load-bearing: the YAML * emitter runs with `sortMapEntries: false` (see * `scripts/generate-openapi.ts`), so the key order of this object is * the path order of the committed `docs/api/openapi.yaml`. Keep the * spread sequence stable when adding a module — append inside the * domain module, not by reordering here. * * Schemas come from `src/lib/validations/*` so the wire contract stays * single-source-of-truth. The `.meta()` annotations on each schema land * the title + description in `components.schemas.*` automatically. * * Routes are intentionally registered as inline operation objects * rather than via a wrapping helper — `zod-openapi`'s `createDocument` * type-checks the route table directly, which catches schema-shape * regressions at typecheck time. */ import type { ZodOpenApiObject } from "zod-openapi"; import { adminDiagnosticPaths, adminInvitePaths } from "./admin"; import { allergyPaths } from "./allergies"; import { authPaths } from "./auth"; import { coachFeedbackPaths, coachPaths, coachReminderSuggestionPaths, coachReminderPaths, coachSuggestedActionPaths, } from "./coach"; import { consentPaths } from "./consent"; import { customMetricPaths } from "./custom-metrics"; import { dailyPaths } from "./daily"; import { cyclePaths } from "./cycle"; import { dashboardWidgetPaths } from "./dashboard"; import { biomarkerPaths } from "./biomarkers"; import { inboundDocumentPaths } from "./documents"; import { devicePaths } from "./devices"; import { exportPaths } from "./export"; import { familyHistoryPaths } from "./family-history"; import { healthRecordPaths } from "./health-record"; import { illnessPaths } from "./illness"; import { importPaths } from "./import"; import { insightsPaths } from "./insights"; import { integrationPaths } from "./integrations"; import { insightsSignalPaths } from "./insights-signals"; import { labsPaths } from "./labs"; import { ocrPaths } from "./ocr"; import { measurementPaths } from "./measurements"; import { measurementReminderPaths } from "./measurement-reminders"; import { mentalHealthPaths } from "./mental-health"; import { medicationPaths, medicationResource } from "./medications"; import { metaPaths } from "./meta"; import { moodPaths } from "./mood"; import { nutrientPaths } from "./nutrients"; import { onboardingPaths } from "./onboarding"; import { profilePaths } from "./profile"; import { settingsPaths } from "./settings"; import { syncPaths } from "./sync"; import { workoutPaths } from "./workouts"; export const openApiPaths: NonNullable = { ...cyclePaths, ...metaPaths, ...healthRecordPaths, ...exportPaths, ...authPaths, ...syncPaths, ...measurementPaths, ...workoutPaths, ...devicePaths, ...medicationPaths, ...profilePaths, ...coachPaths, ...coachReminderSuggestionPaths, ...coachReminderPaths, ...coachSuggestedActionPaths, ...adminInvitePaths, ...coachFeedbackPaths, ...adminDiagnosticPaths, ...insightsPaths, ...insightsSignalPaths, ...moodPaths, ...settingsPaths, ...consentPaths, ...importPaths, ...measurementReminderPaths, ...labsPaths, ...ocrPaths, ...biomarkerPaths, ...illnessPaths, ...mentalHealthPaths, ...allergyPaths, ...familyHistoryPaths, ...inboundDocumentPaths, ...customMetricPaths, ...onboardingPaths, // v1.28 — nutrient-intake sync (appended; spread order is load-bearing). ...nutrientPaths, // v1.28 — HealthKit integration config (appended; spread order is // load-bearing). ...integrationPaths, // v1.28 — the unified daily digest (P3 spine; appended, spread order is // load-bearing). ...dailyPaths, // v1.32.21 (R5a) — dashboard widget layout: previously absent from the // registry entirely, now documented as the reference optimistic-concurrency // contract (appended, spread order is load-bearing). ...dashboardWidgetPaths, }; export const openApiComponents: NonNullable = { // Schemas listed here are forced into `components.schemas` even when no // route references them directly. `Medication` lives in this slot // because its only consumers are the `MedicationListEntry` / // `MedicationDetail` variants which extend it — `.extend()` inlines // the base shape into the derived schema, so without an explicit // registration the standalone `Medication` component would never // emit. The iOS codegen reads from `Medication` directly for the // shared Swift struct backing both variants. schemas: { Medication: medicationResource, }, securitySchemes: { bearerAuth: { type: "http", scheme: "bearer", bearerFormat: "hlk_<64hex>", description: "Native-client API token. Use the `token` field returned by /api/auth/login on a native client.", }, cookieAuth: { type: "apiKey", in: "cookie", name: "healthlog_session", description: "Browser session cookie — set by /api/auth/login.", }, }, };