@fuzdev/fuz_app 0.125.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.
Files changed (88) hide show
  1. package/dist/actions/CLAUDE.md +57 -20
  2. package/dist/actions/action_rpc.d.ts +14 -11
  3. package/dist/actions/action_rpc.d.ts.map +1 -1
  4. package/dist/actions/action_rpc.js +5 -4
  5. package/dist/actions/connection_closer.d.ts +13 -3
  6. package/dist/actions/connection_closer.d.ts.map +1 -1
  7. package/dist/actions/connection_closer.js +7 -5
  8. package/dist/actions/register_action_ws.d.ts +18 -13
  9. package/dist/actions/register_action_ws.d.ts.map +1 -1
  10. package/dist/actions/register_action_ws.js +8 -6
  11. package/dist/actions/register_ws_endpoint.d.ts +6 -3
  12. package/dist/actions/register_ws_endpoint.d.ts.map +1 -1
  13. package/dist/actions/register_ws_endpoint.js +6 -3
  14. package/dist/actions/transports.d.ts +9 -0
  15. package/dist/actions/transports.d.ts.map +1 -1
  16. package/dist/actions/transports.js +9 -0
  17. package/dist/actions/transports_ws_backend.d.ts +15 -0
  18. package/dist/actions/transports_ws_backend.d.ts.map +1 -1
  19. package/dist/actions/transports_ws_backend.js +25 -5
  20. package/dist/actions/ws_endpoint_spec.d.ts +24 -4
  21. package/dist/actions/ws_endpoint_spec.d.ts.map +1 -1
  22. package/dist/actions/ws_endpoint_spec.js +15 -1
  23. package/dist/auth/middleware.d.ts +29 -1
  24. package/dist/auth/middleware.d.ts.map +1 -1
  25. package/dist/auth/middleware.js +35 -1
  26. package/dist/http/surface.d.ts +3 -1
  27. package/dist/http/surface.d.ts.map +1 -1
  28. package/dist/http/surface.js +15 -1
  29. package/dist/rate_limiter.d.ts +25 -3
  30. package/dist/rate_limiter.d.ts.map +1 -1
  31. package/dist/rate_limiter.js +4 -3
  32. package/dist/realtime/sse_auth_guard.d.ts +2 -1
  33. package/dist/realtime/sse_auth_guard.d.ts.map +1 -1
  34. package/dist/realtime/sse_auth_guard.js +4 -2
  35. package/dist/realtime/subscriber_registry.d.ts +12 -0
  36. package/dist/realtime/subscriber_registry.d.ts.map +1 -1
  37. package/dist/realtime/subscriber_registry.js +18 -2
  38. package/dist/server/app_server.d.ts +127 -55
  39. package/dist/server/app_server.d.ts.map +1 -1
  40. package/dist/server/app_server.js +107 -60
  41. package/dist/server/app_server_context.d.ts +17 -9
  42. package/dist/server/app_server_context.d.ts.map +1 -1
  43. package/dist/testing/CLAUDE.md +75 -17
  44. package/dist/testing/app_server.d.ts +6 -3
  45. package/dist/testing/app_server.d.ts.map +1 -1
  46. package/dist/testing/app_server.js +11 -12
  47. package/dist/testing/connection_closer_helpers.d.ts +10 -4
  48. package/dist/testing/connection_closer_helpers.d.ts.map +1 -1
  49. package/dist/testing/connection_closer_helpers.js +4 -0
  50. package/dist/testing/cross_backend/capabilities.d.ts +3 -3
  51. package/dist/testing/cross_backend/default_backend_configs.d.ts +31 -0
  52. package/dist/testing/cross_backend/default_backend_configs.d.ts.map +1 -1
  53. package/dist/testing/cross_backend/default_backend_configs.js +31 -0
  54. package/dist/testing/cross_backend/full_spine_mount.d.ts +35 -11
  55. package/dist/testing/cross_backend/full_spine_mount.d.ts.map +1 -1
  56. package/dist/testing/cross_backend/full_spine_mount.js +26 -9
  57. package/dist/testing/cross_backend/rust_spine_stub_backend_config.d.ts +15 -0
  58. package/dist/testing/cross_backend/rust_spine_stub_backend_config.d.ts.map +1 -1
  59. package/dist/testing/cross_backend/rust_spine_stub_backend_config.js +3 -2
  60. package/dist/testing/cross_backend/testing_backdoor.d.ts.map +1 -1
  61. package/dist/testing/cross_backend/testing_backdoor.js +2 -1
  62. package/dist/testing/cross_backend/testing_reset_actions.d.ts +6 -3
  63. package/dist/testing/cross_backend/testing_reset_actions.d.ts.map +1 -1
  64. package/dist/testing/cross_backend/testing_reset_actions.js +6 -3
  65. package/dist/testing/cross_backend/testing_server_bun.d.ts.map +1 -1
  66. package/dist/testing/cross_backend/testing_server_bun.js +5 -1
  67. package/dist/testing/cross_backend/testing_server_core.d.ts +68 -37
  68. package/dist/testing/cross_backend/testing_server_core.d.ts.map +1 -1
  69. package/dist/testing/cross_backend/testing_server_core.js +20 -12
  70. package/dist/testing/cross_backend/testing_server_deno.js +1 -1
  71. package/dist/testing/cross_backend/testing_server_node.d.ts.map +1 -1
  72. package/dist/testing/cross_backend/testing_server_node.js +20 -7
  73. package/dist/testing/cross_backend/ts_spine_backend_config.d.ts +15 -0
  74. package/dist/testing/cross_backend/ts_spine_backend_config.d.ts.map +1 -1
  75. package/dist/testing/cross_backend/ts_spine_backend_config.js +9 -5
  76. package/dist/testing/cross_backend/ws_action_rate_limit.d.ts +26 -0
  77. package/dist/testing/cross_backend/ws_action_rate_limit.d.ts.map +1 -0
  78. package/dist/testing/cross_backend/ws_action_rate_limit.js +261 -0
  79. package/dist/testing/stubs.d.ts +14 -4
  80. package/dist/testing/stubs.d.ts.map +1 -1
  81. package/dist/testing/stubs.js +31 -13
  82. package/dist/testing/transports/ws_transport.d.ts +7 -0
  83. package/dist/testing/transports/ws_transport.d.ts.map +1 -1
  84. package/dist/testing/transports/ws_transport.js +1 -1
  85. package/dist/testing/ws_round_trip.d.ts +36 -6
  86. package/dist/testing/ws_round_trip.d.ts.map +1 -1
  87. package/dist/testing/ws_round_trip.js +28 -8
  88. 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 — typically parsed via `parse_allowed_origins`.
