@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.
Files changed (94) hide show
  1. package/dist/actions/CLAUDE.md +56 -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/CLAUDE.md +3 -3
  27. package/dist/http/surface.d.ts +12 -9
  28. package/dist/http/surface.d.ts.map +1 -1
  29. package/dist/rate_limiter.d.ts +43 -3
  30. package/dist/rate_limiter.d.ts.map +1 -1
  31. package/dist/rate_limiter.js +27 -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 +128 -55
  39. package/dist/server/app_server.d.ts.map +1 -1
  40. package/dist/server/app_server.js +110 -61
  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 +83 -25
  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 +20 -20
  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 +12 -12
  52. package/dist/testing/cross_backend/default_backend_configs.d.ts.map +1 -1
  53. package/dist/testing/cross_backend/default_backend_configs.js +11 -10
  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 +16 -1
  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 +5 -4
  60. package/dist/testing/cross_backend/spine_surface_constants.d.ts +43 -3
  61. package/dist/testing/cross_backend/spine_surface_constants.d.ts.map +1 -1
  62. package/dist/testing/cross_backend/spine_surface_constants.js +43 -3
  63. package/dist/testing/cross_backend/testing_backdoor.d.ts +15 -1
  64. package/dist/testing/cross_backend/testing_backdoor.d.ts.map +1 -1
  65. package/dist/testing/cross_backend/testing_backdoor.js +51 -6
  66. package/dist/testing/cross_backend/testing_reset_actions.d.ts +6 -3
  67. package/dist/testing/cross_backend/testing_reset_actions.d.ts.map +1 -1
  68. package/dist/testing/cross_backend/testing_reset_actions.js +6 -3
  69. package/dist/testing/cross_backend/testing_server_bun.d.ts.map +1 -1
  70. package/dist/testing/cross_backend/testing_server_bun.js +5 -1
  71. package/dist/testing/cross_backend/testing_server_core.d.ts +72 -41
  72. package/dist/testing/cross_backend/testing_server_core.d.ts.map +1 -1
  73. package/dist/testing/cross_backend/testing_server_core.js +22 -14
  74. package/dist/testing/cross_backend/testing_server_deno.js +1 -1
  75. package/dist/testing/cross_backend/testing_server_node.d.ts.map +1 -1
  76. package/dist/testing/cross_backend/testing_server_node.js +20 -7
  77. package/dist/testing/cross_backend/ts_spine_backend_config.d.ts +15 -2
  78. package/dist/testing/cross_backend/ts_spine_backend_config.d.ts.map +1 -1
  79. package/dist/testing/cross_backend/ts_spine_backend_config.js +10 -8
  80. package/dist/testing/cross_backend/ws_action_rate_limit.d.ts +26 -0
  81. package/dist/testing/cross_backend/ws_action_rate_limit.d.ts.map +1 -0
  82. package/dist/testing/cross_backend/ws_action_rate_limit.js +261 -0
  83. package/dist/testing/middleware.d.ts.map +1 -1
  84. package/dist/testing/middleware.js +4 -3
  85. package/dist/testing/stubs.d.ts +17 -4
  86. package/dist/testing/stubs.d.ts.map +1 -1
  87. package/dist/testing/stubs.js +46 -13
  88. package/dist/testing/transports/ws_transport.d.ts +7 -0
  89. package/dist/testing/transports/ws_transport.d.ts.map +1 -1
  90. package/dist/testing/transports/ws_transport.js +1 -1
  91. package/dist/testing/ws_round_trip.d.ts +43 -37
  92. package/dist/testing/ws_round_trip.d.ts.map +1 -1
  93. package/dist/testing/ws_round_trip.js +28 -46
  94. package/package.json +2 -2
@@ -1,5 +1,6 @@
1
1
  import '../assert_dev_env.js';
2
2
  import { peer_ping_action } from '../../actions/peer_ping.js';
3
+ import { protocol_actions } from '../../actions/protocol.js';
3
4
  import { create_standard_rpc_actions } from '../../auth/standard_rpc_actions.js';
4
5
  import { create_all_cell_actions } from '../../auth/all_cell_actions.js';
5
6
  import { create_actor_lookup_actions } from '../../auth/actor_lookup_actions.js';
@@ -7,7 +8,6 @@ import { create_actor_search_actions } from '../../auth/actor_search_actions.js'
7
8
  import { create_testing_action_manifest_action, create_testing_actions } from './testing_reset_actions.js';
8
9
  import { test_cell_gated_create_authorize } from './test_cell_gated_create_authorize.js';
9
10
  import { spine_roles, spine_session_options } from './default_spine_surface.js';
