@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
@@ -1,9 +1,9 @@
1
1
  import './assert_dev_env.js';
2
2
  import type { SessionOptions } from '../auth/session_cookie.js';
3
3
  import { type RpcEndpointsSuiteOption } from './rpc_helpers.js';
4
- import type { BackendCapabilities } from './cross_backend/capabilities.js';
4
+ import type { AppSurfaceSpec } from '../http/surface.js';
5
+ import { type BackendCapabilities } from './cross_backend/capabilities.js';
5
6
  import type { SetupTest } from './cross_backend/setup.js';
6
- import type { SurfaceSource } from './transports/surface_source.js';
7
7
  /**
8
8
  * Configuration for `describe_standard_integration_tests`.
9
9
  */
@@ -15,11 +15,16 @@ export interface StandardIntegrationTestOptions {
15
15
  */
16
16
  setup_test: SetupTest;
17
17
  /**
18
- * Source of the app surface for route iteration and error-coverage
19
- * scoping. Currently requires `kind: 'inline'` the cross-process
20
- * snapshot variant lands alongside the spawned-backend transport plumbing.
18
+ * App surface (with route specs + middleware specs) for route iteration
19
+ * and error-coverage scoping. The same shape feeds both in-process and
20
+ * cross-process tests the test process always constructs the spec in
21
+ * TS (via `create_test_app_surface_spec` or a consumer's equivalent);
22
+ * cross-process-ness is a property of the transport + per-test fixture,
23
+ * not the schema source. The on-disk `auth_attack_surface.json` is an
24
+ * observability artifact for human inspection + gen-time drift gating,
25
+ * not the source the test runtime reads from.
21
26
  */
22
- surface_source: SurfaceSource;
27
+ surface_source: AppSurfaceSpec;
23
28
  /** Backend capability declarations — companion to `fixture.in_process` narrowing. */
24
29
  capabilities: BackendCapabilities;
25
30
  /**
@@ -65,6 +70,22 @@ export interface StandardIntegrationTestOptions {
65
70
  * Each test group asserts that required routes exist, failing with a descriptive
66
71
  * message if the consumer's route specs are misconfigured.
67
72
  *
73
+ * The two signup-invite-edge-case tests call `invite_create_action_spec`
74
+ * (admin-gated) over the fixture's session, so consumers wiring signup +
75
+ * admin actions must thread `extra_keeper_roles: [ROLE_ADMIN]` through
76
+ * either `default_in_process_suite_options` or
77
+ * `default_cross_process_setup(handle, {extra_keeper_roles:
78
+ * [ROLE_ADMIN]})`. In both modes the fixture's `fixture.account` is the
79
+ * fresh keeper, and the extra-keeper-roles list grants the bootstrapped
80
+ * keeper additional roles inline (cross-process via `_testing_reset`'s
81
+ * bootstrap-time seeding; in-process via `bootstrap_test_keeper`) — no
82
+ * per-role RPC cost, no offer/accept round-trip. The tests run against
83
+ * the production `open_signup: false` default — the cross-process
84
+ * per-test secondary mint via `fixture.create_account()` is
85
+ * invite-gated (keeper drives `invite_create` before signup) so the
86
+ * harness doesn't need to flip the setting. Consumers that don't wire
87
+ * signup or `invite_create` silently skip these two tests.
88
+ *
68
89
  * @throws Error at setup time when `options.rpc_endpoints` is empty — the
69
90
  * suite hard-fails via `require_rpc_endpoint_path` rather than running
70
91
  * tests that would crash mid-suite trying to dispatch
@@ -1 +1 @@
1
- {"version":3,"file":"integration.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/integration.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAsB7B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAO9D,OAAO,EAKN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AAkB1B,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,iCAAiC,CAAC;AACzE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,0BAA0B,CAAC;AACxD,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,gCAAgC,CAAC;AAElE;;GAEG;AACH,MAAM,WAAW,8BAA8B;IAC9C;;;;OAIG;IACH,UAAU,EAAE,SAAS,CAAC;IACtB;;;;OAIG;IACH,cAAc,EAAE,aAAa,CAAC;IAC9B,qFAAqF;IACrF,YAAY,EAAE,mBAAmB,CAAC;IAClC;;;;;OAKG;IACH,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC;;;;;;;;;;;;OAYG;IACH,aAAa,EAAE,uBAAuB,CAAC;IACvC;;;;;;;OAOG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,mCAAmC,GAC/C,SAAS,8BAA8B,KACrC,IAy3CF,CAAC"}
1
+ {"version":3,"file":"integration.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/integration.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAsB7B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAO9D,OAAO,EAKN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AAkB1B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAU,KAAK,mBAAmB,EAAC,MAAM,iCAAiC,CAAC;AAClF,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,0BAA0B,CAAC;AAGxD;;GAEG;AACH,MAAM,WAAW,8BAA8B;IAC9C;;;;OAIG;IACH,UAAU,EAAE,SAAS,CAAC;IACtB;;;;;;;;;OASG;IACH,cAAc,EAAE,cAAc,CAAC;IAC/B,qFAAqF;IACrF,YAAY,EAAE,mBAAmB,CAAC;IAClC;;;;;OAKG;IACH,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC;;;;;;;;;;;;OAYG;IACH,aAAa,EAAE,uBAAuB,CAAC;IACvC;;;;;;;OAOG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,mCAAmC,GAC/C,SAAS,8BAA8B,KACrC,IAy5CF,CAAC"}
@@ -24,6 +24,8 @@ import { ApiError, ERROR_FORBIDDEN_ORIGIN } from '../http/error_schemas.js';
24
24
  import { is_public_auth } from '../http/auth_shape.js';
25
25
  import { account_verify_action_spec, account_session_list_action_spec, account_session_revoke_action_spec, account_session_revoke_all_action_spec, account_token_create_action_spec, account_token_list_action_spec, account_token_revoke_action_spec, } from '../auth/account_action_specs.js';
26
26
  import { invite_create_action_spec } from '../auth/admin_action_specs.js';
27
+ import { test_if } from './cross_backend/capabilities.js';
28
+ import { DEFAULT_TEST_PASSWORD } from './app_server.js';
27
29
  /**
28
30
  * Standard integration test suite for fuz_app auth routes.
29
31
  *
@@ -36,24 +38,35 @@ import { invite_create_action_spec } from '../auth/admin_action_specs.js';
36
38
  * Each test group asserts that required routes exist, failing with a descriptive
37
39
  * message if the consumer's route specs are misconfigured.
38
40
  *
41
+ * The two signup-invite-edge-case tests call `invite_create_action_spec`
42
+ * (admin-gated) over the fixture's session, so consumers wiring signup +
43
+ * admin actions must thread `extra_keeper_roles: [ROLE_ADMIN]` through
44
+ * either `default_in_process_suite_options` or
45
+ * `default_cross_process_setup(handle, {extra_keeper_roles:
46
+ * [ROLE_ADMIN]})`. In both modes the fixture's `fixture.account` is the
47
+ * fresh keeper, and the extra-keeper-roles list grants the bootstrapped
48
+ * keeper additional roles inline (cross-process via `_testing_reset`'s
49
+ * bootstrap-time seeding; in-process via `bootstrap_test_keeper`) — no
50
+ * per-role RPC cost, no offer/accept round-trip. The tests run against
51
+ * the production `open_signup: false` default — the cross-process
52
+ * per-test secondary mint via `fixture.create_account()` is
53
+ * invite-gated (keeper drives `invite_create` before signup) so the
54
+ * harness doesn't need to flip the setting. Consumers that don't wire
55
+ * signup or `invite_create` silently skip these two tests.
56
+ *
39
57
  * @throws Error at setup time when `options.rpc_endpoints` is empty — the
40
58
  * suite hard-fails via `require_rpc_endpoint_path` rather than running
41
59
  * tests that would crash mid-suite trying to dispatch
42
60
  * `account_verify` / `account_session_*` / `account_token_*`.
43
61
  */
44
62
  export const describe_standard_integration_tests = (options) => {
45
- if (options.surface_source.kind !== 'inline') {
46
- throw new Error("describe_standard_integration_tests requires surface_source.kind === 'inline' — " +
47
- 'the cross-process snapshot variant lands with the spawned-backend transport');
48
- }
49
- const route_specs = options.surface_source.spec.route_specs;
63
+ const route_specs = options.surface_source.route_specs;
50
64
  // Hard-fail early so consumers see a clear setup error instead of a
51
65
  // confusing test failure when `rpc_endpoints` is missing. Factory-form
52
66
  // callers are resolved with a stub ctx purely to extract the endpoint
53
67
  // path; the running backend handles live dispatch.
54
68
  const rpc_endpoints_for_setup = resolve_rpc_endpoints_for_setup(options.rpc_endpoints, options.session_options);
55
69
  const rpc_path = require_rpc_endpoint_path(rpc_endpoints_for_setup);
56
- void options.capabilities;
57
70
  describe('standard_integration', () => {
58
71
  const { cookie_name } = options.session_options;
59
72
  // Error coverage tracking across test groups
@@ -96,7 +109,7 @@ export const describe_standard_integration_tests = (options) => {
96
109
  },
97
110
  body: JSON.stringify({
98
111
  username: fixture.account.username,
99
- password: 'test-password-123',
112
+ password: DEFAULT_TEST_PASSWORD,
100
113
  }),
101
114
  });
102
115
  assert.strictEqual(res.status, 200);
@@ -140,7 +153,7 @@ export const describe_standard_integration_tests = (options) => {
140
153
  },
141
154
  body: JSON.stringify({
142
155
  username: 'nonexistent_user',
143
- password: 'test-password-123',
156
+ password: DEFAULT_TEST_PASSWORD,
144
157
  }),
145
158
  });