32
- * Passed straight to `verify_request_source` on upgrade.
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: ReadonlyArray<RegExp>;
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 a zap-style admin-only WS endpoint.
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;;;;;;;;;;;GAWG;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;;;OAGG;IACH,eAAe,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACvC;;;;;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"}
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
- export {};
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;AAGjE;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACrC,eAAe,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC/B,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,yDAAyD;IACzD,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,CAuE/B,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"}
@@ -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 = '/api/*', daemon_token_state } = options;
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
@@ -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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"}
@@ -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.allowed_origins.map((re) => re.toString()),
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
@@ -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-actor action-dispatcher rate limiting: 1200
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`) silently disable rate limiting when `null`
102
- * is passed — no checks are performed and all requests are allowed through.
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;;;;;;;;;;;;;;;;GAgBG;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"}
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"}
@@ -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-actor action-dispatcher rate limiting: 1200
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`) silently disable rate limiting when `null`
85
- * is passed — no checks are performed and all requests are allowed through.
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;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,4BAA4B,GAAI,CAAC,EAC7C,UAAU,kBAAkB,CAAC,CAAC,CAAC,KAC7B,gBAID,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"}
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;CAwE3C"}
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.scope === identity || subscriber.groups?.has(identity)) {
260
+ if (predicate(subscriber))
244
261
  to_close.push(subscriber);
245
- }
246
262
  }
247
263
  let failed = false;
248
264
  let first_error;