10
- import { SPINE_RPC_PATH } from './spine_surface_constants.js';
11
11
  /**
12
12
  * Build the complete live RPC action list the spine test binary mounts on
13
13
  * its single endpoint: the declared `create_standard_rpc_actions` bundle plus
@@ -54,12 +54,29 @@ export const build_full_spine_rpc_actions = (deps, options) => {
54
54
  return actions;
55
55
  };
56
56
  /**
57
- * Factory-form full mount at {@link SPINE_RPC_PATH}, the shape
58
- * `create_app_server`'s `rpc_endpoints` slot accepts. The spine binary wires
59
- * this directly; the surface builder (`create_spine_surface_spec`) keeps using
60
- * the narrower `spine_rpc_endpoints` so the declared surface stays the
61
- * standard bundle only.
57
+ * Build the full live mount for both of the spine binary's endpoints: the
58
+ * RPC list, and the WS list that serves the same actions behind the protocol
59
+ * actions.
60
+ *
61
+ * The Rust `testing_spine_stub` serves one action registry on RPC and WS, so
62
+ * mounting the full list on WS keeps the two spines' WS method sets equal —
63
+ * the cell verbs among them, whose dispatcher-charged rate limit
64
+ * `describe_ws_action_rate_limit_cross_tests` drives over a socket. The one
65
+ * difference is `cancel`: a registered protocol action on TS, read-loop-owned
66
+ * (never dispatched) on Rust.
67
+ *
68
+ * @param deps - the backend `AppDeps`
69
+ * @param options - daemon-token state + optional WS notification sender
70
+ * @returns the RPC and WS action lists, built once and sharing handler instances
62
71
  */
63
- export const full_spine_rpc_endpoints = (ctx, options) => [
64
- { path: SPINE_RPC_PATH, actions: build_full_spine_rpc_actions(ctx.deps, options) }
65
- ];
72
+ export const build_full_spine_mount = (deps, options) => {
73
+ const rpc_actions = build_full_spine_rpc_actions(deps, options);
74
+ const protocol_methods = new Set(protocol_actions.map((action) => action.spec.method));
75
+ return {
76
+ rpc_actions,
77
+ ws_actions: [
78
+ ...protocol_actions,
79
+ ...rpc_actions.filter((action) => !protocol_methods.has(action.spec.method))
80
+ ]
81
+ };
82
+ };
@@ -13,7 +13,7 @@ export declare const RUST_SPINE_STUB_DATABASE_URL_ENV = "FUZ_TESTING_RUST_SPINE_
13
13
  /**
14
14
  * Env var the stub reads for the absolute path of the committed
15
15
  * `expected_schema.json` its `/ready` gate introspects against. Pointed at the
16
- * **same** fixture the TS spine reads ({@link SPINE_EXPECTED_SCHEMA_URL}) —
16
+ * **same** fixture the TS spine reads (`SPINE_EXPECTED_SCHEMA_URL`) —
17
17
  * column-presence is engine-portable, so one file is the cross-impl contract.
18
18
  */
19
19
  export declare const RUST_SPINE_STUB_EXPECTED_SCHEMA_PATH_ENV = "FUZ_RUST_SPINE_STUB_EXPECTED_SCHEMA_PATH";
@@ -51,6 +51,21 @@ export interface SpineStubBackendConfigOptions {
51
51
  * TS spine binary wires the equivalent set unconditionally.
52
52
  */
53
53
  readonly trusted_proxies?: string;
54
+ /**
55
+ * Enable the action rate limiters (`FUZ_ACTION_RATE_LIMIT_ENABLED=true`) —
56
+ * one per-IP and one per-account limiter shared by the RPC and WS
57
+ * endpoints. Off by default, like `enable_login_rate_limit`; set only for
58
+ * the dedicated security cross project, which drives them through
59
+ * `ws_action_rate_limit.ts`. Mirrors `TsSpineBackendConfigOptions.enable_action_rate_limit`.
60
+ */
61
+ readonly enable_action_rate_limit?: boolean;
62
+ /**
63
+ * Replace both action limiters' `max_attempts`
64
+ * (`FUZ_ACTION_RATE_LIMIT_MAX_ATTEMPTS`) so a suite reaches the cap in a few
65
+ * calls. Requires `enable_action_rate_limit` — the binary refuses to boot
66
+ * otherwise. Mirrors `TsSpineBackendConfigOptions.action_rate_limit_max_attempts`.
67
+ */
68
+ readonly action_rate_limit_max_attempts?: number;
54
69
  }
