@fuzdev/fuz_app 0.65.0 → 0.67.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 (159) hide show
  1. package/dist/actions/CLAUDE.md +65 -86
  2. package/dist/actions/action_codegen.d.ts +1 -1
  3. package/dist/actions/action_codegen.js +1 -1
  4. package/dist/actions/action_event_data.d.ts +1 -1
  5. package/dist/auth/CLAUDE.md +83 -104
  6. package/dist/auth/audit_log_schema.js +2 -2
  7. package/dist/auth/daemon_token_middleware.d.ts +15 -5
  8. package/dist/auth/daemon_token_middleware.d.ts.map +1 -1
  9. package/dist/auth/daemon_token_middleware.js +24 -15
  10. package/dist/auth/invite_queries.d.ts +17 -7
  11. package/dist/auth/invite_queries.d.ts.map +1 -1
  12. package/dist/auth/invite_queries.js +19 -8
  13. package/dist/auth/signup_routes.d.ts +47 -1
  14. package/dist/auth/signup_routes.d.ts.map +1 -1
  15. package/dist/auth/signup_routes.js +103 -52
  16. package/dist/env/resolve.d.ts +44 -7
  17. package/dist/env/resolve.d.ts.map +1 -1
  18. package/dist/env/resolve.js +94 -27
  19. package/dist/http/CLAUDE.md +47 -52
  20. package/dist/http/jsonrpc.d.ts +23 -7
  21. package/dist/http/jsonrpc.d.ts.map +1 -1
  22. package/dist/http/jsonrpc.js +19 -3
  23. package/dist/http/surface.d.ts +9 -2
  24. package/dist/http/surface.d.ts.map +1 -1
  25. package/dist/runtime/mock.d.ts +1 -1
  26. package/dist/runtime/mock.js +1 -1
  27. package/dist/testing/CLAUDE.md +659 -511
  28. package/dist/testing/admin_integration.d.ts +5 -5
  29. package/dist/testing/admin_integration.d.ts.map +1 -1
  30. package/dist/testing/admin_integration.js +95 -39
  31. package/dist/testing/app_server.d.ts +16 -1
  32. package/dist/testing/app_server.d.ts.map +1 -1
  33. package/dist/testing/app_server.js +18 -3
  34. package/dist/testing/audit_completeness.d.ts +7 -5
  35. package/dist/testing/audit_completeness.d.ts.map +1 -1
  36. package/dist/testing/audit_completeness.js +5 -9
  37. package/dist/testing/bootstrap_success.js +2 -2
  38. package/dist/testing/cross_backend/backend_config.d.ts +113 -0
  39. package/dist/testing/cross_backend/backend_config.d.ts.map +1 -0
  40. package/dist/testing/cross_backend/backend_config.js +1 -0
  41. package/dist/testing/cross_backend/bench/bench_report.d.ts +46 -0
  42. package/dist/testing/cross_backend/bench/bench_report.d.ts.map +1 -0
  43. package/dist/testing/cross_backend/bench/bench_report.js +83 -0
  44. package/dist/testing/cross_backend/bench/run_cross_impl_bench.d.ts +44 -0
  45. package/dist/testing/cross_backend/bench/run_cross_impl_bench.d.ts.map +1 -0
  46. package/dist/testing/cross_backend/bench/run_cross_impl_bench.js +38 -0
  47. package/dist/testing/cross_backend/bench/scenario.d.ts +57 -0
  48. package/dist/testing/cross_backend/bench/scenario.d.ts.map +1 -0
  49. package/dist/testing/cross_backend/bench/scenario.js +28 -0
  50. package/dist/testing/cross_backend/bootstrap_backend.d.ts +41 -0
  51. package/dist/testing/cross_backend/bootstrap_backend.d.ts.map +1 -0
  52. package/dist/testing/cross_backend/bootstrap_backend.js +34 -0
  53. package/dist/testing/cross_backend/build_test_backend_paths.d.ts +24 -0
  54. package/dist/testing/cross_backend/build_test_backend_paths.d.ts.map +1 -0
  55. package/dist/testing/cross_backend/build_test_backend_paths.js +33 -0
  56. package/dist/testing/cross_backend/capabilities.d.ts +3 -2
  57. package/dist/testing/cross_backend/capabilities.d.ts.map +1 -1
  58. package/dist/testing/cross_backend/default_backend_configs.d.ts +122 -0
  59. package/dist/testing/cross_backend/default_backend_configs.d.ts.map +1 -0
  60. package/dist/testing/cross_backend/default_backend_configs.js +111 -0
  61. package/dist/testing/cross_backend/default_secrets.d.ts +40 -0
  62. package/dist/testing/cross_backend/default_secrets.d.ts.map +1 -0
  63. package/dist/testing/cross_backend/default_secrets.js +39 -0
  64. package/dist/testing/cross_backend/default_spine_surface.d.ts +64 -0
  65. package/dist/testing/cross_backend/default_spine_surface.d.ts.map +1 -0
  66. package/dist/testing/cross_backend/default_spine_surface.js +121 -0
  67. package/dist/testing/cross_backend/setup.d.ts +270 -34
  68. package/dist/testing/cross_backend/setup.d.ts.map +1 -1
  69. package/dist/testing/cross_backend/setup.js +495 -15
  70. package/dist/testing/cross_backend/spawn_backend.d.ts +58 -0
  71. package/dist/testing/cross_backend/spawn_backend.d.ts.map +1 -0
  72. package/dist/testing/cross_backend/spawn_backend.js +229 -0
  73. package/dist/testing/cross_backend/spine_stub_backend_config.d.ts +66 -0
  74. package/dist/testing/cross_backend/spine_stub_backend_config.d.ts.map +1 -0
  75. package/dist/testing/cross_backend/spine_stub_backend_config.js +49 -0
  76. package/dist/testing/cross_backend/sse_round_trip.d.ts +37 -0
  77. package/dist/testing/cross_backend/sse_round_trip.d.ts.map +1 -0
  78. package/dist/testing/cross_backend/sse_round_trip.js +137 -0
  79. package/dist/testing/cross_backend/standard.d.ts +96 -0
  80. package/dist/testing/cross_backend/standard.d.ts.map +1 -0
  81. package/dist/testing/cross_backend/standard.js +49 -0
  82. package/dist/testing/cross_backend/testing_reset_actions.d.ts +171 -0
  83. package/dist/testing/cross_backend/testing_reset_actions.d.ts.map +1 -0
  84. package/dist/testing/cross_backend/testing_reset_actions.js +213 -0
  85. package/dist/testing/cross_backend/testing_server_bun.d.ts +5 -0
  86. package/dist/testing/cross_backend/testing_server_bun.d.ts.map +1 -0
  87. package/dist/testing/cross_backend/testing_server_bun.js +59 -0
  88. package/dist/testing/cross_backend/testing_server_core.d.ts +140 -0
  89. package/dist/testing/cross_backend/testing_server_core.d.ts.map +1 -0
  90. package/dist/testing/cross_backend/testing_server_core.js +68 -0
  91. package/dist/testing/cross_backend/testing_server_deno.d.ts +5 -0
  92. package/dist/testing/cross_backend/testing_server_deno.d.ts.map +1 -0
  93. package/dist/testing/cross_backend/testing_server_deno.js +37 -0
  94. package/dist/testing/cross_backend/testing_server_node.d.ts +5 -0
  95. package/dist/testing/cross_backend/testing_server_node.d.ts.map +1 -0
  96. package/dist/testing/cross_backend/testing_server_node.js +50 -0
  97. package/dist/testing/cross_backend/ts_spine_backend_config.d.ts +72 -0
  98. package/dist/testing/cross_backend/ts_spine_backend_config.d.ts.map +1 -0
  99. package/dist/testing/cross_backend/ts_spine_backend_config.js +112 -0
  100. package/dist/testing/cross_backend/ws_round_trip.d.ts +35 -0
  101. package/dist/testing/cross_backend/ws_round_trip.d.ts.map +1 -0
  102. package/dist/testing/cross_backend/ws_round_trip.js +113 -0
  103. package/dist/testing/data_exposure.d.ts +4 -6
  104. package/dist/testing/data_exposure.d.ts.map +1 -1
  105. package/dist/testing/data_exposure.js +1 -5
  106. package/dist/testing/db_entities.d.ts +18 -7
  107. package/dist/testing/db_entities.d.ts.map +1 -1
  108. package/dist/testing/db_entities.js +18 -7
  109. package/dist/testing/integration.d.ts +27 -6
  110. package/dist/testing/integration.d.ts.map +1 -1
  111. package/dist/testing/integration.js +93 -58
  112. package/dist/testing/round_trip.d.ts +4 -5
  113. package/dist/testing/round_trip.d.ts.map +1 -1
  114. package/dist/testing/round_trip.js +1 -5
  115. package/dist/testing/rpc_helpers.d.ts +10 -4
  116. package/dist/testing/rpc_helpers.d.ts.map +1 -1
  117. package/dist/testing/rpc_helpers.js +1 -1
  118. package/dist/testing/rpc_round_trip.d.ts +5 -5
  119. package/dist/testing/rpc_round_trip.d.ts.map +1 -1
  120. package/dist/testing/rpc_round_trip.js +1 -5
  121. package/dist/testing/sse_round_trip.d.ts.map +1 -1
  122. package/dist/testing/sse_round_trip.js +1 -68
  123. package/dist/testing/standard.d.ts +4 -5
  124. package/dist/testing/standard.d.ts.map +1 -1
  125. package/dist/testing/stubs.d.ts +10 -3
  126. package/dist/testing/stubs.d.ts.map +1 -1
  127. package/dist/testing/stubs.js +9 -2
  128. package/dist/testing/testing_rate_limiter.d.ts +59 -0
  129. package/dist/testing/testing_rate_limiter.d.ts.map +1 -0
  130. package/dist/testing/testing_rate_limiter.js +74 -0
  131. package/dist/testing/transports/bootstrap.d.ts +52 -0
  132. package/dist/testing/transports/bootstrap.d.ts.map +1 -0
  133. package/dist/testing/transports/bootstrap.js +70 -0
  134. package/dist/testing/transports/fetch_transport.d.ts +81 -0
  135. package/dist/testing/transports/fetch_transport.d.ts.map +1 -0
  136. package/dist/testing/transports/fetch_transport.js +74 -0
  137. package/dist/testing/transports/sse_frame_reader.d.ts +41 -0
  138. package/dist/testing/transports/sse_frame_reader.d.ts.map +1 -0
  139. package/dist/testing/transports/sse_frame_reader.js +84 -0
  140. package/dist/testing/transports/sse_transport.d.ts +54 -0
  141. package/dist/testing/transports/sse_transport.d.ts.map +1 -0
  142. package/dist/testing/transports/sse_transport.js +51 -0
  143. package/dist/testing/transports/ws_client.d.ts +108 -0
  144. package/dist/testing/transports/ws_client.d.ts.map +1 -0
  145. package/dist/testing/transports/ws_client.js +56 -0
  146. package/dist/testing/transports/ws_transport.d.ts +43 -0
  147. package/dist/testing/transports/ws_transport.d.ts.map +1 -0
  148. package/dist/testing/transports/ws_transport.js +169 -0
  149. package/dist/testing/ws_round_trip.d.ts +21 -103
  150. package/dist/testing/ws_round_trip.d.ts.map +1 -1
  151. package/dist/testing/ws_round_trip.js +42 -40
  152. package/dist/ui/CLAUDE.md +5 -3
  153. package/dist/ui/MenuLink.svelte +16 -16
  154. package/dist/ui/MenuLink.svelte.d.ts +13 -4
  155. package/dist/ui/MenuLink.svelte.d.ts.map +1 -1
  156. package/package.json +20 -3
  157. package/dist/testing/transports/surface_source.d.ts +0 -51
  158. package/dist/testing/transports/surface_source.d.ts.map +0 -1
  159. package/dist/testing/transports/surface_source.js +0 -19
