@fuzdev/fuz_app 0.128.0 → 0.130.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 (112) hide show
  1. package/dist/actions/CLAUDE.md +23 -6
  2. package/dist/actions/connection_closer.d.ts +3 -1
  3. package/dist/actions/connection_closer.d.ts.map +1 -1
  4. package/dist/actions/register_action_ws.d.ts +46 -1
  5. package/dist/actions/register_action_ws.d.ts.map +1 -1
  6. package/dist/actions/register_action_ws.js +105 -14
  7. package/dist/actions/transports.d.ts +2 -1
  8. package/dist/actions/transports.d.ts.map +1 -1
  9. package/dist/actions/transports.js +2 -1
  10. package/dist/actions/transports_ws_backend.d.ts +37 -4
  11. package/dist/actions/transports_ws_backend.d.ts.map +1 -1
  12. package/dist/actions/transports_ws_backend.js +68 -4
  13. package/dist/auth/CLAUDE.md +1 -1
  14. package/dist/auth/actor_lookup_action_specs.d.ts +2 -2
  15. package/dist/auth/actor_lookup_action_specs.js +2 -2
  16. package/dist/auth/audit_emitter.d.ts +14 -7
  17. package/dist/auth/audit_emitter.d.ts.map +1 -1
  18. package/dist/auth/audit_emitter.js +6 -8
  19. package/dist/auth/audit_log_routes.d.ts +7 -3
  20. package/dist/auth/audit_log_routes.d.ts.map +1 -1
  21. package/dist/auth/audit_log_routes.js +48 -26
  22. package/dist/auth/bearer_auth.d.ts +3 -2
  23. package/dist/auth/bearer_auth.d.ts.map +1 -1
  24. package/dist/auth/bearer_auth.js +3 -2
  25. package/dist/auth/request_context.d.ts +1 -1
  26. package/dist/auth/request_context.js +1 -1
  27. package/dist/auth/token_scope.d.ts +4 -2
  28. package/dist/auth/token_scope.d.ts.map +1 -1
  29. package/dist/auth/token_scope.js +10 -2
  30. package/dist/http/CLAUDE.md +4 -5
  31. package/dist/http/auth_shape.d.ts +3 -2
  32. package/dist/http/auth_shape.d.ts.map +1 -1
  33. package/dist/http/auth_shape.js +3 -2
  34. package/dist/http/common_routes.d.ts +1 -14
  35. package/dist/http/common_routes.d.ts.map +1 -1
  36. package/dist/http/common_routes.js +1 -19
  37. package/dist/http/ip_canonical.d.ts +1 -1
  38. package/dist/http/ip_canonical.js +1 -1
  39. package/dist/http/jsonrpc_errors.d.ts.map +1 -1
  40. package/dist/http/jsonrpc_errors.js +7 -5
  41. package/dist/realtime/sse.d.ts +14 -1
  42. package/dist/realtime/sse.d.ts.map +1 -1
  43. package/dist/realtime/sse.js +77 -1
  44. package/dist/realtime/sse_auth_guard.d.ts +3 -1
  45. package/dist/realtime/sse_auth_guard.d.ts.map +1 -1
  46. package/dist/realtime/sse_auth_guard.js +4 -2
  47. package/dist/realtime/subscriber_registry.d.ts +44 -8
  48. package/dist/realtime/subscriber_registry.d.ts.map +1 -1
  49. package/dist/realtime/subscriber_registry.js +64 -10
  50. package/dist/server/app_server.d.ts +122 -8
  51. package/dist/server/app_server.d.ts.map +1 -1
  52. package/dist/server/app_server.js +136 -91
  53. package/dist/server/surface_route.d.ts +32 -0
  54. package/dist/server/surface_route.d.ts.map +1 -0
  55. package/dist/server/surface_route.js +46 -0
  56. package/dist/testing/CLAUDE.md +33 -12
  57. package/dist/testing/app_server.d.ts +39 -4
  58. package/dist/testing/app_server.d.ts.map +1 -1
  59. package/dist/testing/app_server.js +84 -68
  60. package/dist/testing/audit_completeness.js +1 -1
  61. package/dist/testing/audit_drift_guard.d.ts +1 -1
  62. package/dist/testing/cross_backend/default_spine_surface.d.ts +2 -2
  63. package/dist/testing/cross_backend/default_spine_surface.d.ts.map +1 -1
  64. package/dist/testing/cross_backend/default_spine_surface.js +5 -2
  65. package/dist/testing/cross_backend/identity_parity.js +1 -1
  66. package/dist/testing/cross_backend/in_process_setup.d.ts.map +1 -1
  67. package/dist/testing/cross_backend/in_process_setup.js +4 -1
  68. package/dist/testing/cross_backend/method_coverage.d.ts +1 -1
  69. package/dist/testing/cross_backend/method_coverage.d.ts.map +1 -1
  70. package/dist/testing/cross_backend/method_coverage.js +2 -2
  71. package/dist/testing/cross_backend/peer_ping_ws.d.ts +1 -1
  72. package/dist/testing/cross_backend/peer_ping_ws.d.ts.map +1 -1
  73. package/dist/testing/cross_backend/peer_ping_ws.js +4 -4
  74. package/dist/testing/cross_backend/role_grant_offer_notification_ws.d.ts +1 -1
  75. package/dist/testing/cross_backend/role_grant_offer_notification_ws.d.ts.map +1 -1
  76. package/dist/testing/cross_backend/setup.d.ts +4 -4
  77. package/dist/testing/cross_backend/setup.js +1 -1
  78. package/dist/testing/cross_backend/sse_round_trip.d.ts +1 -1
  79. package/dist/testing/cross_backend/sse_round_trip.d.ts.map +1 -1
  80. package/dist/testing/cross_backend/testing_reset_actions.d.ts +24 -14
  81. package/dist/testing/cross_backend/testing_reset_actions.d.ts.map +1 -1
  82. package/dist/testing/cross_backend/testing_reset_actions.js +40 -32
  83. package/dist/testing/cross_backend/testing_server_bun.d.ts +1 -1
  84. package/dist/testing/cross_backend/testing_server_bun.d.ts.map +1 -1
  85. package/dist/testing/cross_backend/testing_server_bun.js +80 -64
  86. package/dist/testing/cross_backend/testing_server_core.d.ts +10 -4
  87. package/dist/testing/cross_backend/testing_server_core.d.ts.map +1 -1
  88. package/dist/testing/cross_backend/testing_server_deno.d.ts +1 -1
  89. package/dist/testing/cross_backend/testing_server_deno.d.ts.map +1 -1
  90. package/dist/testing/cross_backend/testing_server_deno.js +1 -1
  91. package/dist/testing/cross_backend/testing_server_node.d.ts +1 -1
  92. package/dist/testing/cross_backend/testing_server_node.d.ts.map +1 -1
  93. package/dist/testing/cross_backend/testing_server_node.js +2 -2
  94. package/dist/testing/cross_backend/ws_inbound_dispatch.d.ts +20 -0
  95. package/dist/testing/cross_backend/ws_inbound_dispatch.d.ts.map +1 -0
  96. package/dist/testing/cross_backend/ws_inbound_dispatch.js +177 -0
  97. package/dist/testing/cross_backend/ws_round_trip.d.ts +1 -1
  98. package/dist/testing/cross_backend/ws_round_trip.d.ts.map +1 -1
  99. package/dist/testing/cross_backend/ws_round_trip.js +11 -9
  100. package/dist/testing/stubs.d.ts +45 -7
  101. package/dist/testing/stubs.d.ts.map +1 -1
  102. package/dist/testing/stubs.js +60 -31
  103. package/dist/testing/ws_round_trip.d.ts +1 -3
  104. package/dist/testing/ws_round_trip.d.ts.map +1 -1
  105. package/dist/ui/AdminSurface.svelte +3 -1
  106. package/dist/ui/AdminSurface.svelte.d.ts.map +1 -1
  107. package/dist/ui/CLAUDE.md +3 -1
  108. package/dist/ui/async_slot.svelte.d.ts +4 -4
  109. package/dist/ui/async_slot.svelte.js +4 -4
  110. package/dist/ui/keyed_async_slot.svelte.d.ts +4 -4
  111. package/dist/ui/keyed_async_slot.svelte.js +3 -3
  112. package/package.json +1 -1