55
70
  /**
56
71
  * Build the `BackendConfig` for `testing_spine_stub`. Resolves the binary
@@ -1 +1 @@
1
- {"version":3,"file":"rust_spine_stub_backend_config.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/rust_spine_stub_backend_config.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA0C9B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AASzD,uGAAuG;AACvG,eAAO,MAAM,uBAAuB,oCAAoC,CAAC;AAEzE;;;;;;GAMG;AACH,eAAO,MAAM,gCAAgC,6CAA6C,CAAC;AAE3F;;;;;GAKG;AACH,eAAO,MAAM,wCAAwC,6CAA6C,CAAC;AAqBnG,kGAAkG;AAClG,eAAO,MAAM,4BAA4B,OAAO,CAAC;AAEjD,0FAA0F;AAC1F,eAAO,MAAM,oCAAoC,sDACG,CAAC;AAErD,MAAM,WAAW,6BAA6B;IAC7C,8DAA8D;IAC9D,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B;;;OAGG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;;;;OAOG;IACH,QAAQ,CAAC,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAC3C;;;;;;OAMG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;CAClC;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,8BAA8B,GAC1C,UAAS,6BAAkC,KACzC,aAkDF,CAAC"}
1
+ {"version":3,"file":"rust_spine_stub_backend_config.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/rust_spine_stub_backend_config.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA0C9B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAYzD,uGAAuG;AACvG,eAAO,MAAM,uBAAuB,oCAAoC,CAAC;AAEzE;;;;;;GAMG;AACH,eAAO,MAAM,gCAAgC,6CAA6C,CAAC;AAE3F;;;;;GAKG;AACH,eAAO,MAAM,wCAAwC,6CAA6C,CAAC;AAqBnG,kGAAkG;AAClG,eAAO,MAAM,4BAA4B,OAAO,CAAC;AAEjD,0FAA0F;AAC1F,eAAO,MAAM,oCAAoC,sDACG,CAAC;AAErD,MAAM,WAAW,6BAA6B;IAC7C,8DAA8D;IAC9D,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B;;;OAGG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;;;;OAOG;IACH,QAAQ,CAAC,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAC3C;;;;;;OAMG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC;;;;;;OAMG;IACH,QAAQ,CAAC,wBAAwB,CAAC,EAAE,OAAO,CAAC;IAC5C;;;;;OAKG;IACH,QAAQ,CAAC,8BAA8B,CAAC,EAAE,MAAM,CAAC;CACjD;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,8BAA8B,GAC1C,UAAS,6BAAkC,KACzC,aAmDF,CAAC"}
@@ -38,8 +38,8 @@ import '../assert_dev_env.js';
38
38
  */
39
39
  import { fileURLToPath } from 'node:url';
40
40
  import { build_test_backend_paths } from './build_test_backend_paths.js';
41
- import { SPINE_EXPECTED_SCHEMA_URL } from './spine_surface_constants.js';
42
- import { LOGIN_RATE_LIMIT_ENABLED_ENV, make_default_rust_backend_config, rust_default_capabilities } from './default_backend_configs.js';
41
+ import { LOGIN_RATE_LIMIT_ENABLED_ENV, SPINE_EXPECTED_SCHEMA_URL } from './spine_surface_constants.js';
42
+ import { action_rate_limit_env, make_default_rust_backend_config, rust_default_capabilities } from './default_backend_configs.js';
43
43
  /** Env var naming the prebuilt `testing_spine_stub` binary. Required when `binary_path` is omitted. */
44
44
  export const RUST_SPINE_STUB_BIN_ENV = 'FUZ_TESTING_RUST_SPINE_STUB_BIN';
45
45
  /**
@@ -53,7 +53,7 @@ export const RUST_SPINE_STUB_DATABASE_URL_ENV = 'FUZ_TESTING_RUST_SPINE_STUB_DAT
53
53
  /**
54
54
  * Env var the stub reads for the absolute path of the committed
55
55
  * `expected_schema.json` its `/ready` gate introspects against. Pointed at the
56
- * **same** fixture the TS spine reads ({@link SPINE_EXPECTED_SCHEMA_URL}) —
56
+ * **same** fixture the TS spine reads (`SPINE_EXPECTED_SCHEMA_URL`) —
57
57
  * column-presence is engine-portable, so one file is the cross-impl contract.
58
58
  */
59
59
  export const RUST_SPINE_STUB_EXPECTED_SCHEMA_PATH_ENV = 'FUZ_RUST_SPINE_STUB_EXPECTED_SCHEMA_PATH';
@@ -127,7 +127,8 @@ export const rust_spine_stub_backend_config = (options = {}) => {
127
127
  // limiters + trust the loopback proxy so the limiter keys on the
128
128
  // resolved `X-Forwarded-For` IP. The stub reads both directly.
129
129
  ...(enable_login_rate_limit ? { [LOGIN_RATE_LIMIT_ENABLED_ENV]: 'true' } : {}),
130
- ...(trusted_proxies !== undefined ? { FUZ_TRUSTED_PROXIES: trusted_proxies } : {})
130
+ ...(trusted_proxies !== undefined ? { FUZ_TRUSTED_PROXIES: trusted_proxies } : {}),
131
+ ...action_rate_limit_env(options)
131
132
  }