@@ -0,0 +1,68 @@
1
+ import '../assert_dev_env.js';
2
+ import { Logger } from '@fuzdev/fuz_util/log.js';
3
+ import { write_daemon_info, read_daemon_info, is_daemon_running } from '../../cli/daemon.js';
4
+ /** Hosts that expose the test binary beyond loopback — refused at startup. */
5
+ const OPEN_HOSTS = new Set(['0.0.0.0', '::', '[::]']);
6
+ /**
7
+ * Boot a test-mode server using the supplied runtime adapter.
8
+ *
9
+ * Mirrors a production `start_server` at the surface level — stale-daemon
10
+ * check, daemon-info write, bind, graceful drain — but the app is the
11
+ * caller's no-domain (or domain) {@link StartTestingServerOptions.build_app}
12
+ * and the runtime boundary is the {@link TestingServerAdapter}. Refuses to
13
+ * bind an open host (the test binary must stay on loopback).
14
+ */
15
+ export const start_testing_server = async (options) => {
16
+ const { adapter, daemon_name, host, port, app_version, build_app } = options;
17
+ const log = options.log ?? new Logger(`[${daemon_name}]`);
18
+ const { runtime } = adapter;
19
+ if (OPEN_HOSTS.has(host)) {
20
+ log.error(`FATAL: binding to '${host}' exposes the test binary to your entire network. ` +
21
+ `Use --host localhost (default) or 127.0.0.1 instead.`);
22
+ adapter.exit(1);
23
+ }
24
+ const stale = await read_daemon_info(runtime, daemon_name);
25
+ if (stale) {
26
+ if (await is_daemon_running(runtime, stale.pid)) {
27
+ log.warn('found running server', stale);
28
+ }
29
+ else {
30
+ log.warn(`stale daemon.json (pid ${stale.pid} not running), replacing`);
31
+ }
32
+ }
33
+ const built = await build_app();
34
+ let ws;
35
+ if (built.mount_websocket) {
36
+ ws = adapter.prepare_websocket(built.app);
37
+ built.mount_websocket(ws.upgrade_websocket);
38
+ }
39
+ await write_daemon_info(runtime, daemon_name, {
40
+ version: 1,
41
+ pid: adapter.pid,
42
+ port,
43
+ started: new Date().toISOString(),
44
+ app_version: app_version ?? '0.0.0-test',
45
+ });
46
+ log.info(`Listening on http://${host}:${port} (${adapter.runtime_label}, test mode)`);
47
+ const server = adapter.serve({ fetch: built.app.fetch, port, hostname: host });
48
+ ws?.attach_to_server?.(server);
49
+ let shutting_down = false;
50
+ const shutdown = async () => {
51
+ if (shutting_down)
52
+ adapter.exit(1);
53
+ shutting_down = true;
54
+ log.info('shutting down...');
55
+ try {
56
+ // Drain HTTP first (stop accepting + let in-flight requests finish)
57
+ // before tearing down the backend, so a request still draining
58
+ // never hits a closed DB.
59
+ await server.shutdown();
60
+ await built.close();
61
+ }
62
+ catch (error) {
63
+ log.error('shutdown error:', error);
64
+ }
65
+ adapter.exit(0);
66
+ };
67
+ adapter.register_shutdown_signals(shutdown);
68
+ };
@@ -0,0 +1,5 @@
1
+ import '../assert_dev_env.js';
2
+ import type { TestingServerAdapter } from './testing_server_core.js';
3
+ /** Build the Deno {@link TestingServerAdapter}. */
4
+ export declare const create_deno_testing_adapter: () => TestingServerAdapter;
5
+ //# sourceMappingURL=testing_server_deno.d.ts.map
@@ -0,0 +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;AAqB9B,OAAO,KAAK,EAAc,oBAAoB,EAAC,MAAM,0BAA0B,CAAC;AAehF,mDAAmD;AACnD,eAAO,MAAM,2BAA2B,QAAO,oBAkB7C,CAAC"}
@@ -0,0 +1,37 @@
1
+ import '../assert_dev_env.js';
2
+ /**
3
+ * Deno runtime adapter for spawnable cross-process test server binaries.
4
+ *
5
+ * Binds `Deno.serve` and `hono/deno`'s module-level `upgradeWebSocket`. The
6
+ * shared `testing_server_core.ts` owns the rest. Counterpart to
7
+ * `testing_server_node.ts` — together they isolate the JS-runtime axis (Deno
8
+ * vs Node V8) on identical TS surfaces, and the Rust spine binary covers the
9
+ * cross-language axis.
10
+ *
11
+ * `Deno` globals are declared locally (mirroring `runtime/deno.ts`) so this
12
+ * module typechecks under fuz_app's Node-based config without a `deno.json`
13
+ * or `@types/deno`. It is only ever *run* under Deno.
14
+ *
15
+ * @module
16
+ */
17
+ import { upgradeWebSocket } from 'hono/deno';
18
+ import { create_deno_runtime } from '../../runtime/deno.js';
19
+ /** Build the Deno {@link TestingServerAdapter}. */
20
+ export const create_deno_testing_adapter = () => ({
21
+ runtime_label: 'Deno',
22
+ runtime: create_deno_runtime([]),
23
+ get_connection_ip: (c) => c.env?.remoteAddr?.hostname,
24
+ // Deno's WS upgrade is module-level and stateless — no post-serve attach.
25
+ prepare_websocket: () => ({ upgrade_websocket: upgradeWebSocket }),
26
+ serve: ({ fetch, port, hostname }) => {
27
+ const server = Deno.serve({ port, hostname }, fetch);
28
+ const handle = { shutdown: () => server.shutdown(), native: server };
29
+ return handle;
30
+ },
31
+ pid: Deno.pid,
32
+ register_shutdown_signals: (handler) => {
33
+ Deno.addSignalListener('SIGINT', () => void handler());
34
+ Deno.addSignalListener('SIGTERM', () => void handler());
35
+ },
36
+ exit: (code) => Deno.exit(code),
37
+ });
@@ -0,0 +1,5 @@
1
+ import '../assert_dev_env.js';
2
+ import type { TestingServerAdapter } from './testing_server_core.js';
3
+ /** Build the Node {@link TestingServerAdapter}. */
4
+ export declare const create_node_testing_adapter: () => TestingServerAdapter;
5
+ //# sourceMappingURL=testing_server_node.d.ts.map
@@ -0,0 +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;AAuB9B,OAAO,KAAK,EAAc,oBAAoB,EAAC,MAAM,0BAA0B,CAAC;AAUhF,mDAAmD;AACnD,eAAO,MAAM,2BAA2B,QAAO,oBAsB7C,CAAC"}
@@ -0,0 +1,50 @@
1
+ import '../assert_dev_env.js';
2
+ /**
3
+ * Node runtime adapter for spawnable cross-process test server binaries.
4
+ *
5
+ * Binds `@hono/node-server`'s `serve()` and `@hono/node-ws`'s two-phase
6
+ * `createNodeWebSocket(app)` / `injectWebSocket(server)`. The shared
7
+ * `testing_server_core.ts` owns the rest. A test binary builds this adapter
8
+ * and hands it to `start_testing_server` alongside its `build_app` seam.
9
+ *
10
+ * `@hono/node-server` + `@hono/node-ws` are **optional** peer deps (same
11
+ * posture as `ws`) — only test binaries import them; production bundles
12
+ * never reach this module (the `assert_dev_env` guard throws on prod load).
13
+ *
14
+ * @module
15
+ */
16
+ import process from 'node:process';
17
+ import { serve } from '@hono/node-server';
18
+ import { getConnInfo } from '@hono/node-server/conninfo';
19
+ import { createNodeWebSocket } from '@hono/node-ws';
20
+ import { create_node_runtime } from '../../runtime/node.js';
21
+ const node_serve_handle = (server) => ({
22
+ shutdown: () => new Promise((resolve, reject) => {
23
+ server.close((err) => (err ? reject(err) : resolve()));
24
+ }),
25
+ native: server,
26
+ });
27
+ /** Build the Node {@link TestingServerAdapter}. */
28
+ export const create_node_testing_adapter = () => ({
29
+ runtime_label: 'Node',
30
+ runtime: create_node_runtime(),
31
+ get_connection_ip: (c) => getConnInfo(c).remote.address,
32
+ prepare_websocket: (app) => {
33
+ const { upgradeWebSocket, injectWebSocket } = createNodeWebSocket({ app });
34
+ return {
35
+ upgrade_websocket: upgradeWebSocket,
36
+ attach_to_server: (handle) => {
37
+ // `handle.native` is the `ServerType` from `serve()` —
38
+ // type-erased at the {@link ServeHandle} seam, so it downcasts here.
39
+ injectWebSocket(handle.native);
40
+ },
41
+ };
42
+ },
43
+ serve: ({ fetch, port, hostname }) => node_serve_handle(serve({ fetch, port, hostname })),
44
+ pid: process.pid,
45
+ register_shutdown_signals: (handler) => {
46
+ process.on('SIGINT', () => void handler());
47
+ process.on('SIGTERM', () => void handler());
48
+ },
49
+ exit: (code) => process.exit(code),
50
+ });
@@ -0,0 +1,72 @@
1
+ import '../assert_dev_env.js';
2
+ /**
3
+ * Cross-process `BackendConfig` presets for fuz_app's domain-free **TS**
4
+ * spine test binary (`src/test/cross_backend/testing_spine_server_{node,deno,bun}.ts`).
5
+ *
6
+ * The TS analog of `spine_stub_backend_config` (which spawns the Rust spine):
7
+ * these spawn fuz_app's own TS impl over real HTTP with no domain layer, so
8
+ * the `cross_backend_ts_node` / `cross_backend_ts_deno` / `cross_backend_ts_bun`
9
+ * self-test projects verify fuz_app's wire path in its own repo across all
10
+ * three JS runtimes. All run against in-memory PGlite (`memory://`) — no
11
+ * external Postgres, unlike the Rust path.
12
+ *
13
+ * The binary writes its daemon token to `{FUZ_TESTING_TS_SPINE_DIR}/run/daemon_token`;
14
+ * anchoring the dir to `paths.root` makes that equal `paths.daemon_token_path`,
15
+ * which `spawn_backend` reads after the health probe.
16
+ *
17
+ * @module
18
+ */
19
+ import type { BackendConfig } from './backend_config.js';
20
+ /** Env var naming the backend root dir; `{dir}/run/daemon_token` must match `bootstrap.daemon_token_path`. */
21
+ export declare const TS_SPINE_DIR_ENV = "FUZ_TESTING_TS_SPINE_DIR";
22
+ /**
23
+ * Audit-log SSE stream path the TS spine binary serves (it wires
24
+ * `audit_log_sse`). Matches `SPINE_SSE_PATH` in `default_spine_surface.ts`
25
+ * and the cross-process SSE suite's default. Scoped to the TS configs
26
+ * (which advertise `capabilities.sse: true`) — the Rust spine doesn't serve
27
+ * the stream, so the shared `ts_default_capabilities` stays `sse: false`.
28
+ */
29
+ export declare const TS_SPINE_SSE_PATH = "/api/admin/audit/stream";
30
+ /** Default port for the Node TS spine binary — slots beside the Rust `spine_stub` (1177). */
31
+ export declare const TS_SPINE_NODE_DEFAULT_PORT = 1178;
32
+ /** Default port for the Deno TS spine binary. */
33
+ export declare const TS_SPINE_DENO_DEFAULT_PORT = 1179;
34
+ /** Default port for the Bun TS spine binary. */
35
+ export declare const TS_SPINE_BUN_DEFAULT_PORT = 1180;
36
+ /** Entry module spawned for the Node TS spine binary. */
37
+ export declare const TS_SPINE_NODE_ENTRY = "src/test/cross_backend/testing_spine_server_node.ts";
38
+ /** Entry module spawned for the Deno TS spine binary. */
39
+ export declare const TS_SPINE_DENO_ENTRY = "src/test/cross_backend/testing_spine_server_deno.ts";
40
+ /** Entry module spawned for the Bun TS spine binary. */
41
+ export declare const TS_SPINE_BUN_ENTRY = "src/test/cross_backend/testing_spine_server_bun.ts";
42
+ export interface TsSpineBackendConfigOptions {
43
+ /** Listening port. Defaults per runtime (`1178` Node, `1179` Deno, `1180` Bun). */
44
+ readonly port?: number;
45
+ /** Database URL. Default `'memory://'` (in-memory PGlite). */
46
+ readonly database_url?: string;
47
+ }
48
+ /**
49
+ * `BackendConfig` for the Node TS spine binary — spawned via `gro run`
50
+ * (Gro's TS loader resolves the `$lib`-free entry's relative imports).
51
+ */
52
+ export declare const ts_spine_node_backend_config: (options?: TsSpineBackendConfigOptions) => BackendConfig;
53
+ /**
54
+ * `BackendConfig` for the Bun TS spine binary — spawned via `bun run`. Bun
55
+ * resolves the entry's relative `.js`→`.ts` source specifiers natively (no
56
+ * flag needed — unlike Deno's `--sloppy-imports`, and like Gro's loader on
57
+ * the Node path), and `Bun.serve` + `hono/bun` need no extra deps.
58
+ */
59
+ export declare const ts_spine_bun_backend_config: (options?: TsSpineBackendConfigOptions) => BackendConfig;
60
+ /**
61
+ * `BackendConfig` for the Deno TS spine binary. The `--allow-*` set mirrors
62
+ * the cross-process needs (net + read/write for the daemon-token file + env
63
+ * + sys); `--unstable-detect-cjs` matches the ecosystem's Deno test entries.
64
+ *
65
+ * `--sloppy-imports` is required because the binary imports fuz_app **source**
66
+ * via relative `.js` specifiers (the `src/lib` convention) — Deno resolves
67
+ * `.js`→`.ts` only under this flag, whereas Gro's loader (the Node path)
68
+ * does so natively. (zzz's Deno entry sidesteps it by importing fuz_app as a
69
+ * built package; this binary tests live source instead.)
70
+ */
71
+ export declare const ts_spine_deno_backend_config: (options?: TsSpineBackendConfigOptions) => BackendConfig;
72
+ //# sourceMappingURL=ts_spine_backend_config.d.ts.map
@@ -0,0 +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,EAAC,aAAa,EAAC,MAAM,qBAAqB,CAAC;AAOvD,8GAA8G;AAC9G,eAAO,MAAM,gBAAgB,6BAA6B,CAAC;AAE3D;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,4BAA4B,CAAC;AAK3D,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;CAC/B;AAED;;;GAGG;AACH,eAAO,MAAM,4BAA4B,GACxC,UAAS,2BAAgC,KACvC,aAgBF,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B,GACvC,UAAS,2BAAgC,KACvC,aAgBF,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,4BAA4B,GACxC,UAAS,2BAAgC,KACvC,aA6BF,CAAC"}
@@ -0,0 +1,112 @@
1
+ import '../assert_dev_env.js';
2
+ import { build_test_backend_paths } from './build_test_backend_paths.js';
3
+ import { make_default_ts_backend_config, ts_default_capabilities, } from './default_backend_configs.js';
4
+ /** Env var naming the backend root dir; `{dir}/run/daemon_token` must match `bootstrap.daemon_token_path`. */
5
+ export const TS_SPINE_DIR_ENV = 'FUZ_TESTING_TS_SPINE_DIR';
6
+ /**
7
+ * Audit-log SSE stream path the TS spine binary serves (it wires
8
+ * `audit_log_sse`). Matches `SPINE_SSE_PATH` in `default_spine_surface.ts`
9
+ * and the cross-process SSE suite's default. Scoped to the TS configs
10
+ * (which advertise `capabilities.sse: true`) — the Rust spine doesn't serve
11
+ * the stream, so the shared `ts_default_capabilities` stays `sse: false`.
12
+ */
13
+ export const TS_SPINE_SSE_PATH = '/api/admin/audit/stream';
14
+ /** Capabilities for the TS spine binary — `ts_default_capabilities` plus `sse` (the binary wires `audit_log_sse`). */
15
+ const ts_spine_capabilities = Object.freeze({ ...ts_default_capabilities, sse: true });
16
+ /** Default port for the Node TS spine binary — slots beside the Rust `spine_stub` (1177). */
17
+ export const TS_SPINE_NODE_DEFAULT_PORT = 1178;
18
+ /** Default port for the Deno TS spine binary. */
19
+ export const TS_SPINE_DENO_DEFAULT_PORT = 1179;
20
+ /** Default port for the Bun TS spine binary. */
21
+ export const TS_SPINE_BUN_DEFAULT_PORT = 1180;
22
+ /** Entry module spawned for the Node TS spine binary. */
23
+ export const TS_SPINE_NODE_ENTRY = 'src/test/cross_backend/testing_spine_server_node.ts';
24
+ /** Entry module spawned for the Deno TS spine binary. */
25
+ export const TS_SPINE_DENO_ENTRY = 'src/test/cross_backend/testing_spine_server_deno.ts';
26
+ /** Entry module spawned for the Bun TS spine binary. */
27
+ export const TS_SPINE_BUN_ENTRY = 'src/test/cross_backend/testing_spine_server_bun.ts';
28
+ /**
29
+ * `BackendConfig` for the Node TS spine binary — spawned via `gro run`
30
+ * (Gro's TS loader resolves the `$lib`-free entry's relative imports).
31
+ */
32
+ export const ts_spine_node_backend_config = (options = {}) => {
33
+ const { port = TS_SPINE_NODE_DEFAULT_PORT, database_url } = options;
34
+ const name = 'ts_spine_node';
35
+ const paths = build_test_backend_paths(name);
36
+ return {
37
+ ...make_default_ts_backend_config({
38
+ name,
39
+ port,
40
+ start_command: ['gro', 'run', TS_SPINE_NODE_ENTRY],
41
+ database_url,
42
+ paths,
43
+ extra_env: { [TS_SPINE_DIR_ENV]: paths.root },
44
+ capabilities: ts_spine_capabilities,
45
+ }),
46
+ sse_path: TS_SPINE_SSE_PATH,
47
+ };
48
+ };
49
+ /**
50
+ * `BackendConfig` for the Bun TS spine binary — spawned via `bun run`. Bun
51
+ * resolves the entry's relative `.js`→`.ts` source specifiers natively (no
52
+ * flag needed — unlike Deno's `--sloppy-imports`, and like Gro's loader on
53
+ * the Node path), and `Bun.serve` + `hono/bun` need no extra deps.
54
+ */
55
+ export const ts_spine_bun_backend_config = (options = {}) => {
56
+ const { port = TS_SPINE_BUN_DEFAULT_PORT, database_url } = options;
57
+ const name = 'ts_spine_bun';
58
+ const paths = build_test_backend_paths(name);
59
+ return {
60
+ ...make_default_ts_backend_config({
61
+ name,
62
+ port,
63
+ start_command: ['bun', 'run', TS_SPINE_BUN_ENTRY],
64
+ database_url,
65
+ paths,
66
+ extra_env: { [TS_SPINE_DIR_ENV]: paths.root },
67
+ capabilities: ts_spine_capabilities,
68
+ }),
69
+ sse_path: TS_SPINE_SSE_PATH,
70
+ };
71
+ };
72
+ /**
73
+ * `BackendConfig` for the Deno TS spine binary. The `--allow-*` set mirrors
74
+ * the cross-process needs (net + read/write for the daemon-token file + env
75
+ * + sys); `--unstable-detect-cjs` matches the ecosystem's Deno test entries.
76
+ *
77
+ * `--sloppy-imports` is required because the binary imports fuz_app **source**
78
+ * via relative `.js` specifiers (the `src/lib` convention) — Deno resolves
79
+ * `.js`→`.ts` only under this flag, whereas Gro's loader (the Node path)
80
+ * does so natively. (zzz's Deno entry sidesteps it by importing fuz_app as a
81
+ * built package; this binary tests live source instead.)
82
+ */
83
+ export const ts_spine_deno_backend_config = (options = {}) => {
84
+ const { port = TS_SPINE_DENO_DEFAULT_PORT, database_url } = options;
85
+ const name = 'ts_spine_deno';
86
+ const paths = build_test_backend_paths(name);
87
+ return {
88
+ ...make_default_ts_backend_config({
89
+ name,
90
+ port,
91
+ start_command: [
92
+ 'deno',
93
+ 'run',
94
+ '--allow-net',
95
+ '--allow-read',
96
+ '--allow-env',
97
+ '--allow-write',
98
+ '--allow-sys',
99
+ '--allow-ffi',
100
+ '--allow-run',
101
+ '--unstable-detect-cjs',
102
+ '--sloppy-imports',
103
+ TS_SPINE_DENO_ENTRY,
104
+ ],
105
+ database_url,
106
+ paths,
107
+ extra_env: { [TS_SPINE_DIR_ENV]: paths.root },
108
+ capabilities: ts_spine_capabilities,
109
+ }),
110
+ sse_path: TS_SPINE_SSE_PATH,
111
+ };
112
+ };
@@ -0,0 +1,35 @@
1
+ import '../assert_dev_env.js';
2
+ import { type BackendCapabilities } from './capabilities.js';
3
+ import type { SetupTest } from './setup.js';
4
+ /** Configuration for {@link describe_cross_process_ws_tests}. */
5
+ export interface CrossProcessWsTestOptions {
6
+ /**
7
+ * Per-test fixture producer (`default_cross_process_setup(handle)`).
8
+ * The authenticated case reads the fresh-per-test keeper's session
9
+ * cookies from `fixture.transport.cookies()` to thread onto the upgrade.
10
+ */
11
+ readonly setup_test: SetupTest;
12
+ /** Backend capability flags; every case gates on `capabilities.ws`. */
13
+ readonly capabilities: BackendCapabilities;
14
+ /** Base URL the backend is reachable at (e.g. `http://localhost:1178`). */
15
+ readonly base_url: string;
16
+ /** WebSocket endpoint path on the backend (e.g. `/api/ws`). */
17
+ readonly ws_path: string;
18
+ /** Origin for the authenticated upgrade. Defaults to `base_url`. */
19
+ readonly origin?: string;
20
+ /**
21
+ * RPC endpoint path (e.g. `/api/rpc`) used by the close-on-revoke case to
22
+ * fire `account_session_revoke_all` over the keeper's session channel.
23
+ * When omitted, that case is skipped — it depends on the standard account
24
+ * actions being mounted on the RPC endpoint.
25
+ */
26
+ readonly rpc_path?: string;
27
+ }
28
+ /**
29
+ * Register the cross-process WS round-trip suite. Up to four cases over a
30
+ * real upgrade: authed `heartbeat` round-trip, anonymous-upgrade refusal,
31
+ * disallowed-origin refusal, and — when `rpc_path` is supplied —
32
+ * session-revocation closing the live socket.
33
+ */
34
+ export declare const describe_cross_process_ws_tests: (options: CrossProcessWsTestOptions) => void;
35
+ //# sourceMappingURL=ws_round_trip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ws_round_trip.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/ws_round_trip.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAmD9B,OAAO,EAAC,KAAK,mBAAmB,EAAU,MAAM,mBAAmB,CAAC;AACpE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,YAAY,CAAC;AAK1C,iEAAiE;AACjE,MAAM,WAAW,yBAAyB;IACzC;;;;OAIG;IACH,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;IACzB,oEAAoE;IACpE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;GAKG;AACH,eAAO,MAAM,+BAA+B,GAAI,SAAS,yBAAyB,KAAG,IAsEpF,CAAC"}
@@ -0,0 +1,113 @@
1
+ import '../assert_dev_env.js';
2
+ /**
3
+ * Cross-process WebSocket round-trip suite — the cross-process counterpart
4
+ * to the in-process `testing/ws_round_trip.ts` harness.
5
+ *
6
+ * Where the in-process harness drives `register_action_ws` against a fake
7
+ * Hono upgrade (no wire), this suite performs a **real** `WebSocket`
8
+ * upgrade against a spawned backend via `create_ws_transport` (the `ws`
9
+ * npm package), so the actual upgrade handshake + per-connection auth +
10
+ * JSON-RPC dispatch over the socket are exercised end-to-end. It is the
11
+ * only coverage of the spawned binary's live WS path — the standard
12
+ * cross-process bundle (`describe_standard_cross_process_tests`) omits WS
13
+ * by design, so consumers call this alongside it.
14
+ *
15
+ * **Consumer-agnostic.** Every case drives the `heartbeat` protocol action,
16
+ * which `assert_ws_endpoints_include_protocol_actions` guarantees is present
17
+ * on every WS endpoint — so the suite needs no knowledge of a consumer's
18
+ * domain WS methods. It validates the transport, not the domain.
19
+ *
20
+ * The first three cases mirror the upgrade stack `register_ws_endpoint` wires
21
+ * (origin check → `require_auth` → dispatch): an authenticated upgrade
22
+ * round-trips `heartbeat`; an anonymous upgrade is refused; a
23
+ * disallowed-origin upgrade is refused. Per-connection auth is enforced at
24
+ * upgrade time (not per message), so the negative cases assert the upgrade
25
+ * itself rejects rather than a per-message error frame.
26
+ *
27
+ * A fourth case (gated on `rpc_path`) covers server-initiated close: an
28
+ * authenticated socket is dropped when the account's sessions are revoked
29
+ * mid-connection. Per-message dispatch never re-checks credential validity,
30
+ * so the live socket survives on the audit-fed `create_ws_auth_guard` seam —
31
+ * firing `account_session_revoke_all` over the keeper's session channel
32
+ * emits `session_revoke_all`, which closes the socket. Omit `rpc_path` to
33
+ * skip it (consumers without the standard account actions on their RPC
34
+ * endpoint).
35
+ *
36
+ * Gated on `capabilities.ws` — backends without an end-to-end WS transport
37
+ * skip (the cases still surface as `.skip` in the report). Cross-process
38
+ * only: `create_ws_transport` needs a real bound socket, so wire it from a
39
+ * `*.cross.test.ts` file, never an in-process setup.
40
+ *
41
+ * @module
42
+ */
43
+ import { assert, describe } from 'vitest';
44
+ import { assert_rejects } from '@fuzdev/fuz_util/testing.js';
45
+ import { heartbeat_action_spec } from '../../actions/heartbeat.js';
46
+ import { account_session_revoke_all_action_spec } from '../../auth/account_action_specs.js';
47
+ import { create_ws_transport } from '../transports/ws_transport.js';
48
+ import { create_rpc_post_init } from '../rpc_helpers.js';
49
+ import { test_if } from './capabilities.js';
50
+ /** Origin guaranteed to fail the `http://localhost:*` allowlist the test backends run with. */
51
+ const DISALLOWED_ORIGIN = 'http://disallowed.example';
52
+ /**
53
+ * Register the cross-process WS round-trip suite. Up to four cases over a
54
+ * real upgrade: authed `heartbeat` round-trip, anonymous-upgrade refusal,
55
+ * disallowed-origin refusal, and — when `rpc_path` is supplied —
56
+ * session-revocation closing the live socket.
57
+ */
58
+ export const describe_cross_process_ws_tests = (options) => {
59
+ const { setup_test, capabilities, base_url, ws_path, origin, rpc_path } = options;
60
+ describe('cross-process websocket', () => {
61
+ test_if(capabilities.ws, 'authenticated upgrade round-trips heartbeat', async () => {
62
+ const fixture = await setup_test();
63
+ const client = await create_ws_transport({
64
+ base_url,
65
+ ws_path,
66
+ cookies: fixture.transport.cookies(),
67
+ origin,
68
+ });
69
+ try {
70
+ const result = await client.request(1, heartbeat_action_spec.method, {});
71
+ assert.deepStrictEqual(result, {}, 'heartbeat returns an empty result over the wire');
72
+ }
73
+ finally {
74
+ await client.close();
75
+ }
76
+ });
77
+ // Per-connection auth fires at upgrade time (`require_auth`), so an
78
+ // anonymous socket never opens — the upgrade is refused outright.
79
+ test_if(capabilities.ws, 'anonymous upgrade is refused', async () => {
80
+ await assert_rejects(() => create_ws_transport({ base_url, ws_path, cookies: [], origin }));
81
+ });
82
+ // Origin is checked before auth, so cookies are irrelevant here.
83
+ test_if(capabilities.ws, 'disallowed-origin upgrade is refused', async () => {
84
+ await assert_rejects(() => create_ws_transport({ base_url, ws_path, cookies: [], origin: DISALLOWED_ORIGIN }));
85
+ });
86
+ // Per-message dispatch never re-checks credential validity, so a live
87
+ // socket only drops via the audit-fed `create_ws_auth_guard`. Revoke the
88
+ // keeper's sessions over its own session channel → `session_revoke_all`
89
+ // closes the socket. Gated on `rpc_path` (depends on the standard
90
+ // account actions on the RPC endpoint).
91
+ test_if(capabilities.ws && rpc_path !== undefined, 'session revocation closes the live socket', async () => {
92
+ const fixture = await setup_test();
93
+ const client = await create_ws_transport({
94
+ base_url,
95
+ ws_path,
96
+ cookies: fixture.transport.cookies(),
97
+ origin,
98
+ });
99
+ try {
100
+ // Confirm the socket dispatches before revoking, so a failed
101
+ // close assertion can't be confused with a dead connection.
102
+ await client.request(1, heartbeat_action_spec.method, {});
103
+ const res = await fixture.transport(rpc_path, create_rpc_post_init(account_session_revoke_all_action_spec.method));
104
+ assert.strictEqual(res.status, 200, `account_session_revoke_all RPC failed (status=${res.status})`);
105
+ const closed = await client.wait_for_close(2000);
106
+ assert.ok(closed, 'socket did not close within 2s after session_revoke_all');
107
+ }
108
+ finally {
109
+ await client.close();
110
+ }
111
+ });
112
+ });
113
+ };
@@ -1,8 +1,7 @@
1
1
  import './assert_dev_env.js';
