@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.
- package/dist/actions/CLAUDE.md +57 -20
- package/dist/actions/action_rpc.d.ts +14 -11
- package/dist/actions/action_rpc.d.ts.map +1 -1
- package/dist/actions/action_rpc.js +5 -4
- package/dist/actions/connection_closer.d.ts +13 -3
- package/dist/actions/connection_closer.d.ts.map +1 -1
- package/dist/actions/connection_closer.js +7 -5
- package/dist/actions/register_action_ws.d.ts +18 -13
- package/dist/actions/register_action_ws.d.ts.map +1 -1
- package/dist/actions/register_action_ws.js +8 -6
- package/dist/actions/register_ws_endpoint.d.ts +6 -3
- package/dist/actions/register_ws_endpoint.d.ts.map +1 -1
- package/dist/actions/register_ws_endpoint.js +6 -3
- package/dist/actions/transports.d.ts +9 -0
- package/dist/actions/transports.d.ts.map +1 -1
- package/dist/actions/transports.js +9 -0
- package/dist/actions/transports_ws_backend.d.ts +15 -0
- package/dist/actions/transports_ws_backend.d.ts.map +1 -1
- package/dist/actions/transports_ws_backend.js +25 -5
- package/dist/actions/ws_endpoint_spec.d.ts +24 -4
- package/dist/actions/ws_endpoint_spec.d.ts.map +1 -1
- package/dist/actions/ws_endpoint_spec.js +15 -1
- package/dist/auth/middleware.d.ts +29 -1
- package/dist/auth/middleware.d.ts.map +1 -1
- package/dist/auth/middleware.js +35 -1
- package/dist/http/surface.d.ts +3 -1
- package/dist/http/surface.d.ts.map +1 -1
- package/dist/http/surface.js +15 -1
- package/dist/rate_limiter.d.ts +25 -3
- package/dist/rate_limiter.d.ts.map +1 -1
- package/dist/rate_limiter.js +4 -3
- package/dist/realtime/sse_auth_guard.d.ts +2 -1
- package/dist/realtime/sse_auth_guard.d.ts.map +1 -1
- package/dist/realtime/sse_auth_guard.js +4 -2
- package/dist/realtime/subscriber_registry.d.ts +12 -0
- package/dist/realtime/subscriber_registry.d.ts.map +1 -1
- package/dist/realtime/subscriber_registry.js +18 -2
- package/dist/server/app_server.d.ts +127 -55
- package/dist/server/app_server.d.ts.map +1 -1
- package/dist/server/app_server.js +107 -60
- package/dist/server/app_server_context.d.ts +17 -9
- package/dist/server/app_server_context.d.ts.map +1 -1
- package/dist/testing/CLAUDE.md +75 -17
- package/dist/testing/app_server.d.ts +6 -3
- package/dist/testing/app_server.d.ts.map +1 -1
- package/dist/testing/app_server.js +11 -12
- package/dist/testing/connection_closer_helpers.d.ts +10 -4
- package/dist/testing/connection_closer_helpers.d.ts.map +1 -1
- package/dist/testing/connection_closer_helpers.js +4 -0
- package/dist/testing/cross_backend/capabilities.d.ts +3 -3
- package/dist/testing/cross_backend/default_backend_configs.d.ts +31 -0
- package/dist/testing/cross_backend/default_backend_configs.d.ts.map +1 -1
- package/dist/testing/cross_backend/default_backend_configs.js +31 -0
- package/dist/testing/cross_backend/full_spine_mount.d.ts +35 -11
- package/dist/testing/cross_backend/full_spine_mount.d.ts.map +1 -1
- package/dist/testing/cross_backend/full_spine_mount.js +26 -9
- package/dist/testing/cross_backend/rust_spine_stub_backend_config.d.ts +15 -0
- package/dist/testing/cross_backend/rust_spine_stub_backend_config.d.ts.map +1 -1
- package/dist/testing/cross_backend/rust_spine_stub_backend_config.js +3 -2
- package/dist/testing/cross_backend/testing_backdoor.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_backdoor.js +2 -1
- package/dist/testing/cross_backend/testing_reset_actions.d.ts +6 -3
- package/dist/testing/cross_backend/testing_reset_actions.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_reset_actions.js +6 -3
- package/dist/testing/cross_backend/testing_server_bun.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_server_bun.js +5 -1
- package/dist/testing/cross_backend/testing_server_core.d.ts +68 -37
- package/dist/testing/cross_backend/testing_server_core.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_server_core.js +20 -12
- package/dist/testing/cross_backend/testing_server_deno.js +1 -1
- package/dist/testing/cross_backend/testing_server_node.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_server_node.js +20 -7
- package/dist/testing/cross_backend/ts_spine_backend_config.d.ts +15 -0
- package/dist/testing/cross_backend/ts_spine_backend_config.d.ts.map +1 -1
- package/dist/testing/cross_backend/ts_spine_backend_config.js +9 -5
- package/dist/testing/cross_backend/ws_action_rate_limit.d.ts +26 -0
- package/dist/testing/cross_backend/ws_action_rate_limit.d.ts.map +1 -0
- package/dist/testing/cross_backend/ws_action_rate_limit.js +261 -0
- package/dist/testing/stubs.d.ts +14 -4
- package/dist/testing/stubs.d.ts.map +1 -1
- package/dist/testing/stubs.js +31 -13
- package/dist/testing/transports/ws_transport.d.ts +7 -0
- package/dist/testing/transports/ws_transport.d.ts.map +1 -1
- package/dist/testing/transports/ws_transport.js +1 -1
- package/dist/testing/ws_round_trip.d.ts +36 -6
- package/dist/testing/ws_round_trip.d.ts.map +1 -1
- package/dist/testing/ws_round_trip.js +28 -8
- package/package.json +2 -2
|
@@ -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;
|
|
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;AAUzD,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"}
|
|
@@ -39,7 +39,7 @@ import '../assert_dev_env.js';
|
|
|
39
39
|
import { fileURLToPath } from 'node:url';
|
|
40
40
|
import { build_test_backend_paths } from './build_test_backend_paths.js';
|
|
41
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';
|
|
42
|
+
import { LOGIN_RATE_LIMIT_ENABLED_ENV, 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
|
/**
|
|
@@ -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 +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;
|
|
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;AA6D9B,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"}
|
|
@@ -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
|
|
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.
|
|
@@ -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
|
|
167
|
-
* forget audit emits are awaited before its response returns — by
|
|
168
|
-
* a later drain call runs, prior emits are already durable.
|
|
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
|
|
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
|
|
173
|
-
* forget audit emits are awaited before its response returns — by
|
|
174
|
-
* a later drain call runs, prior emits are already durable.
|
|
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,
|
|
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
|
-
|
|
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,
|
|
@@ -7,15 +7,20 @@ import '../assert_dev_env.js';
|
|
|
7
7
|
* the `cross_backend/*` suites (and the cross-impl bench) can drive it the
|
|
8
8
|
* same way they drive the Rust spine. This module owns the runtime-neutral
|
|
9
9
|
* orchestration — stale-daemon check, daemon-info write, serve, post-serve
|
|
10
|
-
* WS attach, graceful
|
|
10
|
+
* WS attach, graceful shutdown — and delegates the runtime-boundary
|
|
11
11
|
* primitives (HTTP serve, WS upgrade construction, signals, pid, exit) to a
|
|
12
|
-
* {@link TestingServerAdapter}. The
|
|
13
|
-
* `testing/cross_backend/testing_server_node.ts` (`@hono/node-server` + `@hono/node-ws`)
|
|
14
|
-
* `testing/cross_backend/testing_server_deno.ts` (`Deno.serve` + `@hono/deno`)
|
|
12
|
+
* {@link TestingServerAdapter}. The shipped adapters are
|
|
13
|
+
* `testing/cross_backend/testing_server_node.ts` (`@hono/node-server` + `@hono/node-ws`),
|
|
14
|
+
* `testing/cross_backend/testing_server_deno.ts` (`Deno.serve` + `@hono/deno`), and
|
|
15
|
+
* `testing/cross_backend/testing_server_bun.ts` (`Bun.serve` + `@hono/bun`).
|
|
15
16
|
*
|
|
16
|
-
* The app itself — routes, RPC, DB, `_testing_reset`,
|
|
17
|
-
*
|
|
18
|
-
*
|
|
17
|
+
* The app itself — routes, RPC, DB, `_testing_reset`, WS endpoints — is the
|
|
18
|
+
* caller's {@link StartTestingServerOptions.build_app} seam, so this core
|
|
19
|
+
* stays domain-free. WebSocket endpoints mount through `create_app_server`'s
|
|
20
|
+
* `ws_endpoints`: `build_app` asks its context to prepare the runtime's
|
|
21
|
+
* upgrade helper and passes the resulting factory as
|
|
22
|
+
* `create_upgrade_websocket`; the core attaches it to the server once
|
|
23
|
+
* `serve` returns (Node's `injectWebSocket`). fuz_app's own `testing_spine_server` passes a
|
|
19
24
|
* no-domain build; consumers (zzz, fuz_forge) pass their domain build.
|
|
20
25
|
*
|
|
21
26
|
* **NEVER ships in a release.** This module lives under `cross_backend/` and
|
|
@@ -33,32 +38,52 @@ import type { RuntimeDeps } from '../../runtime/deps.js';
|
|
|
33
38
|
/**
|
|
34
39
|
* Adapter-built handle to a bound HTTP server.
|
|
35
40
|
*
|
|
36
|
-
* `shutdown` stops accepting new connections and
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
41
|
+
* `shutdown` stops accepting new connections at once and settles when the
|
|
42
|
+
* in-flight ones have drained — the core starts it, closes the app (which
|
|
43
|
+
* ends live WebSockets), then awaits it. `native` is an adapter-specific
|
|
44
|
+
* server reference — used by Node's `@hono/node-ws` `injectWebSocket(server)`
|
|
45
|
+
* post-serve hook.
|
|
40
46
|
*/
|
|
41
47
|
export interface ServeHandle {
|
|
42
48
|
shutdown: () => Promise<void>;
|
|
43
49
|
/** Adapter-specific server ref for post-serve hooks. Type-erased at the seam. */
|
|
44
50
|
native?: unknown;
|
|
45
51
|
}
|
|
52
|
+
/** Options for {@link TestingServerAdapter.prepare_websocket}. */
|
|
53
|
+
export interface PrepareWebsocketOptions {
|
|
54
|
+
/**
|
|
55
|
+
* Largest inbound WebSocket message, in bytes — pass the largest
|
|
56
|
+
* `WsEndpointSpec.max_message_bytes` of the mounted endpoints; a smaller
|
|
57
|
+
* value refuses messages the endpoint would accept. Node's `ws` server takes
|
|
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.
|
|
63
|
+
*
|
|
64
|
+
* @default DEFAULT_WS_MAX_MESSAGE_BYTES
|
|
65
|
+
*/
|
|
66
|
+
max_message_bytes?: number;
|
|
67
|
+
}
|
|
46
68
|
/**
|
|
47
69
|
* Result of an adapter's WS preparation step.
|
|
48
70
|
*
|
|
49
|
-
* `
|
|
50
|
-
*
|
|
51
|
-
* `serve()` returns a {@link ServeHandle} —
|
|
52
|
-
* `injectWebSocket(server)
|
|
71
|
+
* `create_upgrade_websocket` is the factory a build passes to
|
|
72
|
+
* `create_app_server` as `AppServerOptions.create_upgrade_websocket`.
|
|
73
|
+
* `attach_to_server` runs after `serve()` returns a {@link ServeHandle} —
|
|
74
|
+
* Node uses it for `injectWebSocket(server)`, and it does nothing when the
|
|
75
|
+
* factory was never called (no `ws_endpoints`); Deno and Bun leave it
|
|
76
|
+
* undefined.
|
|
53
77
|
*/
|
|
54
78
|
export interface PreparedWebsocket {
|
|
55
|
-
|
|
79
|
+
create_upgrade_websocket: (app: Hono) => UpgradeWebSocket;
|
|
56
80
|
attach_to_server?: (handle: ServeHandle) => void;
|
|
57
81
|
}
|
|
58
82
|
/**
|
|
59
83
|
* Runtime adapter contract for the test-binary entry. Each adapter
|
|
60
|
-
* (`testing/cross_backend/testing_server_node.ts`, `testing/cross_backend/testing_server_deno.ts
|
|
61
|
-
* hands the shape to
|
|
84
|
+
* (`testing/cross_backend/testing_server_node.ts`, `testing/cross_backend/testing_server_deno.ts`,
|
|
85
|
+
* `testing/cross_backend/testing_server_bun.ts`) implements this and hands the shape to
|
|
86
|
+
* {@link start_testing_server}.
|
|
62
87
|
*/
|
|
63
88
|
export interface TestingServerAdapter {
|
|
64
89
|
/** Human-readable runtime label for log output (e.g. `"Node"`, `"Deno"`). */
|
|
@@ -67,8 +92,8 @@ export interface TestingServerAdapter {
|
|
|
67
92
|
runtime: RuntimeDeps;
|
|
68
93
|
/** Extract the raw TCP connection IP from a Hono context. */
|
|
69
94
|
get_connection_ip: (c: Context) => string | undefined;
|
|
70
|
-
/**
|
|
71
|
-
prepare_websocket: (
|
|
95
|
+
/** Prepare the runtime's WS upgrade helper and its post-serve attach step. */
|
|
96
|
+
prepare_websocket: (options?: PrepareWebsocketOptions) => PreparedWebsocket;
|
|
72
97
|
/** Bind `app.fetch` to `port` on `hostname`; return a {@link ServeHandle}. */
|
|
73
98
|
serve: (options: {
|
|
74
99
|
fetch: Hono['fetch'];
|
|
@@ -82,22 +107,29 @@ export interface TestingServerAdapter {
|
|
|
82
107
|
/** Forceful exit on graceful-shutdown completion or fatal error. */
|
|
83
108
|
exit: (code: number) => never;
|
|
84
109
|
}
|
|
85
|
-
/**
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
110
|
+
/** What the core hands a {@link StartTestingServerOptions.build_app} seam. */
|
|
111
|
+
export interface BuildTestingAppContext {
|
|
112
|
+
/**
|
|
113
|
+
* Prepare the runtime adapter's WS upgrade helper and return the factory
|
|
114
|
+
* to pass to `create_app_server` as `create_upgrade_websocket`. The core
|
|
115
|
+
* runs the adapter's attach step once the server is bound, so a build
|
|
116
|
+
* that mounts `ws_endpoints` needs nothing else. An HTTP-only build
|
|
117
|
+
* doesn't call it. Call it at most once per build: the Node adapter
|
|
118
|
+
* attaches one upgrade listener per preparation, and two would race on
|
|
119
|
+
* the shared socket.
|
|
120
|
+
*/
|
|
121
|
+
prepare_websocket: (options?: PrepareWebsocketOptions) => (app: Hono) => UpgradeWebSocket;
|
|
122
|
+
}
|
|
123
|
+
/** The assembled app a {@link StartTestingServerOptions.build_app} seam returns. */
|
|
94
124
|
export interface BuiltTestingApp {
|
|
95
|
-
/** The assembled Hono app (HTTP routes
|
|
125
|
+
/** The assembled Hono app (HTTP routes, RPC, and WS endpoints already mounted). */
|
|
96
126
|
app: Hono;
|
|
97
|
-
/**
|
|
127
|
+
/**
|
|
128
|
+
* Tear down backend(s) + DB + any rotation on graceful shutdown. Called
|
|
129
|
+
* after the listener stops accepting connections and before its drain is
|
|
130
|
+
* awaited, so it must end live WebSockets (`AppServer.close` does).
|
|
131
|
+
*/
|
|
98
132
|
close: () => Promise<void>;
|
|
99
|
-
/** Mount WS endpoint(s) given the runtime-prepared upgrade closure. */
|
|
100
|
-
mount_websocket?: (upgrade_websocket: UpgradeWebSocket) => void;
|
|
101
133
|
}
|
|
102
134
|
/** Options for {@link start_testing_server}. */
|
|
103
135
|
export interface StartTestingServerOptions {
|
|
@@ -120,10 +152,9 @@ export interface StartTestingServerOptions {
|
|
|
120
152
|
/**
|
|
121
153
|
* Build the app. Closes over the entry's runtime + connection-IP getter
|
|
122
154
|
* + password deps + resolved config — so this core never touches the
|
|
123
|
-
* domain. Returns the assembled app
|
|
124
|
-
* `mount_websocket` hook.
|
|
155
|
+
* domain. Returns the assembled app and a `close` teardown.
|
|
125
156
|
*/
|
|
126
|
-
build_app: () => Promise<BuiltTestingApp>;
|
|
157
|
+
build_app: (context: BuildTestingAppContext) => Promise<BuiltTestingApp>;
|
|
127
158
|
/** Optional logger; defaults to a `[daemon_name]`-namespaced `Logger`. */
|
|
128
159
|
log?: LoggerType;
|
|
129
160
|
}
|
|
@@ -141,7 +172,7 @@ export declare const is_loopback_host: (host: string) => boolean;
|
|
|
141
172
|
* Boot a test-mode server using the supplied runtime adapter.
|
|
142
173
|
*
|
|
143
174
|
* Mirrors a production `start_server` at the surface level — stale-daemon
|
|
144
|
-
* check, daemon-info write, bind, graceful
|
|
175
|
+
* check, daemon-info write, bind, graceful shutdown — but the app is the
|
|
145
176
|
* caller's no-domain (or domain) {@link StartTestingServerOptions.build_app}
|
|
146
177
|
* and the runtime boundary is the {@link TestingServerAdapter}. Refuses any
|
|
147
178
|
* non-loopback bind host (the test binary must stay on loopback — see
|
|
@@ -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":"AAAA,OAAO,sBAAsB,CAAC;AAE9B
|
|
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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"}
|
|
@@ -18,7 +18,7 @@ export const is_loopback_host = (host) => {
|
|
|
18
18
|
* Boot a test-mode server using the supplied runtime adapter.
|
|
19
19
|
*
|
|
20
20
|
* Mirrors a production `start_server` at the surface level — stale-daemon
|
|
21
|
-
* check, daemon-info write, bind, graceful
|
|
21
|
+
* check, daemon-info write, bind, graceful shutdown — but the app is the
|
|
22
22
|
* caller's no-domain (or domain) {@link StartTestingServerOptions.build_app}
|
|
23
23
|
* and the runtime boundary is the {@link TestingServerAdapter}. Refuses any
|
|
24
24
|
* non-loopback bind host (the test binary must stay on loopback — see
|
|
@@ -42,12 +42,14 @@ export const start_testing_server = async (options) => {
|
|
|
42
42
|
log.warn(`stale daemon.json (pid ${stale.pid} not running), replacing`);
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
45
|
+
const prepared_websockets = [];
|
|
46
|
+
const built = await build_app({
|
|
47
|
+
prepare_websocket: (ws_options) => {
|
|
48
|
+
const prepared = adapter.prepare_websocket(ws_options);
|
|
49
|
+
prepared_websockets.push(prepared);
|
|
50
|
+
return prepared.create_upgrade_websocket;
|
|
51
|
+
}
|
|
52
|
+
});
|
|
51
53
|
await write_daemon_info(runtime, daemon_name, {
|
|
52
54
|
version: 1,
|
|
53
55
|
pid: adapter.pid,
|
|
@@ -57,7 +59,8 @@ export const start_testing_server = async (options) => {
|
|
|
57
59
|
});
|
|
58
60
|
log.info(`Listening on http://${host}:${port} (${adapter.runtime_label}, test mode)`);
|
|
59
61
|
const server = adapter.serve({ fetch: built.app.fetch, port, hostname: host });
|
|
60
|
-
|
|
62
|
+
for (const prepared of prepared_websockets)
|
|
63
|
+
prepared.attach_to_server?.(server);
|
|
61
64
|
let shutting_down = false;
|
|
62
65
|
const shutdown = async () => {
|
|
63
66
|
if (shutting_down)
|
|
@@ -65,11 +68,16 @@ export const start_testing_server = async (options) => {
|
|
|
65
68
|
shutting_down = true;
|
|
66
69
|
log.info('shutting down...');
|
|
67
70
|
try {
|
|
68
|
-
//
|
|
69
|
-
//
|
|
70
|
-
//
|
|
71
|
-
|
|
71
|
+
// Stop accepting first so no new request reaches a closed DB, but
|
|
72
|
+
// don't await the drain yet: live WebSockets hold it open until
|
|
73
|
+
// `built.close()` ends them (`AppServer.close`), so awaiting it
|
|
74
|
+
// first would wait on sockets nothing is closing. A request already
|
|
75
|
+
// in flight when the signal lands may still see the backend close
|
|
76
|
+
// under it — acceptable for a test binary, where shutdown follows
|
|
77
|
+
// the suite.
|
|
78
|
+
const drained = server.shutdown();
|
|
72
79
|
await built.close();
|
|
80
|
+
await drained;
|
|
73
81
|
}
|
|
74
82
|
catch (error) {
|
|
75
83
|
log.error('shutdown error:', error);
|
|
@@ -23,7 +23,7 @@ export const create_deno_testing_adapter = () => ({
|
|
|
23
23
|
runtime: create_deno_runtime([]),
|
|
24
24
|
get_connection_ip: (c) => c.env?.remoteAddr?.hostname,
|
|
25
25
|
// Deno's WS upgrade is module-level and stateless — no post-serve attach.
|
|
26
|
-
prepare_websocket: () => ({
|
|
26
|
+
prepare_websocket: () => ({ create_upgrade_websocket: () => upgradeWebSocket }),
|
|
27
27
|
serve: ({ fetch, port, hostname }) => {
|
|
28
28
|
const server = Deno.serve({ port, hostname }, fetch);
|
|
29
29
|
const handle = { shutdown: () => server.shutdown(), native: server };
|
|
@@ -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;
|
|
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"}
|
|
@@ -3,9 +3,12 @@ import '../assert_dev_env.js';
|
|
|
3
3
|
* Node runtime adapter for spawnable cross-process test server binaries.
|
|
4
4
|
*
|
|
5
5
|
* Binds `@hono/node-server`'s `serve()` and `@hono/node-ws`'s two-phase
|
|
6
|
-
* `createNodeWebSocket({app})` / `injectWebSocket(server)
|
|
7
|
-
* `
|
|
8
|
-
* and
|
|
6
|
+
* `createNodeWebSocket({app})` / `injectWebSocket(server)`: the factory
|
|
7
|
+
* `prepare_websocket` returns builds the first half from the app
|
|
8
|
+
* `create_app_server` assembles, and the core runs the second once `serve()`
|
|
9
|
+
* returns. The shared `testing/cross_backend/testing_server_core.ts` owns
|
|
10
|
+
* the rest. A test binary builds this adapter and hands it to
|
|
11
|
+
* `start_testing_server` alongside its `build_app` seam.
|
|
9
12
|
*
|
|
10
13
|
* `@hono/node-server` + `@hono/node-ws` are **optional** peer deps (same
|
|
11
14
|
* posture as `ws`) — only test binaries import them; production bundles
|
|
@@ -17,6 +20,7 @@ import process from 'node:process';
|
|
|
17
20
|
import { serve } from '@hono/node-server';
|
|
18
21
|
import { getConnInfo } from '@hono/node-server/conninfo';
|
|
19
22
|
import { createNodeWebSocket } from '@hono/node-ws';
|
|
23
|
+
import { DEFAULT_WS_MAX_MESSAGE_BYTES } from '../../actions/transports.js';
|
|
20
24
|
import { create_node_runtime } from '../../runtime/node.js';
|
|
21
25
|
const node_serve_handle = (server) => ({
|
|
22
26
|
shutdown: () => new Promise((resolve, reject) => {
|
|
@@ -29,14 +33,23 @@ export const create_node_testing_adapter = () => ({
|
|
|
29
33
|
runtime_label: 'Node',
|
|
30
34
|
runtime: create_node_runtime(),
|
|
31
35
|
get_connection_ip: (c) => getConnInfo(c).remote.address,
|
|
32
|
-
prepare_websocket: (
|
|
33
|
-
const
|
|
36
|
+
prepare_websocket: (options) => {
|
|
37
|
+
const max_payload = options?.max_message_bytes ?? DEFAULT_WS_MAX_MESSAGE_BYTES;
|
|
38
|
+
let node_ws;
|
|
34
39
|
return {
|
|
35
|
-
|
|
40
|
+
create_upgrade_websocket: (app) => {
|
|
41
|
+
node_ws = createNodeWebSocket({ app });
|
|
42
|
+
// `@hono/node-ws` builds its `ws` server with no options and takes
|
|
43
|
+
// none, so its frame cap would stay `ws`'s 100 MiB default. `ws` reads
|
|
44
|
+
// `options.maxPayload` per upgrade, so setting it here — before any
|
|
45
|
+
// connection — caps every socket at the endpoint's message limit.
|
|
46
|
+
node_ws.wss.options.maxPayload = max_payload;
|
|
47
|
+
return node_ws.upgradeWebSocket;
|
|
48
|
+
},
|
|
36
49
|
attach_to_server: (handle) => {
|
|
37
50
|
// `handle.native` is the `ServerType` from `serve()` —
|
|
38
51
|
// type-erased at the {@link ServeHandle} seam, so it downcasts here.
|
|
39
|
-
injectWebSocket(handle.native);
|
|
52
|
+
node_ws?.injectWebSocket(handle.native);
|
|
40
53
|
}
|
|
41
54
|
};
|
|
42
55
|
},
|
|
@@ -47,6 +47,21 @@ export interface TsSpineBackendConfigOptions {
|
|
|
47
47
|
* client IP. Mirrors `SpineStubBackendConfigOptions.enable_login_rate_limit`.
|
|
48
48
|
*/
|
|
49
49
|
readonly enable_login_rate_limit?: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Enable the action rate limiters (`FUZ_ACTION_RATE_LIMIT_ENABLED=true`) —
|
|
52
|
+
* one per-IP and one per-account limiter shared by the RPC and WS
|
|
53
|
+
* endpoints. Off by default, like `enable_login_rate_limit`; set only for
|
|
54
|
+
* the dedicated security cross project, which drives them through
|
|
55
|
+
* `ws_action_rate_limit.ts`. Mirrors `SpineStubBackendConfigOptions.enable_action_rate_limit`.
|
|
56
|
+
*/
|
|
57
|
+
readonly enable_action_rate_limit?: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Replace both action limiters' `max_attempts`
|
|
60
|
+
* (`FUZ_ACTION_RATE_LIMIT_MAX_ATTEMPTS`) so a suite reaches the cap in a few
|
|
61
|
+
* calls. Requires `enable_action_rate_limit` — the binary refuses to boot
|
|
62
|
+
* otherwise. Mirrors `SpineStubBackendConfigOptions.action_rate_limit_max_attempts`.
|
|
63
|
+
*/
|
|
64
|
+
readonly action_rate_limit_max_attempts?: number;
|
|
50
65
|
}
|
|
51
66
|
/**
|
|
52
67
|
* `BackendConfig` for the Node TS spine binary — spawned via `gro run`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ts_spine_backend_config.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/ts_spine_backend_config.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"ts_spine_backend_config.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/ts_spine_backend_config.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAUzD,8GAA8G;AAC9G,eAAO,MAAM,gBAAgB,6BAA6B,CAAC;AA2C3D,6FAA6F;AAC7F,eAAO,MAAM,0BAA0B,OAAO,CAAC;AAE/C,iDAAiD;AACjD,eAAO,MAAM,0BAA0B,OAAO,CAAC;AAE/C,gDAAgD;AAChD,eAAO,MAAM,yBAAyB,OAAO,CAAC;AAE9C,yDAAyD;AACzD,eAAO,MAAM,mBAAmB,wDAAwD,CAAC;AAEzF,yDAAyD;AACzD,eAAO,MAAM,mBAAmB,wDAAwD,CAAC;AAEzF,wDAAwD;AACxD,eAAO,MAAM,kBAAkB,uDAAuD,CAAC;AAEvF,MAAM,WAAW,2BAA2B;IAC3C,mFAAmF;IACnF,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,8DAA8D;IAC9D,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B;;;;;;;;;OASG;IACH,QAAQ,CAAC,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAC3C;;;;;;OAMG;IACH,QAAQ,CAAC,wBAAwB,CAAC,EAAE,OAAO,CAAC;IAC5C;;;;;OAKG;IACH,QAAQ,CAAC,8BAA8B,CAAC,EAAE,MAAM,CAAC;CACjD;AAWD;;;GAGG;AACH,eAAO,MAAM,4BAA4B,GACxC,UAAS,2BAAgC,KACvC,aAoBF,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,GACvC,UAAS,2BAAgC,KACvC,aAoBF,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,4BAA4B,GACxC,UAAS,2BAAgC,KACvC,aAiCF,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import '../assert_dev_env.js';
|
|
2
2
|
import { build_test_backend_paths } from './build_test_backend_paths.js';
|
|
3
|
-
import { LOGIN_RATE_LIMIT_ENABLED_ENV, make_default_ts_backend_config, ts_default_capabilities } from './default_backend_configs.js';
|
|
3
|
+
import { LOGIN_RATE_LIMIT_ENABLED_ENV, action_rate_limit_env, make_default_ts_backend_config, ts_default_capabilities } from './default_backend_configs.js';
|
|
4
4
|
import { SPINE_SSE_PATH } from './spine_surface_constants.js';
|
|
5
5
|
/** Env var naming the backend root dir; `{dir}/run/daemon_token` must match `bootstrap.daemon_token_path`. */
|
|
6
6
|
export const TS_SPINE_DIR_ENV = 'FUZ_TESTING_TS_SPINE_DIR';
|
|
@@ -9,7 +9,8 @@ export const TS_SPINE_DIR_ENV = 'FUZ_TESTING_TS_SPINE_DIR';
|
|
|
9
9
|
* (the binary wires `audit_log_sse`), `ready` (the binary live-mounts the
|
|
10
10
|
* `/ready` deploy gate in `build_spine_app`), `peer_request` (the backend
|
|
11
11
|
* WS transport's `request_connection` path drives server→client `peer/ping`),
|
|
12
|
-
* `ws_account_actions` (the binary mounts
|
|
12
|
+
* `ws_account_actions` (the binary mounts its full action set on `/api/ws`,
|
|
13
|
+
* the account actions among them),
|
|
13
14
|
* and `cell_gated_create` (the binary's `full_spine_mount` mounts the
|
|
14
15
|
* `test_cell_gated_create_authorize` policy).
|
|
15
16
|
*/
|
|
@@ -78,7 +79,8 @@ export const ts_spine_node_backend_config = (options = {}) => {
|
|
|
78
79
|
paths,
|
|
79
80
|
extra_env: {
|
|
80
81
|
[TS_SPINE_DIR_ENV]: paths.root,
|
|
81
|
-
...login_rate_limit_env(enable_login_rate_limit)
|
|
82
|
+
...login_rate_limit_env(enable_login_rate_limit),
|
|
83
|
+
...action_rate_limit_env(options)
|
|
82
84
|
},
|
|
83
85
|
capabilities: ts_spine_capabilities
|
|
84
86
|
}),
|
|
@@ -105,7 +107,8 @@ export const ts_spine_bun_backend_config = (options = {}) => {
|
|
|
105
107
|
paths,
|
|
106
108
|
extra_env: {
|
|
107
109
|
[TS_SPINE_DIR_ENV]: paths.root,
|
|
108
|
-
...login_rate_limit_env(enable_login_rate_limit)
|
|
110
|
+
...login_rate_limit_env(enable_login_rate_limit),
|
|
111
|
+
...action_rate_limit_env(options)
|
|
109
112
|
},
|
|
110
113
|
capabilities: ts_spine_bun_capabilities
|
|
111
114
|
}),
|
|
@@ -149,7 +152,8 @@ export const ts_spine_deno_backend_config = (options = {}) => {
|
|
|
149
152
|
paths,
|
|
150
153
|
extra_env: {
|
|
151
154
|
[TS_SPINE_DIR_ENV]: paths.root,
|
|
152
|
-
...login_rate_limit_env(enable_login_rate_limit)
|
|
155
|
+
...login_rate_limit_env(enable_login_rate_limit),
|
|
156
|
+
...action_rate_limit_env(options)
|
|
153
157
|
},
|
|
154
158
|
capabilities: ts_spine_capabilities
|
|
155
159
|
}),
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import '../assert_dev_env.js';
|
|
2
|
+
import type { SetupTest } from './setup.js';
|
|
3
|
+
/** Options for {@link describe_ws_action_rate_limit_cross_tests}. */
|
|
4
|
+
export interface WsActionRateLimitCrossTestOptions {
|
|
5
|
+
/** Per-test fixture producer (cross-process only — see the module doc). */
|
|
6
|
+
readonly setup_test: SetupTest;
|
|
7
|
+
/** Base URL the backend is reachable at (e.g. `http://localhost:1177`). */
|
|
8
|
+
readonly base_url: string;
|
|
9
|
+
/** WebSocket endpoint path (e.g. `/api/ws`). */
|
|
10
|
+
readonly ws_path: string;
|
|
11
|
+
/** JSON-RPC endpoint path. Default `/api/rpc` (the spine convention). */
|
|
12
|
+
readonly rpc_path?: string;
|
|
13
|
+
/**
|
|
14
|
+
* The `max_attempts` both action limiters were started with
|
|
15
|
+
* (`action_rate_limit_max_attempts` on the backend config). At least 2 —
|
|
16
|
+
* the shared-bucket case splits the budget across the two transports.
|
|
17
|
+
*/
|
|
18
|
+
readonly max_attempts: number;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Register the action rate-limit suite: the account axis over WS, one account
|
|
22
|
+
* bucket across HTTP RPC and WS, the per-IP axis keyed by `X-Forwarded-For`
|
|
23
|
+
* across both transports, and the account axis at the RPC and WS dispatchers.
|
|
24
|
+
*/
|
|
25
|
+
export declare const describe_ws_action_rate_limit_cross_tests: (options: WsActionRateLimitCrossTestOptions) => void;
|
|
26
|
+
//# sourceMappingURL=ws_action_rate_limit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ws_action_rate_limit.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/ws_action_rate_limit.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAmE9B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAyC5C,qEAAqE;AACrE,MAAM,WAAW,iCAAiC;IACjD,2EAA2E;IAC3E,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC;IAC/B,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,gDAAgD;IAChD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,yEAAyE;IACzE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC9B;AAkBD;;;;GAIG;AACH,eAAO,MAAM,yCAAyC,GACrD,SAAS,iCAAiC,KACxC,IAqRF,CAAC"}
|