132
133
  });
133
134
  };
@@ -1,7 +1,8 @@
1
1
  import '../assert_dev_env.js';
2
2
  /**
3
- * Pure spine-surface path + role constants — the hono-free leaf split out of
4
- * `default_spine_surface.ts`.
3
+ * Pure spine-surface constants — wire paths, roles, the fixture URL, and the
4
+ * env-var names the backend configs set for the spawned spine binaries. A
5
+ * hono-free leaf split out of `default_spine_surface.ts`.
5
6
  *
6
7
  * Cross-process suite modules (which drive a separately-spawned backend binary
7
8
  * over HTTP) need only the wire path / role / fixture-URL, not the in-process
@@ -10,7 +11,13 @@ import '../assert_dev_env.js';
10
11
  * `session_middleware` → `hono/cookie` — onto a backend-spawning consumer with
11
12
  * no `hono` peer installed (a Rust-only spine consumer). Keeping these constants
12
13
  * on this handler-free leaf lets such a consumer import the path without the
13
- * peer. `default_spine_surface.ts` re-exports them for in-process callers.
14
+ * peer. `default_spine_surface.ts` imports the ones it uses from here.
15
+ *
16
+ * The env-var names live here so both sides of each contract share one
17
+ * constant: the backend configs that set them (`default_backend_configs.ts`,
18
+ * `ts_spine_backend_config.ts`, `rust_spine_stub_backend_config.ts`) and the
19
+ * spawned TS spine binary that reads them, which imports this leaf rather than
20
+ * the config builders.
14
21
  *
15
22
  * @module
16
23
  */
@@ -56,4 +63,37 @@ export declare const SPINE_PARTICIPANT_ROLE = "participant";
56
63
  * engine-portable, so one fixture is the cross-impl contract.
57
64
  */
58
65
  export declare const SPINE_EXPECTED_SCHEMA_URL: URL;
66
+ /**
67
+ * Env var both spine binaries read to enable their login rate limiters
68
+ * (`'true'` on / unset off). The cross-language contract for the login-security
69
+ * cross project: the TS binary reads it via `runtime.env_get` (a test-only flag,
70
+ * not in `BaseServerEnv`); the Rust `testing_spine_stub` reads it via
71
+ * `std::env::var` — so one backend-config option drives both impls
72
+ * (`ts_spine_backend_config` and `rust_spine_stub_backend_config` set it).
73
+ */
74
+ export declare const LOGIN_RATE_LIMIT_ENABLED_ENV = "FUZ_LOGIN_RATE_LIMIT_ENABLED";
75
+ /**
76
+ * Env var both spine binaries read to enable their action rate limiters
77
+ * (`'true'` on / unset off) — one per-IP and one per-account limiter, shared by
78
+ * the RPC and WS endpoints (and, on the Rust stub, the auth-family handlers
79
+ * that charge in-handler). The cross-language contract for the action
80
+ * rate-limit cross suite (`ws_action_rate_limit.ts`); same delivery as
81
+ * `LOGIN_RATE_LIMIT_ENABLED_ENV`. Off, neither spine builds an action
82
+ * limiter.
83
+ */
84
+ export declare const ACTION_RATE_LIMIT_ENABLED_ENV = "FUZ_ACTION_RATE_LIMIT_ENABLED";
85
+ /**
86
+ * Env var replacing both action limiters' `max_attempts` (a positive integer;
87
+ * the windows stay `default_action_ip_rate_limit`'s /
88
+ * `default_action_account_rate_limit`'s). Both spine binaries refuse to boot
89
+ * when it is set without `ACTION_RATE_LIMIT_ENABLED_ENV` or is not a positive
90
+ * integer, so a suite never asserts a throttle the backend didn't build.
91
+ */
92
+ export declare const ACTION_RATE_LIMIT_MAX_ATTEMPTS_ENV = "FUZ_ACTION_RATE_LIMIT_MAX_ATTEMPTS";
93
+ /**
94
+ * Env var naming the TS spine backend's root dir, set by
95
+ * `ts_spine_backend_config`; the spawned binary writes its daemon token to
96
+ * `{dir}/run/daemon_token`, which must match `bootstrap.daemon_token_path`.
97
+ */
98
+ export declare const TS_SPINE_DIR_ENV = "FUZ_TESTING_TS_SPINE_DIR";
59
99
  //# sourceMappingURL=spine_surface_constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"spine_surface_constants.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/spine_surface_constants.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;GAcG;AAEH,iEAAiE;AACjE,eAAO,MAAM,cAAc,aAAa,CAAC;AAEzC;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,4BAA4B,CAAC;AAExD;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,gBAAgB,CAAC;AAEpD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,sBAAsB,gBAAgB,CAAC;AAEpD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,yBAAyB,EAAE,GAAwD,CAAC"}