2
- import type { AppSurface } from '../http/surface.js';
2
+ import type { AppSurface, AppSurfaceSpec } from '../http/surface.js';
3
3
  import type { BackendCapabilities } from './cross_backend/capabilities.js';
4
4
  import type { SetupTest } from './cross_backend/setup.js';
5
- import type { SurfaceSource } from './transports/surface_source.js';
6
5
  /**
7
6
  * Recursively collect all property names from a JSON Schema.
8
7
  *
@@ -23,11 +22,10 @@ export interface DataExposureTestOptions {
23
22
  /** Per-test fixture-producing function (per-describe cadence). */
24
23
  setup_test: SetupTest;
25
24
  /**
26
- * Source of the app surface for schema-level + route-iteration checks.
27
- * Currently requires `kind: 'inline'` the cross-process snapshot
28
- * variant lands alongside the spawned-backend transport plumbing.
25
+ * App surface for schema-level + route-iteration checks. Constructed in
26
+ * TS by the consumer; same shape for in-process and cross-process tests.
29
27
  */
30
- surface_source: SurfaceSource;
28
+ surface_source: AppSurfaceSpec;
31
29
  /** Backend capability declarations. */
32
30
  capabilities: BackendCapabilities;
33
31
  /** Fields that must never appear in any response. Default: `sensitive_field_blocklist`. */
