@fuzdev/fuz_app 0.134.0 → 0.136.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions/CLAUDE.md +93 -11
- package/dist/actions/register_action_ws.d.ts +23 -3
- package/dist/actions/register_action_ws.d.ts.map +1 -1
- package/dist/actions/register_action_ws.js +57 -37
- package/dist/actions/transports.d.ts +23 -0
- package/dist/actions/transports.d.ts.map +1 -1
- package/dist/actions/transports.js +23 -0
- package/dist/actions/transports_ws_backend.d.ts +133 -10
- package/dist/actions/transports_ws_backend.d.ts.map +1 -1
- package/dist/actions/transports_ws_backend.js +237 -34
- package/dist/actions/ws_endpoint_spec.d.ts +9 -0
- package/dist/actions/ws_endpoint_spec.d.ts.map +1 -1
- package/dist/actions/ws_outbound_writer.d.ts +206 -0
- package/dist/actions/ws_outbound_writer.d.ts.map +1 -0
- package/dist/actions/ws_outbound_writer.js +431 -0
- package/dist/auth/CLAUDE.md +10 -4
- package/dist/auth/account_action_specs.d.ts +7 -0
- package/dist/auth/account_action_specs.d.ts.map +1 -1
- package/dist/auth/account_action_specs.js +11 -1
- package/dist/auth/audit_emitter.d.ts +4 -0
- package/dist/auth/audit_emitter.d.ts.map +1 -1
- package/dist/auth/audit_emitter.js +18 -2
- package/dist/auth/audit_log_routes.d.ts.map +1 -1
- package/dist/auth/audit_log_routes.js +3 -1
- package/dist/auth/cell_action_specs.d.ts +10 -0
- package/dist/auth/cell_action_specs.d.ts.map +1 -1
- package/dist/auth/cell_action_specs.js +17 -3
- package/dist/auth/cell_actions.js +1 -1
- package/dist/auth/role_grant_offer_action_specs.d.ts.map +1 -1
- package/dist/auth/role_grant_offer_action_specs.js +7 -2
- package/dist/auth/role_schema.d.ts +14 -3
- package/dist/auth/role_schema.d.ts.map +1 -1
- package/dist/auth/role_schema.js +14 -2
- package/dist/auth/scope_kind_schema.d.ts +10 -0
- package/dist/auth/scope_kind_schema.d.ts.map +1 -1
- package/dist/auth/scope_kind_schema.js +11 -0
- package/dist/db/migrate.d.ts +1 -1
- package/dist/db/migrate.js +2 -2
- package/dist/env/load.d.ts +1 -1
- package/dist/env/load.js +1 -1
- package/dist/http/CLAUDE.md +2 -1
- package/dist/http/body_limit.d.ts +74 -0
- package/dist/http/body_limit.d.ts.map +1 -0
- package/dist/http/body_limit.js +100 -0
- package/dist/http/db_routes.d.ts.map +1 -1
- package/dist/http/db_routes.js +5 -3
- package/dist/http/error_schemas.d.ts +2 -0
- package/dist/http/error_schemas.d.ts.map +1 -1
- package/dist/http/error_schemas.js +2 -0
- package/dist/realtime/outbound_budget.d.ts +91 -0
- package/dist/realtime/outbound_budget.d.ts.map +1 -0
- package/dist/realtime/outbound_budget.js +108 -0
- package/dist/realtime/sse.d.ts +36 -3
- package/dist/realtime/sse.d.ts.map +1 -1
- package/dist/realtime/sse.js +58 -6
- package/dist/realtime/sse_constants.d.ts +12 -0
- package/dist/realtime/sse_constants.d.ts.map +1 -1
- package/dist/realtime/sse_constants.js +12 -0
- package/dist/server/app_server.d.ts.map +1 -1
- package/dist/server/app_server.js +3 -6
- package/dist/testing/CLAUDE.md +96 -19
- package/dist/testing/admin_integration.js +1 -1
- package/dist/testing/audit_completeness.d.ts +1 -1
- package/dist/testing/audit_completeness.js +1 -1
- package/dist/testing/audit_drift_guard.d.ts +19 -6
- package/dist/testing/audit_drift_guard.d.ts.map +1 -1
- package/dist/testing/audit_drift_guard.js +25 -9
- package/dist/testing/cross_backend/body_size.d.ts +18 -5
- package/dist/testing/cross_backend/body_size.d.ts.map +1 -1
- package/dist/testing/cross_backend/body_size.js +233 -34
- package/dist/testing/cross_backend/body_size_smuggling.d.ts +0 -12
- package/dist/testing/cross_backend/body_size_smuggling.d.ts.map +1 -1
- package/dist/testing/cross_backend/body_size_smuggling.js +103 -108
- package/dist/testing/cross_backend/capabilities.d.ts +3 -21
- package/dist/testing/cross_backend/capabilities.d.ts.map +1 -1
- package/dist/testing/cross_backend/capabilities.js +1 -3
- package/dist/testing/cross_backend/cell_crud.d.ts.map +1 -1
- package/dist/testing/cross_backend/cell_crud.js +31 -2
- package/dist/testing/cross_backend/conformance_case.d.ts +3 -3
- package/dist/testing/cross_backend/credential_header_robustness.d.ts.map +1 -1
- package/dist/testing/cross_backend/credential_header_robustness.js +18 -54
- package/dist/testing/cross_backend/default_backend_configs.d.ts.map +1 -1
- package/dist/testing/cross_backend/default_backend_configs.js +2 -8
- package/dist/testing/cross_backend/role_grant_role_grammar.d.ts +6 -0
- package/dist/testing/cross_backend/role_grant_role_grammar.d.ts.map +1 -0
- package/dist/testing/cross_backend/role_grant_role_grammar.js +117 -0
- package/dist/testing/cross_backend/rust_spine_stub_backend_config.d.ts +2 -3
- package/dist/testing/cross_backend/rust_spine_stub_backend_config.d.ts.map +1 -1
- package/dist/testing/cross_backend/rust_spine_stub_backend_config.js +2 -3
- package/dist/testing/cross_backend/testing_backdoor.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_backdoor.js +10 -4
- package/dist/testing/cross_backend/testing_reset_actions.d.ts +87 -2
- package/dist/testing/cross_backend/testing_reset_actions.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_reset_actions.js +106 -2
- package/dist/testing/cross_backend/token_lifetime.d.ts.map +1 -1
- package/dist/testing/cross_backend/token_lifetime.js +34 -1
- package/dist/testing/cross_backend/ts_spine_backend_config.d.ts.map +1 -1
- package/dist/testing/cross_backend/ts_spine_backend_config.js +8 -13
- package/dist/testing/cross_backend/ws_outbound_overflow.d.ts +29 -0
- package/dist/testing/cross_backend/ws_outbound_overflow.d.ts.map +1 -0
- package/dist/testing/cross_backend/ws_outbound_overflow.js +276 -0
- package/dist/testing/integration.js +1 -1
- package/dist/testing/schema_introspect.d.ts +30 -2
- package/dist/testing/schema_introspect.d.ts.map +1 -1
- package/dist/testing/schema_introspect.js +38 -7
- package/dist/testing/transports/raw_http.d.ts +78 -0
- package/dist/testing/transports/raw_http.d.ts.map +1 -0
- package/dist/testing/transports/raw_http.js +141 -0
- package/dist/testing/transports/ws_transport.d.ts +4 -2
- package/dist/testing/transports/ws_transport.d.ts.map +1 -1
- package/dist/testing/transports/ws_transport.js +2 -1
- package/dist/testing/ws_round_trip.d.ts +32 -2
- package/dist/testing/ws_round_trip.d.ts.map +1 -1
- package/dist/testing/ws_round_trip.js +26 -4
- package/package.json +1 -1
- package/dist/env/resolve.d.ts +0 -163
- package/dist/env/resolve.d.ts.map +0 -1
- package/dist/env/resolve.js +0 -267
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Request body size limit — rejects an oversized body with `413`, and a
|
|
3
|
+
* `Content-Length` it cannot read with `400`, before auth and validation.
|
|
4
|
+
*
|
|
5
|
+
* Wraps Hono's `bodyLimit` with a header-first check:
|
|
6
|
+
*
|
|
7
|
+
* - A `Content-Length` that is not a plain run of ASCII digits (`abc`, `-1`,
|
|
8
|
+
* `+5`, `1e9`, `0x1F4`, empty, or a combined `5, 500`) is refused with `400`
|
|
9
|
+
* `{error: 'invalid_content_length'}`. A cap cannot be applied to a length
|
|
10
|
+
* that does not parse, and `bodyLimit` passes such a request on uncounted.
|
|
11
|
+
* The runtimes' HTTP parsers answer their own bodiless `400` to most of
|
|
12
|
+
* these before the application sees them, so this branch is defense in
|
|
13
|
+
* depth where they do and the refusal where they do not: Node's refuses
|
|
14
|
+
* them all; Deno and Bun hand over a repeated equal header as one combined
|
|
15
|
+
* value (`50, 50`) and refuse the rest (observed on Node 24.14.1, Deno
|
|
16
|
+
* 2.8.3, Bun 1.4.3). The Rust spine's parser (hyper) refuses a malformed
|
|
17
|
+
* value and differing repeats, and accepts an equal repeat as the one
|
|
18
|
+
* value.
|
|
19
|
+
* - A request whose `Content-Length` exceeds the cap is refused with `413`
|
|
20
|
+
* `{error: 'payload_too_large'}`, whatever its method. A digit run of any
|
|
21
|
+
* length compares as a number, so one too long to represent exactly is over
|
|
22
|
+
* the cap, never unreadable. Over a socket that branch is reached on Node
|
|
23
|
+
* and Deno, whose parsers hand over any length below 2^64 and refuse a
|
|
24
|
+
* longer one with their own `400`. `Bun.serve` hands none over: with its
|
|
25
|
+
* default options it answers a length past 128 MiB with its own `413`, and
|
|
26
|
+
* one of 2^63 - 1 or more with its own `400` (observed on Node 24.14.1,
|
|
27
|
+
* Deno 2.8.3, Bun 1.4.3).
|
|
28
|
+
* - Both refusals answer on the header alone — without touching
|
|
29
|
+
* `c.req.raw.body` — and carry `Connection: close`.
|
|
30
|
+
* - A request with a well-formed `Content-Length` beside `Transfer-Encoding`,
|
|
31
|
+
* or with no `Content-Length`, falls through to `bodyLimit`, which measures
|
|
32
|
+
* the bytes that arrive: with `Transfer-Encoding` the declared length does
|
|
33
|
+
* not frame the body. `bodyLimit` reads the body into memory, up to the
|
|
34
|
+
* cap, **before** the next middleware runs, so that `413` — sent once more
|
|
35
|
+
* than the cap has been read, with no `Connection: close` — also comes
|
|
36
|
+
* ahead of the origin check, auth and the handler. The Rust spine counts
|
|
37
|
+
* such a body as its handler reads it instead, so there a refusal made on
|
|
38
|
+
* the headers answers first; which status an over-cap body with no declared
|
|
39
|
+
* length gets when another refusal also applies is implementation-defined
|
|
40
|
+
* across the two (`docs/security.md` §"Body Size Limiting").
|
|
41
|
+
* The Node, Deno and Bun parsers refuse a request carrying both headers
|
|
42
|
+
* with their own `400`; hyper accepts one, drops its `Content-Length`,
|
|
43
|
+
* frames the body as chunked, and closes the connection after the response.
|
|
44
|
+
* - A well-formed `Content-Length` within the cap is trusted to frame the
|
|
45
|
+
* body, as the runtime's HTTP parser enforces.
|
|
46
|
+
*
|
|
47
|
+
* What the connection does after the header `413` is the runtime's
|
|
48
|
+
* (`docs/security.md` §"Body Size Limiting"):
|
|
49
|
+
*
|
|
50
|
+
* - **Node** (`@hono/node-server`) closes at once, the body unread. The
|
|
51
|
+
* `Connection: close` header is what does it: without one the adapter
|
|
52
|
+
* holds the connection for a drain window and then closes or, the body
|
|
53
|
+
* untouched and arriving within the window, reads it off and serves the
|
|
54
|
+
* next request.
|
|
55
|
+
* - **Deno** closes once the whole declared body has arrived and holds the
|
|
56
|
+
* connection open while a client withholds it; a request pipelined behind
|
|
57
|
+
* the body is not served. Neither the header nor what the handler does with
|
|
58
|
+
* the body changes that (observed on Deno 2.8.3).
|
|
59
|
+
* - **Bun** closes at once, the body unread, honouring the header. Bun 1.4.3
|
|
60
|
+
* is the tested floor: an older Bun kept the connection after the `413` and
|
|
61
|
+
* served the next request (correctly framed), so run Bun at the floor or
|
|
62
|
+
* later.
|
|
63
|
+
*
|
|
64
|
+
* @module
|
|
65
|
+
*/
|
|
66
|
+
import { bodyLimit } from 'hono/body-limit';
|
|
67
|
+
import { ERROR_INVALID_CONTENT_LENGTH, ERROR_PAYLOAD_TOO_LARGE } from './error_schemas.js';
|
|
68
|
+
/** A well-formed `Content-Length` value: one or more ASCII digits and nothing else. */
|
|
69
|
+
const CONTENT_LENGTH_DIGITS = /^[0-9]+$/;
|
|
70
|
+
/**
|
|
71
|
+
* Create the body size limit middleware.
|
|
72
|
+
*
|
|
73
|
+
* @param max_size - the largest accepted body, in bytes
|
|
74
|
+
* @returns middleware answering `413` `{error: 'payload_too_large'}` past the cap and `400` `{error: 'invalid_content_length'}` to a `Content-Length` that is not a run of digits
|
|
75
|
+
*/
|
|
76
|
+
export const create_body_limit_middleware = (max_size) => {
|
|
77
|
+
const streaming_limit = bodyLimit({
|
|
78
|
+
maxSize: max_size,
|
|
79
|
+
onError: (c) => c.json({ error: ERROR_PAYLOAD_TOO_LARGE }, 413)
|
|
80
|
+
});
|
|
81
|
+
return async (c, next) => {
|
|
82
|
+
const content_length = c.req.header('content-length');
|
|
83
|
+
if (content_length !== undefined) {
|
|
84
|
+
if (!CONTENT_LENGTH_DIGITS.test(content_length)) {
|
|
85
|
+
// a length that does not parse cannot be capped, and `bodyLimit`
|
|
86
|
+
// would pass the request on without counting it
|
|
87
|
+
return c.json({ error: ERROR_INVALID_CONTENT_LENGTH }, 400, { connection: 'close' });
|
|
88
|
+
}
|
|
89
|
+
// `Number` of a digit run is never `NaN`; past exact precision it is
|
|
90
|
+
// still a huge number (or `Infinity`), so it compares as over the cap
|
|
91
|
+
if (!c.req.header('transfer-encoding') && Number(content_length) > max_size) {
|
|
92
|
+
// refused on the header alone, the body untouched; `Connection: close`
|
|
93
|
+
// makes `@hono/node-server` and Bun close at once instead of holding
|
|
94
|
+
// the connection or serving the request behind the body
|
|
95
|
+
return c.json({ error: ERROR_PAYLOAD_TOO_LARGE }, 413, { connection: 'close' });
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return streaming_limit(c, next);
|
|
99
|
+
};
|
|
100
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db_routes.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/db_routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAEnD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAqC,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAiBpF;;GAEG;AACH,MAAM,WAAW,SAAS;IACzB,UAAU,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC9B,WAAW,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACpB;AAED,sDAAsD;AACtD,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAC/C,sDAAsD;AACtD,eAAO,MAAM,uBAAuB,OAAO,CAAC;AAE5C;;;;;;GAMG;AACH,eAAO,MAAM,6BAA6B,OAAO,CAAC;AAElD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,oBAAoB,EAAE,aAAa,CAAC,MAAM,CAKrD,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,oBAAoB,EAAE,aAAa,CAAC,MAAM,CAKrD,CAAC;AAEH;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC3B;;;;;;;;OAQG;IACH,KAAK,EAAE;QACN,IAAI,EAAE,CACL,GAAG,EAAE;YACJ,eAAe,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;YACtC,mBAAmB,EAAE,KAAK,CAAC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;SACvD,EACD,KAAK,EAAE;YACN,UAAU,EAAE,qBAAqB,CAAC;YAClC,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC;YACxB,EAAE,EAAE,MAAM,CAAC;YACX,QAAQ,EAAE;gBAAE,KAAK,EAAE,MAAM,CAAC;gBAAC,SAAS,EAAE,MAAM,CAAC;gBAAC,EAAE,EAAE,MAAM,CAAA;aAAE,CAAC;SAC3D,KACG,IAAI,CAAC;KACV,CAAC;CACF;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;;;OAOG;IACH,gBAAgB,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACxC,8EAA8E;IAC9E,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC3D,+EAA+E;IAC/E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,oBAAoB,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CAC7C;AA2CD;;GAEG;AACH,eAAO,MAAM,qBAAqB,GACjC,MAAM,WAAW,EACjB,SAAS,cAAc,KACrB,KAAK,CAAC,SAAS,
|
|
1
|
+
{"version":3,"file":"db_routes.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/db_routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAEnD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAqC,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAiBpF;;GAEG;AACH,MAAM,WAAW,SAAS;IACzB,UAAU,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC9B,WAAW,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACpB;AAED,sDAAsD;AACtD,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAC/C,sDAAsD;AACtD,eAAO,MAAM,uBAAuB,OAAO,CAAC;AAE5C;;;;;;GAMG;AACH,eAAO,MAAM,6BAA6B,OAAO,CAAC;AAElD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,oBAAoB,EAAE,aAAa,CAAC,MAAM,CAKrD,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,oBAAoB,EAAE,aAAa,CAAC,MAAM,CAKrD,CAAC;AAEH;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC3B;;;;;;;;OAQG;IACH,KAAK,EAAE;QACN,IAAI,EAAE,CACL,GAAG,EAAE;YACJ,eAAe,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;YACtC,mBAAmB,EAAE,KAAK,CAAC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;SACvD,EACD,KAAK,EAAE;YACN,UAAU,EAAE,qBAAqB,CAAC;YAClC,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC;YACxB,EAAE,EAAE,MAAM,CAAC;YACX,QAAQ,EAAE;gBAAE,KAAK,EAAE,MAAM,CAAC;gBAAC,SAAS,EAAE,MAAM,CAAC;gBAAC,EAAE,EAAE,MAAM,CAAA;aAAE,CAAC;SAC3D,KACG,IAAI,CAAC;KACV,CAAC;CACF;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;;;OAOG;IACH,gBAAgB,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACxC,8EAA8E;IAC9E,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC3D,+EAA+E;IAC/E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,oBAAoB,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CAC7C;AA2CD;;GAEG;AACH,eAAO,MAAM,qBAAqB,GACjC,MAAM,WAAW,EACjB,SAAS,cAAc,KACrB,KAAK,CAAC,SAAS,CA8XjB,CAAC"}
|
package/dist/http/db_routes.js
CHANGED
|
@@ -424,9 +424,11 @@ export const create_db_route_specs = (deps, options) => {
|
|
|
424
424
|
return c.json({ error: ERROR_ROW_NOT_FOUND }, 404);
|
|
425
425
|
}
|
|
426
426
|
// 23503 foreign_key_violation / 23001 restrict_violation — the
|
|
427
|
-
// same referencing-row refusal
|
|
428
|
-
// DELETE RESTRICT`
|
|
429
|
-
//
|
|
427
|
+
// same referencing-row refusal. Which one depends on the
|
|
428
|
+
// constraint: `ON DELETE RESTRICT` raises 23001 on PG 18, PGlite
|
|
429
|
+
// and pglet (23503 on PG ≤17), and `NO ACTION` — the default,
|
|
430
|
+
// when the constraint names no action — raises 23503 on all of
|
|
431
|
+
// them.
|
|
430
432
|
if (code === '23503' || code === '23001') {
|
|
431
433
|
const pg_err = err;
|
|
432
434
|
log?.warn('Foreign key violation:', pg_err.detail, pg_err.constraint);
|
|
@@ -53,6 +53,8 @@ export declare const ERROR_RATE_LIMIT_EXCEEDED: "rate_limit_exceeded";
|
|
|
53
53
|
export declare const ERROR_INVALID_CREDENTIALS: "invalid_credentials";
|
|
54
54
|
/** Request body exceeds the maximum allowed size. */
|
|
55
55
|
export declare const ERROR_PAYLOAD_TOO_LARGE: "payload_too_large";
|
|
56
|
+
/** Request `Content-Length` header is not a plain run of ASCII digits. */
|
|
57
|
+
export declare const ERROR_INVALID_CONTENT_LENGTH: "invalid_content_length";
|
|
56
58
|
/** Request origin not in allowlist. */
|
|
57
59
|
export declare const ERROR_FORBIDDEN_ORIGIN: "forbidden_origin";
|
|
58
60
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error_schemas.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/error_schemas.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAe,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAI9D,0CAA0C;AAC1C,eAAO,MAAM,0BAA0B,EAAG,sBAA+B,CAAC;AAE1E,uDAAuD;AACvD,eAAO,MAAM,uBAAuB,EAAG,mBAA4B,CAAC;AAEpE,6CAA6C;AAC7C,eAAO,MAAM,0BAA0B,EAAG,sBAA+B,CAAC;AAE1E,8CAA8C;AAC9C,eAAO,MAAM,0BAA0B,EAAG,sBAA+B,CAAC;AAI1E,wCAAwC;AACxC,eAAO,MAAM,6BAA6B,EAAG,yBAAkC,CAAC;AAEhF,+CAA+C;AAC/C,eAAO,MAAM,8BAA8B,EAAG,0BAAmC,CAAC;AAElF;;;;;;;;GAQG;AACH,eAAO,MAAM,8BAA8B,EAAG,0BAAmC,CAAC;AAElF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,0BAA0B,EAAG,sBAA+B,CAAC;AAE1E,yCAAyC;AACzC,eAAO,MAAM,yBAAyB,EAAG,qBAA8B,CAAC;AAExE,sFAAsF;AACtF,eAAO,MAAM,yBAAyB,EAAG,qBAA8B,CAAC;AAExE,qDAAqD;AACrD,eAAO,MAAM,uBAAuB,EAAG,mBAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"error_schemas.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/error_schemas.ts"],"names":[],"mappings":"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"}
|
|
@@ -55,6 +55,8 @@ export const ERROR_RATE_LIMIT_EXCEEDED = 'rate_limit_exceeded';
|
|
|
55
55
|
export const ERROR_INVALID_CREDENTIALS = 'invalid_credentials';
|
|
56
56
|
/** Request body exceeds the maximum allowed size. */
|
|
57
57
|
export const ERROR_PAYLOAD_TOO_LARGE = 'payload_too_large';
|
|
58
|
+
/** Request `Content-Length` header is not a plain run of ASCII digits. */
|
|
59
|
+
export const ERROR_INVALID_CONTENT_LENGTH = 'invalid_content_length';
|
|
58
60
|
// --- Origin & bearer token verification ---
|
|
59
61
|
/** Request origin not in allowlist. */
|
|
60
62
|
export const ERROR_FORBIDDEN_ORIGIN = 'forbidden_origin';
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The byte budget of the frames waiting to be written to one connection — a
|
|
3
|
+
* WebSocket or an SSE stream.
|
|
4
|
+
*
|
|
5
|
+
* A producer never waits on a recipient: a broadcast is synchronous and called
|
|
6
|
+
* from anywhere, so a client that stopped reading makes the server hold what it
|
|
7
|
+
* has not taken. `OutboundBudget` is the bound on that, and it is accounting
|
|
8
|
+
* only — its owner holds the frames and decides what "waiting" means for its
|
|
9
|
+
* connection (`WsOutboundWriter` for a WebSocket, `create_sse_response` for an
|
|
10
|
+
* SSE stream).
|
|
11
|
+
*
|
|
12
|
+
* - **The charge.** Each waiting frame is charged its payload bytes — the
|
|
13
|
+
* UTF-8 length of its text — plus `OUTBOUND_FRAME_OVERHEAD_BYTES`.
|
|
14
|
+
* - **The rule.** A frame is admitted when the charges already waiting plus
|
|
15
|
+
* its own stay within the budget — and, whatever its size, when nothing is
|
|
16
|
+
* waiting, so a single message larger than the whole budget is deliverable.
|
|
17
|
+
*
|
|
18
|
+
* Nothing counts frames: any number may wait while their charges fit. The twin
|
|
19
|
+
* of the Rust spine's `fuz_realtime` outbound queue, with the same charge and
|
|
20
|
+
* the same rule.
|
|
21
|
+
*
|
|
22
|
+
* @module
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* What a waiting frame is charged against its budget on top of its payload
|
|
26
|
+
* bytes.
|
|
27
|
+
*
|
|
28
|
+
* It stands for what a queued frame costs beyond its text, so a frame with
|
|
29
|
+
* little or no payload is not free: a budget of `B` never holds more than `B`
|
|
30
|
+
* divided by this many frames, whatever their size. A fixed charge, not a
|
|
31
|
+
* measurement of memory use. Same value as the Rust spine's constant.
|
|
32
|
+
*/
|
|
33
|
+
export declare const OUTBOUND_FRAME_OVERHEAD_BYTES = 64;
|
|
34
|
+
/** What was waiting when a frame did not fit its connection's budget. */
|
|
35
|
+
export interface OutboundOverflow {
|
|
36
|
+
/** Payload bytes waiting, without the per-frame overhead the budget also charges. */
|
|
37
|
+
queued_bytes: number;
|
|
38
|
+
/** Frames waiting. */
|
|
39
|
+
queued_frames: number;
|
|
40
|
+
/** Payload bytes of the frame that did not fit, without its overhead. */
|
|
41
|
+
frame_bytes: number;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* The accounting for one connection's waiting frames (module doc).
|
|
45
|
+
*
|
|
46
|
+
* `admit` charges a frame that fits, `release` frees the charge of one that is
|
|
47
|
+
* no longer waiting, and `clear` frees them all.
|
|
48
|
+
*/
|
|
49
|
+
export declare class OutboundBudget {
|
|
50
|
+
#private;
|
|
51
|
+
/** The budget, in bytes. */
|
|
52
|
+
readonly max_bytes: number;
|
|
53
|
+
/**
|
|
54
|
+
* @param max_bytes - the budget, in bytes; `0` admits one frame at a time
|
|
55
|
+
* @throws Error when `max_bytes` is not a non-negative safe integer
|
|
56
|
+
*/
|
|
57
|
+
constructor(max_bytes: number);
|
|
58
|
+
/** Payload bytes waiting, without the per-frame overhead. */
|
|
59
|
+
get queued_bytes(): number;
|
|
60
|
+
/** Frames waiting. */
|
|
61
|
+
get queued_frames(): number;
|
|
62
|
+
/**
|
|
63
|
+
* Charge a frame of `frame_bytes` payload bytes if it fits: when nothing is
|
|
64
|
+
* waiting, or when the charges waiting plus its own stay within the budget.
|
|
65
|
+
*
|
|
66
|
+
* @param frame_bytes - the frame's payload length in UTF-8 bytes
|
|
67
|
+
* @returns whether the frame was admitted and charged
|
|
68
|
+
* @mutates this - adds the frame's charge when it is admitted
|
|
69
|
+
*/
|
|
70
|
+
admit(frame_bytes: number): boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Free the charge of one admitted frame that is no longer waiting.
|
|
73
|
+
*
|
|
74
|
+
* @param frame_bytes - the payload length the frame was admitted with
|
|
75
|
+
* @mutates this - removes the frame's charge
|
|
76
|
+
*/
|
|
77
|
+
release(frame_bytes: number): void;
|
|
78
|
+
/**
|
|
79
|
+
* Free every charge — the owner discarded what was waiting.
|
|
80
|
+
*
|
|
81
|
+
* @mutates this - removes every charge
|
|
82
|
+
*/
|
|
83
|
+
clear(): void;
|
|
84
|
+
/**
|
|
85
|
+
* What is waiting, for the log line of a frame that did not fit.
|
|
86
|
+
*
|
|
87
|
+
* @param frame_bytes - the payload length of the frame that did not fit
|
|
88
|
+
*/
|
|
89
|
+
to_overflow(frame_bytes: number): OutboundOverflow;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=outbound_budget.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outbound_budget.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/realtime/outbound_budget.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,6BAA6B,KAAK,CAAC;AAEhD,yEAAyE;AACzE,MAAM,WAAW,gBAAgB;IAChC,qFAAqF;IACrF,YAAY,EAAE,MAAM,CAAC;IACrB,sBAAsB;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,yEAAyE;IACzE,WAAW,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,qBAAa,cAAc;;IAC1B,4BAA4B;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAK3B;;;OAGG;gBACS,SAAS,EAAE,MAAM;IAO7B,6DAA6D;IAC7D,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED,sBAAsB;IACtB,IAAI,aAAa,IAAI,MAAM,CAE1B;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO;IAanC;;;;;OAKG;IACH,OAAO,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAKlC;;;;OAIG;IACH,KAAK,IAAI,IAAI;IAKb;;;;OAIG;IACH,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,gBAAgB;CAGlD"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The byte budget of the frames waiting to be written to one connection — a
|
|
3
|
+
* WebSocket or an SSE stream.
|
|
4
|
+
*
|
|
5
|
+
* A producer never waits on a recipient: a broadcast is synchronous and called
|
|
6
|
+
* from anywhere, so a client that stopped reading makes the server hold what it
|
|
7
|
+
* has not taken. `OutboundBudget` is the bound on that, and it is accounting
|
|
8
|
+
* only — its owner holds the frames and decides what "waiting" means for its
|
|
9
|
+
* connection (`WsOutboundWriter` for a WebSocket, `create_sse_response` for an
|
|
10
|
+
* SSE stream).
|
|
11
|
+
*
|
|
12
|
+
* - **The charge.** Each waiting frame is charged its payload bytes — the
|
|
13
|
+
* UTF-8 length of its text — plus `OUTBOUND_FRAME_OVERHEAD_BYTES`.
|
|
14
|
+
* - **The rule.** A frame is admitted when the charges already waiting plus
|
|
15
|
+
* its own stay within the budget — and, whatever its size, when nothing is
|
|
16
|
+
* waiting, so a single message larger than the whole budget is deliverable.
|
|
17
|
+
*
|
|
18
|
+
* Nothing counts frames: any number may wait while their charges fit. The twin
|
|
19
|
+
* of the Rust spine's `fuz_realtime` outbound queue, with the same charge and
|
|
20
|
+
* the same rule.
|
|
21
|
+
*
|
|
22
|
+
* @module
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* What a waiting frame is charged against its budget on top of its payload
|
|
26
|
+
* bytes.
|
|
27
|
+
*
|
|
28
|
+
* It stands for what a queued frame costs beyond its text, so a frame with
|
|
29
|
+
* little or no payload is not free: a budget of `B` never holds more than `B`
|
|
30
|
+
* divided by this many frames, whatever their size. A fixed charge, not a
|
|
31
|
+
* measurement of memory use. Same value as the Rust spine's constant.
|
|
32
|
+
*/
|
|
33
|
+
export const OUTBOUND_FRAME_OVERHEAD_BYTES = 64;
|
|
34
|
+
/**
|
|
35
|
+
* The accounting for one connection's waiting frames (module doc).
|
|
36
|
+
*
|
|
37
|
+
* `admit` charges a frame that fits, `release` frees the charge of one that is
|
|
38
|
+
* no longer waiting, and `clear` frees them all.
|
|
39
|
+
*/
|
|
40
|
+
export class OutboundBudget {
|
|
41
|
+
/** The budget, in bytes. */
|
|
42
|
+
max_bytes;
|
|
43
|
+
#bytes = 0;
|
|
44
|
+
#frames = 0;
|
|
45
|
+
/**
|
|
46
|
+
* @param max_bytes - the budget, in bytes; `0` admits one frame at a time
|
|
47
|
+
* @throws Error when `max_bytes` is not a non-negative safe integer
|
|
48
|
+
*/
|
|
49
|
+
constructor(max_bytes) {
|
|
50
|
+
if (!Number.isSafeInteger(max_bytes) || max_bytes < 0) {
|
|
51
|
+
throw new Error(`OutboundBudget: max_bytes must be a non-negative integer, got ${max_bytes}`);
|
|
52
|
+
}
|
|
53
|
+
this.max_bytes = max_bytes;
|
|
54
|
+
}
|
|
55
|
+
/** Payload bytes waiting, without the per-frame overhead. */
|
|
56
|
+
get queued_bytes() {
|
|
57
|
+
return this.#bytes;
|
|
58
|
+
}
|
|
59
|
+
/** Frames waiting. */
|
|
60
|
+
get queued_frames() {
|
|
61
|
+
return this.#frames;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Charge a frame of `frame_bytes` payload bytes if it fits: when nothing is
|
|
65
|
+
* waiting, or when the charges waiting plus its own stay within the budget.
|
|
66
|
+
*
|
|
67
|
+
* @param frame_bytes - the frame's payload length in UTF-8 bytes
|
|
68
|
+
* @returns whether the frame was admitted and charged
|
|
69
|
+
* @mutates this - adds the frame's charge when it is admitted
|
|
70
|
+
*/
|
|
71
|
+
admit(frame_bytes) {
|
|
72
|
+
if (this.#frames !== 0 &&
|
|
73
|
+
this.#bytes + frame_bytes + (this.#frames + 1) * OUTBOUND_FRAME_OVERHEAD_BYTES >
|
|
74
|
+
this.max_bytes) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
this.#bytes += frame_bytes;
|
|
78
|
+
this.#frames++;
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Free the charge of one admitted frame that is no longer waiting.
|
|
83
|
+
*
|
|
84
|
+
* @param frame_bytes - the payload length the frame was admitted with
|
|
85
|
+
* @mutates this - removes the frame's charge
|
|
86
|
+
*/
|
|
87
|
+
release(frame_bytes) {
|
|
88
|
+
this.#bytes -= frame_bytes;
|
|
89
|
+
this.#frames--;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Free every charge — the owner discarded what was waiting.
|
|
93
|
+
*
|
|
94
|
+
* @mutates this - removes every charge
|
|
95
|
+
*/
|
|
96
|
+
clear() {
|
|
97
|
+
this.#bytes = 0;
|
|
98
|
+
this.#frames = 0;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* What is waiting, for the log line of a frame that did not fit.
|
|
102
|
+
*
|
|
103
|
+
* @param frame_bytes - the payload length of the frame that did not fit
|
|
104
|
+
*/
|
|
105
|
+
to_overflow(frame_bytes) {
|
|
106
|
+
return { queued_bytes: this.#bytes, queued_frames: this.#frames, frame_bytes };
|
|
107
|
+
}
|
|
108
|
+
}
|
package/dist/realtime/sse.d.ts
CHANGED
|
@@ -4,6 +4,22 @@
|
|
|
4
4
|
* Provides generic helpers for creating SSE response streams
|
|
5
5
|
* and a notification type aligned with JSON-RPC 2.0.
|
|
6
6
|
*
|
|
7
|
+
* ## Outbound bound
|
|
8
|
+
*
|
|
9
|
+
* `SseStream.send` never waits on its client: each frame is written to the
|
|
10
|
+
* response stream, which holds it until the client reads. What a stream holds
|
|
11
|
+
* unread is kept within `SSE_OUTBOUND_QUEUE_BYTES` — each frame charged its
|
|
12
|
+
* bytes as written (`data: ` prefix and terminator included) plus
|
|
13
|
+
* `OUTBOUND_FRAME_OVERHEAD_BYTES`, and a frame always accepted when nothing is
|
|
14
|
+
* unread, so a single frame larger than the budget is still deliverable. A
|
|
15
|
+
* frame that does not fit **ends the stream**: it is not written, what was
|
|
16
|
+
* unread is dropped, the body ends with no final frame, and the stream's
|
|
17
|
+
* `on_close` listeners run. One `warn` line names the stream's account (when
|
|
18
|
+
* the caller passed it) and what was unread; no audit row is written, since each would itself be fanned to every
|
|
19
|
+
* stream. A client that is reading reconnects and misses the frames in
|
|
20
|
+
* between. The twin of the Rust spine's `fuz_realtime` SSE bound — the same
|
|
21
|
+
* budget and charge.
|
|
22
|
+
*
|
|
7
23
|
* @module
|
|
8
24
|
*/
|
|
9
25
|
import type { Context } from 'hono';
|
|
@@ -15,7 +31,11 @@ import type { Logger } from '@fuzdev/fuz_util/log.ts';
|
|
|
15
31
|
* Transport-agnostic — works with any serializable type.
|
|
16
32
|
*/
|
|
17
33
|
export interface SseStream<T = unknown> {
|
|
18
|
-
/**
|
|
34
|
+
/**
|
|
35
|
+
* Send data to the client as a JSON SSE event. Never waits: a frame the
|
|
36
|
+
* stream's outbound budget does not fit ends the stream instead (module doc,
|
|
37
|
+
* "Outbound bound").
|
|
38
|
+
*/
|
|
19
39
|
send: (data: T) => void;
|
|
20
40
|
/** Send a comment (for keep-alive pings). */
|
|
21
41
|
comment: (text: string) => void;
|
|
@@ -40,6 +60,14 @@ export interface SseNotification {
|
|
|
40
60
|
/** Method-specific payload. */
|
|
41
61
|
params: unknown;
|
|
42
62
|
}
|
|
63
|
+
/** Options for `create_sse_response`. */
|
|
64
|
+
export interface SseResponseOptions {
|
|
65
|
+
/**
|
|
66
|
+
* The account the stream belongs to, named in the warning logged when the
|
|
67
|
+
* stream ends on its outbound budget.
|
|
68
|
+
*/
|
|
69
|
+
account_id?: string | null;
|
|
70
|
+
}
|
|
43
71
|
/**
|
|
44
72
|
* Create an SSE response for a Hono context.
|
|
45
73
|
*
|
|
@@ -59,10 +87,15 @@ export interface SseNotification {
|
|
|
59
87
|
* Uses `hono_stream.write()` directly (not `writeSSE`) to avoid
|
|
60
88
|
* Hono's HTML callback resolution — keeps the same `data: JSON\n\n` format.
|
|
61
89
|
*
|
|
62
|
-
*
|
|
90
|
+
* What the stream holds unread is bounded by `SSE_OUTBOUND_QUEUE_BYTES`; a
|
|
91
|
+
* frame past it ends the stream (module doc, "Outbound bound").
|
|
92
|
+
*
|
|
93
|
+
* @param log - logger for serialization and `on_close` listener errors, and
|
|
94
|
+
* for the warning when the stream ends on its outbound budget
|
|
95
|
+
* @param options - what the overflow warning names
|
|
63
96
|
* @returns object with the streaming `Response` and an `SseStream` controller
|
|
64
97
|
*/
|
|
65
|
-
export declare const create_sse_response: <T = unknown>(c: Context, log: Logger) => {
|
|
98
|
+
export declare const create_sse_response: <T = unknown>(c: Context, log: Logger, options?: SseResponseOptions) => {
|
|
66
99
|
response: Response;
|
|
67
100
|
stream: SseStream<T>;
|
|
68
101
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sse.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/realtime/sse.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"sse.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/realtime/sse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAEpC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAMtD;;;;GAIG;AACH,MAAM,WAAW,SAAS,CAAC,CAAC,GAAG,OAAO;IACrC;;;;OAIG;IACH,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;IACxB,6CAA6C;IAC7C,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,wBAAwB;IACxB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB;;;;;OAKG;IACH,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;CACnC;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC/B,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAC;IACf,+BAA+B;IAC/B,MAAM,EAAE,OAAO,CAAC;CAChB;AAED,yCAAyC;AACzC,MAAM,WAAW,kBAAkB;IAClC;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AA8DD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,mBAAmB,GAAI,CAAC,GAAG,OAAO,EAC9C,GAAG,OAAO,EACV,KAAK,MAAM,EACX,UAAU,kBAAkB,KAC1B;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,CAAA;CAyF5C,CAAC;AAEF,gFAAgF;AAChF,MAAM,WAAW,SAAS;IACzB,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAC;IACf,wDAAwD;IACxD,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC;IAClB,8DAA8D;IAC9D,WAAW,EAAE,MAAM,CAAC;IACpB,uEAAuE;IACvE,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,4BAA4B,GAAI,CAAC,SAAS,eAAe,EACrE,aAAa;IAAE,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,KAAK,IAAI,CAAA;CAAE,EAC9D,aAAa,KAAK,CAAC,SAAS,CAAC,EAC7B,KAAK,MAAM,KACT;IAAE,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,KAAK,IAAI,CAAA;CAmBjD,CAAC"}
|
package/dist/realtime/sse.js
CHANGED
|
@@ -4,12 +4,30 @@
|
|
|
4
4
|
* Provides generic helpers for creating SSE response streams
|
|
5
5
|
* and a notification type aligned with JSON-RPC 2.0.
|
|
6
6
|
*
|
|
7
|
+
* ## Outbound bound
|
|
8
|
+
*
|
|
9
|
+
* `SseStream.send` never waits on its client: each frame is written to the
|
|
10
|
+
* response stream, which holds it until the client reads. What a stream holds
|
|
11
|
+
* unread is kept within `SSE_OUTBOUND_QUEUE_BYTES` — each frame charged its
|
|
12
|
+
* bytes as written (`data: ` prefix and terminator included) plus
|
|
13
|
+
* `OUTBOUND_FRAME_OVERHEAD_BYTES`, and a frame always accepted when nothing is
|
|
14
|
+
* unread, so a single frame larger than the budget is still deliverable. A
|
|
15
|
+
* frame that does not fit **ends the stream**: it is not written, what was
|
|
16
|
+
* unread is dropped, the body ends with no final frame, and the stream's
|
|
17
|
+
* `on_close` listeners run. One `warn` line names the stream's account (when
|
|
18
|
+
* the caller passed it) and what was unread; no audit row is written, since each would itself be fanned to every
|
|
19
|
+
* stream. A client that is reading reconnects and misses the frames in
|
|
20
|
+
* between. The twin of the Rust spine's `fuz_realtime` SSE bound — the same
|
|
21
|
+
* budget and charge.
|
|
22
|
+
*
|
|
7
23
|
* @module
|
|
8
24
|
*/
|
|
9
25
|
import { streamSSE } from 'hono/streaming';
|
|
10
26
|
import { z } from 'zod';
|
|
11
27
|
import { DEV } from 'esm-env';
|
|
12
|
-
import {
|
|
28
|
+
import { utf8_length } from '../actions/transports.js';
|
|
29
|
+
import { OutboundBudget } from './outbound_budget.js';
|
|
30
|
+
import { SSE_CONNECTED_COMMENT, SSE_OUTBOUND_QUEUE_BYTES } from './sse_constants.js';
|
|
13
31
|
const is_node_connection_stream = (value) => {
|
|
14
32
|
if (typeof value !== 'object' || value === null)
|
|
15
33
|
return false;
|
|
@@ -85,10 +103,15 @@ const watch_client_disconnect = (c, on_gone) => {
|
|
|
85
103
|
* Uses `hono_stream.write()` directly (not `writeSSE`) to avoid
|
|
86
104
|
* Hono's HTML callback resolution — keeps the same `data: JSON\n\n` format.
|
|
87
105
|
*
|
|
88
|
-
*
|
|
106
|
+
* What the stream holds unread is bounded by `SSE_OUTBOUND_QUEUE_BYTES`; a
|
|
107
|
+
* frame past it ends the stream (module doc, "Outbound bound").
|
|
108
|
+
*
|
|
109
|
+
* @param log - logger for serialization and `on_close` listener errors, and
|
|
110
|
+
* for the warning when the stream ends on its outbound budget
|
|
111
|
+
* @param options - what the overflow warning names
|
|
89
112
|
* @returns object with the streaming `Response` and an `SseStream` controller
|
|
90
113
|
*/
|
|
91
|
-
export const create_sse_response = (c, log) => {
|
|
114
|
+
export const create_sse_response = (c, log, options) => {
|
|
92
115
|
const { promise, resolve } = Promise.withResolvers();
|
|
93
116
|
const close_listeners = [];
|
|
94
117
|
let resolved = false;
|
|
@@ -107,24 +130,53 @@ export const create_sse_response = (c, log) => {
|
|
|
107
130
|
}
|
|
108
131
|
};
|
|
109
132
|
let sse_stream;
|
|
133
|
+
// charges the frames written to the stream and not yet read from it
|
|
134
|
+
const budget = new OutboundBudget(SSE_OUTBOUND_QUEUE_BYTES);
|
|
110
135
|
const response = streamSSE(c, async (hono_stream) => {
|
|
136
|
+
// Write one frame within the budget, or end the stream. The write
|
|
137
|
+
// settles once the response body has taken the frame, which frees its
|
|
138
|
+
// charge.
|
|
139
|
+
const write = (frame) => {
|
|
140
|
+
const bytes = utf8_length(frame);
|
|
141
|
+
if (!budget.admit(bytes)) {
|
|
142
|
+
// same line as the Rust spine's registry, so one grep finds either
|
|
143
|
+
log.warn('sse: outbound queue overflow, ending the stream', {
|
|
144
|
+
account_id: options?.account_id ?? null,
|
|
145
|
+
...budget.to_overflow(bytes)
|
|
146
|
+
});
|
|
147
|
+
budget.clear();
|
|
148
|
+
// drops what the stream still holds and ends the body; `do_close`
|
|
149
|
+
// runs as its abort listener
|
|
150
|
+
hono_stream.abort();
|
|
151
|
+
do_close();
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
void hono_stream.write(frame).then(() => {
|
|
155
|
+
// a stream that ended has had its charges cleared
|
|
156
|
+
if (!resolved && !hono_stream.aborted)
|
|
157
|
+
budget.release(bytes);
|
|
158
|
+
});
|
|
159
|
+
};
|
|
111
160
|
sse_stream = {
|
|
112
161
|
send(data) {
|
|
113
162
|
if (resolved || hono_stream.aborted)
|
|
114
163
|
return;
|
|
164
|
+
let frame;
|
|
115
165
|
try {
|
|
116
166
|
// JSON.stringify (no space arg) never produces literal newlines,
|
|
117
167
|
// so single-line `data:` framing is safe per the SSE spec.
|
|
118
|
-
|
|
168
|
+
frame = `data: ${JSON.stringify(data)}\n\n`;
|
|
119
169
|
}
|
|
120
170
|
catch (e) {
|
|
121
171
|
log.error('send failed to serialize data:', e);
|
|
172
|
+
return;
|
|
122
173
|
}
|
|
174
|
+
write(frame);
|
|
123
175
|
},
|
|
124
176
|
comment(text) {
|
|
125
177
|
if (resolved || hono_stream.aborted)
|
|
126
178
|
return;
|
|
127
|
-
|
|
179
|
+
write(`: ${text}\n`);
|
|
128
180
|
},
|
|
129
181
|
close: do_close,
|
|
130
182
|
on_close(fn) {
|
|
@@ -143,7 +195,7 @@ export const create_sse_response = (c, log) => {
|
|
|
143
195
|
hono_stream.onAbort(do_close);
|
|
144
196
|
// flush an SSE comment to push headers through proxies (Vite, nginx),
|
|
145
197
|
// ensuring EventSource fires onopen without waiting for the first data event
|
|
146
|
-
|
|
198
|
+
write(SSE_CONNECTED_COMMENT);
|
|
147
199
|
await promise;
|
|
148
200
|
});
|
|
149
201
|
// after the callback above has built `sse_stream`, which runs synchronously
|
|
@@ -14,4 +14,16 @@
|
|
|
14
14
|
* SSE tests assert the stream emits this on connect.
|
|
15
15
|
*/
|
|
16
16
|
export declare const SSE_CONNECTED_COMMENT = ": connected\n\n";
|
|
17
|
+
/**
|
|
18
|
+
* The byte budget of what one SSE stream holds for its client to read
|
|
19
|
+
* (`realtime/sse.ts` module doc, "Outbound bound").
|
|
20
|
+
*
|
|
21
|
+
* 1 MiB — equal to the default cap on one request body
|
|
22
|
+
* (`DEFAULT_MAX_BODY_SIZE`). An audit row is bounded by the request that
|
|
23
|
+
* produced it, so on a server that keeps that default the budget holds a burst
|
|
24
|
+
* of ordinary rows or one at the largest. The value is fixed and does not
|
|
25
|
+
* follow the server's body limit. Same value as the Rust spine's
|
|
26
|
+
* `SSE_OUTBOUND_QUEUE_BYTES`.
|
|
27
|
+
*/
|
|
28
|
+
export declare const SSE_OUTBOUND_QUEUE_BYTES: number;
|
|
17
29
|
//# sourceMappingURL=sse_constants.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sse_constants.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/realtime/sse_constants.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,oBAAoB,CAAC"}
|
|
1
|
+
{"version":3,"file":"sse_constants.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/realtime/sse_constants.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,oBAAoB,CAAC;AAEvD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,wBAAwB,QAAc,CAAC"}
|
|
@@ -14,3 +14,15 @@
|
|
|
14
14
|
* SSE tests assert the stream emits this on connect.
|
|
15
15
|
*/
|
|
16
16
|
export const SSE_CONNECTED_COMMENT = `: connected\n\n`;
|
|
17
|
+
/**
|
|
18
|
+
* The byte budget of what one SSE stream holds for its client to read
|
|
19
|
+
* (`realtime/sse.ts` module doc, "Outbound bound").
|
|
20
|
+
*
|
|
21
|
+
* 1 MiB — equal to the default cap on one request body
|
|
22
|
+
* (`DEFAULT_MAX_BODY_SIZE`). An audit row is bounded by the request that
|
|
23
|
+
* produced it, so on a server that keeps that default the budget holds a burst
|
|
24
|
+
* of ordinary rows or one at the largest. The value is fixed and does not
|
|
25
|
+
* follow the server's body limit. Same value as the Rust spine's
|
|
26
|
+
* `SSE_OUTBOUND_QUEUE_BYTES`.
|
|
27
|
+
*/
|
|
28
|
+
export const SSE_OUTBOUND_QUEUE_BYTES = 1024 * 1024;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app_server.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/server/app_server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,IAAI,EAAE,KAAK,OAAO,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"app_server.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/server/app_server.ts"],"names":[],"mappings":"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"}
|