1
+ {"version":3,"file":"spine_surface_constants.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/spine_surface_constants.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,iEAAiE;AACjE,eAAO,MAAM,cAAc,aAAa,CAAC;AAEzC;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,4BAA4B,CAAC;AAExD;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,gBAAgB,CAAC;AAEpD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,sBAAsB,gBAAgB,CAAC;AAEpD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,yBAAyB,EAAE,GAAwD,CAAC;AAEjG;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,iCAAiC,CAAC;AAE3E;;;;;;;;GAQG;AACH,eAAO,MAAM,6BAA6B,kCAAkC,CAAC;AAE7E;;;;;;GAMG;AACH,eAAO,MAAM,kCAAkC,uCAAuC,CAAC;AAEvF;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,6BAA6B,CAAC"}
@@ -1,7 +1,8 @@
1
1
  import '../assert_dev_env.js';
2
2
  /**
3
- * Pure spine-surface path + role constants — the hono-free leaf split out of
4
- * `default_spine_surface.ts`.
3
+ * Pure spine-surface constants — wire paths, roles, the fixture URL, and the
4
+ * env-var names the backend configs set for the spawned spine binaries. A
5
+ * hono-free leaf split out of `default_spine_surface.ts`.
5
6
  *
6
7
  * Cross-process suite modules (which drive a separately-spawned backend binary
7
8
  * over HTTP) need only the wire path / role / fixture-URL, not the in-process
@@ -10,7 +11,13 @@ import '../assert_dev_env.js';
10
11
  * `session_middleware` → `hono/cookie` — onto a backend-spawning consumer with
11
12
  * no `hono` peer installed (a Rust-only spine consumer). Keeping these constants
12
13
  * on this handler-free leaf lets such a consumer import the path without the
13
- * peer. `default_spine_surface.ts` re-exports them for in-process callers.
14
+ * peer. `default_spine_surface.ts` imports the ones it uses from here.
15
+ *
16
+ * The env-var names live here so both sides of each contract share one
17
+ * constant: the backend configs that set them (`default_backend_configs.ts`,
18
+ * `ts_spine_backend_config.ts`, `rust_spine_stub_backend_config.ts`) and the
19
+ * spawned TS spine binary that reads them, which imports this leaf rather than
20
+ * the config builders.
14
21
  *
15
22
  * @module
16
23
  */
@@ -56,3 +63,36 @@ export const SPINE_PARTICIPANT_ROLE = 'participant';
56
63
  * engine-portable, so one fixture is the cross-impl contract.
57
64
  */
58
65
  export const SPINE_EXPECTED_SCHEMA_URL = new URL('./expected_schema.json', import.meta.url);
66
+ /**
67
+ * Env var both spine binaries read to enable their login rate limiters
68
+ * (`'true'` on / unset off). The cross-language contract for the login-security
69
+ * cross project: the TS binary reads it via `runtime.env_get` (a test-only flag,
70
+ * not in `BaseServerEnv`); the Rust `testing_spine_stub` reads it via
71
+ * `std::env::var` — so one backend-config option drives both impls
72
+ * (`ts_spine_backend_config` and `rust_spine_stub_backend_config` set it).
73
+ */
74
+ export const LOGIN_RATE_LIMIT_ENABLED_ENV = 'FUZ_LOGIN_RATE_LIMIT_ENABLED';
75
+ /**
76
+ * Env var both spine binaries read to enable their action rate limiters
77
+ * (`'true'` on / unset off) — one per-IP and one per-account limiter, shared by
78
+ * the RPC and WS endpoints (and, on the Rust stub, the auth-family handlers
79
+ * that charge in-handler). The cross-language contract for the action
80
+ * rate-limit cross suite (`ws_action_rate_limit.ts`); same delivery as
81
+ * `LOGIN_RATE_LIMIT_ENABLED_ENV`. Off, neither spine builds an action
82
+ * limiter.
83
+ */
84
+ export const ACTION_RATE_LIMIT_ENABLED_ENV = 'FUZ_ACTION_RATE_LIMIT_ENABLED';
85
+ /**
86
+ * Env var replacing both action limiters' `max_attempts` (a positive integer;
87
+ * the windows stay `default_action_ip_rate_limit`'s /
88
+ * `default_action_account_rate_limit`'s). Both spine binaries refuse to boot
89
+ * when it is set without `ACTION_RATE_LIMIT_ENABLED_ENV` or is not a positive
90
+ * integer, so a suite never asserts a throttle the backend didn't build.
91
+ */
92
+ export const ACTION_RATE_LIMIT_MAX_ATTEMPTS_ENV = 'FUZ_ACTION_RATE_LIMIT_MAX_ATTEMPTS';
93
+ /**
94
+ * Env var naming the TS spine backend's root dir, set by
95
+ * `ts_spine_backend_config`; the spawned binary writes its daemon token to
96
+ * `{dir}/run/daemon_token`, which must match `bootstrap.daemon_token_path`.
97
+ */
98
+ export const TS_SPINE_DIR_ENV = 'FUZ_TESTING_TS_SPINE_DIR';
@@ -1,6 +1,20 @@
1
1
  import '../assert_dev_env.js';
