|
| 1 | +--- |
| 2 | +"@objectstack/service-storage": patch |
| 3 | +"@objectstack/service-i18n": patch |
| 4 | +"@objectstack/client": patch |
| 5 | +--- |
| 6 | + |
| 7 | +fix(client,service-i18n): ledger the autonomously-mounted service routes, and repair the two i18n calls that reached nothing (#3636) |
| 8 | + |
| 9 | +Tranche 3 of the #3563 route audit — the last un-audited server surface. The |
| 10 | +dispatcher ledger (#3563) and the REST ledger (#3587) each stop at their own |
| 11 | +package boundary, and two services mount routes outside both: they reach for |
| 12 | +the `http-server` service and register straight on `IHttpServer`, so neither |
| 13 | +`RouteManager` nor `RestServer.getRoutes()` has ever seen them. That left the |
| 14 | +SDK's entire storage surface, plus all of i18n, in the pre-#3563 posture: |
| 15 | +expressed, working, guarded by nothing. |
| 16 | + |
| 17 | +**Ledgers + guards.** `storage-route-ledger.ts` (10 routes) and |
| 18 | +`i18n-route-ledger.ts` (3) sit next to the registrars that mount them, each |
| 19 | +enumerated for real — the registrar runs against a capturing mock |
| 20 | +`IHttpServer` and its registration calls *are* the route set, so a new route |
| 21 | +lands with a reviewed disposition or fails CI. The client half is |
| 22 | +`packages/client/src/service-route-ledger-coverage.test.ts`; ledgers cross the |
| 23 | +boundary as relative source imports, never a service→client package edge. |
| 24 | + |
| 25 | +**Two wire-level 404s fixed.** `i18n.getTranslations` sent |
| 26 | +`/i18n/translations?locale=xx` and `i18n.getFieldLabels` sent |
| 27 | +`/i18n/labels/:object?locale=xx`, while every serving surface — service-i18n's |
| 28 | +mounts, the dispatcher's HTTP mounts, and the `plugin-rest-api.zod.ts` |
| 29 | +contract — mounts only the path form. Neither call could ever be answered. |
| 30 | +Both had carried a green `sdk` row in the dispatcher ledger since tranche 1, |
| 31 | +because that guard asks whether the client *method* exists, not whether it |
| 32 | +speaks a URL anything mounts. The client now sends the path dialect, the same |
| 33 | +resolution #3611 gave `meta.getView`, and a new suite drives the real client |
| 34 | +at a real router so a revert cannot pass quietly. |
| 35 | + |
| 36 | +**One response-shape fix.** service-i18n's success bodies omitted the |
| 37 | +`success` flag that `ObjectStackClient.unwrapResponse` keys on, so the SDK |
| 38 | +returned the raw `{ data: … }` wrapper against that provider while returning |
| 39 | +the declared unwrapped shape against the dispatcher — one method, two shapes, |
| 40 | +decided by which plugin mounted the route. Its three handlers now emit the |
| 41 | +`{ success: true, data }` envelope the `i18n` route group declares. `data` did |
| 42 | +not move, so direct body readers are unaffected. |
| 43 | + |
| 44 | +Storage audited clean: 7 routes SDK-expressed, 3 reviewed `server-only` (the |
| 45 | +browser capability URL objectql stamps into file-field payloads, and the two |
| 46 | +local-driver loopbacks). The chunked-upload family, flagged for triage, turned |
| 47 | +out fully expressed. Both ledgers ratchet `gap` and `mismatch` at zero. |
| 48 | + |
| 49 | +Filed, not fixed: `GET {base}/_local/file/:key` is built by three call sites |
| 50 | +and mounted by none (#3641); the cross-surface URL conformance guard that would |
| 51 | +have caught all of the above mechanically is the capstone (#3642). |
0 commit comments