@@ -26,10 +26,10 @@ import '../assert_dev_env.js';
26
26
  * non-sensitive — see the design doc); the WS upgrade itself still
27
27
  * authenticates, so the suite drives it over the keeper's session.
28
28
  *
29
- * Gated on `capabilities.peer_request` — `true` only for the Rust spine
30
- * (server-initiated requests landed Rust-first canonical); the TS family
31
- * skips until its server transport's request path lands (deferred twin-impl
32
- * convergence). Cross-process only: `create_ws_transport` needs a real bound
29
+ * Gated on `capabilities.peer_request`, which a backend declares once it
30
+ * mounts `peer/ping` on a WS endpoint and the HTTP RPC endpoint — the TS
31
+ * spine binaries (`BackendWebsocketTransport.request_connection`) and the
32
+ * Rust spine both do. Cross-process only: `create_ws_transport` needs a real bound
33
33
  * socket, so wire it from a `*.cross.test.ts`.
34
34
  *
35
35
  * @module
@@ -1,7 +1,7 @@
1
1
  import '../assert_dev_env.js';
2
2
  import { type BackendCapabilities } from './capabilities.js';
3
3
  import type { SetupTest } from './setup.js';
4
- /** Configuration for {@link describe_role_grant_offer_notification_ws_tests}. */
4
+ /** Configuration for `describe_role_grant_offer_notification_ws_tests`. */
5
5
  export interface RoleGrantOfferNotificationWsTestOptions {
6
6
  /** Per-test fixture producer (`default_cross_process_setup(handle, ...)`). */
7
7
  readonly setup_test: SetupTest;
@@ -1 +1 @@
1
- {"version":3,"file":"role_grant_offer_notification_ws.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/role_grant_offer_notification_ws.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAqE9B,OAAO,EAAE,KAAK,mBAAmB,EAAW,MAAM,mBAAmB,CAAC;AACtE,OAAO,KAAK,EAAE,SAAS,EAAmC,MAAM,YAAY,CAAC;AAK7E,iFAAiF;AACjF,MAAM,WAAW,uCAAuC;IACvD,8EAA8E;IAC9E,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC;IAC/B,uEAAuE;IACvE,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAAC;IAC3C,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,+DAA+D;IAC/D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,+CAA+C,GAC3D,SAAS,uCAAuC,KAC9C,IAuWF,CAAC"}
1
+ {"version":3,"file":"role_grant_offer_notification_ws.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/role_grant_offer_notification_ws.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAqE9B,OAAO,EAAE,KAAK,mBAAmB,EAAW,MAAM,mBAAmB,CAAC;AACtE,OAAO,KAAK,EAAE,SAAS,EAAmC,MAAM,YAAY,CAAC;AAK7E,2EAA2E;AAC3E,MAAM,WAAW,uCAAuC;IACvD,8EAA8E;IAC9E,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC;IAC/B,uEAAuE;IACvE,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAAC;IAC3C,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,+DAA+D;IAC/D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,+CAA+C,GAC3D,SAAS,uCAAuC,KAC9C,IAuWF,CAAC"}
@@ -327,7 +327,7 @@ export interface BootstrappedBackendHandle extends BackendHandle {
327
327
  */
328
328
  export type ReconstructedBootstrappedBackendHandle = Omit<BootstrappedBackendHandle, 'child' | 'teardown'>;
329
329
  /**
330
- * Serializable subset of {@link BootstrappedBackendHandle} suitable for
330
+ * Serializable subset of `BootstrappedBackendHandle` suitable for
331
331
  * vitest's `project.provide()` — vitest 4 hard-rejects non-serializable
332
332
  * values, so the live `child: ChildProcess` + `teardown: () => Promise<void>`
333
333
  * + `keeper_transport: FetchTransport` (closure) must stay in the
@@ -335,8 +335,8 @@ export type ReconstructedBootstrappedBackendHandle = Omit<BootstrappedBackendHan
335
335
  * (`config`, `daemon_token`, `keeper_account`, `keeper_actor`,
336
336
  * `keeper_cookies`) round-trip through structured clone fine.
337
337
  *
338
- * `globalSetup` calls {@link serialize_bootstrapped_handle} before
339
- * `project.provide`; test files call {@link reconstruct_bootstrapped_handle}
338
+ * `globalSetup` calls `serialize_bootstrapped_handle` before
339
+ * `project.provide`; test files call `reconstruct_bootstrapped_handle`
340
340
  * on the injected value to rebuild a usable handle (without `child` /
341
341
  * `teardown` — lifecycle stays with `globalSetup`).
342
342
  */
@@ -354,7 +354,7 @@ export interface SerializableBootstrappedBackendHandle {
354
354
  export declare const serialize_bootstrapped_handle: (handle: BootstrappedBackendHandle) => SerializableBootstrappedBackendHandle;
355
355
  /**
356
356
  * Rebuild a usable handle from the serialized subset. Synthesizes a
357
- * fresh {@link FetchTransport} primed with the keeper's `Set-Cookie`
357
+ * fresh `FetchTransport` primed with the keeper's `Set-Cookie`
358
358
  * values so `_testing_reset` and other keeper-authenticated calls work.
359
359
  * The returned shape omits `child` and `teardown` — lifecycle stays
360
360
  * with `globalSetup`; tests that try to teardown themselves wouldn't
@@ -67,7 +67,7 @@ export const serialize_bootstrapped_handle = (handle) => ({
67
67
  });
68
68
  /**
69
69
  * Rebuild a usable handle from the serialized subset. Synthesizes a
70
- * fresh {@link FetchTransport} primed with the keeper's `Set-Cookie`
70
+ * fresh `FetchTransport` primed with the keeper's `Set-Cookie`
71
71
  * values so `_testing_reset` and other keeper-authenticated calls work.
72
72
  * The returned shape omits `child` and `teardown` — lifecycle stays
73
73
  * with `globalSetup`; tests that try to teardown themselves wouldn't
@@ -1,7 +1,7 @@
1
1
  import '../assert_dev_env.js';
2
2
  import { type BackendCapabilities } from './capabilities.js';
3
3
  import type { SetupTest } from './setup.js';
4
- /** Configuration for {@link describe_cross_process_sse_tests}. */
4
+ /** Configuration for `describe_cross_process_sse_tests`. */
5
5
  export interface CrossProcessSseTestOptions {
6
6
  /**
7
7
  * Per-test fixture producer (`default_cross_process_setup(handle)`). Each
@@ -1 +1 @@
1
- {"version":3,"file":"sse_round_trip.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/sse_round_trip.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA8E9B,OAAO,EAAE,KAAK,mBAAmB,EAAW,MAAM,mBAAmB,CAAC;AACtE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAK5C,kEAAkE;AAClE,MAAM,WAAW,0BAA0B;IAC1C;;;;;;OAMG;IACH,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC;IAC/B,wEAAwE;IACxE,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAAC;IAC3C,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,6EAA6E;IAC7E,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,6DAA6D;IAC7D,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvC;AA0BD;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC,GAAI,SAAS,0BAA0B,KAAG,IA2PtF,CAAC"}
1
+ {"version":3,"file":"sse_round_trip.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/sse_round_trip.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA8E9B,OAAO,EAAE,KAAK,mBAAmB,EAAW,MAAM,mBAAmB,CAAC;AACtE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAK5C,4DAA4D;AAC5D,MAAM,WAAW,0BAA0B;IAC1C;;;;;;OAMG;IACH,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC;IAC/B,wEAAwE;IACxE,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAAC;IAC3C,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,6EAA6E;IAC7E,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,6DAA6D;IAC7D,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvC;AA0BD;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC,GAAI,SAAS,0BAA0B,KAAG,IA2PtF,CAAC"}
@@ -2,7 +2,7 @@ import '../assert_dev_env.js';
2
2
  /**
3
3
  * Test-binary RPC actions for cross-process integration tests.
4
4
  *
5
- * Six daemon-token-authed actions, bundled by `create_testing_actions`:
5
+ * The daemon-token-authed actions bundled by `create_testing_actions`:
6
6
  * **`_testing_reset`** (DB wipe + keeper re-seed), **`_testing_drain_effects`**
7
7
  * (audit barrier), **`_testing_mint_session`** (forge an
8
8
  * expired-by-construction server-side session for the expiry conformance
@@ -31,11 +31,11 @@ import '../assert_dev_env.js';
31
31
  * new keeper + secondary credentials return as the action output so
32
32
  * the per-test fixture closes over them.
33
33
  *
34
- * The redesign converges in-process and cross-process keeper
35
- * lifetimes: both modes now run against a freshly bootstrapped keeper
36
- * per test. Mutation-cascade tests (password change, revoke-all,
37
- * hardcoded-username signup uniqueness) and direct keeper-vs-admin
38
- * probes work uniformly cross-process.
34
+ * In-process and cross-process keeper lifetimes match: both modes run
35
+ * against a freshly bootstrapped keeper per test, so mutation-cascade
36
+ * tests (password change, revoke-all, hardcoded-username signup
37
+ * uniqueness) and direct keeper-vs-admin probes work uniformly
38
+ * cross-process.
39
39
  *
40
40
  * **Keeper ≠ admin.** The `keeper` and `admin` roles are independent.
41
41
  * Keeper authorizes daemon-token / bootstrap paths; admin authorizes
@@ -47,9 +47,8 @@ import '../assert_dev_env.js';
47
47
  * via `extra_accounts: [{username, roles: [ROLE_KEEPER]}]` so the
48
48
  * account is seeded at this same bootstrap-equivalent step.
49
49
  *
50
- * **No free-form runtime bypass.** Earlier drafts considered a separate
51
- * `_testing_seed_role_grant` action for arbitrary direct grants; that
52
- * was rejected because a runtime bypass would let tests skip the
50
+ * **No free-form runtime bypass.** There is no action for arbitrary
51
+ * direct role grants: a runtime bypass would let tests skip the
53
52
  * production consent flow's side-effects (audit emit, WS fan-out) and
54
53
  * silently mask bugs in those paths. The bypass that does exist —
55
54
  * `extra_accounts` — is framed as bootstrap-time seeding, the same
@@ -449,6 +448,18 @@ export declare const testing_action_manifest_action_spec: {
449
448
  readonly async: true;
450
449
  readonly description: string;
451
450
  };
451
+ /**
452
+ * Build the `_testing_action_manifest` action over a backend's full live RPC
453
+ * mount. The handler closes over a manifest computed once at assembly time
454
+ * from every `mounted` spec except the protocol methods (`PROTOCOL_METHODS`)
455
+ * **plus this action's own spec** — the manifest action is itself a live
456
+ * method, so it must appear in the dump it serves. `mounted` excludes it
457
+ * (it's appended to the mount *after* the rest is assembled, in
458
+ * `build_full_spine_rpc_actions`), so its static spec is folded in here; the
459
+ * Rust mirror folds in its own descriptor the same way.
460
+ *
461
+ * @param mounted - every other action on the backend's live RPC mount
462
+ */
452
463
  export declare const create_testing_action_manifest_action: (mounted: ReadonlyArray<RpcAction>) => RpcAction;
453
464
  /** Options for `create_testing_actions`. */
454
465
  export interface CreateTestingActionsOptions {
@@ -460,9 +471,10 @@ export interface CreateTestingActionsOptions {
460
471
  */
461
472
  readonly session_options: SessionOptions<string>;
462
473
  /**
463
- * Daemon-token runtime state — the reset action mutates
464
- * `state.keeper_account_id` to point at the freshly seeded keeper
465
- * after the old row is wiped. Pass the same `DaemonTokenState`
474
+ * Daemon-token runtime state — the reset action points
475
+ * `state.keeper_account_id` at the freshly seeded keeper once its
476
+ * transaction commits (a post-commit effect, so a reset that rolls back
477
+ * leaves the previous keeper cached). Pass the same `DaemonTokenState`
466
478
  * instance the daemon-token middleware reads.
467
479
  */
468
480
  readonly daemon_token_state: DaemonTokenState;
@@ -496,6 +508,4 @@ export interface CreateTestingActionsOptions {
496
508
  * without updating this handler fails CI.
497
509
  */
498
510
  export declare const create_testing_actions: (deps: AppDeps, options: CreateTestingActionsOptions) => Array<RpcAction>;
499
- /** Set of auth-namespace tables `_testing_reset` wipes. Mirrored by the coverage test. */
500
- export declare const testing_reset_wiped_tables: string[];
501
511
  //# sourceMappingURL=testing_reset_actions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"testing_reset_actions.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/testing_reset_actions.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoEG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,OAAO,EAAc,KAAK,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAKzE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAC;AAqCzC;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;QAiBpC;;;;;;;;WAQG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAWyC,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,iCAAiC;;;;;;;;;;;;;;;;CAWA,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;CAwBC,CAAC;AAE/C;;;;;;;;GAQG;AACH,eAAO,MAAM,mCAAmC,GAAI,OAAO,YAAY,KAAG,SAIvE,CAAC;AAEJ;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;;CAeK,CAAC;AAE/C;;;;;;;;;GASG;AACH,eAAO,MAAM,mCAAmC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAWF,CAAC;AAE/C;;;;GAIG;AACH,eAAO,MAAM,qCAAqC,QAAO,SAGvD,CAAC;AAEH;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,qCAAqC;;;;;;;;;;;;;;;;;;;;CAYJ,CAAC;AAE/C;;;;GAIG;AACH,eAAO,MAAM,uCAAuC,QAAO,SAGzD,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,mCAAmC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAaF,CAAC;AAyB/C,eAAO,MAAM,qCAAqC,GACjD,SAAS,aAAa,CAAC,SAAS,CAAC,KAC/B,SAMF,CAAC;AAEF,4CAA4C;AAC5C,MAAM,WAAW,2BAA2B;IAC3C;;;;;OAKG;IACH,QAAQ,CAAC,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACjD;;;;;OAKG;IACH,QAAQ,CAAC,kBAAkB,EAAE,gBAAgB,CAAC;IAC9C;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACxD;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,sBAAsB,GAClC,MAAM,OAAO,EACb,SAAS,2BAA2B,KAClC,KAAK,CAAC,SAAS,CAsIjB,CAAC;AAEF,0FAA0F;AAC1F,eAAO,MAAM,0BAA0B,UAAmC,CAAC"}
1
+ {"version":3,"file":"testing_reset_actions.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/testing_reset_actions.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmEG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,OAAO,EAAc,KAAK,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAMzE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAC;AAoCzC;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;QAiBpC;;;;;;;;WAQG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAWyC,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,iCAAiC;;;;;;;;;;;;;;;;CAWA,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;CAwBC,CAAC;AAE/C;;;;;;;;GAQG;AACH,eAAO,MAAM,mCAAmC,GAAI,OAAO,YAAY,KAAG,SAIvE,CAAC;AAEJ;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;;CAeK,CAAC;AAE/C;;;;;;;;;GASG;AACH,eAAO,MAAM,mCAAmC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAWF,CAAC;AAE/C;;;;GAIG;AACH,eAAO,MAAM,qCAAqC,QAAO,SAGvD,CAAC;AAEH;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,qCAAqC;;;;;;;;;;;;;;;;;;;;CAYJ,CAAC;AAE/C;;;;GAIG;AACH,eAAO,MAAM,uCAAuC,QAAO,SAGzD,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,mCAAmC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAaF,CAAC;AAkB/C;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,qCAAqC,GACjD,SAAS,aAAa,CAAC,SAAS,CAAC,KAC/B,SAMF,CAAC;AAEF,4CAA4C;AAC5C,MAAM,WAAW,2BAA2B;IAC3C;;;;;OAKG;IACH,QAAQ,CAAC,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACjD;;;;;;OAMG;IACH,QAAQ,CAAC,kBAAkB,EAAE,gBAAgB,CAAC;IAC9C;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACxD;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,sBAAsB,GAClC,MAAM,OAAO,EACb,SAAS,2BAA2B,KAClC,KAAK,CAAC,SAAS,CA4IjB,CAAC"}
@@ -2,7 +2,7 @@ import '../assert_dev_env.js';
2
2
  /**
3
3
  * Test-binary RPC actions for cross-process integration tests.
4
4
  *
5
- * Six daemon-token-authed actions, bundled by `create_testing_actions`:
5
+ * The daemon-token-authed actions bundled by `create_testing_actions`:
6
6
  * **`_testing_reset`** (DB wipe + keeper re-seed), **`_testing_drain_effects`**
7
7
  * (audit barrier), **`_testing_mint_session`** (forge an
8
8
  * expired-by-construction server-side session for the expiry conformance
@@ -31,11 +31,11 @@ import '../assert_dev_env.js';
31
31
  * new keeper + secondary credentials return as the action output so
32
32
  * the per-test fixture closes over them.
33
33
  *
34
- * The redesign converges in-process and cross-process keeper
35
- * lifetimes: both modes now run against a freshly bootstrapped keeper
36
- * per test. Mutation-cascade tests (password change, revoke-all,
37
- * hardcoded-username signup uniqueness) and direct keeper-vs-admin
38
- * probes work uniformly cross-process.
34
+ * In-process and cross-process keeper lifetimes match: both modes run
35
+ * against a freshly bootstrapped keeper per test, so mutation-cascade
36
+ * tests (password change, revoke-all, hardcoded-username signup
37
+ * uniqueness) and direct keeper-vs-admin probes work uniformly
38
+ * cross-process.
39
39
  *
40
40
  * **Keeper ≠ admin.** The `keeper` and `admin` roles are independent.
41
41
  * Keeper authorizes daemon-token / bootstrap paths; admin authorizes
@@ -47,9 +47,8 @@ import '../assert_dev_env.js';
47
47
  * via `extra_accounts: [{username, roles: [ROLE_KEEPER]}]` so the
48
48
  * account is seeded at this same bootstrap-equivalent step.
49
49
  *
50
- * **No free-form runtime bypass.** Earlier drafts considered a separate
51
- * `_testing_seed_role_grant` action for arbitrary direct grants; that
52
- * was rejected because a runtime bypass would let tests skip the
50
+ * **No free-form runtime bypass.** There is no action for arbitrary
51
+ * direct role grants: a runtime bypass would let tests skip the
53
52
  * production consent flow's side-effects (audit emit, WS fan-out) and
54
53
  * silently mask bugs in those paths. The bypass that does exist —
55
54
  * `extra_accounts` — is framed as bootstrap-time seeding, the same
@@ -73,10 +72,10 @@ import { Uuid } from '@fuzdev/fuz_util/id.ts';
73
72
  import { fact_hash_bytes } from '@fuzdev/fuz_util/fact_hash.ts';
74
73
  import { FactHashSchema } from '@fuzdev/fuz_util/hash_schemas.ts';
75
74
  import { rpc_action } from '../../actions/action_rpc.js';
75
+ import { emit_after_commit } from '../../http/pending_effects.js';
76
76
  import { protocol_action_specs } from '../../actions/protocol.js';
77
77
  import { query_put_fact } from '../../db/fact_queries.js';
78
78
  import { ROLE_ADMIN, ROLE_KEEPER } from '../../auth/role_schema.js';
79
- import { auth_integration_truncate_tables } from '../db.js';
80
79
  import { query_schema_snapshot, SchemaSnapshot, query_migration_tracker, MigrationTracker } from '../schema_introspect.js';
81
80
  import { ActionManifest, build_action_manifest } from './action_manifest.js';
82
81
  import { query_create_actor } from '../../auth/account_queries.js';
@@ -86,8 +85,8 @@ import { DEFAULT_TEST_PASSWORD } from '../test_credentials.js';
86
85
  * Shared `auth` axis for every `_testing_*` action: keeper-only via the
87
86
  * daemon-token credential, no acting actor. This is the entire structural
88
87
  * fence on the backdoor surface (these actions run direct DB writes the
89
- * production wire never exposes), so all five specs reference this one const
90
- * rather than re-declaring it — a single source of truth the gate test
88
+ * production wire never exposes), so every `_testing_*` spec references this
89
+ * one const rather than re-declaring it — a single source of truth the gate test
91
90
  * (`testing_actions_auth.test.ts`) pins. Mirrors the Rust `DAEMON_TOKEN_ONLY`
92
91
  * / shared `AuthSpec` in `fuz_testing`.
93
92
  */
@@ -385,26 +384,31 @@ export const testing_action_manifest_action_spec = {
385
384
  '{method, auth, side_effects, rate_limit} manifest for cross-impl method-set + ' +
386
385
  'auth-shape parity diffing.'
387
386
  };
387
+ /**
388
+ * The protocol methods (`heartbeat` / `cancel` / `peer/ping`) the
389
+ * `_testing_action_manifest` dump leaves out, so the cross-impl diff stays
390
+ * apples-to-apples: the two impls organize them differently (`peer/ping` is
391
+ * on the TS spine's WS **and** HTTP-RPC endpoints; heartbeat/cancel WS-only;
392
+ * the Rust stub compiles one shared registry serving both transports), so
393
+ * including them would be a spurious divergence (see `action_manifest.ts`
394
+ * §Scope). The exclusion set is the live `protocol_action_specs` bundle —
395
+ * kept in lockstep with the static `PROTOCOL_ACTION_METHODS` by a drift-guard
396
+ * test — so this stays off the heavyweight `action_codegen` module the spawned
397
+ * binary would otherwise pull in.
398
+ */
399
+ const PROTOCOL_METHODS = new Set(protocol_action_specs.map((spec) => spec.method));
388
400
  /**
389
401
  * Build the `_testing_action_manifest` action over a backend's full live RPC
390
402
  * mount. The handler closes over a manifest computed once at assembly time
391
- * from every `mounted` spec **plus this action's own spec** — the manifest
392
- * action is itself a live method, so it must appear in the dump it serves.
393
- * `mounted` excludes it (it's appended to the mount *after* the rest is
394
- * assembled, in `build_full_spine_rpc_actions`), so its static spec is folded
395
- * in here; the Rust mirror folds in its own descriptor the same way.
403
+ * from every `mounted` spec except the protocol methods (`PROTOCOL_METHODS`)
404
+ * **plus this action's own spec** — the manifest action is itself a live
405
+ * method, so it must appear in the dump it serves. `mounted` excludes it
406
+ * (it's appended to the mount *after* the rest is assembled, in
407
+ * `build_full_spine_rpc_actions`), so its static spec is folded in here; the
408
+ * Rust mirror folds in its own descriptor the same way.
396
409
  *
397
- * Protocol actions (`heartbeat` / `cancel` / `peer/ping`) are filtered out of
398
- * the manifest here so the cross-impl diff stays apples-to-apples: the two
399
- * impls organize them differently (`peer/ping` is on the TS spine's WS **and**
400
- * HTTP-RPC endpoints; heartbeat/cancel WS-only; the Rust stub compiles one
401
- * shared registry serving both transports), so including them would be a
402
- * spurious divergence (see `action_manifest.ts` §Scope). The exclusion set is
403
- * the live `protocol_action_specs` bundle — kept in lockstep with the static
404
- * `PROTOCOL_ACTION_METHODS` by a drift-guard test — so this stays off the
405
- * heavyweight `action_codegen` module the spawned binary would otherwise pull in.
410
+ * @param mounted - every other action on the backend's live RPC mount
406
411
  */
407
- const PROTOCOL_METHODS = new Set(protocol_action_specs.map((spec) => spec.method));
408
412
  export const create_testing_action_manifest_action = (mounted) => {
409
413
  const manifest = build_action_manifest([
410
414
  ...mounted.map((action) => action.spec).filter((spec) => !PROTOCOL_METHODS.has(spec.method)),
@@ -510,9 +514,15 @@ export const create_testing_actions = (deps, options) => {
510
514
  // 6. Refresh the daemon-token cache so subsequent daemon-token
511
515
  // requests resolve to the freshly seeded keeper. The
512
516
  // middleware's lazy-refresh path only fires when the cached
513
- // id is null; setting it directly here avoids one round-trip
514
- // of stale-id-then-refresh on the next call.
515
- daemon_token_state.keeper_account_id = keeper.account.id;
517
+ // id is null, so the reset sets it — after the commit, so a
518
+ // reset that rolls back (a throwing `reset_state`, a failed
519
+ // COMMIT) leaves the cache on the keeper still in the database
520
+ // rather than one that never landed, and the next reset can
521
+ // still authenticate.
522
+ const keeper_account_id = keeper.account.id;
523
+ emit_after_commit(ctx, () => {
524
+ daemon_token_state.keeper_account_id = keeper_account_id;
525
+ });
516
526
  // 7. Fire domain-state reset (zzz workspaces/terminals/scratch,
517
527
  // fuz_forge cell/fact/file truncation, or no-op for spine_stub).
518
528
  // Pass the transactional `ctx.db` so DB-domain truncation runs
@@ -549,5 +559,3 @@ export const create_testing_actions = (deps, options) => {
549
559
  create_testing_migration_tracker_action()
550
560
  ];
551
561
  };
552
- /** Set of auth-namespace tables `_testing_reset` wipes. Mirrored by the coverage test. */
553
- export const testing_reset_wiped_tables = auth_integration_truncate_tables;
@@ -1,5 +1,5 @@
1
1
  import '../assert_dev_env.js';
2
2
  import type { TestingServerAdapter } from './testing_server_core.js';
3
- /** Build the Bun {@link TestingServerAdapter}. */
3
+ /** Build the Bun `TestingServerAdapter`. */
4
4
  export declare const create_bun_testing_adapter: () => TestingServerAdapter;
5
5
  //# sourceMappingURL=testing_server_bun.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"testing_server_bun.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/testing_server_bun.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA6B9B,OAAO,KAAK,EAAe,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAelF,kDAAkD;AAClD,eAAO,MAAM,0BAA0B,QAAO,oBA8D5C,CAAC"}
1
+ {"version":3,"file":"testing_server_bun.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/testing_server_bun.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA8B9B,OAAO,KAAK,EAAe,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAyBlF,4CAA4C;AAC5C,eAAO,MAAM,0BAA0B,QAAO,oBAoE7C,CAAC"}
@@ -23,68 +23,84 @@ import '../assert_dev_env.js';
23
23
  */
24
24
  import process from 'node:process';
25
25
  import { getConnInfo, upgradeWebSocket, websocket } from '@hono/bun';
26
+ import { DEFAULT_WS_MAX_MESSAGE_BYTES } from '../../actions/transports.js';
26
27
  import { create_node_runtime } from '../../runtime/node.js';
27
- /** Build the Bun {@link TestingServerAdapter}. */
28
- export const create_bun_testing_adapter = () => ({
29
- runtime_label: 'Bun',
30
- runtime: create_node_runtime(),
31
- get_connection_ip: (c) => getConnInfo(c).remote.address,
32
- // Bun's WS upgrade is module-level and stateless (like Deno) — no
33
- // post-serve attach. The `websocket` handler is threaded into `serve`
34
- // below, where `Bun.serve` wants it.
35
- // TODO: `Bun.serve({websocket: {maxPayloadLength}})` (default 16 MiB) could
36
- // carry the endpoint's `max_message_bytes` as a frame cap, like Node's
37
- // `maxPayload`; until then the per-message check in `register_ws_endpoint`
38
- // closes an oversized message with `WS_CLOSE_MESSAGE_TOO_BIG` (1009).
39
- prepare_websocket: () => ({ create_upgrade_websocket: () => upgradeWebSocket }),
40
- serve: ({ fetch, port, hostname }) => {
41
- const server = Bun.serve({
42
- fetch: fetch,
43
- port,
44
- hostname,
45
- // Harmless for HTTP-only binaries — Bun only invokes it for sockets
46
- // upgraded via `upgradeWebSocket`.
47
- websocket
48
- });
49
- const handle = {
50
- // Bun bug (1.3.14): after a *server-initiated* WebSocket close
51
- // (`ServerWebSocket.close()` / `@hono/bun`'s `WSContext.close()`),
52
- // `server.stop()` never resolves — Bun doesn't decrement its
53
- // active-connection count for a server-closed socket, so the stop
54
- // waits forever for a connection it already closed. The trigger is
55
- // orthogonal to HTTP load, hono-vs-raw `Bun.serve`, in-vs-cross
56
- // process, the force flag (`stop()`/`stop(false)`/`stop(true)` all
57
- // hang), and the client runtime — a single server-closed WS is
58
- // necessary and sufficient. Client-initiated close or leaving the
59
- // socket open both stop cleanly in ~0ms. In this suite the trigger is
60
- // any server-initiated WS close — a revocation's (the `ws.cross.test.ts`
61
- // close-on-revoke cases), a cap eviction's, an oversized message's —
62
- // which is why teardown hangs after those and not under HTTP-only or
63
- // client-closed WS traffic.
64
- //
65
- // So initiate a force-close (`true` drops active connections, no
66
- // drain) but DON'T await it: awaiting hangs `start_testing_server`'s
67
- // shutdown forever — `built.close()` and `exit(0)` never run, and the
68
- // spawning harness blocks on a child that never exits (observed as a
69
- // multi-minute hang needing SIGKILL). The force-close still tears the
70
- // live sockets down; the `exit(0)` the core fires immediately after
71
- // does the real teardown a few ms later. Node/Deno don't need this —
72
- // their `shutdown()`/`close()` resolve normally. The `.catch` guards a
73
- // future Bun that rejects rather than hangs; if a future Bun resolves
74
- // the promise after a server-initiated close, revert to
75
- // `await server.stop(true)` to mirror the Node/Deno adapters.
76
- shutdown: () => {
77
- void Promise.resolve(server.stop(true)).catch(() => { });
78
- return Promise.resolve();
79
- },
80
- native: server
81
- };
82
- return handle;
83
- },
84
- pid: process.pid,
85
- register_shutdown_signals: (handler) => {
86
- process.on('SIGINT', () => void handler());
87
- process.on('SIGTERM', () => void handler());
88
- },
89
- exit: (code) => process.exit(code)
90
- });
28
+ /**
29
+ * How far above the endpoint's message limit Bun's own frame cap sits. Bun
30
+ * drops a socket past `maxPayloadLength` without a close frame (the client sees
31
+ * 1006), unlike Node's `ws`, which closes with `WS_CLOSE_MESSAGE_TOO_BIG` — so
32
+ * the cap leaves headroom for the per-message check in `register_ws_endpoint`
33
+ * to answer a message just over the limit with that code, and still refuses a
34
+ * grossly oversized one before buffering it toward Bun's 16 MiB default.
35
+ */
36
+ const BUN_WS_MAX_PAYLOAD_MULTIPLIER = 2;
37
+ /** Build the Bun `TestingServerAdapter`. */
38
+ export const create_bun_testing_adapter = () => {
39
+ // set by `prepare_websocket`, read by `serve` — the core prepares before it serves
40
+ let max_message_bytes = DEFAULT_WS_MAX_MESSAGE_BYTES;
41
+ return {
42
+ runtime_label: 'Bun',
43
+ runtime: create_node_runtime(),
44
+ get_connection_ip: (c) => getConnInfo(c).remote.address,
45
+ // Bun's WS upgrade is module-level and stateless (like Deno) — no
46
+ // post-serve attach. The `websocket` handler is threaded into `serve`
47
+ // below, where `Bun.serve` wants it, carrying the frame cap.
48
+ prepare_websocket: (options) => {
49
+ max_message_bytes = options?.max_message_bytes ?? DEFAULT_WS_MAX_MESSAGE_BYTES;
50
+ return { create_upgrade_websocket: () => upgradeWebSocket };
51
+ },
52
+ serve: ({ fetch, port, hostname }) => {
53
+ const server = Bun.serve({
54
+ fetch: fetch,
55
+ port,
56
+ hostname,
57
+ // Harmless for HTTP-only binaries — Bun only invokes it for sockets
58
+ // upgraded via `upgradeWebSocket`.
59
+ websocket: {
60
+ ...websocket,
61
+ maxPayloadLength: BUN_WS_MAX_PAYLOAD_MULTIPLIER * max_message_bytes
62
+ }
63
+ });
64
+ const handle = {
65
+ // Bun bug (1.3.14): after a *server-initiated* WebSocket close
66
+ // (`ServerWebSocket.close()` / `@hono/bun`'s `WSContext.close()`),
67
+ // `server.stop()` never resolves — Bun doesn't decrement its
68
+ // active-connection count for a server-closed socket, so the stop
69
+ // waits forever for a connection it already closed. The trigger is
70
+ // orthogonal to HTTP load, hono-vs-raw `Bun.serve`, in-vs-cross
71
+ // process, the force flag (`stop()`/`stop(false)`/`stop(true)` all
72
+ // hang), and the client runtime — a single server-closed WS is
73
+ // necessary and sufficient. Client-initiated close or leaving the
74
+ // socket open both stop cleanly in ~0ms. In this suite the trigger is
75
+ // any server-initiated WS close — a revocation's (the `ws.cross.test.ts`
76
+ // close-on-revoke cases), a cap eviction's, an oversized message's —
77
+ // which is why teardown hangs after those and not under HTTP-only or
78
+ // client-closed WS traffic.
79
+ //
80
+ // So initiate a force-close (`true` drops active connections, no
81
+ // drain) but DON'T await it: awaiting hangs `start_testing_server`'s
82
+ // shutdown forever — `built.close()` and `exit(0)` never run, and the
83
+ // spawning harness blocks on a child that never exits (observed as a
84
+ // multi-minute hang needing SIGKILL). The force-close still tears the
85
+ // live sockets down; the `exit(0)` the core fires immediately after
86
+ // does the real teardown a few ms later. Node/Deno don't need this —
87
+ // their `shutdown()`/`close()` resolve normally. The `.catch` guards a
88
+ // future Bun that rejects rather than hangs; if a future Bun resolves
89
+ // the promise after a server-initiated close, revert to
90
+ // `await server.stop(true)` to mirror the Node/Deno adapters.
91
+ shutdown: () => {
92
+ void Promise.resolve(server.stop(true)).catch(() => { });
93
+ return Promise.resolve();
94
+ },
95
+ native: server
96
+ };
97
+ return handle;
98
+ },
99
+ pid: process.pid,
100
+ register_shutdown_signals: (handler) => {
101
+ process.on('SIGINT', () => void handler());
102
+ process.on('SIGTERM', () => void handler());
103
+ },
104
+ exit: (code) => process.exit(code)
105
+ };
106
+ };
@@ -56,10 +56,16 @@ export interface PrepareWebsocketOptions {
56
56
  * `WsEndpointSpec.max_message_bytes` of the mounted endpoints; a smaller
57
57
  * value refuses messages the endpoint would accept. Node's `ws` server takes
58
58
  * it as its frame cap (`maxPayload`), so an oversized message is refused
59
- * before it is buffered whole; Deno and Bun ignore it, leaving the
60
- * per-message check `register_ws_endpoint` makes (both close with
61
- * `WS_CLOSE_MESSAGE_TOO_BIG`). The default sits far below `ws`'s own
62
- * 100 MiB, so a build raising an endpoint's cap must pass it here too.
59
+ * before it is buffered whole. Bun takes twice it as its frame cap
60
+ * (`maxPayloadLength`): past its cap Bun drops the socket without a close
61
+ * frame, so the headroom leaves a message just over the limit to the
62
+ * per-message check `register_ws_endpoint` makes, while a grossly oversized
63
+ * one is still refused before it is buffered whole. Deno ignores it — its
64
+ * upgrade takes no frame cap — leaving that per-message check alone. Every
65
+ * runtime closes a message just over the limit with
66
+ * `WS_CLOSE_MESSAGE_TOO_BIG`. The default sits far below `ws`'s own 100 MiB
67
+ * and Bun's 16 MiB, so a build raising an endpoint's cap must pass it here
68
+ * too.
63
69
  *
64
70
  * @default DEFAULT_WS_MAX_MESSAGE_BYTES
65
71
  */
@@ -1 +1 @@
1
- {"version":3,"file":"testing_server_core.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/testing_server_core.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"testing_server_core.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/testing_server_core.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import '../assert_dev_env.js';
2
2
  import type { TestingServerAdapter } from './testing_server_core.js';
3
- /** Build the Deno {@link TestingServerAdapter}. */
3
+ /** Build the Deno `TestingServerAdapter`. */
4
4
  export declare const create_deno_testing_adapter: () => TestingServerAdapter;
5
5
  //# sourceMappingURL=testing_server_deno.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"testing_server_deno.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/testing_server_deno.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAsB9B,OAAO,KAAK,EAAe,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAelF,mDAAmD;AACnD,eAAO,MAAM,2BAA2B,QAAO,oBAkB7C,CAAC"}
1
+ {"version":3,"file":"testing_server_deno.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/testing_server_deno.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAsB9B,OAAO,KAAK,EAAe,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAelF,6CAA6C;AAC7C,eAAO,MAAM,2BAA2B,QAAO,oBAkB7C,CAAC"}
@@ -17,7 +17,7 @@ import '../assert_dev_env.js';
17
17
  */
18
18
  import { upgradeWebSocket } from '@hono/deno';
19
19
  import { create_deno_runtime } from '../../runtime/deno.js';
20
- /** Build the Deno {@link TestingServerAdapter}. */
20
+ /** Build the Deno `TestingServerAdapter`. */
21
21
  export const create_deno_testing_adapter = () => ({
22
22
  runtime_label: 'Deno',
23
23
  runtime: create_deno_runtime([]),
@@ -1,5 +1,5 @@
1
1
  import '../assert_dev_env.js';
2
2
  import type { TestingServerAdapter } from './testing_server_core.js';
3
- /** Build the Node {@link TestingServerAdapter}. */
3
+ /** Build the Node `TestingServerAdapter`. */
4
4
  export declare const create_node_testing_adapter: () => TestingServerAdapter;
5
5
  //# sourceMappingURL=testing_server_node.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"testing_server_node.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/testing_server_node.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA2B9B,OAAO,KAAK,EAAe,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAUlF,mDAAmD;AACnD,eAAO,MAAM,2BAA2B,QAAO,oBA+B7C,CAAC"}
1
+ {"version":3,"file":"testing_server_node.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/testing_server_node.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA2B9B,OAAO,KAAK,EAAe,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAUlF,6CAA6C;AAC7C,eAAO,MAAM,2BAA2B,QAAO,oBA+B7C,CAAC"}
@@ -28,7 +28,7 @@ const node_serve_handle = (server) => ({
28
28
  }),
29
29
  native: server
30
30
  });
31
- /** Build the Node {@link TestingServerAdapter}. */
31
+ /** Build the Node `TestingServerAdapter`. */
32
32
  export const create_node_testing_adapter = () => ({
33
33
  runtime_label: 'Node',
34
34
  runtime: create_node_runtime(),
@@ -48,7 +48,7 @@ export const create_node_testing_adapter = () => ({
48
48
  },
49
49
  attach_to_server: (handle) => {
50
50
  // `handle.native` is the `ServerType` from `serve()` —
51
- // type-erased at the {@link ServeHandle} seam, so it downcasts here.
51
+ // type-erased at the `ServeHandle` seam, so it downcasts here.
52
52
  node_ws?.injectWebSocket(handle.native);
53
53
  }
54
54
  };
@@ -0,0 +1,20 @@
1
+ import '../assert_dev_env.js';
2
+ import { type BackendCapabilities } from './capabilities.js';
3
+ import type { SetupTest } from './setup.js';
4
+ /** Configuration for `describe_ws_inbound_dispatch_cross_tests`. */
5
+ export interface WsInboundDispatchCrossTestOptions {
6
+ /** Per-test fixture producer (`default_cross_process_setup(handle)`). */
7
+ readonly setup_test: SetupTest;
8
+ /** Backend capability flags; every case gates on `capabilities.peer_request`. */
9
+ readonly capabilities: BackendCapabilities;
10
+ /** Base URL the backend is reachable at (e.g. `http://localhost:1177`). */
11
+ readonly base_url: string;
12
+ /** WebSocket endpoint path on the backend (e.g. `/api/ws`). */
13
+ readonly ws_path: string;
14
+ }
15
+ /**
16
+ * Register the duplicate-id and in-flight-ceiling cases. Gated on
17
+ * `capabilities.peer_request` (the cases hold requests with `peer/ping`).
18
+ */
19
+ export declare const describe_ws_inbound_dispatch_cross_tests: (options: WsInboundDispatchCrossTestOptions) => void;
20
+ //# sourceMappingURL=ws_inbound_dispatch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ws_inbound_dispatch.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/ws_inbound_dispatch.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA2C9B,OAAO,EAAE,KAAK,mBAAmB,EAAW,MAAM,mBAAmB,CAAC;AACtE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAiB5C,oEAAoE;AACpE,MAAM,WAAW,iCAAiC;IACjD,yEAAyE;IACzE,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC;IAC/B,iFAAiF;IACjF,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAAC;IAC3C,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,+DAA+D;IAC/D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CACzB;AAiED;;;GAGG;AACH,eAAO,MAAM,wCAAwC,GACpD,SAAS,iCAAiC,KACxC,IA8GF,CAAC"}