@fuzdev/fuz_app 0.124.0 → 0.126.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 +58 -21
- package/dist/actions/action_rpc.d.ts +14 -11
- package/dist/actions/action_rpc.d.ts.map +1 -1
- package/dist/actions/action_rpc.js +5 -4
- package/dist/actions/connection_closer.d.ts +13 -3
- package/dist/actions/connection_closer.d.ts.map +1 -1
- package/dist/actions/connection_closer.js +7 -5
- package/dist/actions/register_action_ws.d.ts +18 -13
- package/dist/actions/register_action_ws.d.ts.map +1 -1
- package/dist/actions/register_action_ws.js +9 -7
- package/dist/actions/register_ws_endpoint.d.ts +6 -3
- package/dist/actions/register_ws_endpoint.d.ts.map +1 -1
- package/dist/actions/register_ws_endpoint.js +6 -3
- package/dist/actions/transports.d.ts +9 -0
- package/dist/actions/transports.d.ts.map +1 -1
- package/dist/actions/transports.js +9 -0
- package/dist/actions/transports_ws_backend.d.ts +16 -1
- package/dist/actions/transports_ws_backend.d.ts.map +1 -1
- package/dist/actions/transports_ws_backend.js +26 -6
- package/dist/actions/ws_endpoint_spec.d.ts +24 -4
- package/dist/actions/ws_endpoint_spec.d.ts.map +1 -1
- package/dist/actions/ws_endpoint_spec.js +15 -1
- package/dist/auth/middleware.d.ts +29 -1
- package/dist/auth/middleware.d.ts.map +1 -1
- package/dist/auth/middleware.js +35 -1
- package/dist/http/surface.d.ts +3 -1
- package/dist/http/surface.d.ts.map +1 -1
- package/dist/http/surface.js +15 -1
- package/dist/rate_limiter.d.ts +25 -3
- package/dist/rate_limiter.d.ts.map +1 -1
- package/dist/rate_limiter.js +4 -3
- package/dist/realtime/sse_auth_guard.d.ts +2 -1
- package/dist/realtime/sse_auth_guard.d.ts.map +1 -1
- package/dist/realtime/sse_auth_guard.js +4 -2
- package/dist/realtime/subscriber_registry.d.ts +12 -0
- package/dist/realtime/subscriber_registry.d.ts.map +1 -1
- package/dist/realtime/subscriber_registry.js +18 -2
- package/dist/server/app_server.d.ts +127 -51
- package/dist/server/app_server.d.ts.map +1 -1
- package/dist/server/app_server.js +107 -60
- package/dist/server/app_server_context.d.ts +17 -9
- package/dist/server/app_server_context.d.ts.map +1 -1
- package/dist/server/static.d.ts +1 -1
- package/dist/testing/CLAUDE.md +77 -19
- package/dist/testing/app_server.d.ts +6 -3
- package/dist/testing/app_server.d.ts.map +1 -1
- package/dist/testing/app_server.js +11 -12
- package/dist/testing/connection_closer_helpers.d.ts +10 -4
- package/dist/testing/connection_closer_helpers.d.ts.map +1 -1
- package/dist/testing/connection_closer_helpers.js +4 -0
- package/dist/testing/cross_backend/capabilities.d.ts +3 -3
- package/dist/testing/cross_backend/default_backend_configs.d.ts +31 -0
- package/dist/testing/cross_backend/default_backend_configs.d.ts.map +1 -1
- package/dist/testing/cross_backend/default_backend_configs.js +31 -0
- package/dist/testing/cross_backend/full_spine_mount.d.ts +35 -11
- package/dist/testing/cross_backend/full_spine_mount.d.ts.map +1 -1
- package/dist/testing/cross_backend/full_spine_mount.js +26 -9
- package/dist/testing/cross_backend/rust_spine_stub_backend_config.d.ts +15 -0
- 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 +3 -2
- package/dist/testing/cross_backend/testing_backdoor.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_backdoor.js +2 -1
- package/dist/testing/cross_backend/testing_reset_actions.d.ts +6 -3
- package/dist/testing/cross_backend/testing_reset_actions.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_reset_actions.js +6 -3
- package/dist/testing/cross_backend/testing_server_bun.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_server_bun.js +11 -7
- package/dist/testing/cross_backend/testing_server_core.d.ts +68 -37
- package/dist/testing/cross_backend/testing_server_core.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_server_core.js +20 -12
- package/dist/testing/cross_backend/testing_server_deno.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_server_deno.js +5 -4
- package/dist/testing/cross_backend/testing_server_node.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_server_node.js +20 -7
- package/dist/testing/cross_backend/ts_spine_backend_config.d.ts +17 -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 +11 -6
- package/dist/testing/cross_backend/ws_action_rate_limit.d.ts +26 -0
- package/dist/testing/cross_backend/ws_action_rate_limit.d.ts.map +1 -0
- package/dist/testing/cross_backend/ws_action_rate_limit.js +261 -0
- package/dist/testing/stubs.d.ts +14 -4
- package/dist/testing/stubs.d.ts.map +1 -1
- package/dist/testing/stubs.js +31 -13
- package/dist/testing/transports/ws_transport.d.ts +7 -0
- package/dist/testing/transports/ws_transport.d.ts.map +1 -1
- package/dist/testing/transports/ws_transport.js +1 -1
- package/dist/testing/ws_round_trip.d.ts +36 -6
- package/dist/testing/ws_round_trip.d.ts.map +1 -1
- package/dist/testing/ws_round_trip.js +28 -8
- package/package.json +15 -5
|
@@ -51,7 +51,7 @@ import { Logger } from '@fuzdev/fuz_util/log.ts';
|
|
|
51
51
|
import { create_uuid } from '@fuzdev/fuz_util/id.ts';
|
|
52
52
|
import { jsonrpc_error_messages } from '../http/jsonrpc_errors.js';
|
|
53
53
|
import { create_jsonrpc_error_response, create_jsonrpc_request, to_jsonrpc_message_id, is_jsonrpc_request } from '../http/jsonrpc_helpers.js';
|
|
54
|
-
import { WS_CLOSE_CONNECTION_LIMIT, WS_CLOSE_SESSION_REVOKED, WS_CLOSE_SESSION_REVOKED_REASON } from './transports.js';
|
|
54
|
+
import { WS_CLOSE_CONNECTION_LIMIT, WS_CLOSE_GOING_AWAY, WS_CLOSE_GOING_AWAY_REASON, WS_CLOSE_SESSION_REVOKED, WS_CLOSE_SESSION_REVOKED_REASON } from './transports.js';
|
|
55
55
|
import { PendingPeerRequests } from './peer_request.js';
|
|
56
56
|
/** Type guard for `FilterableBroadcastTransport`. */
|
|
57
57
|
export const is_filterable_broadcast_transport = (transport) => 'broadcast_filtered' in transport &&
|
|
@@ -204,7 +204,7 @@ export class BackendWebsocketTransport {
|
|
|
204
204
|
* no-op for an unknown id.
|
|
205
205
|
*
|
|
206
206
|
* Keyed by id rather than by `WSContext` because a runtime adapter may hand
|
|
207
|
-
* each socket event its own context object (
|
|
207
|
+
* each socket event its own context object (`@hono/bun` does), so the one a
|
|
208
208
|
* close event carries can't identify the connection.
|
|
209
209
|
*
|
|
210
210
|
* Removal only: the socket is not closed and the registered
|
|
@@ -227,10 +227,13 @@ export class BackendWebsocketTransport {
|
|
|
227
227
|
* socket's connection is already removed and its handlers aborted, so
|
|
228
228
|
* nothing more is dispatched or delivered on it.
|
|
229
229
|
*
|
|
230
|
+
* @param predicate - which connections to close
|
|
231
|
+
* @param code - the close code each socket gets
|
|
232
|
+
* @param reason - the close reason each socket gets
|
|
230
233
|
* @returns the number of sockets closed
|
|
231
234
|
* @throws the first error a socket's `close` threw, after every match was attempted
|
|
232
235
|
*/
|
|
233
|
-
#close_where(predicate) {
|
|
236
|
+
#close_where(predicate, code = WS_CLOSE_SESSION_REVOKED, reason = WS_CLOSE_SESSION_REVOKED_REASON) {
|
|
234
237
|
let count = 0;
|
|
235
238
|
let failed = false;
|
|
236
239
|
let first_error;
|
|
@@ -238,7 +241,7 @@ export class BackendWebsocketTransport {
|
|
|
238
241
|
for (const [connection_id, entry] of this.#connections) {
|
|
239
242
|
if (predicate(entry.identity)) {
|
|
240
243
|
try {
|
|
241
|
-
this.#
|
|
244
|
+
this.#end_connection(connection_id, entry, code, reason);
|
|
242
245
|
count++;
|
|
243
246
|
}
|
|
244
247
|
catch (error) {
|
|
@@ -293,18 +296,35 @@ export class BackendWebsocketTransport {
|
|
|
293
296
|
close_sockets_for_token(api_token_id) {
|
|
294
297
|
return this.#close_where((id) => id.api_token_id === api_token_id);
|
|
295
298
|
}
|
|
299
|
+
/**
|
|
300
|
+
* Close every connection, pending or admitted, with `WS_CLOSE_GOING_AWAY` —
|
|
301
|
+
* the shutdown close `AppServer.close` runs. Not a revocation: the client
|
|
302
|
+
* reconnects under its ordinary backoff.
|
|
303
|
+
*
|
|
304
|
+
* Each closed connection is removed and its controller aborted, as a
|
|
305
|
+
* revocation does, so its heartbeat timer stops and nothing more dispatches
|
|
306
|
+
* on it. A socket whose `close` throws does not stop the loop.
|
|
307
|
+
*
|
|
308
|
+
* @returns the number of sockets closed
|
|
309
|
+
* @mutates this - removes every connection, aborts its registered
|
|
310
|
+
* controller, and closes its underlying `WSContext` with `WS_CLOSE_GOING_AWAY`
|
|
311
|
+
* @throws the first error a socket's `close` threw, after every connection was attempted
|
|
312
|
+
*/
|
|
313
|
+
close_all_sockets() {
|
|
314
|
+
return this.#close_where(() => true, WS_CLOSE_GOING_AWAY, WS_CLOSE_GOING_AWAY_REASON);
|
|
315
|
+
}
|
|
296
316
|
#cleanup_connection(connection_id) {
|
|
297
317
|
this.#connections.delete(connection_id);
|
|
298
318
|
// Wake any handler still awaiting a reply on this socket — the peer is
|
|
299
319
|
// gone, so the request can never complete.
|
|
300
320
|
this.#pending.drain(connection_id);
|
|
301
321
|
}
|
|
302
|
-
#
|
|
322
|
+
#end_connection(connection_id, entry, code, reason) {
|
|
303
323
|
this.#cleanup_connection(connection_id);
|
|
304
324
|
// abort before the close so a handler observing `ctx.signal` bails out
|
|
305
325
|
// without waiting for the close handshake
|
|
306
326
|
entry.abort_controller?.abort();
|
|
307
|
-
entry.ws.close(
|
|
327
|
+
entry.ws.close(code, reason);
|
|
308
328
|
}
|
|
309
329
|
/**
|
|
310
330
|
* Make room for one more admitted connection on `account_id`: when the
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
* by `create_app_server`'s `ws_endpoints` option (mirror of `RpcEndpointSpec`
|
|
4
4
|
* for HTTP RPC).
|
|
5
5
|
*
|
|
6
|
+
* Also `resolve_ws_endpoints`, which fills in the server's `allowed_origins`.
|
|
7
|
+
*
|
|
6
8
|
* Lives in its own module so both `server/app_server.ts` (which mounts
|
|
7
9
|
* endpoints from these specs) and `http/surface.ts` (which threads the
|
|
8
10
|
* resolved spec list into surface generation) can import it without a
|
|
@@ -28,10 +30,14 @@ export interface WsEndpointSpec {
|
|
|
28
30
|
/** Hono mount path (e.g. `/api/ws`). */
|
|
29
31
|
path: string;
|
|
30
32
|
/**
|
|
31
|
-
* Origin allowlist regexes —
|
|
32
|
-
*
|
|
33
|
+
* Origin allowlist regexes for the upgrade — passed straight to
|
|
34
|
+
* `verify_request_source`. Defaults to the server's
|
|
35
|
+
* `AppServerOptions.allowed_origins`, the list the HTTP routes check.
|
|
36
|
+
* Set it only to narrow one endpoint: the auth middleware's origin check
|
|
37
|
+
* runs on the upgrade too, so a request reaches the endpoint only when
|
|
38
|
+
* its origin passes both lists.
|
|
33
39
|
*/
|
|
34
|
-
allowed_origins
|
|
40
|
+
allowed_origins?: ReadonlyArray<RegExp>;
|
|
35
41
|
/**
|
|
36
42
|
* The actions registered on this endpoint. Spread `protocol_actions`
|
|
37
43
|
* from `actions/protocol.ts` first to complete the
|
|
@@ -43,7 +49,7 @@ export interface WsEndpointSpec {
|
|
|
43
49
|
* Roles permitted to upgrade — any-of disjunction. Omit (or pass `[]`)
|
|
44
50
|
* to skip the upgrade-time role gate; per-action `auth` on each spec
|
|
45
51
|
* still applies at dispatch time via `perform_action`. Pass
|
|
46
|
-
* `[ROLE_ADMIN]` for
|
|
52
|
+
* `[ROLE_ADMIN]` for an admin-only WS endpoint.
|
|
47
53
|
*/
|
|
48
54
|
required_roles?: ReadonlyArray<RoleName>;
|
|
49
55
|
/**
|
|
@@ -136,4 +142,18 @@ export interface WsEndpointSpec {
|
|
|
136
142
|
*/
|
|
137
143
|
extra_audit_handlers?: ReadonlyArray<AuditEventHandler>;
|
|
138
144
|
}
|
|
145
|
+
/** A `WsEndpointSpec` whose `allowed_origins` is resolved — its own, or the server's. */
|
|
146
|
+
export type ResolvedWsEndpointSpec = WsEndpointSpec & {
|
|
147
|
+
allowed_origins: ReadonlyArray<RegExp>;
|
|
148
|
+
};
|
|
149
|
+
/**
|
|
150
|
+
* Fill in the server's `allowed_origins` on each WS endpoint spec that omits
|
|
151
|
+
* its own, so every consumer of the resolved list — the mount, the surface —
|
|
152
|
+
* reads the effective patterns.
|
|
153
|
+
*
|
|
154
|
+
* @param ws_endpoints - the resolved `ws_endpoints` option
|
|
155
|
+
* @param allowed_origins - the server's allowlist, the default
|
|
156
|
+
* @returns the specs, each with `allowed_origins` set
|
|
157
|
+
*/
|
|
158
|
+
export declare const resolve_ws_endpoints: (ws_endpoints: ReadonlyArray<WsEndpointSpec> | undefined, allowed_origins: ReadonlyArray<RegExp>) => Array<ResolvedWsEndpointSpec> | undefined;
|
|
139
159
|
//# sourceMappingURL=ws_endpoint_spec.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ws_endpoint_spec.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/ws_endpoint_spec.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"ws_endpoint_spec.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/ws_endpoint_spec.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAC5E,OAAO,KAAK,EACX,sBAAsB,EACtB,kBAAkB,EAClB,iBAAiB,EACjB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAEvE;;;;;;;;GAQG;AACH,MAAM,WAAW,cAAc;IAC9B,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACxC;;;;;OAKG;IACH,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC/B;;;;;OAKG;IACH,cAAc,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;IACzC;;;;OAIG;IACH,SAAS,CAAC,EAAE,yBAAyB,CAAC;IACtC;;;;;;OAMG;IACH,2BAA2B,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5C;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,GAAG,sBAAsB,CAAC;IAC7C,6DAA6D;IAC7D,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;OAIG;IACH,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,iBAAiB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClE;;;;OAIG;IACH,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,kBAAkB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAoCG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;;;;OAQG;IACH,oBAAoB,CAAC,EAAE,aAAa,CAAC,iBAAiB,CAAC,CAAC;CACxD;AAED,yFAAyF;AACzF,MAAM,MAAM,sBAAsB,GAAG,cAAc,GAAG;IAAE,eAAe,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CAAE,CAAC;AAEjG;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,GAChC,cAAc,aAAa,CAAC,cAAc,CAAC,GAAG,SAAS,EACvD,iBAAiB,aAAa,CAAC,MAAM,CAAC,KACpC,KAAK,CAAC,sBAAsB,CAAC,GAAG,SAI/B,CAAC"}
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
* by `create_app_server`'s `ws_endpoints` option (mirror of `RpcEndpointSpec`
|
|
4
4
|
* for HTTP RPC).
|
|
5
5
|
*
|
|
6
|
+
* Also `resolve_ws_endpoints`, which fills in the server's `allowed_origins`.
|
|
7
|
+
*
|
|
6
8
|
* Lives in its own module so both `server/app_server.ts` (which mounts
|
|
7
9
|
* endpoints from these specs) and `http/surface.ts` (which threads the
|
|
8
10
|
* resolved spec list into surface generation) can import it without a
|
|
@@ -10,4 +12,16 @@
|
|
|
10
12
|
*
|
|
11
13
|
* @module
|
|
12
14
|
*/
|
|
13
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Fill in the server's `allowed_origins` on each WS endpoint spec that omits
|
|
17
|
+
* its own, so every consumer of the resolved list — the mount, the surface —
|
|
18
|
+
* reads the effective patterns.
|
|
19
|
+
*
|
|
20
|
+
* @param ws_endpoints - the resolved `ws_endpoints` option
|
|
21
|
+
* @param allowed_origins - the server's allowlist, the default
|
|
22
|
+
* @returns the specs, each with `allowed_origins` set
|
|
23
|
+
*/
|
|
24
|
+
export const resolve_ws_endpoints = (ws_endpoints, allowed_origins) => ws_endpoints?.map((endpoint) => ({
|
|
25
|
+
...endpoint,
|
|
26
|
+
allowed_origins: endpoint.allowed_origins ?? allowed_origins
|
|
27
|
+
}));
|
|
@@ -10,13 +10,41 @@ import type { SessionOptions } from './session_cookie.js';
|
|
|
10
10
|
import type { AppDeps } from './deps.js';
|
|
11
11
|
import type { DaemonTokenState } from './daemon_token.js';
|
|
12
12
|
import type { MiddlewareSpec } from '../http/middleware_spec.js';
|
|
13
|
+
/**
|
|
14
|
+
* The Hono path pattern the auth middleware stack mounts on by default —
|
|
15
|
+
* origin verification, session parsing, request context, bearer and daemon
|
|
16
|
+
* token auth all run for the paths it matches, and no others.
|
|
17
|
+
*
|
|
18
|
+
* `create_app_server` mounts the stack here, and refuses at assembly (via
|
|
19
|
+
* `assert_endpoint_in_auth_scope`, which `create_test_app_surface_spec` also
|
|
20
|
+
* runs) an `rpc_endpoints` or `ws_endpoints` path the pattern does not match (tested
|
|
21
|
+
* with `middleware_applies`, which follows Hono: `'/api/*'` matches `/api`
|
|
22
|
+
* and everything under `/api/`): an endpoint outside it would get no
|
|
23
|
+
* session parsing, so every call or upgrade would be unauthenticated.
|
|
24
|
+
*/
|
|
25
|
+
export declare const AUTH_MIDDLEWARE_PATH = "/api/*";
|
|
26
|
+
/**
|
|
27
|
+
* Throw when an endpoint path sits outside the auth middleware's scope
|
|
28
|
+
* (`AUTH_MIDDLEWARE_PATH`) — there it would get no session or bearer
|
|
29
|
+
* parsing, so every call or upgrade would be unauthenticated.
|
|
30
|
+
* `middleware_applies` matches the way Hono matches the middleware's pattern.
|
|
31
|
+
*
|
|
32
|
+
* `create_app_server` calls it for every `rpc_endpoints` and `ws_endpoints`
|
|
33
|
+
* path at assembly, and `create_test_app_surface_spec` does the same, so a
|
|
34
|
+
* surface snapshot never records an endpoint the real server refuses.
|
|
35
|
+
*
|
|
36
|
+
* @param option - the option the path came from, named in the error
|
|
37
|
+
* @param path - the endpoint path to check
|
|
38
|
+
* @throws Error when `path` is outside `AUTH_MIDDLEWARE_PATH`
|
|
39
|
+
*/
|
|
40
|
+
export declare const assert_endpoint_in_auth_scope: (option: "rpc_endpoints" | "ws_endpoints", path: string) => void;
|
|
13
41
|
/**
|
|
14
42
|
* Per-factory configuration for the standard auth middleware stack.
|
|
15
43
|
*/
|
|
16
44
|
export interface AuthMiddlewareOptions {
|
|
17
45
|
allowed_origins: Array<RegExp>;
|
|
18
46
|
session_options: SessionOptions<string>;
|
|
19
|
-
/** Path pattern for middleware (default: `'/api/*'`). */
|
|
47
|
+
/** Path pattern for middleware (default: `AUTH_MIDDLEWARE_PATH`, `'/api/*'`). */
|
|
20
48
|
path?: string;
|
|
21
49
|
/** Daemon token state for keeper auth. Omit to disable daemon token middleware. */
|
|
22
50
|
daemon_token_state?: DaemonTokenState;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAIjE;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,oBAAoB,WAAW,CAAC;AAE7C;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,6BAA6B,GACzC,QAAQ,eAAe,GAAG,cAAc,EACxC,MAAM,MAAM,KACV,IAOF,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACrC,eAAe,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC/B,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,iFAAiF;IACjF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,mFAAmF;IACnF,kBAAkB,CAAC,EAAE,gBAAgB,CAAC;CACtC;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,4BAA4B,GACxC,MAAM,OAAO,EACb,SAAS,qBAAqB,KAC5B,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,CA4E/B,CAAC"}
|
package/dist/auth/middleware.js
CHANGED
|
@@ -7,6 +7,40 @@
|
|
|
7
7
|
* @module
|
|
8
8
|
*/
|
|
9
9
|
import { ApiError } from '../http/error_schemas.js';
|
|
10
|
+
import { middleware_applies } from '../http/schema_helpers.js';
|
|
11
|
+
/**
|
|
12
|
+
* The Hono path pattern the auth middleware stack mounts on by default —
|
|
13
|
+
* origin verification, session parsing, request context, bearer and daemon
|
|
14
|
+
* token auth all run for the paths it matches, and no others.
|
|
15
|
+
*
|
|
16
|
+
* `create_app_server` mounts the stack here, and refuses at assembly (via
|
|
17
|
+
* `assert_endpoint_in_auth_scope`, which `create_test_app_surface_spec` also
|
|
18
|
+
* runs) an `rpc_endpoints` or `ws_endpoints` path the pattern does not match (tested
|
|
19
|
+
* with `middleware_applies`, which follows Hono: `'/api/*'` matches `/api`
|
|
20
|
+
* and everything under `/api/`): an endpoint outside it would get no
|
|
21
|
+
* session parsing, so every call or upgrade would be unauthenticated.
|
|
22
|
+
*/
|
|
23
|
+
export const AUTH_MIDDLEWARE_PATH = '/api/*';
|
|
24
|
+
/**
|
|
25
|
+
* Throw when an endpoint path sits outside the auth middleware's scope
|
|
26
|
+
* (`AUTH_MIDDLEWARE_PATH`) — there it would get no session or bearer
|
|
27
|
+
* parsing, so every call or upgrade would be unauthenticated.
|
|
28
|
+
* `middleware_applies` matches the way Hono matches the middleware's pattern.
|
|
29
|
+
*
|
|
30
|
+
* `create_app_server` calls it for every `rpc_endpoints` and `ws_endpoints`
|
|
31
|
+
* path at assembly, and `create_test_app_surface_spec` does the same, so a
|
|
32
|
+
* surface snapshot never records an endpoint the real server refuses.
|
|
33
|
+
*
|
|
34
|
+
* @param option - the option the path came from, named in the error
|
|
35
|
+
* @param path - the endpoint path to check
|
|
36
|
+
* @throws Error when `path` is outside `AUTH_MIDDLEWARE_PATH`
|
|
37
|
+
*/
|
|
38
|
+
export const assert_endpoint_in_auth_scope = (option, path) => {
|
|
39
|
+
if (!middleware_applies(AUTH_MIDDLEWARE_PATH, path)) {
|
|
40
|
+
throw new Error(`${option} path ${path} is outside the auth middleware's scope ` +
|
|
41
|
+
`(${AUTH_MIDDLEWARE_PATH}) — it would see every caller as unauthenticated — mount it under /api/`);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
10
44
|
/**
|
|
11
45
|
* Create the auth middleware stack.
|
|
12
46
|
*
|
|
@@ -21,7 +55,7 @@ import { ApiError } from '../http/error_schemas.js';
|
|
|
21
55
|
*/
|
|
22
56
|
export const create_auth_middleware_specs = async (deps, options) => {
|
|
23
57
|
const { keyring, db } = deps;
|
|
24
|
-
const { allowed_origins, session_options, path =
|
|
58
|
+
const { allowed_origins, session_options, path = AUTH_MIDDLEWARE_PATH, daemon_token_state } = options;
|
|
25
59
|
const query_deps = { db };
|
|
26
60
|
// Dynamic imports preserve the bundle-split for type-only consumers of
|
|
27
61
|
// this module (`MiddlewareSpec`, `AuthMiddlewareOptions`, etc.). The
|
package/dist/http/surface.d.ts
CHANGED
|
@@ -179,7 +179,9 @@ export interface GenerateAppSurfaceOptions {
|
|
|
179
179
|
* Mounted WS endpoints (the same array `create_app_server.ws_endpoints`
|
|
180
180
|
* auto-mounts). Each entry's actions surface into
|
|
181
181
|
* `AppSurface.ws_endpoints[i].methods` for attack-surface tests +
|
|
182
|
-
* startup logging.
|
|
182
|
+
* startup logging. Each must carry its effective `allowed_origins` —
|
|
183
|
+
* `create_app_server` fills in the server's list where a spec omits it —
|
|
184
|
+
* and generation throws on one that doesn't.
|
|
183
185
|
*/
|
|
184
186
|
ws_endpoints?: ReadonlyArray<WsEndpointSpec>;
|
|
185
187
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"surface.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/surface.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"surface.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/surface.ts"],"names":[],"mappings":"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"}
|
package/dist/http/surface.js
CHANGED
|
@@ -8,6 +8,20 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { z } from 'zod';
|
|
10
10
|
import { schema_to_surface, middleware_applies, merge_error_schemas, is_null_schema, is_strict_object_schema } from './schema_helpers.js';
|
|
11
|
+
/**
|
|
12
|
+
* Stringify a WS endpoint's origin allowlist for the surface. Throws when
|
|
13
|
+
* the spec carries none: the surface records the exact patterns the
|
|
14
|
+
* upgrade gate matches, and an omitted list means the caller never
|
|
15
|
+
* resolved the server default, not any-origin.
|
|
16
|
+
*/
|
|
17
|
+
const to_surface_allowed_origins = (ep) => {
|
|
18
|
+
if (!ep.allowed_origins) {
|
|
19
|
+
throw new Error(`generate_app_surface: ws endpoint ${ep.path} has no allowed_origins — ` +
|
|
20
|
+
"resolve the server's allowed_origins into the spec before surface generation " +
|
|
21
|
+
"(resolve_ws_endpoints, or create_test_app_surface_spec's allowed_origins option)");
|
|
22
|
+
}
|
|
23
|
+
return ep.allowed_origins.map((re) => re.toString());
|
|
24
|
+
};
|
|
11
25
|
// --- Surface generation ---
|
|
12
26
|
/**
|
|
13
27
|
* Collect error schemas from all middleware that applies to a route path.
|
|
@@ -145,7 +159,7 @@ export const generate_app_surface = (options) => {
|
|
|
145
159
|
ws_endpoints: ws_endpoints?.length
|
|
146
160
|
? ws_endpoints.map((ep) => ({
|
|
147
161
|
path: ep.path,
|
|
148
|
-
allowed_origins: ep
|
|
162
|
+
allowed_origins: to_surface_allowed_origins(ep),
|
|
149
163
|
required_roles: ep.required_roles ?? [],
|
|
150
164
|
// `local_call` specs are frontend-side helpers — registry-only
|
|
151
165
|
// on the backend, never dispatched over WS. Drop them from the
|
package/dist/rate_limiter.d.ts
CHANGED
|
@@ -66,13 +66,34 @@ export declare const default_login_account_rate_limit: RateLimiterOptions;
|
|
|
66
66
|
*/
|
|
67
67
|
export declare const default_action_ip_rate_limit: RateLimiterOptions;
|
|
68
68
|
/**
|
|
69
|
-
* Default options for per-
|
|
69
|
+
* Default options for per-account action-dispatcher rate limiting: 1200
|
|
70
70
|
* attempts per 15 minutes. Shared by the HTTP RPC and WebSocket action
|
|
71
71
|
* dispatchers. Permissive — sustained ~80/min is well above any human
|
|
72
72
|
* admin workflow; an oracle probing 10k addresses still finishes in
|
|
73
73
|
* ~2 hours, slow enough to surface in audit. Tighten downstream.
|
|
74
74
|
*/
|
|
75
75
|
export declare const default_action_account_rate_limit: RateLimiterOptions;
|
|
76
|
+
/**
|
|
77
|
+
* Whether a server builds the rate limiters it is not handed —
|
|
78
|
+
* `AppServerOptions.rate_limiters`.
|
|
79
|
+
*
|
|
80
|
+
* - `'enforced'` — every limiter left out of the options is a default
|
|
81
|
+
* instance. The only mode a production server uses, and the default.
|
|
82
|
+
* - `'disabled_for_testing'` — every limiter left out is `null`, so nothing
|
|
83
|
+
* is throttled. For in-process test apps and test binaries: they drive many
|
|
84
|
+
* round-trips from one address, and the IP buckets are monotone within their
|
|
85
|
+
* window (a success never refunds them, see `RateLimiter.reset`), so a
|
|
86
|
+
* suite's failures pile up until every later call is refused.
|
|
87
|
+
*
|
|
88
|
+
* A limiter passed explicitly — an instance or `null` — wins over the mode
|
|
89
|
+
* either way, so a rate-limit test enables just the limiter it pins. The
|
|
90
|
+
* disabled mode is loud: `create_app_server` adds a surface warning, which
|
|
91
|
+
* `log_startup_summary` logs at assembly.
|
|
92
|
+
*
|
|
93
|
+
* Twin of the Rust spine's `fuz_auth::RateLimiterMode` (`Enforced` /
|
|
94
|
+
* `DisabledForTesting`).
|
|
95
|
+
*/
|
|
96
|
+
export type RateLimiterMode = 'enforced' | 'disabled_for_testing';
|
|
76
97
|
/**
|
|
77
98
|
* Result of a rate limit check or record operation.
|
|
78
99
|
*/
|
|
@@ -98,8 +119,9 @@ export interface RateLimitResult {
|
|
|
98
119
|
* LRU trade-off described on `RateLimiterOptions.max_keys`.
|
|
99
120
|
*
|
|
100
121
|
* Parameters that accept `RateLimiter | null` (e.g. `login_ip_rate_limiter`,
|
|
101
|
-
* `login_account_rate_limiter`)
|
|
102
|
-
*
|
|
122
|
+
* `login_account_rate_limiter`) disable rate limiting when `null` is passed —
|
|
123
|
+
* no checks are performed and all requests are allowed through.
|
|
124
|
+
* `create_app_server` surfaces each disabled limiter as a warning diagnostic.
|
|
103
125
|
*/
|
|
104
126
|
export declare class RateLimiter {
|
|
105
127
|
#private;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rate_limiter.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/rate_limiter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAKpC;;;;;;GAMG;AACH,eAAO,MAAM,6BAA6B,SAAU,CAAC;AAErD;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC,kDAAkD;IAClD,YAAY,EAAE,MAAM,CAAC;IACrB,+CAA+C;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,iEAAiE;IACjE,mBAAmB,EAAE,MAAM,CAAC;IAC5B;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,2BAA2B,EAAE,kBAKzC,CAAC;AAEF,uFAAuF;AACvF,eAAO,MAAM,gCAAgC,EAAE,kBAK9C,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B,EAAE,kBAK1C,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,iCAAiC,EAAE,kBAK/C,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,eAAe;IAC/B,sCAAsC;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,0CAA0C;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,sEAAsE;IACtE,WAAW,EAAE,MAAM,CAAC;CACpB;AAED
|
|
1
|
+
{"version":3,"file":"rate_limiter.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/rate_limiter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAKpC;;;;;;GAMG;AACH,eAAO,MAAM,6BAA6B,SAAU,CAAC;AAErD;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC,kDAAkD;IAClD,YAAY,EAAE,MAAM,CAAC;IACrB,+CAA+C;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,iEAAiE;IACjE,mBAAmB,EAAE,MAAM,CAAC;IAC5B;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,2BAA2B,EAAE,kBAKzC,CAAC;AAEF,uFAAuF;AACvF,eAAO,MAAM,gCAAgC,EAAE,kBAK9C,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B,EAAE,kBAK1C,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,iCAAiC,EAAE,kBAK/C,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,sBAAsB,CAAC;AAElE;;GAEG;AACH,MAAM,WAAW,eAAe;IAC/B,sCAAsC;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,0CAA0C;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,sEAAsE;IACtE,WAAW,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,WAAW;;IACvB,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAC;gBAOzB,OAAO,EAAE,kBAAkB;IAcvC,8BAA8B;IAC9B,IAAI,IAAI,IAAI,MAAM,CAEjB;IAcD;;;;;;;;;;OAUG;IACH,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,GAAE,MAAmB,GAAG,eAAe;IA2B7D;;;;;;OAMG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,GAAE,MAAmB,GAAG,eAAe;IA0B9D;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACH,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIxB;;;;;OAKG;IACH,OAAO,CAAC,GAAG,GAAE,MAAmB,GAAG,IAAI;IAgBvC;;;;OAIG;IACH,OAAO,IAAI,IAAI;CAMf;AAED;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,GAAI,UAAU,OAAO,CAAC,kBAAkB,CAAC,KAAG,WAE3E,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B,GAAI,GAAG,OAAO,EAAE,aAAa,MAAM,KAAG,QAI7E,CAAC"}
|
package/dist/rate_limiter.js
CHANGED
|
@@ -55,7 +55,7 @@ export const default_action_ip_rate_limit = {
|
|
|
55
55
|
max_keys: DEFAULT_RATE_LIMITER_MAX_KEYS
|
|
56
56
|
};
|
|
57
57
|
/**
|
|
58
|
-
* Default options for per-
|
|
58
|
+
* Default options for per-account action-dispatcher rate limiting: 1200
|
|
59
59
|
* attempts per 15 minutes. Shared by the HTTP RPC and WebSocket action
|
|
60
60
|
* dispatchers. Permissive — sustained ~80/min is well above any human
|
|
61
61
|
* admin workflow; an oracle probing 10k addresses still finishes in
|
|
@@ -81,8 +81,9 @@ export const default_action_account_rate_limit = {
|
|
|
81
81
|
* LRU trade-off described on `RateLimiterOptions.max_keys`.
|
|
82
82
|
*
|
|
83
83
|
* Parameters that accept `RateLimiter | null` (e.g. `login_ip_rate_limiter`,
|
|
84
|
-
* `login_account_rate_limiter`)
|
|
85
|
-
*
|
|
84
|
+
* `login_account_rate_limiter`) disable rate limiting when `null` is passed —
|
|
85
|
+
* no checks are performed and all requests are allowed through.
|
|
86
|
+
* `create_app_server` surfaces each disabled limiter as a warning diagnostic.
|
|
86
87
|
*/
|
|
87
88
|
export class RateLimiter {
|
|
88
89
|
options;
|
|
@@ -35,7 +35,8 @@ export declare const AUDIT_LOG_CHANNEL = "audit_log";
|
|
|
35
35
|
* their `groups` — pending registrations included. The audit stream route
|
|
36
36
|
* registers `scope = session hash` and `groups = [account id]`; a route that
|
|
37
37
|
* admits bearer tokens registers the API token id too, and
|
|
38
|
-
* `close_sockets_for_token` then reaches it.
|
|
38
|
+
* `close_sockets_for_token` then reaches it. `close_all_sockets` is
|
|
39
|
+
* `SubscriberRegistry.close_all` — every stream, for shutdown.
|
|
39
40
|
*
|
|
40
41
|
* Twin of the Rust spine's `SocketRevoker` impl on `SseRegistry`.
|
|
41
42
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sse_auth_guard.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/realtime/sse_auth_guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAGtD,OAAO,EAIN,KAAK,aAAa,EAClB,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACxF,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAE3D,2DAA2D;AAC3D,eAAO,MAAM,iBAAiB,cAAc,CAAC;AAE7C
|
|
1
|
+
{"version":3,"file":"sse_auth_guard.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/realtime/sse_auth_guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAGtD,OAAO,EAIN,KAAK,aAAa,EAClB,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACxF,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAE3D,2DAA2D;AAC3D,eAAO,MAAM,iBAAiB,cAAc,CAAC;AAE7C;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,4BAA4B,GAAI,CAAC,EAC7C,UAAU,kBAAkB,CAAC,CAAC,CAAC,KAC7B,gBAKD,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,eAAO,MAAM,qBAAqB,GAAI,CAAC,EACtC,UAAU,kBAAkB,CAAC,CAAC,CAAC,EAC/B,eAAe,MAAM,GAAG,IAAI,EAC5B,KAAK,MAAM,KACT,CAAC,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CA4DjC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC3B;;;;;OAKG;IACH,QAAQ,EAAE,kBAAkB,CAAC,eAAe,CAAC,CAAC;IAC9C,kFAAkF;IAClF,GAAG,EAAE,MAAM,CAAC;IACZ,yJAAyJ;IACzJ,cAAc,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;CAC/C;AAED;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,EAAE,KAAK,CAAC,SAAS,CAOlD,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,2BAA2B,KAAK,CAAC;AAE9C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,eAAO,MAAM,oBAAoB,GAAI,SAAS;IAC7C,mEAAmE;IACnE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;;OAOG;IACH,iBAAiB,EAAE,cAAc,GAAG,IAAI,CAAC;IACzC;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B,KAAG,WAgBH,CAAC"}
|
|
@@ -33,14 +33,16 @@ export const AUDIT_LOG_CHANNEL = 'audit_log';
|
|
|
33
33
|
* their `groups` — pending registrations included. The audit stream route
|
|
34
34
|
* registers `scope = session hash` and `groups = [account id]`; a route that
|
|
35
35
|
* admits bearer tokens registers the API token id too, and
|
|
36
|
-
* `close_sockets_for_token` then reaches it.
|
|
36
|
+
* `close_sockets_for_token` then reaches it. `close_all_sockets` is
|
|
37
|
+
* `SubscriberRegistry.close_all` — every stream, for shutdown.
|
|
37
38
|
*
|
|
38
39
|
* Twin of the Rust spine's `SocketRevoker` impl on `SseRegistry`.
|
|
39
40
|
*/
|
|
40
41
|
export const create_sse_connection_closer = (registry) => ({
|
|
41
42
|
close_sockets_for_session: (session_token_hash) => registry.close_by_identity(session_token_hash),
|
|
42
43
|
close_sockets_for_token: (api_token_id) => registry.close_by_identity(api_token_id),
|
|
43
|
-
close_sockets_for_account: (account_id) => registry.close_by_identity(account_id)
|
|
44
|
+
close_sockets_for_account: (account_id) => registry.close_by_identity(account_id),
|
|
45
|
+
close_all_sockets: () => registry.close_all()
|
|
44
46
|
});
|
|
45
47
|
/**
|
|
46
48
|
* Create an audit event handler that closes SSE streams on a successful
|
|
@@ -236,5 +236,17 @@ export declare class SubscriberRegistry<T> {
|
|
|
236
236
|
* @throws the first error a stream's `close` threw, after every match was attempted
|
|
237
237
|
*/
|
|
238
238
|
close_by_identity(identity: string): number;
|
|
239
|
+
/**
|
|
240
|
+
* Force-close every subscriber, pending or admitted — the shutdown close
|
|
241
|
+
* `AppServer.close` runs through the registry's `ConnectionCloser`.
|
|
242
|
+
*
|
|
243
|
+
* A stream whose `close` throws does not stop the loop: every subscriber is
|
|
244
|
+
* removed and closed, and the first error is thrown afterward.
|
|
245
|
+
*
|
|
246
|
+
* @returns the number of subscribers closed
|
|
247
|
+
* @mutates registry - removes every subscriber and closes its stream
|
|
248
|
+
* @throws the first error a stream's `close` threw, after every subscriber was attempted
|
|
249
|
+
*/
|
|
250
|
+
close_all(): number;
|
|
239
251
|
}
|
|
240
252
|
//# sourceMappingURL=subscriber_registry.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subscriber_registry.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/realtime/subscriber_registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAE1C,0EAA0E;AAC1E,MAAM,WAAW,UAAU,CAAC,CAAC;IAC5B,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;IACrB,sEAAsE;IACtE,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;IAC7B,mDAAmD;IACnD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,qEAAqE;IACrE,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;CAC3B;AASD,wCAAwC;AACxC,MAAM,WAAW,yBAAyB;IACzC;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,0EAA0E;AAC1E,MAAM,WAAW,gBAAgB;IAChC,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACjC;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,MAAM,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CAC/B;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,mBAAmB;IACnC;;;;OAIG;IACH,WAAW,EAAE,MAAM,IAAI,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyEG;AACH,qBAAa,kBAAkB,CAAC,CAAC;;gBAQpB,OAAO,CAAC,EAAE,yBAAyB;IAI/C;;;OAGG;IACH,IAAI,KAAK,IAAI,MAAM,CAMlB;IAED;;;OAGG;IACH,IAAI,aAAa,IAAI,MAAM,CAM1B;IAED;;;;;;;;;;;;;OAaG;IACH,SAAS,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,MAAM,IAAI;IASvE;;;;;;;;;;;;OAYG;IACH,iBAAiB,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,mBAAmB;IAYlE;;;;;;;;;;;;;;OAcG;IACH,KAAK,CAAC,OAAO,EAAE,mBAAmB,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,OAAO;IASlE;;;;;;;OAOG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI;IASzC;;;;;;;;;;;;;;;;;;OAkBG;IACH,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;
|
|
1
|
+
{"version":3,"file":"subscriber_registry.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/realtime/subscriber_registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAE1C,0EAA0E;AAC1E,MAAM,WAAW,UAAU,CAAC,CAAC;IAC5B,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;IACrB,sEAAsE;IACtE,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;IAC7B,mDAAmD;IACnD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,qEAAqE;IACrE,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;CAC3B;AASD,wCAAwC;AACxC,MAAM,WAAW,yBAAyB;IACzC;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,0EAA0E;AAC1E,MAAM,WAAW,gBAAgB;IAChC,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACjC;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,MAAM,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CAC/B;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,mBAAmB;IACnC;;;;OAIG;IACH,WAAW,EAAE,MAAM,IAAI,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyEG;AACH,qBAAa,kBAAkB,CAAC,CAAC;;gBAQpB,OAAO,CAAC,EAAE,yBAAyB;IAI/C;;;OAGG;IACH,IAAI,KAAK,IAAI,MAAM,CAMlB;IAED;;;OAGG;IACH,IAAI,aAAa,IAAI,MAAM,CAM1B;IAED;;;;;;;;;;;;;OAaG;IACH,SAAS,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,MAAM,IAAI;IASvE;;;;;;;;;;;;OAYG;IACH,iBAAiB,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,mBAAmB;IAYlE;;;;;;;;;;;;;;OAcG;IACH,KAAK,CAAC,OAAO,EAAE,mBAAmB,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,OAAO;IASlE;;;;;;;OAOG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI;IASzC;;;;;;;;;;;;;;;;;;OAkBG;IACH,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAM3C;;;;;;;;;;OAUG;IACH,SAAS,IAAI,MAAM;CA0EnB"}
|
|
@@ -236,13 +236,29 @@ export class SubscriberRegistry {
|
|
|
236
236
|
* @throws the first error a stream's `close` threw, after every match was attempted
|
|
237
237
|
*/
|
|
238
238
|
close_by_identity(identity) {
|
|
239
|
+
return this.#close_where((subscriber) => subscriber.scope === identity || !!subscriber.groups?.has(identity));
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Force-close every subscriber, pending or admitted — the shutdown close
|
|
243
|
+
* `AppServer.close` runs through the registry's `ConnectionCloser`.
|
|
244
|
+
*
|
|
245
|
+
* A stream whose `close` throws does not stop the loop: every subscriber is
|
|
246
|
+
* removed and closed, and the first error is thrown afterward.
|
|
247
|
+
*
|
|
248
|
+
* @returns the number of subscribers closed
|
|
249
|
+
* @mutates registry - removes every subscriber and closes its stream
|
|
250
|
+
* @throws the first error a stream's `close` threw, after every subscriber was attempted
|
|
251
|
+
*/
|
|
252
|
+
close_all() {
|
|
253
|
+
return this.#close_where(() => true);
|
|
254
|
+
}
|
|
255
|
+
#close_where(predicate) {
|
|
239
256
|
// collect first, then close — avoids mutating the Set during iteration
|
|
240
257
|
// (stream.close() fires on_close listeners which may call unsubscribe)
|
|
241
258
|
const to_close = [];
|
|
242
259
|
for (const subscriber of this.#subscribers) {
|
|
243
|
-
if (subscriber
|
|
260
|
+
if (predicate(subscriber))
|
|
244
261
|
to_close.push(subscriber);
|
|
245
|
-
}
|
|
246
262
|
}
|
|
247
263
|
let failed = false;
|
|
248
264
|
let first_error;
|