mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-11 05:42:19 +00:00
Publish the vaccination booster mint and upload suggestion
The iOS tracker was told both endpoints were in the spec; neither was
registered. Publish POST /api/vaccinations/{id}/booster (201 mint /
200 re-anchor with the resolved MeasurementReminder DTO) and
GET /api/vaccinations/suggest (the server-decided one/many/none
verdict), and regenerate the YAML. A structural guard now derives the
expected path set from the route files so the next vaccination route
cannot ship unpublished.
This commit is contained in:
1 parent
cb86b24c0d
commit
0cec8b07bd
3 files changed
+390
No files matched your search
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Every vaccination route that exists on disk is published in the
|
||||
* OpenAPI route table.
|
||||
*
|
||||
* The iOS tracker was told the booster mint and the upload suggestion
|
||||
* were in the spec while neither was registered — the one false
|
||||
* statement to the client. This guard recomputes the expected path set
|
||||
* from the route files themselves, so the next vaccination route
|
||||
* cannot ship unpublished either.
|
||||
*
|
||||
* Watched red: with the `/api/vaccinations/{id}/booster` and
|
||||
* `/api/vaccinations/suggest` entries removed from `vaccinationPaths`
|
||||
* this fails naming both paths — the exact pre-fix state.
|
||||
*/
|
||||
import { readdirSync, statSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { vaccinationPaths } from "../routes/vaccinations";
|
||||
|
||||
const ROUTE_ROOT = join(__dirname, "../../../app/api/vaccinations");
|
||||
|
||||
/** Collect every route.ts under the vaccinations API tree as a spec path. */
|
||||
function collectRoutePaths(dir: string, urlPrefix: string): string[] {
|
||||
const found: string[] = [];
|
||||
for (const entry of readdirSync(dir)) {
|
||||
const full = join(dir, entry);
|
||||
if (statSync(full).isDirectory()) {
|
||||
// Next dynamic segment `[id]` publishes as `{id}`.
|
||||
const segment = entry.replace(/^\[(.+)\]$/, "{$1}");
|
||||
found.push(...collectRoutePaths(full, `${urlPrefix}/${segment}`));
|
||||
} else if (entry === "route.ts") {
|
||||
found.push(urlPrefix);
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
describe("vaccination route publication", () => {
|
||||
it("publishes every vaccination route file", () => {
|
||||
const expected = collectRoutePaths(ROUTE_ROOT, "/api/vaccinations").sort();
|
||||
// Self-check: the walker found the tree (an empty set proves nothing).
|
||||
expect(expected.length).toBeGreaterThanOrEqual(6);
|
||||
const published = Object.keys(vaccinationPaths).sort();
|
||||
const missing = expected.filter((p) => !published.includes(p));
|
||||
expect(
|
||||
missing,
|
||||
"vaccination route files without an OpenAPI path entry — register them in src/lib/openapi/routes/vaccinations.ts and run pnpm openapi:generate",
|
||||
).toEqual([]);
|
||||
});
|
||||
|
||||
it("publishes the booster mint and the upload suggestion with their verbs", () => {
|
||||
expect(
|
||||
vaccinationPaths["/api/vaccinations/{id}/booster"]?.post,
|
||||
).toBeDefined();
|
||||
expect(vaccinationPaths["/api/vaccinations/suggest"]?.get).toBeDefined();
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user