|
| 1 | +--- |
| 2 | +"@objectstack/spec": patch |
| 3 | +"@objectstack/service-datasource": patch |
| 4 | +"@objectstack/rest": patch |
| 5 | +--- |
| 6 | + |
| 7 | +fix(service-datasource,rest)!: external-datasource refusals answer their own error code (#4249) |
| 8 | + |
| 9 | +#4225 / #4234 fixed the 503 `message` on the three routes in |
| 10 | +`service-datasource/admin-routes.ts` that dispatch to `external-datasource` |
| 11 | +rather than `datasource-admin`. The identical mis-attribution survived one field |
| 12 | +over, on the 400 path — and machine-readably: one shared `badRequest` helper |
| 13 | +hard-coded `DATASOURCE_ADMIN_ERROR`, which the ADR-0112 ledger defines as a |
| 14 | +refusal *from the datasource-admin service*. So a `no such schema` raised by the |
| 15 | +external-datasource introspector was reported as datasource-admin's, and where |
| 16 | +#4225 misled a human reading prose, this misrouted a client switching on |
| 17 | +`error.code`. |
| 18 | + |
| 19 | +`EXTERNAL_DATASOURCE_ERROR` is now registered in the error-code ledger — under |
| 20 | +`@objectstack/service-datasource` and `@objectstack/rest`, the two packages that |
| 21 | +emit it; per the ledger's own rule the per-package rows are provenance, not |
| 22 | +identity — and `badRequest` takes the same `ServiceName` the route passed to |
| 23 | +`resolve` (#4234), so the code, like the 503 message, comes from the service the |
| 24 | +route actually dispatches to. |
| 25 | + |
| 26 | +Wire-visible changes: |
| 27 | + |
| 28 | +- **The three external-datasource routes' 400 `error.code`** — |
| 29 | + `GET /datasources/:name/remote-tables`, `POST /datasources/:name/test`, |
| 30 | + `POST /datasources/:name/object-draft` — is now `EXTERNAL_DATASOURCE_ERROR` |
| 31 | + (was `DATASOURCE_ADMIN_ERROR`). Status, envelope, and `error.message` are |
| 32 | + unchanged, as is everything on the six datasource-admin routes. No consumer |
| 33 | + branches on the old code (grepped both repos, all the ADR-0112 sweep forms). |
| 34 | +- **The rest surface's two introspection routes now have a failure contract at |
| 35 | + all.** `GET /datasources/:name/external/tables` and |
| 36 | + `POST /datasources/:name/external/tables/:remote/draft` carried no |
| 37 | + `try`/`catch`, so the very same service operations that answer 400 through |
| 38 | + the admin surface surfaced here as the adapter's non-envelope |
| 39 | + `500 { error: 'No response from handler' }`. They now answer |
| 40 | + `400 EXTERNAL_DATASOURCE_ERROR` in the declared envelope — one operation, one |
| 41 | + failure contract, on both paths. (`EXTERNAL_IMPORT_ERROR` on the import route |
| 42 | + is unchanged: a refused import is a different act from a failed |
| 43 | + introspection, and its name says so.) |
| 44 | + |
| 45 | +Why a new registered code rather than reusing one: ADR-0112's ledger asks |
| 46 | +*generic* conditions to reuse the standard catalog — that argument carried |
| 47 | +#4225's 503, where `SERVICE_UNAVAILABLE` is correct for all nine routes and only |
| 48 | +the free-text `message` named the service. A refusal specific to one service is |
| 49 | +exactly what registered extension codes are for, and the closed `ErrorCode` |
| 50 | +union means correcting the attribution had to be a ledger edit. Widening |
| 51 | +`EXTERNAL_IMPORT_ERROR` to cover introspection was rejected because these are |
| 52 | +not imports; leaving the throws uncaught was rejected because the adapter's 500 |
| 53 | +is not the declared envelope. |
| 54 | + |
| 55 | +The conformance rows that pinned the drift move with it, and each surface now |
| 56 | +pins the refusal code per route the way #4234 pinned the 503 message per route. |
| 57 | + |
| 58 | +Pre-existing, like #4225: #3843 carried every code string over verbatim. |
0 commit comments