2
2
  import type { RpcPathCrossSuiteOptions } from './setup.js';
3
3
  /** Options for the testing-backdoor negative-credential suite. */
4
- export type TestingBackdoorCrossTestOptions = RpcPathCrossSuiteOptions;
4
+ export interface TestingBackdoorCrossTestOptions extends RpcPathCrossSuiteOptions {
5
+ /**
6
+ * Where the backend's WebSocket endpoint is, for the session-socket cases.
7
+ * Pass it when the backend serves the `_testing_*` actions on its WS
8
+ * endpoint too; omitted, those cases are skipped.
9
+ */
10
+ readonly ws?: {
11
+ /** Base URL the backend is reachable at (e.g. `http://localhost:1178`). */
12
+ readonly base_url: string;
13
+ /** WebSocket endpoint path on the backend (e.g. `/api/ws`). */
14
+ readonly ws_path: string;
15
+ /** Origin for the upgrade. Defaults to `base_url`. */
16
+ readonly origin?: string;
17
+ };
18
+ }
5
19
  export declare const describe_testing_backdoor_cross_tests: (options: TestingBackdoorCrossTestOptions) => void;
6
20
  //# sourceMappingURL=testing_backdoor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"testing_backdoor.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/testing_backdoor.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA4D9B,OAAO,KAAK,EAAE,wBAAwB,EAAe,MAAM,YAAY,CAAC;AAqExE,kEAAkE;AAClE,MAAM,MAAM,+BAA+B,GAAG,wBAAwB,CAAC;AAEvE,eAAO,MAAM,qCAAqC,GACjD,SAAS,+BAA+B,KACtC,IAiCF,CAAC"}
1
+ {"version":3,"file":"testing_backdoor.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/testing_backdoor.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA2E9B,OAAO,KAAK,EAAE,wBAAwB,EAAe,MAAM,YAAY,CAAC;AA0ExE,kEAAkE;AAClE,MAAM,WAAW,+BAAgC,SAAQ,wBAAwB;IAChF;;;;OAIG;IACH,QAAQ,CAAC,EAAE,CAAC,EAAE;QACb,2EAA2E;QAC3E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;QAC1B,+DAA+D;QAC/D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QACzB,sDAAsD;QACtD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;CACF;AAED,eAAO,MAAM,qCAAqC,GACjD,SAAS,+BAA+B,KACtC,IAyEF,CAAC"}
@@ -12,7 +12,8 @@ import '../assert_dev_env.js';
12
12
  * info-leak of the set were the gate to break). Their only structural fence
13
13
  * is the **daemon-token** credential gate on
14
14
  * each spec's `auth` axis. A test binary live-mounts them on its RPC
15
- * endpoint but keeps them off the declared surface — so the spec-derived
15
+ * endpoint (and, on fuz_app's spine binary and the Rust stub, its WS
16
+ * endpoint) but keeps them off the declared surface — so the spec-derived
16
17
  * `describe_rpc_attack_surface_tests` never enumerates them, and nothing
17
18
  * else fires them with a non-daemon credential to prove the gate holds
18
19
  * end-to-end. This suite does, against each impl's real auth resolution.
@@ -28,6 +29,14 @@ import '../assert_dev_env.js';
28
29
  * `credential_type_required` — same ceiling; an api token cannot reach
29
30
  * keeper operations.
30
31
  *
32
+ * Over WebSocket (when `ws` is supplied), the same methods sent on a socket
33
+ * opened with the keeper's **session** cookie answer the same `forbidden`
34
+ * error with `credential_type_required`: the upgrade admits a session, but
35
+ * each message runs the same per-action gates as HTTP RPC, so a socket is no
36
+ * way around the daemon-token channel. Anonymous and bearer have no WS case —
37
+ * an anonymous upgrade is refused before any message, and the upgrade client
38
+ * threads cookies.
39
+ *
31
40
  * Each method is sent with **valid** params so each case varies only the
