|
| 1 | +--- |
| 2 | +'@objectstack/spec': minor |
| 3 | +'@objectstack/rest': minor |
| 4 | +--- |
| 5 | + |
| 6 | +feat(spec,rest)!: the served OpenAPI `info` carries the publisher's `api.documentation` identity; `api.documentation.version` retired (#20294) |
| 7 | + |
| 8 | +Clause-②: yes (narrowing) |
| 9 | + |
| 10 | +**BREAKING** — shipped as `minor` under the launch-window convention |
| 11 | +(`check-changeset-no-major` refuses `major` until GA; breaking-ness is carried by |
| 12 | +this banner, the `(narrowing)` arm above and the ADR-0087 disposition below, |
| 13 | +never by the level). The breaking half is one key: `api.documentation.version`. |
| 14 | + |
| 15 | +`RestServerConfig.api.documentation` (`RestApiConfigSchema`) declared nine |
| 16 | +members, and `RestServer` parsed them, copied them into its config — and never |
| 17 | +read them back. Measured before this change, with every member authored: both |
| 18 | +doors that serve the OpenAPI document (`{apiPath}/openapi.json` and its |
| 19 | +environment-scoped twin) answered the bundled artifact's `info` unchanged, 0 of 9 |
| 20 | +honoured. ADR-0049 enforce-or-remove, split by who owns each field: |
| 21 | + |
| 22 | +- **Enforced — the publisher's identity.** `title`, `description`, |
| 23 | + `termsOfService`, `contact` (`name` / `url` / `email`) and `license` (`name` / |
| 24 | + `url`) now overlay the served `info` on both doors. A member you leave unset |
| 25 | + keeps the bundled value, and a config with nothing authored — no block, |
| 26 | + `documentation: {}` — serves `info` byte-identical to |
| 27 | + `@objectstack/spec/openapi.json`, exactly as before. `contact` and `license` |
| 28 | + replace the bundled object **whole**: `license: { name: 'MIT' }` serves |
| 29 | + `{ name: 'MIT' }` with no URL, never MIT at the bundled Apache-2.0 URL, and a |
| 30 | + partial `contact` never keeps ObjectStack's name or URL. |
| 31 | +- **Retired — `documentation.version`.** The served `info.version` is the |
| 32 | + protocol version, the version of the `@objectstack/spec` package that generated |
| 33 | + the document, with no configured override: an earlier ruling made it equal the |
| 34 | + published artifact's so an integrator can read which protocol version they are |
| 35 | + talking to. A publisher-set version would give the field a third meaning, so |
| 36 | + the key is now refused. |
| 37 | + |
| 38 | +``` |
| 39 | +FROM new RestServer(server, protocol, { api: { documentation: { title: 'Acme Orders API', version: '2.3.0' } } }) |
| 40 | + -> constructed; GET /api/v1/openapi.json served info.title 'ObjectStack REST API' |
| 41 | + and info.version = the spec version — both authored values ignored |
| 42 | +TO -> throws: REST API configuration is invalid: `api` does not satisfy |
| 43 | + `RestApiConfigSchema` … |
| 44 | + - api.documentation.version: `api.documentation.version` was removed in |
| 45 | + @objectstack/spec 17.5.0 (ADR-0049 enforce-or-remove) — … Delete the key. To publish |
| 46 | + your app's own release number, write it into `api.documentation.description`, … |
| 47 | +
|
| 48 | +FROM new RestServer(server, protocol, { api: { documentation: { title: 'Acme Orders API' } } }) |
| 49 | + -> GET /api/v1/openapi.json: info.title 'ObjectStack REST API' |
| 50 | +TO -> GET /api/v1/openapi.json: info.title 'Acme Orders API' (and on the environment-scoped door) |
| 51 | +
|
| 52 | +FROM RestApiConfigSchema.parse({ documentation: { description: 'd' } }).documentation |
| 53 | + -> { title: 'ObjectStack API', description: 'd' } // a default no document ever served |
| 54 | +TO -> { description: 'd' } |
| 55 | +``` |
| 56 | + |
| 57 | +**Fix.** `api.documentation.version` → delete the key. The served |
| 58 | +`info.version` is always the protocol version; to publish your app's own release |
| 59 | +number, write it into `api.documentation.description`. `tsc` refuses the key at |
| 60 | +the authoring site (its input type is `never`), and `RestServer` construction and |
| 61 | +the REST plugin's `start` refuse it with that prescription. |
| 62 | + |
| 63 | +**What else changes.** `documentation.title` is `.optional()` instead of |
| 64 | +`.default('ObjectStack API')`: that default was materialized into every present |
| 65 | +block and never served, so the parsed block now carries exactly what was |
| 66 | +authored (the parsed `title` is typed `string | undefined` now). `api.version` (the route identifier) and the runtime version still |
| 67 | +never reach `info.version`. A host that authors none of these keys — every |
| 68 | +CLI-started deployment, since `os serve` forwards only `enableProjectScoping` |
| 69 | +and `projectResolution` — serves the same document as before. |
| 70 | + |
| 71 | +### The kit |
| 72 | + |
| 73 | +- **Schema.** The eight identity members carry describes naming the served |
| 74 | + `info` field; `version` is a `retiredKey()` tombstone inside the live |
| 75 | + `documentation` block (a non-strict `z.object()`, so a bare deletion would have |
| 76 | + stripped it in silence), next to the `enabled` tombstone. |
| 77 | +- **REST server.** `registerOpenApiEndpoints` builds `info` through a pure |
| 78 | + helper that returns a NEW object — the cached artifact's own `info` is never |
| 79 | + written — and the same handler serves both doors. |
| 80 | +- **ADR-0087.** `RETIRED_KEYS_BY_MAJOR[18]` gains |
| 81 | + `api/RestApiConfig:documentation.version`; the D3 entry |
| 82 | + `rest-api-documentation-version-retired` carries the prescription to |
| 83 | + `os migrate meta` and the upgrade guide. No D2 conversion: a `RestServerConfig` |
| 84 | + is plugin TS configuration, never a stack collection member or a stored row. |
| 85 | +- **Ledger and docs.** `liveness/rest_api.json`: the eight identity leaves and |
| 86 | + the `contact` / `license` containers flip to `live` with the overlay as |
| 87 | + evidence; the `version` row stays `dead` with a REMOVED note. The generated |
| 88 | + `state-counts.md` moves `rest_api` from 12 live / 12 dead to 20 / 4; the |
| 89 | + `rest-server` reference page is regenerated. |
| 90 | + |
| 91 | +<!-- adr-0087: registered rest-api-documentation-version-retired --> |
0 commit comments