146
159
  assert.strictEqual(res.status, 401);
@@ -161,7 +174,7 @@ export const describe_standard_integration_tests = (options) => {
161
174
  },
162
175
  body: JSON.stringify({
163
176
  username: ` ${fixture.account.username} `,
164
- password: 'test-password-123',
177
+ password: DEFAULT_TEST_PASSWORD,
165
178
  }),
166
179
  });
167
180
  assert.strictEqual(res.status, 200);
@@ -184,7 +197,7 @@ export const describe_standard_integration_tests = (options) => {
184
197
  },
185
198
  body: JSON.stringify({
186
199
  username: fixture.account.username,
187
- password: 'test-password-123',
200
+ password: DEFAULT_TEST_PASSWORD,
188
201
  }),
189
202
  });
190
203
  assert.strictEqual(login_res.status, 200);
@@ -273,7 +286,7 @@ export const describe_standard_integration_tests = (options) => {
273
286
  },
274
287
  body: JSON.stringify({
275
288
  username: fixture.account.username,
276
- password: 'test-password-123',
289
+ password: DEFAULT_TEST_PASSWORD,
277
290
  }),
278
291
  });
279
292
  assert.strictEqual(res.status, 200);
@@ -291,7 +304,7 @@ export const describe_standard_integration_tests = (options) => {
291
304
  test('no cookie on protected route returns 401', async () => {
292
305
  const fixture = await options.setup_test();
293
306
  const res = await rpc_call_for_spec({
294
- app: { request: fixture.transport },
307
+ app: { request: fixture.fresh_transport() },
295
308
  path: rpc_path,
296
309
  spec: account_verify_action_spec,
297
310
  params: undefined,
@@ -310,9 +323,9 @@ export const describe_standard_integration_tests = (options) => {
310
323
  });
311
324
  assert.strictEqual(res.status, 401);
312
325
  });
313
- test('expired cookie returns 401', async () => {
326
+ test_if(options.capabilities.in_process_only, 'expired cookie returns 401', async () => {
314
327
  const fixture = await options.setup_test();
315
- assert(fixture.in_process, 'expired-cookie generation requires in-process keyring');
328
+ assert(fixture.in_process);
316
329
  const expired_cookie = await create_expired_test_cookie(fixture.keyring, options.session_options);
317
330
  const res = await rpc_call_for_spec({
318
331
  app: { request: fixture.transport },
@@ -409,7 +422,7 @@ export const describe_standard_integration_tests = (options) => {
409
422
  method: 'POST',
410
423
  headers,
411
424
  body: JSON.stringify({
412
- current_password: 'test-password-123',
425
+ current_password: DEFAULT_TEST_PASSWORD,
413
426
  new_password: 'new-password-456',
414
427
  }),
415
428
  });
@@ -473,9 +486,9 @@ export const describe_standard_integration_tests = (options) => {
473
486
  });
474
487
  // --- 5. Origin verification ---
475
488
  describe('origin verification', () => {
476
- test('evil origin is rejected with 403', async () => {
489
+ test_if(options.capabilities.in_process_only, 'evil origin is rejected with 403', async () => {
477
490
  const fixture = await options.setup_test();
478
- assert(fixture.in_process, 'manual cookie composition requires backend_internals');
491
+ assert(fixture.in_process);
479
492
  // `verify_request_source` runs before the RPC dispatcher and returns a
480
493
  // plain REST `{error}` body — not a JSON-RPC envelope. Skip `rpc_call`.
481
494
  const res = await fixture.transport(rpc_path, {
@@ -507,9 +520,9 @@ export const describe_standard_integration_tests = (options) => {
507
520
  });
508
521
  assert.strictEqual(res.status, 200);
509
522
  });
510
- test('no origin header is allowed (direct access)', async () => {
523
+ test_if(options.capabilities.in_process_only, 'no origin header is allowed (direct access)', async () => {
511
524
  const fixture = await options.setup_test();
512
- assert(fixture.in_process, 'manual cookie composition requires backend_internals');
525
+ assert(fixture.in_process);
513
526
  // Probe the "no Origin / no Referer" path; `suppress_default_origin`
514
527
  // skips the default `origin` header.
515
528
  const res = await rpc_call_for_spec({
@@ -539,8 +552,11 @@ export const describe_standard_integration_tests = (options) => {
539
552
  });
540
553
  test('invalid bearer token returns 401', async () => {
541
554
  const fixture = await options.setup_test();
555
+ // `origin: null` — bearer auth requires no browser-context
556
+ // indicator; the default `Origin: <base_url>` would silently
557
+ // discard the bearer cross-process.
542
558
  const res = await rpc_call_for_spec({
543
- app: { request: fixture.transport },
559
+ app: { request: fixture.fresh_transport({ origin: null }) },
544
560
  path: rpc_path,
545
561
  spec: account_verify_action_spec,
546
562
  params: undefined,
@@ -552,9 +568,11 @@ export const describe_standard_integration_tests = (options) => {
552
568
  test('bearer token with Origin header is rejected', async () => {
553
569
  const fixture = await options.setup_test();
554
570
  const bearer_headers = fixture.create_bearer_headers();
555
- // Without Origin — works.
571
+ // Without Origin — works. `origin: null` so the transport
572
+ // doesn't auto-add the default Origin (which would discard
573
+ // the bearer as browser-context cross-process).
556
574
  const ok_res = await rpc_call_for_spec({
557
- app: { request: fixture.transport },
575
+ app: { request: fixture.fresh_transport({ origin: null }) },
558
576
  path: rpc_path,
559
577
  spec: account_verify_action_spec,
560
578
  params: undefined,
@@ -564,7 +582,7 @@ export const describe_standard_integration_tests = (options) => {
564
582
  assert.strictEqual(ok_res.status, 200);
565
583
  // With Origin — bearer silently discarded (browser context), falls through to no auth.
566
584
  const res = await rpc_call_for_spec({
567
- app: { request: fixture.transport },
585
+ app: { request: fixture.fresh_transport() },
568
586
  path: rpc_path,
569
587
  spec: account_verify_action_spec,
570
588
  params: undefined,
@@ -587,9 +605,13 @@ export const describe_standard_integration_tests = (options) => {
587
605
  });
588
606
  assert.ok(create_res.ok, 'account_token_create should succeed');
589
607
  const { token, id } = create_res.result;
590
- // Verify token works
608
+ // Verify token works — fresh transport so the per-test session
609
+ // cookie in `fixture.transport`'s jar can't give a false pass
610
+ // when the bearer is the credential under test. `origin: null`
611
+ // so the transport doesn't auto-add a default Origin (which
612
+ // would discard the bearer as browser-context cross-process).
591
613
  const use_res = await rpc_call_for_spec({
592
- app: { request: fixture.transport },
614
+ app: { request: fixture.fresh_transport({ origin: null }) },
593
615
  path: rpc_path,
594
616
  spec: account_verify_action_spec,
595
617
  params: undefined,
@@ -606,9 +628,10 @@ export const describe_standard_integration_tests = (options) => {
606
628
  headers: fixture.create_session_headers(),
607
629
  });
608
630
  assert.ok(revoke_res.ok, 'account_token_revoke should succeed');
609
- // Token should no longer work
631
+ // Token should no longer work — fresh transport same reason as
632
+ // the `use_res` call above.
610
633
  const after_res = await rpc_call_for_spec({
611
- app: { request: fixture.transport },
634
+ app: { request: fixture.fresh_transport({ origin: null }) },
612
635
  path: rpc_path,
613
636
  spec: account_verify_action_spec,
614
637
  params: undefined,
@@ -805,7 +828,7 @@ export const describe_standard_integration_tests = (options) => {
805
828
  const fixture = await options.setup_test();
806
829
  const logout_route = find_auth_route(route_specs, '/logout', 'POST');
807
830
  assert.ok(logout_route, 'Expected POST /logout route — ensure create_route_specs includes account routes');
808
- const res = await fixture.transport(logout_route.path, {
831
+ const res = await fixture.fresh_transport()(logout_route.path, {
809
832
  method: 'POST',
810
833
  headers: {
811
834
  host: 'localhost',
@@ -832,8 +855,13 @@ export const describe_standard_integration_tests = (options) => {
832
855
  // against the shared endpoint path. The dispatcher runs auth before
833
856
  // params validation, so any well-formed param body works — we just
834
857
  // need each call to be type-correct wrt its spec.
858
+ //
859
+ // Fresh transport so the per-test session cookie in
860
+ // `fixture.transport`'s jar doesn't leak into these unauthed
861
+ // probes and convert their expected 401s into 200s.
862
+ const unauthed = fixture.fresh_transport();
835
863
  const session_list = await rpc_call_for_spec({
836
- app: { request: fixture.transport },
864
+ app: { request: unauthed },
837
865
  path: rpc_path,
838
866
  spec: account_session_list_action_spec,
839
867
  params: undefined,
@@ -842,7 +870,7 @@ export const describe_standard_integration_tests = (options) => {
842
870
  assert.strictEqual(session_list.status, 401);
843
871
  error_collector.record(route_specs, 'POST', rpc_path, 401);
844
872
  const session_revoke_all = await rpc_call_for_spec({
845
- app: { request: fixture.transport },
873
+ app: { request: unauthed },
846
874
  path: rpc_path,
847
875
  spec: account_session_revoke_all_action_spec,
848
876
  params: undefined,
@@ -851,7 +879,7 @@ export const describe_standard_integration_tests = (options) => {
851
879
  assert.strictEqual(session_revoke_all.status, 401);
852
880
  error_collector.record(route_specs, 'POST', rpc_path, 401);
853
881
  const token_list = await rpc_call_for_spec({
854
- app: { request: fixture.transport },
882
+ app: { request: unauthed },
855
883
  path: rpc_path,
856
884
  spec: account_token_list_action_spec,
857
885
  params: undefined,
@@ -860,7 +888,7 @@ export const describe_standard_integration_tests = (options) => {
860
888
  assert.strictEqual(token_list.status, 401);
861
889
  error_collector.record(route_specs, 'POST', rpc_path, 401);
862
890
  const token_create = await rpc_call_for_spec({
863
- app: { request: fixture.transport },
891
+ app: { request: unauthed },
864
892
  path: rpc_path,
865
893
  spec: account_token_create_action_spec,
866
894
  params: { name: 'unauth-probe' },
@@ -869,7 +897,7 @@ export const describe_standard_integration_tests = (options) => {
869
897
  assert.strictEqual(token_create.status, 401);
870
898
  error_collector.record(route_specs, 'POST', rpc_path, 401);
871
899
  const verify = await rpc_call_for_spec({
872
- app: { request: fixture.transport },
900
+ app: { request: unauthed },
873
901
  path: rpc_path,
874
902
  spec: account_verify_action_spec,
875
903
  params: undefined,
@@ -880,7 +908,7 @@ export const describe_standard_integration_tests = (options) => {
880
908
  // Also exercise POST /logout without auth (still REST)
881
909
  const logout_route = find_auth_route(route_specs, '/logout', 'POST');
882
910
  if (logout_route) {
883
- const res = await fixture.transport(logout_route.path, {
911
+ const res = await unauthed(logout_route.path, {
884
912
  method: 'POST',
885
913
  headers: { host: 'localhost', 'content-type': 'application/json' },
886
914
  body: JSON.stringify({}),
@@ -895,7 +923,7 @@ export const describe_standard_integration_tests = (options) => {
895
923
  test('401 responses contain no leaky fields', async () => {
896
924
  const fixture = await options.setup_test();
897
925
  const res = await rpc_call_for_spec({
898
- app: { request: fixture.transport },
926
+ app: { request: fixture.fresh_transport() },
899
927
  path: rpc_path,
900
928
  spec: account_verify_action_spec,
901
929
  params: undefined,
@@ -911,9 +939,9 @@ export const describe_standard_integration_tests = (options) => {
911
939
  });
912
940
  // --- 11. Expired credential rejection ---
913
941
  describe('expired credential rejection', () => {
914
- test('expired session cookie returns 401', async () => {
942
+ test_if(options.capabilities.in_process_only, 'expired session cookie returns 401', async () => {
915
943
  const fixture = await options.setup_test();
916
- assert(fixture.in_process, 'expired-cookie generation requires in-process keyring');
944
+ assert(fixture.in_process);
917
945
  const expired_cookie = await create_expired_test_cookie(fixture.keyring, options.session_options);
918
946
  const res = await rpc_call_for_spec({
919
947
  app: { request: fixture.transport },
@@ -924,9 +952,9 @@ export const describe_standard_integration_tests = (options) => {
924
952
  });
925
953
  assert.strictEqual(res.status, 401, 'Expired session cookie should be rejected');
926
954
  });
927
- test('expired session cookie returns 401 on mutation route', async () => {
955
+ test_if(options.capabilities.in_process_only, 'expired session cookie returns 401 on mutation route', async () => {
928
956
  const fixture = await options.setup_test();
929
- assert(fixture.in_process, 'expired-cookie generation requires in-process keyring');
957
+ assert(fixture.in_process);
930
958
  const logout_route = find_auth_route(route_specs, '/logout', 'POST');
931
959
  assert.ok(logout_route, 'Expected POST /logout route — ensure create_route_specs includes account routes');
932
960
  const expired_cookie = await create_expired_test_cookie(fixture.keyring, options.session_options);
@@ -950,7 +978,7 @@ export const describe_standard_integration_tests = (options) => {
950
978
  const bearer_headers = fixture.create_bearer_headers({
951
979
  'content-type': 'application/json',
952
980
  });
953
- const res = await fixture.transport(logout_route.path, {
981
+ const res = await fixture.fresh_transport()(logout_route.path, {
954
982
  method: 'POST',
955
983
  headers: { ...bearer_headers, origin: 'http://localhost:5173' },
956
984
  });
@@ -964,7 +992,7 @@ export const describe_standard_integration_tests = (options) => {
964
992
  const bearer_headers = fixture.create_bearer_headers({
965
993
  'content-type': 'application/json',
966
994
  });
967
- const res = await fixture.transport(password_route.path, {
995
+ const res = await fixture.fresh_transport()(password_route.path, {
968
996
  method: 'POST',
969
997
  headers: { ...bearer_headers, referer: 'http://localhost:5173/admin' },
970
998
  });
@@ -1004,7 +1032,7 @@ export const describe_standard_integration_tests = (options) => {
1004
1032
  method: 'POST',
1005
1033
  headers: fixture.create_session_headers({ 'content-type': 'application/json' }),
1006
1034
  body: JSON.stringify({
1007
- current_password: 'test-password-123',
1035
+ current_password: DEFAULT_TEST_PASSWORD,
1008
1036
  new_password: 'new-password-456',
1009
1037
  }),
1010
1038
  });
@@ -1036,18 +1064,24 @@ export const describe_standard_integration_tests = (options) => {
1036
1064
  // rather than fail.
1037
1065
  if (!find_rpc_action(rpc_endpoints_for_setup, invite_create_action_spec.method))
1038
1066
  return;
1039
- // Create an admin to manage invites
1040
- const admin = await fixture.create_account({
1041
- username: 'invite_edge_admin',
1042
- roles: ['admin'],
1043
- });
1067
+ // Drive the admin-gated `invite_create` over the fixture's
1068
+ // session. In both modes the fixture is the fresh keeper,
1069
+ // holding `[ROLE_KEEPER, ROLE_ADMIN, ...extra_keeper_roles]`
1070
+ // from the bootstrap-equivalent seed step — `extra_keeper_roles:
1071
+ // [ROLE_ADMIN]` is technically redundant for the admin suite
1072
+ // but harmless. `fixture.create_session_headers()` resolves to
1073
+ // a session with admin role.
1074
+ // `open_signup` stays at production default (`false`) across both
1075
+ // in-process (per-test bootstrap default) and cross-process (the
1076
+ // invite-gated `mint_account` flow doesn't need it flipped), so
1077
+ // the assertion fires without any mid-test setting toggle.
1044
1078
  // Create invite for alice@example.com via RPC
1045
1079
  const invite_res = await rpc_call_for_spec({
1046
1080
  app: { request: fixture.transport },
1047
1081
  path: rpc_path,
1048
1082
  spec: invite_create_action_spec,
1049
1083
  params: { email: 'alice@example.com' },
1050
- headers: { cookie: `${cookie_name}=${admin.session_cookie}` },
1084
+ headers: fixture.create_session_headers(),
1051
1085
  });
1052
1086
  assert.ok(invite_res.ok, `invite_create failed: ${invite_res.ok ? '' : JSON.stringify(invite_res.error)}`);
1053
1087
  // Try to sign up with a different email — should fail (no matching invite)
@@ -1081,12 +1115,17 @@ export const describe_standard_integration_tests = (options) => {
1081
1115
  // wire admin RPC actions can't exercise invites.
1082
1116
  if (!find_rpc_action(rpc_endpoints_for_setup, invite_create_action_spec.method))
1083
1117
  return;
1084
- // We need admin access create an admin account
1085
- const admin = await fixture.create_account({
1086
- username: 'signup_test_admin',
1087
- roles: ['admin'],
1088
- });
1089
- const admin_headers = { cookie: `${cookie_name}=${admin.session_cookie}` };
1118
+ // Drive admin-gated calls over the fixture's session — see the
1119
+ // previous test's comment for the in-process / cross-process
1120
+ // admin-resolution paths. This test creates a separate
1121
+ // `existing_user` for the username-conflict assertion, so
1122
+ // reusing the fixture's admin session for the invite-creating
1123
+ // path has no cross-account-isolation impact on the test's intent.
1124
+ const admin_headers = fixture.create_session_headers();
1125
+ // Mint the conflict-test sibling account for the username-conflict
1126
+ // assertion below. Both transports preserve hardcoded usernames
1127
+ // now that fresh-keeper-per-test wipes the DB between tests.
1128
+ const existing_user = await fixture.create_account({ username: 'existing_user' });
1090
1129
  // Create an invite for a specific test email via RPC
1091
1130
  const test_email = 'signup-test@example.com';
1092
1131
  const invite_res = await rpc_call_for_spec({
@@ -1113,10 +1152,6 @@ export const describe_standard_integration_tests = (options) => {
1113
1152
  });
1114
1153
  assert.strictEqual(no_match_res.status, 403, 'Expected 403 for non-matching invite');
1115
1154
  const no_match_body = await no_match_res.json();
1116
- // For conflict test: create a second account with a known username,
1117
- // then create an invite for a different email, then try signup with
1118
- // the invited email but the colliding username
1119
- const existing_user = await fixture.create_account({ username: 'existing_user' });
1120
1155
  // Create invite for a different email via RPC
1121
1156
  const conflict_email = 'conflict-test@example.com';
1122
1157
  const invite2_res = await rpc_call_for_spec({
@@ -1,7 +1,7 @@
1
1
  import './assert_dev_env.js';
2
2
  import type { BackendCapabilities } from './cross_backend/capabilities.js';
3
3
  import type { SetupTest } from './cross_backend/setup.js';
4
- import type { SurfaceSource } from './transports/surface_source.js';
4
+ import type { AppSurfaceSpec } from '../http/surface.js';
5
5
  /** Options for `describe_round_trip_validation`. */
6
6
  export interface RoundTripTestOptions {
7
7
  /**
@@ -12,11 +12,10 @@ export interface RoundTripTestOptions {
12
12
  */
13
13
  setup_test: SetupTest;
14
14
  /**
15
- * Source of the app surface for route iteration. Currently requires
16
- * `kind: 'inline'` the cross-process snapshot variant lands alongside
17
- * the spawned-backend transport plumbing.
15
+ * App surface (with route specs) for route iteration. Constructed in
16
+ * TS by the consumer; same shape for in-process and cross-process tests.
18
17
  */
19
- surface_source: SurfaceSource;
18
+ surface_source: AppSurfaceSpec;
20
19
  /** Backend capability declarations — see `cross_backend/capabilities.ts`. */
21
20
  capabilities: BackendCapabilities;
22
21
  /** Routes to skip, in `'METHOD /path'` format. */
@@ -1 +1 @@
1
- {"version":3,"file":"round_trip.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/round_trip.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AA0B7B,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;AAElE,oDAAoD;AACpD,MAAM,WAAW,oBAAoB;IACpC;;;;;OAKG;IACH,UAAU,EAAE,SAAS,CAAC;IACtB;;;;OAIG;IACH,cAAc,EAAE,aAAa,CAAC;IAC9B,6EAA6E;IAC7E,YAAY,EAAE,mBAAmB,CAAC;IAClC,kDAAkD;IAClD,WAAW,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC5B,+EAA+E;IAC/E,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACvD;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,8BAA8B,GAAI,SAAS,oBAAoB,KAAG,IAmE9E,CAAC"}
1
+ {"version":3,"file":"round_trip.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/round_trip.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AA0B7B,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,iCAAiC,CAAC;AACzE,OAAO,KAAK,EAAC,SAAS,EAAc,MAAM,0BAA0B,CAAC;AACrE,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,oBAAoB,CAAC;AAEvD,oDAAoD;AACpD,MAAM,WAAW,oBAAoB;IACpC;;;;;OAKG;IACH,UAAU,EAAE,SAAS,CAAC;IACtB;;;OAGG;IACH,cAAc,EAAE,cAAc,CAAC;IAC/B,6EAA6E;IAC7E,YAAY,EAAE,mBAAmB,CAAC;IAClC,kDAAkD;IAClD,WAAW,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC5B,+EAA+E;IAC/E,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACvD;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,8BAA8B,GAAI,SAAS,oBAAoB,KAAG,IA6D9E,CAAC"}
@@ -33,11 +33,7 @@ import { resolve_valid_path, generate_valid_body } from './schema_generators.js'
33
33
  * with valid input are still validated against their declared error schemas.
34
34
  */
35
35
  export const describe_round_trip_validation = (options) => {
36
- if (options.surface_source.kind !== 'inline') {
37
- throw new Error("describe_round_trip_validation requires surface_source.kind === 'inline' — " +
38
- 'the cross-process snapshot variant lands with the spawned-backend transport');
39
- }
40
- const describe_time_specs = options.surface_source.spec.route_specs;
36
+ const describe_time_specs = options.surface_source.route_specs;
41
37
  const skip_set = new Set(options.skip_routes);
42
38
  // `capabilities` is currently unused by this suite (no in-process-only
43
39
  // reads, no transport-gated cases) but stays on the options for
@@ -104,12 +104,18 @@ export type RpcCallResult = {
104
104
  data?: unknown;
105
105
  };
106
106
  };
107
+ /**
108
+ * App shape accepted by `rpc_call`. Either a Hono-like object with a
109
+ * `.request(input, init)` method (in-process `TestApp.app` directly) or a
110
+ * bare `RpcTestTransport` callable (cross-process `fixture.transport`).
111
+ */
112
+ export type RpcCallApp = {
113
+ request: (input: string, init: RequestInit) => Promise<Response> | Response;
114
+ } | RpcTestTransport;
107
115
  /** Arguments for `rpc_call`. */
108
116
  export interface RpcCallArgs {
109
- /** Hono-like app (anything with a `request(url, init)` method). */
110
- app: {
111
- request: (input: string, init: RequestInit) => Promise<Response> | Response;
112
- };
117
+ /** Hono-like app or bare `RpcTestTransport` callable. */
118
+ app: RpcCallApp;
113
119
  /** RPC endpoint path, e.g. `'/api/rpc'`. */
114
120
  path: string;
115
121
  /** JSON-RPC method name. */
@@ -1 +1 @@
1
- {"version":3,"file":"rpc_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/rpc_helpers.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAa7B,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,OAAO,EAIN,KAAK,gBAAgB,EACrB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,2BAA2B,CAAC;AACzE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,0BAA0B,CAAC;AACxD,OAAO,KAAK,EAAC,qBAAqB,EAAE,mBAAmB,EAAE,eAAe,EAAC,MAAM,oBAAoB,CAAC;AACpG,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAG9D;;;;;;;;;GASG;AACH,MAAM,MAAM,uBAAuB,GAChC,KAAK,CAAC,eAAe,CAAC,GACtB,CAAC,CAAC,GAAG,EAAE,gBAAgB,KAAK,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC;AAEvD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,+BAA+B,GAC3C,eAAe,uBAAuB,EACtC,iBAAiB,cAAc,CAAC,MAAM,CAAC,KACrC,KAAK,CAAC,eAAe,CAuBvB,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,oBAAoB,GAChC,QAAQ,MAAM,EACd,SAAS,OAAO,EAChB,KAAI,MAAM,GAAG,MAAe,KAC1B,WAQF,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,GAC9B,eAAe,MAAM,EACrB,QAAQ,MAAM,EACd,SAAS,OAAO,EAChB,KAAI,MAAM,GAAG,MAAe,KAC1B,MAMF,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,6BAA6B,GACzC,MAAM,OAAO,EACb,gBAAgB,gBAAgB,KAC9B,IAUF,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,+BAA+B,GAAI,MAAM,OAAO,EAAE,gBAAgB,CAAC,CAAC,OAAO,KAAG,IAW1F,CAAC;AAIF;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAErF,2DAA2D;AAC3D,eAAO,MAAM,cAAc,GACzB,KAAK;IACL,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC;CAC5E,KAAG,gBAEmB,CAAC;AAEzB,yEAAyE;AACzE,MAAM,MAAM,aAAa,GACtB;IAAC,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAC,GAC3C;IACA,EAAE,EAAE,KAAK,CAAC;IACV,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAC,CAAC;CACtD,CAAC;AAEL,gCAAgC;AAChC,MAAM,WAAW,WAAW;IAC3B,mEAAmE;IACnE,GAAG,EAAE;QAAC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAA;KAAC,CAAC;IACnF,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,wCAAwC;IACxC,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACrB,mFAAmF;IACnF,IAAI,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IACtB;;;;;OAKG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;CAClC;AAcD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,QAAQ,GAAU,MAAM,WAAW,KAAG,OAAO,CAAC,aAAa,CA0DvE,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,GAChC,MAAM,IAAI,CAAC,WAAW,EAAE,yBAAyB,CAAC,KAChD,OAAO,CAAC,aAAa,CAAuD,CAAC;AAEhF;;;;;GAKG;AACH,MAAM,MAAM,oBAAoB,CAAC,KAAK,SAAS,yBAAyB,IACrE;IAAC,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAA;CAAC,GAC5D;IAAC,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAC,CAAA;CAAC,CAAC;AAEvF,mFAAmF;AACnF,MAAM,MAAM,kBAAkB,CAAC,KAAK,SAAS,yBAAyB,IAAI,IAAI,CAC7E,WAAW,EACX,QAAQ,GAAG,QAAQ,CACnB,GAAG;IACH,2GAA2G;IAC3G,IAAI,EAAE,KAAK,CAAC;IACZ,0CAA0C;IAC1C,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;CAChC,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,iBAAiB,GAAU,KAAK,SAAS,yBAAyB,EAC9E,MAAM,kBAAkB,CAAC,KAAK,CAAC,KAC7B,OAAO,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAarC,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,GAAU,CAAC,EACrC,MAAM,WAAW,EACjB,eAAe,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KACzB,OAAO,CAAC,CAAC,CAcX,CAAC;AAIF;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAC3B,eAAe,aAAa,CAAC,eAAe,CAAC,EAC7C,QAAQ,MAAM,KACZ;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,SAAS,CAAA;CAAC,GAAG,SAOtC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAC3B,eAAe,aAAa,CAAC,qBAAqB,CAAC,EACnD,QAAQ,MAAM,KACZ;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,mBAAmB,CAAA;CAAC,GAAG,SAOrD,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,yBAAyB,GACrC,eAAe,aAAa,CAAC,eAAe,CAAC,KAC3C,MAYF,CAAC"}
1
+ {"version":3,"file":"rpc_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/rpc_helpers.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAa7B,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,OAAO,EAIN,KAAK,gBAAgB,EACrB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,2BAA2B,CAAC;AACzE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,0BAA0B,CAAC;AACxD,OAAO,KAAK,EAAC,qBAAqB,EAAE,mBAAmB,EAAE,eAAe,EAAC,MAAM,oBAAoB,CAAC;AACpG,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAG9D;;;;;;;;;GASG;AACH,MAAM,MAAM,uBAAuB,GAChC,KAAK,CAAC,eAAe,CAAC,GACtB,CAAC,CAAC,GAAG,EAAE,gBAAgB,KAAK,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC;AAEvD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,+BAA+B,GAC3C,eAAe,uBAAuB,EACtC,iBAAiB,cAAc,CAAC,MAAM,CAAC,KACrC,KAAK,CAAC,eAAe,CAuBvB,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,oBAAoB,GAChC,QAAQ,MAAM,EACd,SAAS,OAAO,EAChB,KAAI,MAAM,GAAG,MAAe,KAC1B,WAQF,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,GAC9B,eAAe,MAAM,EACrB,QAAQ,MAAM,EACd,SAAS,OAAO,EAChB,KAAI,MAAM,GAAG,MAAe,KAC1B,MAMF,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,6BAA6B,GACzC,MAAM,OAAO,EACb,gBAAgB,gBAAgB,KAC9B,IAUF,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,+BAA+B,GAAI,MAAM,OAAO,EAAE,gBAAgB,CAAC,CAAC,OAAO,KAAG,IAW1F,CAAC;AAIF;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAErF,2DAA2D;AAC3D,eAAO,MAAM,cAAc,GACzB,KAAK;IACL,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC;CAC5E,KAAG,gBAEmB,CAAC;AAEzB,yEAAyE;AACzE,MAAM,MAAM,aAAa,GACtB;IAAC,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAC,GAC3C;IACA,EAAE,EAAE,KAAK,CAAC;IACV,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAC,CAAC;CACtD,CAAC;AAEL;;;;GAIG;AACH,MAAM,MAAM,UAAU,GACnB;IAAC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAA;CAAC,GAC7E,gBAAgB,CAAC;AAEpB,gCAAgC;AAChC,MAAM,WAAW,WAAW;IAC3B,yDAAyD;IACzD,GAAG,EAAE,UAAU,CAAC;IAChB,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,wCAAwC;IACxC,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACrB,mFAAmF;IACnF,IAAI,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IACtB;;;;;OAKG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;CAClC;AAcD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,QAAQ,GAAU,MAAM,WAAW,KAAG,OAAO,CAAC,aAAa,CA0DvE,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,GAChC,MAAM,IAAI,CAAC,WAAW,EAAE,yBAAyB,CAAC,KAChD,OAAO,CAAC,aAAa,CAAuD,CAAC;AAEhF;;;;;GAKG;AACH,MAAM,MAAM,oBAAoB,CAAC,KAAK,SAAS,yBAAyB,IACrE;IAAC,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAA;CAAC,GAC5D;IAAC,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAC,CAAA;CAAC,CAAC;AAEvF,mFAAmF;AACnF,MAAM,MAAM,kBAAkB,CAAC,KAAK,SAAS,yBAAyB,IAAI,IAAI,CAC7E,WAAW,EACX,QAAQ,GAAG,QAAQ,CACnB,GAAG;IACH,2GAA2G;IAC3G,IAAI,EAAE,KAAK,CAAC;IACZ,0CAA0C;IAC1C,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;CAChC,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,iBAAiB,GAAU,KAAK,SAAS,yBAAyB,EAC9E,MAAM,kBAAkB,CAAC,KAAK,CAAC,KAC7B,OAAO,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAarC,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,GAAU,CAAC,EACrC,MAAM,WAAW,EACjB,eAAe,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KACzB,OAAO,CAAC,CAAC,CAcX,CAAC;AAIF;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAC3B,eAAe,aAAa,CAAC,eAAe,CAAC,EAC7C,QAAQ,MAAM,KACZ;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,SAAS,CAAA;CAAC,GAAG,SAOtC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAC3B,eAAe,aAAa,CAAC,qBAAqB,CAAC,EACnD,QAAQ,MAAM,KACZ;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,mBAAmB,CAAA;CAAC,GAAG,SAOrD,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,yBAAyB,GACrC,eAAe,aAAa,CAAC,eAAe,CAAC,KAC3C,MAYF,CAAC"}
@@ -172,7 +172,7 @@ export const rpc_call = async (args) => {
172
172
  body: post.body,
173
173
  };
174
174
  }
175
- const res = await app.request(url, init);
175
+ const res = await (typeof app === 'function' ? app(url, init) : app.request(url, init));
176
176
  const status = res.status;
177
177
  const body = await res.json();
178
178
  const success = JsonrpcResponse.safeParse(body);
@@ -1,19 +1,19 @@
1
1
  import './assert_dev_env.js';
2
+ import type { AppSurfaceSpec } from '../http/surface.js';
2
3
  import { type RpcEndpointsSuiteOption } from './rpc_helpers.js';
3
4
  import type { BackendCapabilities } from './cross_backend/capabilities.js';
4
5
  import type { SetupTest } from './cross_backend/setup.js';
5
- import type { SurfaceSource } from './transports/surface_source.js';
6
6
  import type { SessionOptions } from '../auth/session_cookie.js';
7
7
  /** Options for `describe_rpc_round_trip_tests`. */
8
8
  export interface RpcRoundTripTestOptions {
9
9
  /** Per-test fixture-producing function (per-describe cadence). */
10
10
  setup_test: SetupTest;
11
11
  /**
12
- * Source of the app surface for RPC endpoint enumeration. Currently
13
- * requires `kind: 'inline'` the cross-process snapshot variant lands
14
- * alongside the spawned-backend transport plumbing.
12
+ * App surface (with route + RPC endpoint specs) for RPC endpoint
13
+ * enumeration. Constructed in TS by the consumer; same shape for
14
+ * in-process and cross-process tests.
15
15
  */
16
- surface_source: SurfaceSource;
16
+ surface_source: AppSurfaceSpec;
17
17
  /** Backend capability declarations. */
18
18
  capabilities: BackendCapabilities;
19
19
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"rpc_round_trip.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/rpc_round_trip.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AA0B7B,OAAO,EAMN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AAE1B,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;AAClE,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAE9D,mDAAmD;AACnD,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;;;;;OAKG;IACH,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC;;;;;OAKG;IACH,aAAa,EAAE,uBAAuB,CAAC;IACvC,qDAAqD;IACrD,YAAY,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC7B,6EAA6E;IAC7E,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACvD;AA6BD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,6BAA6B,GAAI,SAAS,uBAAuB,KAAG,IAwHhF,CAAC"}
1
+ {"version":3,"file":"rpc_round_trip.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/rpc_round_trip.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAwB7B,OAAO,KAAK,EAAC,cAAc,EAAsB,MAAM,oBAAoB,CAAC;AAE5E,OAAO,EAMN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AAE1B,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,iCAAiC,CAAC;AACzE,OAAO,KAAK,EAAC,SAAS,EAAc,MAAM,0BAA0B,CAAC;AACrE,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAE9D,mDAAmD;AACnD,MAAM,WAAW,uBAAuB;IACvC,kEAAkE;IAClE,UAAU,EAAE,SAAS,CAAC;IACtB;;;;OAIG;IACH,cAAc,EAAE,cAAc,CAAC;IAC/B,uCAAuC;IACvC,YAAY,EAAE,mBAAmB,CAAC;IAClC;;;;;OAKG;IACH,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC;;;;;OAKG;IACH,aAAa,EAAE,uBAAuB,CAAC;IACvC,qDAAqD;IACrD,YAAY,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC7B,6EAA6E;IAC7E,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACvD;AA6BD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,6BAA6B,GAAI,SAAS,uBAAuB,KAAG,IAkHhF,CAAC"}
@@ -56,10 +56,6 @@ const pick_rpc_auth_headers = (method, keeper, authed_account, admin_account) =>
56
56
  * `action.spec.output`.
57
57
  */
58
58
  export const describe_rpc_round_trip_tests = (options) => {
59
- if (options.surface_source.kind !== 'inline') {
60
- throw new Error("describe_rpc_round_trip_tests requires surface_source.kind === 'inline' — " +
61
- 'the cross-process snapshot variant lands with the spawned-backend transport');
62
- }
63
59
  const skip_set = new Set(options.skip_methods);
64
60
  // Resolve factory-form endpoints once for setup-time iteration (method
65
61
  // enumeration, surface lookup). The live dispatcher runs against
@@ -67,7 +63,7 @@ export const describe_rpc_round_trip_tests = (options) => {
67
63
  // `.input` / `.output` are ctx-independent, so the stub-resolved specs
68
64
  // match what the running backend serves.
69
65
  const rpc_endpoints_for_setup = resolve_rpc_endpoints_for_setup(options.rpc_endpoints, options.session_options);
70
- const surface_rpc_endpoints = options.surface_source.spec.surface.rpc_endpoints;
66
+ const surface_rpc_endpoints = options.surface_source.surface.rpc_endpoints;
71
67
  void options.capabilities;
72
68
  describe('RPC round-trip validation', () => {
73
69
  let fixture;