@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.
- package/dist/actions/CLAUDE.md +65 -86
- package/dist/actions/action_codegen.d.ts +1 -1
- package/dist/actions/action_codegen.js +1 -1
- package/dist/actions/action_event_data.d.ts +1 -1
- package/dist/auth/CLAUDE.md +83 -104
- package/dist/auth/audit_log_schema.js +2 -2
- package/dist/auth/daemon_token_middleware.d.ts +15 -5
- package/dist/auth/daemon_token_middleware.d.ts.map +1 -1
- package/dist/auth/daemon_token_middleware.js +24 -15
- package/dist/auth/invite_queries.d.ts +17 -7
- package/dist/auth/invite_queries.d.ts.map +1 -1
- package/dist/auth/invite_queries.js +19 -8
- package/dist/auth/signup_routes.d.ts +47 -1
- package/dist/auth/signup_routes.d.ts.map +1 -1
- package/dist/auth/signup_routes.js +103 -52
- package/dist/env/resolve.d.ts +44 -7
- package/dist/env/resolve.d.ts.map +1 -1
- package/dist/env/resolve.js +94 -27
- package/dist/http/CLAUDE.md +47 -52
- package/dist/http/jsonrpc.d.ts +23 -7
- package/dist/http/jsonrpc.d.ts.map +1 -1
- package/dist/http/jsonrpc.js +19 -3
- package/dist/http/surface.d.ts +9 -2
- package/dist/http/surface.d.ts.map +1 -1
- package/dist/runtime/mock.d.ts +1 -1
- package/dist/runtime/mock.js +1 -1
- package/dist/testing/CLAUDE.md +659 -511
- package/dist/testing/admin_integration.d.ts +5 -5
- package/dist/testing/admin_integration.d.ts.map +1 -1
- package/dist/testing/admin_integration.js +95 -39
- package/dist/testing/app_server.d.ts +16 -1
- package/dist/testing/app_server.d.ts.map +1 -1
- package/dist/testing/app_server.js +18 -3
- package/dist/testing/audit_completeness.d.ts +7 -5
- package/dist/testing/audit_completeness.d.ts.map +1 -1
- package/dist/testing/audit_completeness.js +5 -9
- package/dist/testing/bootstrap_success.js +2 -2
- package/dist/testing/cross_backend/backend_config.d.ts +113 -0
- package/dist/testing/cross_backend/backend_config.d.ts.map +1 -0
- package/dist/testing/cross_backend/backend_config.js +1 -0
- package/dist/testing/cross_backend/bench/bench_report.d.ts +46 -0
- package/dist/testing/cross_backend/bench/bench_report.d.ts.map +1 -0
- package/dist/testing/cross_backend/bench/bench_report.js +83 -0
- package/dist/testing/cross_backend/bench/run_cross_impl_bench.d.ts +44 -0
- package/dist/testing/cross_backend/bench/run_cross_impl_bench.d.ts.map +1 -0
- package/dist/testing/cross_backend/bench/run_cross_impl_bench.js +38 -0
- package/dist/testing/cross_backend/bench/scenario.d.ts +57 -0
- package/dist/testing/cross_backend/bench/scenario.d.ts.map +1 -0
- package/dist/testing/cross_backend/bench/scenario.js +28 -0
- package/dist/testing/cross_backend/bootstrap_backend.d.ts +41 -0
- package/dist/testing/cross_backend/bootstrap_backend.d.ts.map +1 -0
- package/dist/testing/cross_backend/bootstrap_backend.js +34 -0
- package/dist/testing/cross_backend/build_test_backend_paths.d.ts +24 -0
- package/dist/testing/cross_backend/build_test_backend_paths.d.ts.map +1 -0
- package/dist/testing/cross_backend/build_test_backend_paths.js +33 -0
- package/dist/testing/cross_backend/capabilities.d.ts +3 -2
- package/dist/testing/cross_backend/capabilities.d.ts.map +1 -1
- package/dist/testing/cross_backend/default_backend_configs.d.ts +122 -0
- package/dist/testing/cross_backend/default_backend_configs.d.ts.map +1 -0
- package/dist/testing/cross_backend/default_backend_configs.js +111 -0
- package/dist/testing/cross_backend/default_secrets.d.ts +40 -0
- package/dist/testing/cross_backend/default_secrets.d.ts.map +1 -0
- package/dist/testing/cross_backend/default_secrets.js +39 -0
- package/dist/testing/cross_backend/default_spine_surface.d.ts +64 -0
- package/dist/testing/cross_backend/default_spine_surface.d.ts.map +1 -0
- package/dist/testing/cross_backend/default_spine_surface.js +121 -0
- package/dist/testing/cross_backend/setup.d.ts +270 -34
- package/dist/testing/cross_backend/setup.d.ts.map +1 -1
- package/dist/testing/cross_backend/setup.js +495 -15
- package/dist/testing/cross_backend/spawn_backend.d.ts +58 -0
- package/dist/testing/cross_backend/spawn_backend.d.ts.map +1 -0
- package/dist/testing/cross_backend/spawn_backend.js +229 -0
- package/dist/testing/cross_backend/spine_stub_backend_config.d.ts +66 -0
- package/dist/testing/cross_backend/spine_stub_backend_config.d.ts.map +1 -0
- package/dist/testing/cross_backend/spine_stub_backend_config.js +49 -0
- package/dist/testing/cross_backend/sse_round_trip.d.ts +37 -0
- package/dist/testing/cross_backend/sse_round_trip.d.ts.map +1 -0
- package/dist/testing/cross_backend/sse_round_trip.js +137 -0
- package/dist/testing/cross_backend/standard.d.ts +96 -0
- package/dist/testing/cross_backend/standard.d.ts.map +1 -0
- package/dist/testing/cross_backend/standard.js +49 -0
- package/dist/testing/cross_backend/testing_reset_actions.d.ts +171 -0
- package/dist/testing/cross_backend/testing_reset_actions.d.ts.map +1 -0
- package/dist/testing/cross_backend/testing_reset_actions.js +213 -0
- package/dist/testing/cross_backend/testing_server_bun.d.ts +5 -0
- package/dist/testing/cross_backend/testing_server_bun.d.ts.map +1 -0
- package/dist/testing/cross_backend/testing_server_bun.js +59 -0
- package/dist/testing/cross_backend/testing_server_core.d.ts +140 -0
- package/dist/testing/cross_backend/testing_server_core.d.ts.map +1 -0
- package/dist/testing/cross_backend/testing_server_core.js +68 -0
- package/dist/testing/cross_backend/testing_server_deno.d.ts +5 -0
- package/dist/testing/cross_backend/testing_server_deno.d.ts.map +1 -0
- package/dist/testing/cross_backend/testing_server_deno.js +37 -0
- package/dist/testing/cross_backend/testing_server_node.d.ts +5 -0
- package/dist/testing/cross_backend/testing_server_node.d.ts.map +1 -0
- package/dist/testing/cross_backend/testing_server_node.js +50 -0
- package/dist/testing/cross_backend/ts_spine_backend_config.d.ts +72 -0
- package/dist/testing/cross_backend/ts_spine_backend_config.d.ts.map +1 -0
- package/dist/testing/cross_backend/ts_spine_backend_config.js +112 -0
- package/dist/testing/cross_backend/ws_round_trip.d.ts +35 -0
- package/dist/testing/cross_backend/ws_round_trip.d.ts.map +1 -0
- package/dist/testing/cross_backend/ws_round_trip.js +113 -0
- package/dist/testing/data_exposure.d.ts +4 -6
- package/dist/testing/data_exposure.d.ts.map +1 -1
- package/dist/testing/data_exposure.js +1 -5
- package/dist/testing/db_entities.d.ts +18 -7
- package/dist/testing/db_entities.d.ts.map +1 -1
- package/dist/testing/db_entities.js +18 -7
- package/dist/testing/integration.d.ts +27 -6
- package/dist/testing/integration.d.ts.map +1 -1
- package/dist/testing/integration.js +93 -58
- package/dist/testing/round_trip.d.ts +4 -5
- package/dist/testing/round_trip.d.ts.map +1 -1
- package/dist/testing/round_trip.js +1 -5
- package/dist/testing/rpc_helpers.d.ts +10 -4
- package/dist/testing/rpc_helpers.d.ts.map +1 -1
- package/dist/testing/rpc_helpers.js +1 -1
- package/dist/testing/rpc_round_trip.d.ts +5 -5
- package/dist/testing/rpc_round_trip.d.ts.map +1 -1
- package/dist/testing/rpc_round_trip.js +1 -5
- package/dist/testing/sse_round_trip.d.ts.map +1 -1
- package/dist/testing/sse_round_trip.js +1 -68
- package/dist/testing/standard.d.ts +4 -5
- package/dist/testing/standard.d.ts.map +1 -1
- package/dist/testing/stubs.d.ts +10 -3
- package/dist/testing/stubs.d.ts.map +1 -1
- package/dist/testing/stubs.js +9 -2
- package/dist/testing/testing_rate_limiter.d.ts +59 -0
- package/dist/testing/testing_rate_limiter.d.ts.map +1 -0
- package/dist/testing/testing_rate_limiter.js +74 -0
- package/dist/testing/transports/bootstrap.d.ts +52 -0
- package/dist/testing/transports/bootstrap.d.ts.map +1 -0
- package/dist/testing/transports/bootstrap.js +70 -0
- package/dist/testing/transports/fetch_transport.d.ts +81 -0
- package/dist/testing/transports/fetch_transport.d.ts.map +1 -0
- package/dist/testing/transports/fetch_transport.js +74 -0
- package/dist/testing/transports/sse_frame_reader.d.ts +41 -0
- package/dist/testing/transports/sse_frame_reader.d.ts.map +1 -0
- package/dist/testing/transports/sse_frame_reader.js +84 -0
- package/dist/testing/transports/sse_transport.d.ts +54 -0
- package/dist/testing/transports/sse_transport.d.ts.map +1 -0
- package/dist/testing/transports/sse_transport.js +51 -0
- package/dist/testing/transports/ws_client.d.ts +108 -0
- package/dist/testing/transports/ws_client.d.ts.map +1 -0
- package/dist/testing/transports/ws_client.js +56 -0
- package/dist/testing/transports/ws_transport.d.ts +43 -0
- package/dist/testing/transports/ws_transport.d.ts.map +1 -0
- package/dist/testing/transports/ws_transport.js +169 -0
- package/dist/testing/ws_round_trip.d.ts +21 -103
- package/dist/testing/ws_round_trip.d.ts.map +1 -1
- package/dist/testing/ws_round_trip.js +42 -40
- package/dist/ui/CLAUDE.md +5 -3
- package/dist/ui/MenuLink.svelte +16 -16
- package/dist/ui/MenuLink.svelte.d.ts +13 -4
- package/dist/ui/MenuLink.svelte.d.ts.map +1 -1
- package/package.json +20 -3
- package/dist/testing/transports/surface_source.d.ts +0 -51
- package/dist/testing/transports/surface_source.d.ts.map +0 -1
- 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 {
|
|
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
|
-
*
|
|
19
|
-
* scoping.
|
|
20
|
-
*
|
|
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:
|
|
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,
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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.
|
|
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
|
-
|
|
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
|
|
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:
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
|
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.
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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.
|
|
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.
|
|
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:
|
|
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
|
-
//
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
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:
|
|
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
|
-
//
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
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 {
|
|
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
|
-
*
|
|
16
|
-
*
|
|
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:
|
|
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,
|
|
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
|
-
|
|
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
|
|
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
|
|
1
|
+
{"version":3,"file":"rpc_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/rpc_helpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -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
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
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:
|
|
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;
|
|
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.
|
|
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;
|