32
41
  * credential. (Validation runs after the gates — the order is 401 → authz →
33
42
  * 403 → 429 → 400 — so the shapes are belt-and-suspenders here rather than load-
@@ -44,7 +53,9 @@ import '../assert_dev_env.js';
44
53
  * binary, not the in-process app — like the ws/sse suites. Wire from a
45
54
  * `*.cross.test.ts`. Requires the standard `_testing_*` actions mounted (the
46
55
  * same precondition `default_cross_process_setup` already imposes for its
47
- * per-test `_testing_reset`); ungated, since every cross backend mounts them.
56
+ * per-test `_testing_reset`); the HTTP cases are ungated, since every cross
57
+ * backend mounts them, and the WS cases run when `ws` is passed — for a
58
+ * backend that also serves them on its WS endpoint.
48
59
  *
49
60
  * `$lib`-free by contract (relative specifiers only), like the sibling
50
61
  * cross-backend suites.
@@ -53,7 +64,11 @@ import '../assert_dev_env.js';
53
64
  */
54
65
  import { describe, test, assert } from 'vitest';
55
66
  import { ERROR_CREDENTIAL_TYPE_REQUIRED } from '../../http/error_schemas.js';
67
+ import { JSONRPC_ERROR_CODES } from '../../http/jsonrpc_errors.js';
56
68
  import { rpc_call } from '../rpc_helpers.js';
69
+ import { create_admitted_ws_transport } from '../transports/ws_transport.js';
70
+ import { is_response_for } from '../transports/ws_client.js';
71
+ import { test_if } from './capabilities.js';
57
72
  import { SPINE_RPC_PATH } from './spine_surface_constants.js';
58
73
  /** A well-formed UUID that never names a real row. */
59
74
  const NIL_UUID = '00000000-0000-0000-0000-000000000000';
@@ -80,18 +95,21 @@ const principals = [
80
95
  {
81
96
  name: 'anonymous',
82
97
  status: 401,
98
+ code: JSONRPC_ERROR_CODES.unauthenticated,
83
99
  // Fresh jar so the keeper cookie (cross-process) can't leak in.
84
100
  resolve: (f) => ({ transport: f.fresh_transport(), headers: {} })
85
101
  },
86
102
  {
87
103
  name: 'session',
88
104
  status: 403,
105
+ code: JSONRPC_ERROR_CODES.forbidden,
89
106
  reason: ERROR_CREDENTIAL_TYPE_REQUIRED,
90
107
  resolve: (f) => ({ transport: f.transport, headers: f.create_session_headers() })
91
108
  },
92
109
  {
93
110
  name: 'bearer',
94
111
  status: 403,
112
+ code: JSONRPC_ERROR_CODES.forbidden,
95
113
  reason: ERROR_CREDENTIAL_TYPE_REQUIRED,
96
114
  // Bearer is discarded in a browser context, so suppress Origin (empty
97
115
  // jar + no Origin) — the credential must actually resolve so the refusal
@@ -104,7 +122,7 @@ const principals = [
104
122
  }
105
123
  ];
106
124
  export const describe_testing_backdoor_cross_tests = (options) => {
107
- const { setup_test } = options;
125
+ const { setup_test, ws } = options;
108
126
  const rpc_path = options.rpc_path ?? SPINE_RPC_PATH;
109
127
  describe('testing backdoor credential gate parity', () => {
110
128
  for (const { method, params } of backdoor_methods) {
@@ -124,12 +142,39 @@ export const describe_testing_backdoor_cross_tests = (options) => {
124
142
  assert.ok(!res.ok, `${label}: expected denial (${principal.status}) but the call succeeded`);
125
143
  assert.strictEqual(res.status, principal.status, `${label}: status`);
126
144
  // `!res.ok` narrows `res` to the error variant for `res.error`.
127
- if (principal.reason !== undefined && !res.ok) {
128
- const reason = res.error.data?.reason;
129
- assert.strictEqual(reason, principal.reason, `${label}: error.data.reason`);
145
+ if (!res.ok) {
146
+ assert.strictEqual(res.error.code, principal.code, `${label}: error.code`);
147
+ if (principal.reason !== undefined) {
148
+ const reason = res.error.data?.reason;
149
+ assert.strictEqual(reason, principal.reason, `${label}: error.data.reason`);
150
+ }
130
151
  }
131
152
  });
132
153
  }
133
154
  }
155
+ for (const { method, params } of backdoor_methods) {
156
+ test_if(ws !== undefined, `${method} over a session socket → forbidden ${ERROR_CREDENTIAL_TYPE_REQUIRED}`, async () => {
157
+ const fixture = await setup_test();
158
+ const client = await create_admitted_ws_transport({
159
+ base_url: ws.base_url,
160
+ ws_path: ws.ws_path,
161
+ cookies: fixture.transport.cookies(),
162
+ origin: ws.origin
163
+ });
164
+ try {
165
+ const id = `backdoor_${method}`;
166
+ await client.send({ jsonrpc: '2.0', id, method, params });
167
+ const frame = await client.wait_for(is_response_for(id));
168
+ const label = `${method} session socket`;
169
+ assert.ok(frame.error, `${label}: expected a credential_type_required error but the call succeeded`);
170
+ assert.strictEqual(frame.error.code, JSONRPC_ERROR_CODES.forbidden, `${label}: code`);
171
+ const reason = frame.error.data?.reason;
172
+ assert.strictEqual(reason, ERROR_CREDENTIAL_TYPE_REQUIRED, `${label}: error.data.reason`);
173
+ }
174
+ finally {
175
+ await client.close();
176
+ }
177
+ });
178
+ }
134
179
  });
135
180
  };