@@ -1 +1 @@
1
- {"version":3,"file":"data_exposure.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/data_exposure.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAqB7B,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,oBAAoB,CAAC;AAYnD,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,iCAAiC,CAAC;AACzE,OAAO,KAAK,EAAC,SAAS,EAAc,MAAM,0BAA0B,CAAC;AACrE,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,gCAAgC,CAAC;AAIlE;;;;;GAKG;AACH,eAAO,MAAM,kCAAkC,GAAI,QAAQ,OAAO,KAAG,GAAG,CAAC,MAAM,CAuB9E,CAAC;AAIF;;GAEG;AACH,eAAO,MAAM,yCAAyC,GACrD,SAAS,UAAU,EACnB,mBAAkB,aAAa,CAAC,MAAM,CAA6B,KACjE,IAWF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,wCAAwC,GACpD,SAAS,UAAU,EACnB,oBAAmB,aAAa,CAAC,MAAM,CAA8B,KACnE,IAcF,CAAC;AAIF,kDAAkD;AAClD,MAAM,WAAW,uBAAuB;IACvC,kEAAkE;IAClE,UAAU,EAAE,SAAS,CAAC;IACtB;;;;OAIG;IACH,cAAc,EAAE,aAAa,CAAC;IAC9B,uCAAuC;IACvC,YAAY,EAAE,mBAAmB,CAAC;IAClC,2FAA2F;IAC3F,gBAAgB,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACzC,iGAAiG;IACjG,iBAAiB,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC1C,kDAAkD;IAClD,WAAW,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CAC5B;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,4BAA4B,GAAI,SAAS,uBAAuB,KAAG,IAiM/E,CAAC"}
1
+ {"version":3,"file":"data_exposure.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/data_exposure.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAqB7B,OAAO,KAAK,EAAC,UAAU,EAAE,cAAc,EAAC,MAAM,oBAAoB,CAAC;AAYnE,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,iCAAiC,CAAC;AACzE,OAAO,KAAK,EAAC,SAAS,EAAc,MAAM,0BAA0B,CAAC;AAIrE;;;;;GAKG;AACH,eAAO,MAAM,kCAAkC,GAAI,QAAQ,OAAO,KAAG,GAAG,CAAC,MAAM,CAuB9E,CAAC;AAIF;;GAEG;AACH,eAAO,MAAM,yCAAyC,GACrD,SAAS,UAAU,EACnB,mBAAkB,aAAa,CAAC,MAAM,CAA6B,KACjE,IAWF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,wCAAwC,GACpD,SAAS,UAAU,EACnB,oBAAmB,aAAa,CAAC,MAAM,CAA8B,KACnE,IAcF,CAAC;AAIF,kDAAkD;AAClD,MAAM,WAAW,uBAAuB;IACvC,kEAAkE;IAClE,UAAU,EAAE,SAAS,CAAC;IACtB;;;OAGG;IACH,cAAc,EAAE,cAAc,CAAC;IAC/B,uCAAuC;IACvC,YAAY,EAAE,mBAAmB,CAAC;IAClC,2FAA2F;IAC3F,gBAAgB,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACzC,iGAAiG;IACjG,iBAAiB,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC1C,kDAAkD;IAClD,WAAW,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CAC5B;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,4BAA4B,GAAI,SAAS,uBAAuB,KAAG,IA2L/E,CAAC"}
@@ -93,11 +93,7 @@ export const assert_non_admin_schemas_no_admin_fields = (surface, admin_only_fie
93
93
  * contain no sensitive fields
94
94
  */
95
95
  export const describe_data_exposure_tests = (options) => {
96
- if (options.surface_source.kind !== 'inline') {
97
- throw new Error("describe_data_exposure_tests requires surface_source.kind === 'inline' — " +
98
- 'the cross-process snapshot variant lands with the spawned-backend transport');
99
- }
100
- const { surface, route_specs } = options.surface_source.spec;
96
+ const { surface, route_specs } = options.surface_source;
101
97
  const { sensitive_fields = sensitive_field_blocklist, admin_only_fields = admin_only_field_blocklist, } = options;
102
98
  const skip_set = new Set(options.skip_routes);
103
99
  void options.capabilities;
@@ -20,13 +20,24 @@ export declare const create_test_account_with_actor: (db: Db, options: {
20
20
  password_hash?: string;
21
21
  }) => Promise<TestAccountWithActor>;
22
22
  /**
23
- * Materialize a role_grant directly via `query_create_role_grant`, bypassing
24
- * the production offer/accept consent flow. Use only when the test focuses on
25
- * revoke or isolation semantics rather than the consent path itself — the
26
- * schema permits null `source_offer_id` for exactly this case
27
- * (`account_schema.ts`). For tests that exercise the production grant flow,
28
- * drive `role_grant_offer_create_action_spec` + `role_grant_offer_accept_action_spec`
29
- * over RPC instead.
23
+ * Materialize a `role_grant` directly via `query_create_role_grant`,
24
+ * bypassing the production offer/accept consent flow.
25
+ *
26
+ * **In-process only.** This helper takes a raw `Db` handle and seeds
27
+ * rows without firing audit fan-out, WebSocket broadcasts, or the
28
+ * `_supersede` notification chain a real grant emits. Cross-process
29
+ * suites must instead drive `role_grant_offer_create_action_spec` +
30
+ * `role_grant_offer_accept_action_spec` via
31
+ * `role_grant_helpers.ts`'s `role_grant_offer_and_accept` so the
32
+ * fixture observes the full post-commit fan-out the way production
33
+ * does — otherwise tests would mask real divergence between the TS
34
+ * and Rust spines.
35
+ *
36
+ * Use this helper for query-level (`*.db.test.ts`) tests that
37
+ * exercise revoke or isolation semantics — not the consent path
38
+ * itself. The schema's `source_offer_id = null` shape is an
39
+ * intentional admin-direct escape; this helper exposes it so
40
+ * suites don't reimplement the same direct-seed wrapper.
30
41
  */
31
42
  export declare const create_test_role_grant_direct: (db: Db, input: CreateRoleGrantInput) => Promise<RoleGrant>;
32
43
  //# sourceMappingURL=db_entities.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"db_entities.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/db_entities.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAsB7B,OAAO,KAAK,EAAC,OAAO,EAAE,KAAK,EAAE,oBAAoB,EAAE,SAAS,EAAC,MAAM,2BAA2B,CAAC;AAC/F,OAAO,KAAK,EAAC,EAAE,EAAC,MAAM,aAAa,CAAC;AAEpC,oFAAoF;AACpF,MAAM,WAAW,oBAAoB;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,CAAC;CACb;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,8BAA8B,GAC1C,IAAI,EAAE,EACN,SAAS;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAC,KACjD,OAAO,CAAC,oBAAoB,CAI7B,CAAC;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,6BAA6B,GACzC,IAAI,EAAE,EACN,OAAO,oBAAoB,KACzB,OAAO,CAAC,SAAS,CAAyC,CAAC"}
1
+ {"version":3,"file":"db_entities.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/db_entities.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAsB7B,OAAO,KAAK,EAAC,OAAO,EAAE,KAAK,EAAE,oBAAoB,EAAE,SAAS,EAAC,MAAM,2BAA2B,CAAC;AAC/F,OAAO,KAAK,EAAC,EAAE,EAAC,MAAM,aAAa,CAAC;AAEpC,oFAAoF;AACpF,MAAM,WAAW,oBAAoB;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,CAAC;CACb;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,8BAA8B,GAC1C,IAAI,EAAE,EACN,SAAS;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAC,KACjD,OAAO,CAAC,oBAAoB,CAI7B,CAAC;AAEH;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,6BAA6B,GACzC,IAAI,EAAE,EACN,OAAO,oBAAoB,KACzB,OAAO,CAAC,SAAS,CAAyC,CAAC"}
@@ -29,12 +29,23 @@ import { query_create_role_grant } from '../auth/role_grant_queries.js';
29
29
  */
30
30
  export const create_test_account_with_actor = async (db, options) => query_create_account_with_actor({ db }, { username: options.username, password_hash: options.password_hash ?? 'hash' });
31
31
  /**
32
- * Materialize a role_grant directly via `query_create_role_grant`, bypassing
33
- * the production offer/accept consent flow. Use only when the test focuses on
34
- * revoke or isolation semantics rather than the consent path itself — the
35
- * schema permits null `source_offer_id` for exactly this case
36
- * (`account_schema.ts`). For tests that exercise the production grant flow,
37
- * drive `role_grant_offer_create_action_spec` + `role_grant_offer_accept_action_spec`
38
- * over RPC instead.
32
+ * Materialize a `role_grant` directly via `query_create_role_grant`,
33
+ * bypassing the production offer/accept consent flow.
34
+ *
35
+ * **In-process only.** This helper takes a raw `Db` handle and seeds
36
+ * rows without firing audit fan-out, WebSocket broadcasts, or the
37
+ * `_supersede` notification chain a real grant emits. Cross-process
38
+ * suites must instead drive `role_grant_offer_create_action_spec` +
39
+ * `role_grant_offer_accept_action_spec` via
40
+ * `role_grant_helpers.ts`'s `role_grant_offer_and_accept` so the
41
+ * fixture observes the full post-commit fan-out the way production
42
+ * does — otherwise tests would mask real divergence between the TS
43
+ * and Rust spines.
44
+ *
45
+ * Use this helper for query-level (`*.db.test.ts`) tests that
46
+ * exercise revoke or isolation semantics — not the consent path
47
+ * itself. The schema's `source_offer_id = null` shape is an
48
+ * intentional admin-direct escape; this helper exposes it so
49
+ * suites don't reimplement the same direct-seed wrapper.
39
50
  */
40
51
  export const create_test_role_grant_direct = async (db, input) => query_create_role_grant({ db }, input);