You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 54ace6a
Browse filesBrowse the repository at this point in the historyBrowse files
fix(client): `packages.get` binds the bare `InstalledPackage` row on both the global and the environment-scoped client, replacing a `{ package }` envelope no surface emits (#12034)
6
+
7
+
`client.packages.get(id)` and `ScopedEnvironmentClient.packages.get(id)` now resolve to **`InstalledPackage`** — the row itself — instead of an object wrapping it.
8
+
9
+
**Migration — read the row directly, not `.package`:**
FROM `{ package: any }` (global) and `{ package: InstalledPackage }` (scoped) TO `InstalledPackage` on both.
22
+
23
+
This is a **narrowing**: a `.package` read compiles today and stops compiling after this change. That is the point of the change rather than a side effect of it — the wrapper was never what the wire sent, so every one of those reads was already `undefined` at runtime, and on the global method the `any` member is what kept the falsehood invisible. Nothing about the request or the wire changes; only the declaration moves to match what the server has been sending.
24
+
25
+
Why it can be bound now, when #11925 deliberately left it erased: this route used to be served by two implementations that disagreed — the runtime dispatcher sent the bare row, the `@objectstack/rest` registrar sent `{ package }` — so no declaration was true on both. The registrar's read routes were removed in #16628, leaving the dispatcher's `/packages` domain as the single implementation. It builds the detail body with the same expression it maps over every `list` row, which is why this type now agrees with the `InstalledPackage[]` that `packages.list` has already declared, and with `GetInstalledPackageResponseSchema` in `@objectstack/spec`, which has declared `data: InstalledPackageSchema` all along.
26
+
27
+
The environment-scoped method is the sharper half of the change: its member was a real `InstalledPackage`, not `any`, so `.package` reads there looked type-safe while returning `undefined` against every surface that has served that path since #16628.
fix(rest): `/discovery` no longer contradicts itself — `services.*.route` follows the mounted paths, like `routes.*` already did (#16674)
6
+
7
+
The `/discovery` document states each service's address twice: once in `routes.X` (the flat convenience map) and once in `services.Y.route` (the per-slot entry). The REST discovery handler rewrote only the first half to the paths this server actually mounts, so any deployment that moved a prefix received a document that disagreed with itself — and the `services` half pointed at a path with nothing mounted on it.
8
+
9
+
Measured on a boot with `crud: { dataPrefix: '/objects' }`, reading `GET /api/v1/discovery`:
10
+
11
+
- before — `routes.data` = `/api/v1/objects` (the mounted path), `services.data.route` = `/api/v1/data` (unmounted)
12
+
- after — both answer `/api/v1/objects`
13
+
14
+
The same split opened on four keys at once for an `apiPath` deployment: `data`, `metadata`, `ui` and `auth`. All four now follow the mount. `services.*.route` is written as a projection of the finished `routes` map, so the two halves cannot state different answers whatever a future substitution does to `routes`.
15
+
16
+
**A default deployment's document does not move by a byte.** With `crud.dataPrefix` at its `/data` default and `metadata.prefix` at `/meta`, the values the correction writes are the values that were already there; only a deployment that had moved a prefix sees a change, and there the old value addressed nothing. Route-less slots (`cache`, `queue`, `job`, and an in-process `realtime` bus) never gain a route, and no advertisement is withdrawn.
17
+
18
+
If you have been reading `services.data.route` on a moved-prefix deployment and compensating for it — by re-deriving the path from `routes.data`, or by hard-coding the prefix — that workaround can go: the field now answers the mounted path directly.
feat(cli)!: `os generate` refuses a metadata name outside the charset `packages/spec` declares for an object `name`, before it derives anything from it (#16726)
6
+
7
+
Maintainer ruling, decision batch #82 (2026-09-08), option A — **a gate, not a sanitiser**. `os generate <type> <name>` used to accept any name at all; since #16724 it has refused names whose emitted TypeScript does not parse. It now also refuses, ahead of that check and ahead of every derivation, any name the object-`name` declaration in `@objectstack/spec` rejects. The refusal names the value and quotes the schema's own rule, and writes nothing.
8
+
9
+
⛔ Nothing is rewritten. The rejected alternative was to derive a legal identifier the way `os create` does, which decouples the name the author wrote from the name that gets emitted with nothing announcing it — the failure mode that multiplies silently when metadata is written in bulk. So the name you author and the name that lands in the file are always the same string.
10
+
11
+
**What this narrows:** kebab-case (`order-line`), uppercase (`Order`), dotted (`foo.bar`) and digit-initial (`2fast`) names were accepted before and are refused now — `order-line` used to generate `order_line.object.ts` binding `orderLine`. Write the snake_case name directly (`os g object order_line`). ⛔ No new charset was minted and no flag bypasses the gate; #16724's parse check is unchanged and stays as the backstop behind it (`class` passes the charset and is still refused for `object`, because `const class:` is not a declaration).
12
+
13
+
<!-- adr-0087: not-required (no-migration-prescription) Nothing authorable or stored moves. No `packages/spec` key, no Zod schema, no authored metadata property and no stored `sys_metadata` shape changes its spelling, type or legality — the charset this gate applies is the one spec ALREADY declares for an object `name`, read rather than redeclared — so `objectstack migrate meta` has nothing to visit, `spec-changes.json` has nothing to project and the upgrade guide has no row to gain. What moves is which ARGUMENT a scaffolding command accepts at authoring time; a name it now refuses was never a legal object `name` in the first place, so no metadata written from an accepted name needs conversion, and files already scaffolded from a refused name are untouched by this change. The remedy is to type a name spec accepts, delivered by the command's own loud refusal at the terminal and by this changelog — the source-code / invocation-side audience the ledger explicitly does not serve (ADR-0087 D8). The other four categories are closed on facts: `@objectstack/cli` publishes to npm (not `unpublished`); no ADR-0087 id is minted in this diff (not `registered`) and none pre-dates the base that would cover it (not `already-registered`); no exported declaration changes shape at all — the gate is a file-local function absent from the package entry — so neither `runtime-interface-only` nor `type-surface-only` has a subject. -->
fix(plugin-hono-server): an escaped throw that declares an ADR-0112 envelope is answered as that envelope, not as a bare `500 INTERNAL_ERROR "No response from handler"` (#16545)
6
+
7
+
`HonoHttpServer.wrap()` is the seam **every direct-mount route passes** — `get` /
8
+
`post` / `put` / `delete` / `patch` each register `this.wrap(handler)`, and
9
+
`IHttpServer` is how `service-datasource`, `packages/rest` and the dispatcher
10
+
bridge all mount. Until now a throw that escaped a route handler was answered
11
+
there as `500 { code: 'INTERNAL_ERROR', message: 'No response from handler' }`,
12
+
with the thrown value discarded — so a producer that had *declared* its refusal
13
+
lost both halves of the declaration on the way to the caller.
14
+
15
+
The measured case: `service-datasource`'s `requireDatasourceAdmin` re-raises
0 commit comments