@@ -163,9 +163,12 @@ export declare const testing_reset_action_spec: {
163
163
  * asserting on audit rows.
164
164
  *
165
165
  * On the TS spine the barrier is **satisfied by construction**: the test
166
- * binary runs `await_pending_effects: true`, so every mutation's fire-and-
167
- * forget audit emits are awaited before its response returns — by the time
168
- * a later drain call runs, prior emits are already durable. The action still
166
+ * binary runs `await_pending_effects: true`, so every **HTTP** mutation's
167
+ * fire-and-forget audit emits are awaited before its response returns — by
168
+ * the time a later drain call runs, prior emits are already durable. A
169
+ * WS-dispatched mutation replies before its effects flush, so on TS this
170
+ * action is not a barrier for WS-originated emits; issue audit-asserting
171
+ * mutations over HTTP. The action still
169
172
  * exists so the cross-backend test body calls the same method on every
170
173
  * backend; the Rust spine (whose audit writes are detached tokio tasks)
171
174
  * does the real await in `AuditEmitter::drain_inflight`.
@@ -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,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;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,iCAAiC;;;;;;;;;;;;;;;;CAWA,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;CAwBC,CAAC;AAE/C;;;;;;GAMG;AACH,eAAO,MAAM,mCAAmC,QAAO,SACmB,CAAC;AAE3E;;;;;;;;;;;;;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;;;;;;;;;;;;;GAaG;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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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,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;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,iCAAiC;;;;;;;;;;;;;;;;CAWA,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;CAwBC,CAAC;AAE/C;;;;;;GAMG;AACH,eAAO,MAAM,mCAAmC,QAAO,SACmB,CAAC;AAE3E;;;;;;;;;;;;;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;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,sBAAsB,GAClC,MAAM,OAAO,EACb,SAAS,2BAA2B,KAClC,KAAK,CAAC,SAAS,CAsIjB,CAAC;AAEF,0FAA0F;AAC1F,eAAO,MAAM,0BAA0B,UAAmC,CAAC"}
@@ -169,9 +169,12 @@ export const testing_reset_action_spec = {
169
169
  * asserting on audit rows.
170
170
  *
171
171
  * On the TS spine the barrier is **satisfied by construction**: the test
172
- * binary runs `await_pending_effects: true`, so every mutation's fire-and-
173
- * forget audit emits are awaited before its response returns — by the time
174
- * a later drain call runs, prior emits are already durable. The action still
172
+ * binary runs `await_pending_effects: true`, so every **HTTP** mutation's
173
+ * fire-and-forget audit emits are awaited before its response returns — by
174
+ * the time a later drain call runs, prior emits are already durable. A
175
+ * WS-dispatched mutation replies before its effects flush, so on TS this
176
+ * action is not a barrier for WS-originated emits; issue audit-asserting
177
+ * mutations over HTTP. The action still
175
178
  * exists so the cross-backend test body calls the same method on every
176
179
  * backend; the Rust spine (whose audit writes are detached tokio tasks)
177
180
  * does the real await in `AuditEmitter::drain_inflight`.
@@ -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,oBA0D5C,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;AA6B9B,OAAO,KAAK,EAAe,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAelF,kDAAkD;AAClD,eAAO,MAAM,0BAA0B,QAAO,oBA8D5C,CAAC"}
@@ -32,7 +32,11 @@ export const create_bun_testing_adapter = () => ({
32
32
  // Bun's WS upgrade is module-level and stateless (like Deno) — no
33
33
  // post-serve attach. The `websocket` handler is threaded into `serve`
34
34
  // below, where `Bun.serve` wants it.
35
- prepare_websocket: () => ({ upgrade_websocket: upgradeWebSocket }),
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 }),
36
40
  serve: ({ fetch, port, hostname }) => {
37
41
  const server = Bun.serve({
38
42
  fetch: fetch,