@fuzdev/fuz_app 0.125.0 → 0.127.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 +56 -20
- 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 +8 -6
- 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 +15 -0
- package/dist/actions/transports_ws_backend.d.ts.map +1 -1
- package/dist/actions/transports_ws_backend.js +25 -5
- 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/CLAUDE.md +3 -3
- package/dist/http/surface.d.ts +12 -9
- package/dist/http/surface.d.ts.map +1 -1
- package/dist/rate_limiter.d.ts +43 -3
- package/dist/rate_limiter.d.ts.map +1 -1
- package/dist/rate_limiter.js +27 -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 +128 -55
- package/dist/server/app_server.d.ts.map +1 -1
- package/dist/server/app_server.js +110 -61
- package/dist/server/app_server_context.d.ts +17 -9
- package/dist/server/app_server_context.d.ts.map +1 -1
- package/dist/testing/CLAUDE.md +83 -25
- 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 +20 -20
- 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 +12 -12
- package/dist/testing/cross_backend/default_backend_configs.d.ts.map +1 -1
- package/dist/testing/cross_backend/default_backend_configs.js +11 -10
- 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 +16 -1
- 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 +5 -4
- package/dist/testing/cross_backend/spine_surface_constants.d.ts +43 -3
- package/dist/testing/cross_backend/spine_surface_constants.d.ts.map +1 -1
- package/dist/testing/cross_backend/spine_surface_constants.js +43 -3
- package/dist/testing/cross_backend/testing_backdoor.d.ts +15 -1
- package/dist/testing/cross_backend/testing_backdoor.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_backdoor.js +51 -6
- 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 +5 -1
- package/dist/testing/cross_backend/testing_server_core.d.ts +72 -41
- package/dist/testing/cross_backend/testing_server_core.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_server_core.js +22 -14
- package/dist/testing/cross_backend/testing_server_deno.js +1 -1
- 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 +15 -2
- package/dist/testing/cross_backend/ts_spine_backend_config.d.ts.map +1 -1
- package/dist/testing/cross_backend/ts_spine_backend_config.js +10 -8
- 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/middleware.d.ts.map +1 -1
- package/dist/testing/middleware.js +4 -3
- package/dist/testing/stubs.d.ts +17 -4
- package/dist/testing/stubs.d.ts.map +1 -1
- package/dist/testing/stubs.js +46 -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 +43 -37
- package/dist/testing/ws_round_trip.d.ts.map +1 -1
- package/dist/testing/ws_round_trip.js +28 -46
- package/package.json +2 -2
|
@@ -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/CLAUDE.md
CHANGED
|
@@ -246,12 +246,12 @@ policy invariants.
|
|
|
246
246
|
|
|
247
247
|
### Types
|
|
248
248
|
|
|
249
|
-
- `AppSurface` — JSON-serializable output (`middleware`, `routes`, `rpc_endpoints`, `env`, `events`, `diagnostics`)
|
|
250
|
-
- `AppSurfaceSpec` — the surface bundled with the **source specs** (`surface`, `route_specs`, `middleware_specs`, `rpc_endpoints`). Runtime-only — use for tests and introspection
|
|
249
|
+
- `AppSurface` — JSON-serializable output (`middleware`, `routes`, `rpc_endpoints`, `ws_endpoints`, `env`, `events`, `diagnostics`)
|
|
250
|
+
- `AppSurfaceSpec` — the surface bundled with the **source specs** (`surface`, `route_specs`, `middleware_specs`, `rpc_endpoints`, `ws_endpoints`). Runtime-only — use for tests and introspection
|
|
251
251
|
- `AppSurfaceRoute`, `AppSurfaceMiddleware`, `AppSurfaceEnv`, `AppSurfaceEvent`, `AppSurfaceRpcEndpoint`, `AppSurfaceRpcMethod` — per-entity entries
|
|
252
252
|
- `AppSurfaceDiagnostic` — `{level: 'warning' | 'info'; category; message; source?}`
|
|
253
253
|
- `RpcEndpointSpec` — `{path, actions: Array<RpcAction>}`; fed into `generate_app_surface` so RPC endpoints appear in the surface without coupling to `create_rpc_endpoint`
|
|
254
|
-
- `GenerateAppSurfaceOptions` — `{route_specs, middleware_specs, env_schema?, event_specs?, rpc_endpoints?}`
|
|
254
|
+
- `GenerateAppSurfaceOptions` — `{route_specs, middleware_specs, env_schema?, event_specs?, rpc_endpoints?, ws_endpoints?}`; `ws_endpoints` takes `ResolvedWsEndpointSpec`s (`allowed_origins` filled in by `resolve_ws_endpoints`), so the surface records the patterns the upgrade gate matches
|
|
255
255
|
|
|
256
256
|
`generate_app_surface(options)` emits a `warning` diagnostic for every
|
|
257
257
|
input schema that's not strict (unknown keys silently strip under
|
package/dist/http/surface.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ import type { RouteAuth } from './auth_shape.js';
|
|
|
14
14
|
import type { RateLimitKey, RouteErrorSchemas } from './error_schemas.js';
|
|
15
15
|
import type { RpcAction } from '../actions/action_rpc.js';
|
|
16
16
|
import type { ActionKind } from '../actions/action_spec.js';
|
|
17
|
-
import type {
|
|
17
|
+
import type { ResolvedWsEndpointSpec } from '../actions/ws_endpoint_spec.js';
|
|
18
18
|
import type { Sensitivity } from '../sensitivity.js';
|
|
19
19
|
/** A route in the generated attack surface (JSON-serializable). */
|
|
20
20
|
export interface AppSurfaceRoute {
|
|
@@ -111,11 +111,12 @@ export interface AppSurfaceWsMethod {
|
|
|
111
111
|
export interface AppSurfaceWsEndpoint {
|
|
112
112
|
path: string;
|
|
113
113
|
/**
|
|
114
|
-
* Upgrade-time origin allowlist
|
|
115
|
-
* regex stringified via
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
114
|
+
* Upgrade-time origin allowlist — the spec's own `allowed_origins`, or the
|
|
115
|
+
* server's when it declares none — one entry per regex, stringified via
|
|
116
|
+
* `RegExp.prototype.toString()` (`'/<source>/<flags>'`). An empty array
|
|
117
|
+
* refuses every request that carries an `Origin`. Reviewers read this as the
|
|
118
|
+
* exact pattern matched at the upgrade gate, not a wildcard approximation.
|
|
119
|
+
* Reconstruct via `new RegExp(source, flags)` if needed.
|
|
119
120
|
*/
|
|
120
121
|
allowed_origins: ReadonlyArray<string>;
|
|
121
122
|
/**
|
|
@@ -161,7 +162,7 @@ export interface AppSurfaceSpec {
|
|
|
161
162
|
route_specs: Array<RouteSpec>;
|
|
162
163
|
middleware_specs: Array<MiddlewareSpec>;
|
|
163
164
|
rpc_endpoints: Array<RpcEndpointSpec>;
|
|
164
|
-
ws_endpoints: Array<
|
|
165
|
+
ws_endpoints: Array<ResolvedWsEndpointSpec>;
|
|
165
166
|
}
|
|
166
167
|
/** An RPC endpoint definition for surface generation. */
|
|
167
168
|
export interface RpcEndpointSpec {
|
|
@@ -179,9 +180,11 @@ export interface GenerateAppSurfaceOptions {
|
|
|
179
180
|
* Mounted WS endpoints (the same array `create_app_server.ws_endpoints`
|
|
180
181
|
* auto-mounts). Each entry's actions surface into
|
|
181
182
|
* `AppSurface.ws_endpoints[i].methods` for attack-surface tests +
|
|
182
|
-
* startup logging.
|
|
183
|
+
* startup logging. Each carries its effective `allowed_origins` —
|
|
184
|
+
* `resolve_ws_endpoints` fills in the server's list where a spec omits
|
|
185
|
+
* it — so the surface records the exact patterns the upgrade gate matches.
|
|
183
186
|
*/
|
|
184
|
-
ws_endpoints?: ReadonlyArray<
|
|
187
|
+
ws_endpoints?: ReadonlyArray<ResolvedWsEndpointSpec>;
|
|
185
188
|
}
|
|
186
189
|
/**
|
|
187
190
|
* Collect error schemas from all middleware that applies to a route path.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"surface.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/surface.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"surface.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/surface.ts"],"names":[],"mappings":"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"}
|
package/dist/rate_limiter.d.ts
CHANGED
|
@@ -66,13 +66,52 @@ 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, and the first limiter it leaves
|
|
92
|
+
* `null` prints `RATE_LIMITERS_DISABLED_BANNER` to stderr once per module instance.
|
|
93
|
+
*
|
|
94
|
+
* Twin of the Rust spine's `fuz_auth::RateLimiterMode` (`Enforced` /
|
|
95
|
+
* `DisabledForTesting`).
|
|
96
|
+
*/
|
|
97
|
+
export type RateLimiterMode = 'enforced' | 'disabled_for_testing';
|
|
98
|
+
/**
|
|
99
|
+
* The stderr line a process prints the first time `'disabled_for_testing'`
|
|
100
|
+
* leaves a limiter `null` — the same text as the Rust spine's.
|
|
101
|
+
*/
|
|
102
|
+
export declare const RATE_LIMITERS_DISABLED_BANNER = "!!! RATE LIMITERS DISABLED \u2014 test-only mode. A production server must never print this.";
|
|
103
|
+
/**
|
|
104
|
+
* Print `RATE_LIMITERS_DISABLED_BANNER` with `console.error`, once per module instance.
|
|
105
|
+
*
|
|
106
|
+
* Deliberately on stderr as well as the surface warning, which goes through
|
|
107
|
+
* the server's logger: a deployment that reached this mode is unprotected on
|
|
108
|
+
* every password-bearing route, and that must show in its first lines of
|
|
109
|
+
* output even with the logger silenced. Once per module instance, so a module
|
|
110
|
+
* instance that assembles many in-process servers prints it once, while every spawned test
|
|
111
|
+
* binary prints it at startup — the twin of the Rust spine's
|
|
112
|
+
* `RateLimiterMode::limiter`.
|
|
113
|
+
*/
|
|
114
|
+
export declare const announce_rate_limiters_disabled: () => void;
|
|
76
115
|
/**
|
|
77
116
|
* Result of a rate limit check or record operation.
|
|
78
117
|
*/
|
|
@@ -98,8 +137,9 @@ export interface RateLimitResult {
|
|
|
98
137
|
* LRU trade-off described on `RateLimiterOptions.max_keys`.
|
|
99
138
|
*
|
|
100
139
|
* Parameters that accept `RateLimiter | null` (e.g. `login_ip_rate_limiter`,
|
|
101
|
-
* `login_account_rate_limiter`)
|
|
102
|
-
*
|
|
140
|
+
* `login_account_rate_limiter`) disable rate limiting when `null` is passed —
|
|
141
|
+
* no checks are performed and all requests are allowed through.
|
|
142
|
+
* `create_app_server` surfaces each disabled limiter as a warning diagnostic.
|
|
103
143
|
*/
|
|
104
144
|
export declare class RateLimiter {
|
|
105
145
|
#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;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,sBAAsB,CAAC;AAElE;;;GAGG;AACH,eAAO,MAAM,6BAA6B,iGACgD,CAAC;AAI3F;;;;;;;;;;GAUG;AACH,eAAO,MAAM,+BAA+B,QAAO,IAIlD,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;;;;;;;;;;;;;;;;;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
|
|
@@ -67,6 +67,29 @@ export const default_action_account_rate_limit = {
|
|
|
67
67
|
cleanup_interval_ms: 5 * 60_000,
|
|
68
68
|
max_keys: DEFAULT_RATE_LIMITER_MAX_KEYS
|
|
69
69
|
};
|
|
70
|
+
/**
|
|
71
|
+
* The stderr line a process prints the first time `'disabled_for_testing'`
|
|
72
|
+
* leaves a limiter `null` — the same text as the Rust spine's.
|
|
73
|
+
*/
|
|
74
|
+
export const RATE_LIMITERS_DISABLED_BANNER = '!!! RATE LIMITERS DISABLED — test-only mode. A production server must never print this.';
|
|
75
|
+
let rate_limiters_disabled_announced = false;
|
|
76
|
+
/**
|
|
77
|
+
* Print `RATE_LIMITERS_DISABLED_BANNER` with `console.error`, once per module instance.
|
|
78
|
+
*
|
|
79
|
+
* Deliberately on stderr as well as the surface warning, which goes through
|
|
80
|
+
* the server's logger: a deployment that reached this mode is unprotected on
|
|
81
|
+
* every password-bearing route, and that must show in its first lines of
|
|
82
|
+
* output even with the logger silenced. Once per module instance, so a module
|
|
83
|
+
* instance that assembles many in-process servers prints it once, while every spawned test
|
|
84
|
+
* binary prints it at startup — the twin of the Rust spine's
|
|
85
|
+
* `RateLimiterMode::limiter`.
|
|
86
|
+
*/
|
|
87
|
+
export const announce_rate_limiters_disabled = () => {
|
|
88
|
+
if (rate_limiters_disabled_announced)
|
|
89
|
+
return;
|
|
90
|
+
rate_limiters_disabled_announced = true;
|
|
91
|
+
console.error(RATE_LIMITERS_DISABLED_BANNER);
|
|
92
|
+
};
|
|
70
93
|
/**
|
|
71
94
|
* In-memory sliding window rate limiter.
|
|
72
95
|
*
|
|
@@ -81,8 +104,9 @@ export const default_action_account_rate_limit = {
|
|
|
81
104
|
* LRU trade-off described on `RateLimiterOptions.max_keys`.
|
|
82
105
|
*
|
|
83
106
|
* Parameters that accept `RateLimiter | null` (e.g. `login_ip_rate_limiter`,
|
|
84
|
-
* `login_account_rate_limiter`)
|
|
85
|
-
*
|
|
107
|
+
* `login_account_rate_limiter`) disable rate limiting when `null` is passed —
|
|
108
|
+
* no checks are performed and all requests are allowed through.
|
|
109
|
+
* `create_app_server` surfaces each disabled limiter as a warning diagnostic.
|
|
86
110
|
*/
|
|
87
111
|
export class RateLimiter {
|
|
88
112
|
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;
|