|
| 1 | +--- |
| 2 | +'@objectstack/rest': minor |
| 3 | +'@objectstack/runtime': patch |
| 4 | +--- |
| 5 | + |
| 6 | +fix(rest, runtime): the runtime dispatcher's `/meta` doors scope a caller to the organization `RestServer` scopes them to, and its item read, book tree and list answer what `RestServer`'s answer (#20408) |
| 7 | + |
| 8 | +Clause-②: yes (widening) — `@objectstack/rest`'s root entry gains seven value exports (`createMetaItemAnswer`, `createMetaBookTreeAnswer`, `metaCallerOrganizationId`, `metaReadOrganizationId`, `projectMetaObjectSchema`, `refuseUnknownMetaListType`, `translateMetaEnvelope`) and five type exports (`MetaItemAnswer`, `MetaItemAnswerSources`, `MetaItemRequest`, `MetaBookTreeAnswer`, `MetaBookTreeSources`), and `MetaListAnswer` gains an optional `cacheControl`. `MetaListAnswerSources`, new in this same release with `createMetaListAnswer`, takes the transport's object-schema masker (`resolveObjectMasker`) instead of a whole-mask port, so the chain decides the cache posture for both transports. Nothing any published version exported is removed, renamed or narrowed. `@objectstack/runtime` publishes no new surface and stays a `patch`. |
| 9 | + |
| 10 | +A host that mounts only the `${prefix}/*` catch-all (`createHonoApp`, and any |
| 11 | +adapter written on the public `HttpDispatcher` API) serves `/meta` through the |
| 12 | +runtime dispatcher. Until now, on such a host: |
| 13 | + |
| 14 | +- **A member removed from an organization kept its metadata partition.** The |
| 15 | + dispatcher's `/meta` doors took the organization from the session's |
| 16 | + `activeOrganizationId` as stored. Under a wall-enforcing tenancy posture the |
| 17 | + identity resolver DROPS a claim naming an organization the caller no longer |
| 18 | + belongs to, and `RestServer` reads that vetted value. The dispatcher did not, |
| 19 | + so for the rest of the session the removed member was served that |
| 20 | + organization's org-scoped overlays (`view`, `dashboard`, `report`, |
| 21 | + `translation`, `email_template`) by the item read, the list, `/published` and |
| 22 | + `?state=draft`, listed its pending drafts on `GET /meta/_drafts`, and had a |
| 23 | + `PUT /meta/:type/:name` land in its partition. Every `/meta` door here now reads |
| 24 | + the vetted organization on the execution context, the value `RestServer` reads. |
| 25 | +- **`GET /meta/:type/:name` answered a different body.** Nothing was translated |
| 26 | + whatever `Accept-Language` or `?locale=` asked for. A doc kept its whole |
| 27 | + `translations` map, in no locale. An object schema came with no |
| 28 | + `sortability`. The answer had no `Vary: Accept-Language`. |
| 29 | +- **`?preview=DRAFT`** (any casing but lower) from a builder read the published |
| 30 | + world on the item read and the list. `RestServer` compares it |
| 31 | + case-insensitively. |
| 32 | +- **`GET /meta/object/:name?preview=draft`** from a builder answered the ACTIVE |
| 33 | + schema, never the pending draft. |
| 34 | +- **`GET /meta/totally_invented_type`** answered `200 {"items": []}`. `RestServer` |
| 35 | + refuses a segment that names no metadata type with `400 INVALID_REQUEST`. |
| 36 | +- **`GET /meta/book/:name/tree`** was no route: `404 ROUTE_NOT_FOUND` to a signed-in |
| 37 | + reader and `401` to an anonymous reader of a `public` book (ADR-0046 §6.7). |
| 38 | +- **An object schema served under an undetermined field visibility** (ADR-0106 |
| 39 | + D6 tier 2: served unmasked) carried no `Cache-Control`. `RestServer` answers |
| 40 | + `private, no-store`. This was true of the list, the item read, `/published` and |
| 41 | + the legacy one-segment object read. |
| 42 | + |
| 43 | +**What changed.** Everything `RestServer`'s `GET /meta/:type/:name` does after |
| 44 | +the store read moved, unchanged, into `createMetaItemAnswer`: absence, the item |
| 45 | +gate, the doc locale collapse, the object mask and its cache posture, and the |
| 46 | +body (the translation and `sortability`, `translateMetaEnvelope`). The book-tree |
| 47 | +route's whole answer moved into `createMetaBookTreeAnswer`, and the list's |
| 48 | +unknown-type refusal into `refuseUnknownMetaListType`. The list chain now |
| 49 | +applies the object mask itself (`projectMetaObjectSchema`) and reports the cache |
| 50 | +posture. The dispatcher's `/meta` domain calls each of these, and takes its |
| 51 | +organization from `metaCallerOrganizationId` / `metaReadOrganizationId`, which |
| 52 | +`RestServer`'s list and item reads ask too. |
| 53 | + |
| 54 | +`RestServer`'s own answers are unchanged: the move is a refactor on that side, |
| 55 | +and every existing REST test passes unedited. |
0 commit comments