Skip to content

Commit 287fd99

Browse files
committed
chore(changeset): hono + plugin-hono-server, the declared-envelope rendering and its export (#23365)
Claude-Session: https://claude.ai/code/session_01Q9PZ5Pzqcus4woVvTZwWNU Co-authored-by: Claude <noreply@anthropic.com>
1 parent 167cebe commit 287fd99

1 file changed

Lines changed: 51 additions & 0 deletions

File tree

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
---
2+
'@objectstack/hono': minor
3+
'@objectstack/plugin-hono-server': minor
4+
---
5+
6+
fix(hono): `createHonoApp` answers an escaped throw that declares an ADR-0112 envelope as that envelope, not as `500 INTERNAL_ERROR` (#23365)
7+
8+
`@objectstack/hono`'s `createHonoApp` has two catch arms: the auth mount's, and
9+
the `${prefix}/*` catch-all's around `HttpDispatcher.dispatch()`. Both answered
10+
an escaped throw from its `statusCode` alone, so a producer that declared
11+
`status` and a registered `code` lost both on this host. A `GET`, `PATCH` or
12+
`DELETE` of `/data/:object/:id` for an id that names no row answered
13+
`500 INTERNAL_ERROR` where the standalone REST server answers
14+
`404 RECORD_NOT_FOUND`. The `/data` version refusals answered `500` too (a stale
15+
`If-Match`'s `409 CONCURRENT_UPDATE`, and `If-Match: ""`'s
16+
`400 VALIDATION_FAILED`), and so did an authorization-store outage
17+
(`AuthzStoreUnavailableError`, `503 SERVICE_UNAVAILABLE`).
18+
19+
**What changed.** Both arms now answer a throw that carries **both** a declared
20+
ADR-0112 status (a key of `HttpStatusErrorCodeMap`) **and** a code registered in
21+
`ErrorCode` as that envelope. The recognition is `declaredEnvelopeForThrow`, the
22+
rule `@objectstack/plugin-hono-server`'s direct-mount routes have used since
23+
#16545, so the two Hono doors answer one throw alike by construction: the same
24+
two conditions, the same 5xx disclosure filter (`looksLikeInternalErrorLeak`),
25+
and `details` and `userMessage` forwarded only when the producer declared them.
26+
27+
**What did NOT change**, pinned in the same PR through a real `createHonoApp`
28+
over the real dispatcher and protocol (`packages/qa/http-conformance`):
29+
30+
- a throw that is **not** such an envelope answers what it answered before. A
31+
bare `Error` is still `500 INTERNAL_ERROR` carrying `code` and `message`, with
32+
no `cause` in the body, and a throw that declares `statusCode` with no
33+
registered code keeps that status;
34+
- ⛔ no error code is minted and no ledger row is added.
35+
36+
`@objectstack/plugin-hono-server` gains one export, `declaredEnvelopeForThrow`,
37+
which was module-private. `createHonoApp` imports it rather than restating the
38+
rule. Its behaviour is unchanged.
39+
40+
Earlier entries say a `createHonoApp` host still renders the `/data` version
41+
refusals as `500`. This change ends that: they are answered `409` and `400` as
42+
declared.
43+
44+
⚠️ **Known gap, stated rather than left silent.** The `409 CONCURRENT_UPDATE`
45+
this host now answers carries `code` and `message`, but not the
46+
`currentVersion` and `currentRecord` that the standalone REST server's `409`
47+
carries. The recogniser forwards only the `details` a producer declares, and
48+
those two fields are own properties of the error. That gap is outside this
49+
change.
50+
51+
Clause-②: yes (widening)

0 commit comments

Comments
 (0)