@fuzdev/fuz_app 0.63.0 → 0.65.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 +525 -827
- package/dist/actions/broadcast_api.d.ts +1 -1
- package/dist/actions/broadcast_api.js +1 -1
- package/dist/actions/cancel.d.ts +2 -2
- package/dist/actions/cancel.js +3 -3
- package/dist/actions/connection_closer.d.ts +65 -0
- package/dist/actions/connection_closer.d.ts.map +1 -0
- package/dist/actions/connection_closer.js +38 -0
- package/dist/actions/register_action_ws.d.ts +2 -2
- package/dist/actions/register_action_ws.d.ts.map +1 -1
- package/dist/actions/register_action_ws.js +23 -2
- package/dist/actions/register_ws_endpoint.d.ts +12 -10
- package/dist/actions/register_ws_endpoint.d.ts.map +1 -1
- package/dist/actions/register_ws_endpoint.js +5 -5
- package/dist/actions/transports_ws_auth_guard.d.ts +25 -10
- package/dist/actions/transports_ws_auth_guard.d.ts.map +1 -1
- package/dist/actions/transports_ws_auth_guard.js +24 -9
- package/dist/actions/ws_endpoint_spec.d.ts +119 -0
- package/dist/actions/ws_endpoint_spec.d.ts.map +1 -0
- package/dist/actions/ws_endpoint_spec.js +13 -0
- package/dist/auth/CLAUDE.md +592 -1808
- package/dist/auth/account_action_specs.d.ts +1 -1
- package/dist/auth/account_actions.d.ts +13 -0
- package/dist/auth/account_actions.d.ts.map +1 -1
- package/dist/auth/account_actions.js +31 -1
- package/dist/auth/account_routes.d.ts +12 -2
- package/dist/auth/account_routes.d.ts.map +1 -1
- package/dist/auth/account_routes.js +55 -8
- package/dist/auth/account_schema.d.ts +4 -4
- package/dist/auth/account_schema.d.ts.map +1 -1
- package/dist/auth/admin_action_specs.d.ts +8 -8
- package/dist/auth/admin_actions.d.ts +11 -0
- package/dist/auth/admin_actions.d.ts.map +1 -1
- package/dist/auth/admin_actions.js +25 -0
- package/dist/auth/api_token_queries.js +1 -1
- package/dist/auth/audit_emitter.d.ts +56 -12
- package/dist/auth/audit_emitter.d.ts.map +1 -1
- package/dist/auth/audit_emitter.js +38 -12
- package/dist/auth/audit_log_ddl.d.ts +1 -1
- package/dist/auth/audit_log_ddl.d.ts.map +1 -1
- package/dist/auth/audit_log_ddl.js +1 -1
- package/dist/auth/audit_log_schema.d.ts +5 -3
- package/dist/auth/audit_log_schema.d.ts.map +1 -1
- package/dist/auth/audit_log_schema.js +5 -3
- package/dist/auth/bootstrap_account.d.ts.map +1 -1
- package/dist/auth/bootstrap_account.js +1 -5
- package/dist/auth/bootstrap_routes.d.ts +8 -2
- package/dist/auth/bootstrap_routes.d.ts.map +1 -1
- package/dist/auth/bootstrap_routes.js +15 -11
- package/dist/auth/invite_schema.d.ts +2 -2
- package/dist/auth/keyring.d.ts +6 -6
- package/dist/auth/keyring.js +8 -8
- package/dist/auth/role_grant_offer_actions.d.ts.map +1 -1
- package/dist/auth/role_grant_offer_actions.js +4 -2
- package/dist/auth/signup_routes.d.ts +1 -1
- package/dist/auth/standard_rpc_actions.d.ts +1 -0
- package/dist/auth/standard_rpc_actions.d.ts.map +1 -1
- package/dist/auth/standard_rpc_actions.js +1 -0
- package/dist/db/create_db.d.ts.map +1 -1
- package/dist/db/create_db.js +13 -0
- package/dist/dev/setup.d.ts +2 -2
- package/dist/dev/setup.js +3 -3
- package/dist/http/CLAUDE.md +225 -483
- package/dist/http/error_schemas.d.ts +0 -4
- package/dist/http/error_schemas.d.ts.map +1 -1
- package/dist/http/error_schemas.js +0 -4
- package/dist/http/ip_canonical.d.ts +100 -0
- package/dist/http/ip_canonical.d.ts.map +1 -0
- package/dist/http/ip_canonical.js +195 -0
- package/dist/http/origin.d.ts +14 -6
- package/dist/http/origin.d.ts.map +1 -1
- package/dist/http/origin.js +14 -32
- package/dist/http/pending_effects.d.ts +1 -1
- package/dist/http/pending_effects.js +1 -1
- package/dist/http/proxy.d.ts +13 -5
- package/dist/http/proxy.d.ts.map +1 -1
- package/dist/http/proxy.js +15 -23
- package/dist/http/surface.d.ts +50 -0
- package/dist/http/surface.d.ts.map +1 -1
- package/dist/http/surface.js +27 -1
- package/dist/primitive_schemas.d.ts +20 -4
- package/dist/primitive_schemas.d.ts.map +1 -1
- package/dist/primitive_schemas.js +25 -4
- package/dist/realtime/sse_auth_guard.d.ts +16 -4
- package/dist/realtime/sse_auth_guard.d.ts.map +1 -1
- package/dist/realtime/sse_auth_guard.js +15 -3
- package/dist/runtime/mock.js +1 -1
- package/dist/server/app_backend.d.ts +66 -19
- package/dist/server/app_backend.d.ts.map +1 -1
- package/dist/server/app_backend.js +57 -34
- package/dist/server/app_server.d.ts +101 -10
- package/dist/server/app_server.d.ts.map +1 -1
- package/dist/server/app_server.js +105 -6
- package/dist/server/env.d.ts +7 -7
- package/dist/server/env.d.ts.map +1 -1
- package/dist/server/env.js +14 -14
- package/dist/server/startup.d.ts.map +1 -1
- package/dist/server/startup.js +12 -0
- package/dist/server/static.d.ts +4 -4
- package/dist/server/static.js +7 -7
- package/dist/testing/CLAUDE.md +269 -59
- package/dist/testing/admin_integration.d.ts +18 -23
- package/dist/testing/admin_integration.d.ts.map +1 -1
- package/dist/testing/admin_integration.js +159 -202
- package/dist/testing/adversarial_headers.d.ts +6 -0
- package/dist/testing/adversarial_headers.d.ts.map +1 -1
- package/dist/testing/adversarial_headers.js +13 -5
- package/dist/testing/app_server.d.ts +148 -60
- package/dist/testing/app_server.d.ts.map +1 -1
- package/dist/testing/app_server.js +143 -54
- package/dist/testing/attack_surface.d.ts +8 -7
- package/dist/testing/attack_surface.d.ts.map +1 -1
- package/dist/testing/attack_surface.js +12 -8
- package/dist/testing/audit_completeness.d.ts +23 -22
- package/dist/testing/audit_completeness.d.ts.map +1 -1
- package/dist/testing/audit_completeness.js +199 -158
- package/dist/testing/audit_drift_guard.d.ts +116 -0
- package/dist/testing/audit_drift_guard.d.ts.map +1 -0
- package/dist/testing/audit_drift_guard.js +134 -0
- package/dist/testing/bootstrap_success.d.ts +28 -0
- package/dist/testing/bootstrap_success.d.ts.map +1 -0
- package/dist/testing/bootstrap_success.js +144 -0
- package/dist/testing/connection_closer_helpers.d.ts +44 -0
- package/dist/testing/connection_closer_helpers.d.ts.map +1 -0
- package/dist/testing/connection_closer_helpers.js +48 -0
- package/dist/testing/cross_backend/capabilities.d.ts +64 -0
- package/dist/testing/cross_backend/capabilities.d.ts.map +1 -0
- package/dist/testing/cross_backend/capabilities.js +47 -0
- package/dist/testing/cross_backend/setup.d.ts +215 -0
- package/dist/testing/cross_backend/setup.d.ts.map +1 -0
- package/dist/testing/cross_backend/setup.js +101 -0
- package/dist/testing/data_exposure.d.ts +14 -15
- package/dist/testing/data_exposure.d.ts.map +1 -1
- package/dist/testing/data_exposure.js +127 -146
- package/dist/testing/db_entities.d.ts +11 -1
- package/dist/testing/db_entities.d.ts.map +1 -1
- package/dist/testing/db_entities.js +13 -1
- package/dist/testing/integration.d.ts +35 -21
- package/dist/testing/integration.d.ts.map +1 -1
- package/dist/testing/integration.js +231 -293
- package/dist/testing/integration_helpers.d.ts +16 -6
- package/dist/testing/integration_helpers.d.ts.map +1 -1
- package/dist/testing/integration_helpers.js +7 -7
- package/dist/testing/mock_fs.d.ts.map +1 -1
- package/dist/testing/mock_fs.js +0 -2
- package/dist/testing/rate_limiting.d.ts.map +1 -1
- package/dist/testing/rate_limiting.js +13 -4
- package/dist/testing/role_grant_helpers.d.ts +31 -0
- package/dist/testing/role_grant_helpers.d.ts.map +1 -0
- package/dist/testing/role_grant_helpers.js +46 -0
- package/dist/testing/round_trip.d.ts +21 -16
- package/dist/testing/round_trip.d.ts.map +1 -1
- package/dist/testing/round_trip.js +65 -86
- package/dist/testing/rpc_helpers.d.ts +2 -1
- package/dist/testing/rpc_helpers.d.ts.map +1 -1
- package/dist/testing/rpc_round_trip.d.ts +24 -21
- package/dist/testing/rpc_round_trip.d.ts.map +1 -1
- package/dist/testing/rpc_round_trip.js +91 -106
- package/dist/testing/schema_introspect.d.ts +106 -0
- package/dist/testing/schema_introspect.d.ts.map +1 -0
- package/dist/testing/schema_introspect.js +123 -0
- package/dist/testing/schema_parity.d.ts +144 -0
- package/dist/testing/schema_parity.d.ts.map +1 -0
- package/dist/testing/schema_parity.js +233 -0
- package/dist/testing/sse_round_trip.d.ts.map +1 -1
- package/dist/testing/sse_round_trip.js +12 -6
- package/dist/testing/standard.d.ts +57 -25
- package/dist/testing/standard.d.ts.map +1 -1
- package/dist/testing/standard.js +62 -5
- package/dist/testing/stubs.d.ts +22 -3
- package/dist/testing/stubs.d.ts.map +1 -1
- package/dist/testing/stubs.js +28 -21
- package/dist/testing/surface_invariants.d.ts +66 -1
- package/dist/testing/surface_invariants.d.ts.map +1 -1
- package/dist/testing/surface_invariants.js +103 -1
- package/dist/testing/transports/surface_source.d.ts +51 -0
- package/dist/testing/transports/surface_source.d.ts.map +1 -0
- package/dist/testing/transports/surface_source.js +19 -0
- package/dist/ui/SurfaceExplorer.svelte +161 -2
- package/dist/ui/SurfaceExplorer.svelte.d.ts.map +1 -1
- package/package.json +4 -4
|
@@ -2,7 +2,7 @@ import './assert_dev_env.js';
|
|
|
2
2
|
import type { RouteSpec, RouteMethod } from '../http/route_spec.js';
|
|
3
3
|
import type { Keyring } from '../auth/keyring.js';
|
|
4
4
|
import { type SessionOptions } from '../auth/session_cookie.js';
|
|
5
|
-
import type {
|
|
5
|
+
import type { TestAccount } from './app_server.js';
|
|
6
6
|
/**
|
|
7
7
|
* Find a route spec matching the given method and path.
|
|
8
8
|
*
|
|
@@ -24,8 +24,8 @@ export type RestAuthRouteSuffix = (typeof rest_auth_route_suffixes)[number];
|
|
|
24
24
|
*
|
|
25
25
|
* Decouples tests from consumer route prefix (`/api/account/login`,
|
|
26
26
|
* `/api/auth/login`, etc.). `suffix` must be one of
|
|
27
|
-
* `rest_auth_route_suffixes` — throws otherwise so
|
|
28
|
-
*
|
|
27
|
+
* `rest_auth_route_suffixes` — throws otherwise so an RPC-only method
|
|
28
|
+
* path (e.g. `/sessions/revoke-all`) fails loudly at the call site
|
|
29
29
|
* instead of silently returning `undefined`.
|
|
30
30
|
*
|
|
31
31
|
* @throws Error if `suffix` is not in `rest_auth_route_suffixes`.
|
|
@@ -89,6 +89,16 @@ export declare const collect_json_keys_recursive: (value: unknown) => Set<string
|
|
|
89
89
|
* @param context - description for error messages
|
|
90
90
|
*/
|
|
91
91
|
export declare const assert_no_sensitive_fields_in_json: (body: unknown, blocklist: ReadonlyArray<string>, context: string) => void;
|
|
92
|
+
/**
|
|
93
|
+
* Header-builder triple shared by `TestApp` (in-process) and `TestFixture`
|
|
94
|
+
* (cross-backend fixture protocol). Both satisfy this shape structurally —
|
|
95
|
+
* `pick_auth_headers` accepts either without a cast.
|
|
96
|
+
*/
|
|
97
|
+
export interface KeeperHeaderProvider {
|
|
98
|
+
create_session_headers: (extra?: Record<string, string>) => Record<string, string>;
|
|
99
|
+
create_bearer_headers: (extra?: Record<string, string>) => Record<string, string>;
|
|
100
|
+
create_daemon_token_headers: (extra?: Record<string, string>) => Record<string, string>;
|
|
101
|
+
}
|
|
92
102
|
/**
|
|
93
103
|
* Pick request headers matching a route spec's auth requirement.
|
|
94
104
|
*
|
|
@@ -96,8 +106,8 @@ export declare const assert_no_sensitive_fields_in_json: (body: unknown, blockli
|
|
|
96
106
|
* - `none` — origin headers only
|
|
97
107
|
* - `authenticated` — the authed account's session cookie
|
|
98
108
|
* - `role: admin` — the admin account's session cookie
|
|
99
|
-
* - `role: <other>` — the
|
|
100
|
-
* - `keeper` — the
|
|
109
|
+
* - `role: <other>` — the keeper provider's session
|
|
110
|
+
* - `keeper` — the keeper provider's daemon token
|
|
101
111
|
*/
|
|
102
|
-
export declare const pick_auth_headers: (spec: RouteSpec,
|
|
112
|
+
export declare const pick_auth_headers: (spec: RouteSpec, keeper: KeeperHeaderProvider, authed_account: TestAccount, admin_account: TestAccount) => Record<string, string>;
|
|
103
113
|
//# sourceMappingURL=integration_helpers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"integration_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/integration_helpers.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAU7B,OAAO,KAAK,EAAC,SAAS,EAAE,WAAW,EAAC,MAAM,uBAAuB,CAAC;AAGlE,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAA8B,KAAK,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAE3F,OAAO,KAAK,EAAC,
|
|
1
|
+
{"version":3,"file":"integration_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/integration_helpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -51,8 +51,8 @@ export const rest_auth_route_suffixes = [
|
|
|
51
51
|
*
|
|
52
52
|
* Decouples tests from consumer route prefix (`/api/account/login`,
|
|
53
53
|
* `/api/auth/login`, etc.). `suffix` must be one of
|
|
54
|
-
* `rest_auth_route_suffixes` — throws otherwise so
|
|
55
|
-
*
|
|
54
|
+
* `rest_auth_route_suffixes` — throws otherwise so an RPC-only method
|
|
55
|
+
* path (e.g. `/sessions/revoke-all`) fails loudly at the call site
|
|
56
56
|
* instead of silently returning `undefined`.
|
|
57
57
|
*
|
|
58
58
|
* @throws Error if `suffix` is not in `rest_auth_route_suffixes`.
|
|
@@ -251,22 +251,22 @@ export const assert_no_sensitive_fields_in_json = (body, blocklist, context) =>
|
|
|
251
251
|
* - `none` — origin headers only
|
|
252
252
|
* - `authenticated` — the authed account's session cookie
|
|
253
253
|
* - `role: admin` — the admin account's session cookie
|
|
254
|
-
* - `role: <other>` — the
|
|
255
|
-
* - `keeper` — the
|
|
254
|
+
* - `role: <other>` — the keeper provider's session
|
|
255
|
+
* - `keeper` — the keeper provider's daemon token
|
|
256
256
|
*/
|
|
257
|
-
export const pick_auth_headers = (spec,
|
|
257
|
+
export const pick_auth_headers = (spec, keeper, authed_account, admin_account) => {
|
|
258
258
|
const { auth } = spec;
|
|
259
259
|
if (is_public_auth(auth)) {
|
|
260
260
|
return { host: 'localhost', origin: 'http://localhost:5173' };
|
|
261
261
|
}
|
|
262
262
|
if (auth.credential_types?.includes('daemon_token')) {
|
|
263
|
-
return
|
|
263
|
+
return keeper.create_daemon_token_headers();
|
|
264
264
|
}
|
|
265
265
|
if (auth.roles?.length) {
|
|
266
266
|
if (auth.roles.includes(ROLE_ADMIN)) {
|
|
267
267
|
return admin_account.create_session_headers();
|
|
268
268
|
}
|
|
269
|
-
return
|
|
269
|
+
return keeper.create_session_headers();
|
|
270
270
|
}
|
|
271
271
|
return authed_account.create_session_headers();
|
|
272
272
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mock_fs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/mock_fs.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,MAAM;IACtB,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/D,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/E,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;CAC/C;AAED;;;;;GAKG;AACH,eAAO,MAAM,cAAc,GAAI,gBAAe,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,KAAG,
|
|
1
|
+
{"version":3,"file":"mock_fs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/mock_fs.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,MAAM;IACtB,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/D,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/E,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;CAC/C;AAED;;;;;GAKG;AACH,eAAO,MAAM,cAAc,GAAI,gBAAe,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,KAAG,MAsB3E,CAAC"}
|
package/dist/testing/mock_fs.js
CHANGED
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
export const create_mock_fs = (initial_files = {}) => {
|
|
14
14
|
const files = { ...initial_files };
|
|
15
15
|
return {
|
|
16
|
-
// eslint-disable-next-line @typescript-eslint/require-await
|
|
17
16
|
read_file: async (path, _encoding) => {
|
|
18
17
|
if (!(path in files)) {
|
|
19
18
|
const error = new Error(`ENOENT: no such file or directory, open '${path}'`);
|
|
@@ -26,7 +25,6 @@ export const create_mock_fs = (initial_files = {}) => {
|
|
|
26
25
|
}
|
|
27
26
|
return file_content;
|
|
28
27
|
},
|
|
29
|
-
// eslint-disable-next-line @typescript-eslint/require-await
|
|
30
28
|
write_file: async (path, content, _encoding) => {
|
|
31
29
|
files[path] = content;
|
|
32
30
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rate_limiting.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/rate_limiting.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"rate_limiting.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/rate_limiting.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AA0B7B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAIrD,OAAO,EAAkB,KAAK,eAAe,EAAC,MAAM,iBAAiB,CAAC;AACtE,OAAO,EAIN,KAAK,SAAS,EACd,MAAM,SAAS,CAAC;AAEjB,OAAO,EAIN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AAK1B;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACvC,4CAA4C;IAC5C,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,wDAAwD;IACxD,kBAAkB,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,KAAK,CAAC,SAAS,CAAC,CAAC;IAChE,iDAAiD;IACjD,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B;;OAEG;IACH,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAChC;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;;;;;;;;OAYG;IACH,aAAa,EAAE,uBAAuB,CAAC;CACvC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,4BAA4B,GAAI,SAAS,uBAAuB,KAAG,IA8P/E,CAAC"}
|
|
@@ -9,6 +9,15 @@ import './assert_dev_env.js';
|
|
|
9
9
|
* Consumers call `describe_rate_limiting_tests` with their route factory and
|
|
10
10
|
* session config — rate limit enforcement tests come for free.
|
|
11
11
|
*
|
|
12
|
+
* Each test body constructs its own `TestApp` with a per-test rate limiter
|
|
13
|
+
* override in `app_options`, so this suite reads its inputs directly from
|
|
14
|
+
* the options bag instead of going through the per-test fixture protocol —
|
|
15
|
+
* the single-fixture model can't carry three different rate-limiter
|
|
16
|
+
* configurations. Consumers pass `default_in_process_suite_options(...)`
|
|
17
|
+
* anyway for shape uniformity with the other Tier 1 suites; the extra
|
|
18
|
+
* `{setup_test, surface_source, capabilities}` fields from the helper
|
|
19
|
+
* spread are ignored by TS and the suite body alike.
|
|
20
|
+
*
|
|
12
21
|
* @module
|
|
13
22
|
*/
|
|
14
23
|
import { describe, test, assert } from 'vitest';
|
|
@@ -44,7 +53,7 @@ export const describe_rate_limiting_tests = (options) => {
|
|
|
44
53
|
// Hard-fail early so consumers see a clear setup error instead of a
|
|
45
54
|
// confusing test failure when `rpc_endpoints` is missing. Factory-form
|
|
46
55
|
// callers are resolved with a stub ctx purely to extract the endpoint
|
|
47
|
-
// path; real handlers run per-test via `
|
|
56
|
+
// path; real handlers run per-test via the top-level `rpc_endpoints` slot on `CreateTestAppOptions`.
|
|
48
57
|
const rpc_endpoints_for_setup = resolve_rpc_endpoints_for_setup(options.rpc_endpoints, options.session_options);
|
|
49
58
|
const rpc_path = require_rpc_endpoint_path(rpc_endpoints_for_setup);
|
|
50
59
|
const init_schema = async (db) => {
|
|
@@ -64,9 +73,9 @@ export const describe_rate_limiting_tests = (options) => {
|
|
|
64
73
|
session_options: options.session_options,
|
|
65
74
|
create_route_specs: options.create_route_specs,
|
|
66
75
|
db: get_db(),
|
|
76
|
+
rpc_endpoints: options.rpc_endpoints,
|
|
67
77
|
app_options: {
|
|
68
78
|
...options.app_options,
|
|
69
|
-
rpc_endpoints: options.rpc_endpoints,
|
|
70
79
|
ip_rate_limiter,
|
|
71
80
|
login_account_rate_limiter: null,
|
|
72
81
|
bearer_ip_rate_limiter: null,
|
|
@@ -117,9 +126,9 @@ export const describe_rate_limiting_tests = (options) => {
|
|
|
117
126
|
session_options: options.session_options,
|
|
118
127
|
create_route_specs: options.create_route_specs,
|
|
119
128
|
db: get_db(),
|
|
129
|
+
rpc_endpoints: options.rpc_endpoints,
|
|
120
130
|
app_options: {
|
|
121
131
|
...options.app_options,
|
|
122
|
-
rpc_endpoints: options.rpc_endpoints,
|
|
123
132
|
ip_rate_limiter: null,
|
|
124
133
|
login_account_rate_limiter,
|
|
125
134
|
bearer_ip_rate_limiter: null,
|
|
@@ -182,9 +191,9 @@ export const describe_rate_limiting_tests = (options) => {
|
|
|
182
191
|
session_options: options.session_options,
|
|
183
192
|
create_route_specs: options.create_route_specs,
|
|
184
193
|
db: get_db(),
|
|
194
|
+
rpc_endpoints: options.rpc_endpoints,
|
|
185
195
|
app_options: {
|
|
186
196
|
...options.app_options,
|
|
187
|
-
rpc_endpoints: options.rpc_endpoints,
|
|
188
197
|
ip_rate_limiter: null,
|
|
189
198
|
login_account_rate_limiter: null,
|
|
190
199
|
bearer_ip_rate_limiter,
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import './assert_dev_env.js';
|
|
2
|
+
import type { Uuid } from '@fuzdev/fuz_util/id.js';
|
|
3
|
+
import type { TestAccount, TestApp } from './app_server.js';
|
|
4
|
+
import type { TestFixture } from './cross_backend/setup.js';
|
|
5
|
+
import { type RpcCallArgs } from './rpc_helpers.js';
|
|
6
|
+
export interface RoleGrantOfferAndAcceptArgs {
|
|
7
|
+
app: RpcCallArgs['app'];
|
|
8
|
+
rpc_path: string;
|
|
9
|
+
/**
|
|
10
|
+
* Account doing the granting. `TestApp` / `TestAccount` cover the
|
|
11
|
+
* in-process shape; `TestFixture` covers the cross-backend fixture
|
|
12
|
+
* protocol. All three carry `account.id` + `create_session_headers`.
|
|
13
|
+
*/
|
|
14
|
+
grantor: TestApp | TestAccount | TestFixture;
|
|
15
|
+
recipient: TestAccount;
|
|
16
|
+
role: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Drive the full consent flow (grantor offer → recipient accept) over the
|
|
20
|
+
* production RPC surface and return the materialized role_grant id.
|
|
21
|
+
*
|
|
22
|
+
* `grantor` and `recipient` carry both the account id (for `to_account_id`
|
|
23
|
+
* derivation) and the `create_session_headers` factory (for cookie-threaded
|
|
24
|
+
* auth) — closing that loop on a single object per party rules out
|
|
25
|
+
* caller-side header/account mismatch.
|
|
26
|
+
*/
|
|
27
|
+
export declare const role_grant_offer_and_accept: (args: RoleGrantOfferAndAcceptArgs) => Promise<{
|
|
28
|
+
offer_id: Uuid;
|
|
29
|
+
role_grant_id: Uuid;
|
|
30
|
+
}>;
|
|
31
|
+
//# sourceMappingURL=role_grant_helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"role_grant_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/role_grant_helpers.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAiB7B,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,wBAAwB,CAAC;AAMjD,OAAO,KAAK,EAAC,WAAW,EAAE,OAAO,EAAC,MAAM,iBAAiB,CAAC;AAC1D,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAoB,KAAK,WAAW,EAAC,MAAM,kBAAkB,CAAC;AAErE,MAAM,WAAW,2BAA2B;IAC3C,GAAG,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,OAAO,EAAE,OAAO,GAAG,WAAW,GAAG,WAAW,CAAC;IAC7C,SAAS,EAAE,WAAW,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;CACb;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,2BAA2B,GACvC,MAAM,2BAA2B,KAC/B,OAAO,CAAC;IAAC,QAAQ,EAAE,IAAI,CAAC;IAAC,aAAa,EAAE,IAAI,CAAA;CAAC,CAyB/C,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import './assert_dev_env.js';
|
|
2
|
+
/**
|
|
3
|
+
* RPC-flow helpers for role_grant lifecycle in tests.
|
|
4
|
+
*
|
|
5
|
+
* Sibling to `db_entities.ts`'s `create_test_role_grant_direct` — that one
|
|
6
|
+
* seeds a role_grant directly via `query_create_role_grant` (bypassing the
|
|
7
|
+
* consent flow) for tests that focus on revoke or isolation semantics. This
|
|
8
|
+
* file ships the RPC-driven complement: `role_grant_offer_and_accept`
|
|
9
|
+
* exercises the same `role_grant_offer_create` + `role_grant_offer_accept`
|
|
10
|
+
* specs the admin UI consumes, so consumer tests pick up post-commit
|
|
11
|
+
* fan-out (audit, SSE broadcasts, `_supersede` notifications) end-to-end.
|
|
12
|
+
*
|
|
13
|
+
* @module
|
|
14
|
+
*/
|
|
15
|
+
import { assert } from 'vitest';
|
|
16
|
+
import { role_grant_offer_accept_action_spec, role_grant_offer_create_action_spec, } from '../auth/role_grant_offer_action_specs.js';
|
|
17
|
+
import { rpc_call_for_spec } from './rpc_helpers.js';
|
|
18
|
+
/**
|
|
19
|
+
* Drive the full consent flow (grantor offer → recipient accept) over the
|
|
20
|
+
* production RPC surface and return the materialized role_grant id.
|
|
21
|
+
*
|
|
22
|
+
* `grantor` and `recipient` carry both the account id (for `to_account_id`
|
|
23
|
+
* derivation) and the `create_session_headers` factory (for cookie-threaded
|
|
24
|
+
* auth) — closing that loop on a single object per party rules out
|
|
25
|
+
* caller-side header/account mismatch.
|
|
26
|
+
*/
|
|
27
|
+
export const role_grant_offer_and_accept = async (args) => {
|
|
28
|
+
const create_res = await rpc_call_for_spec({
|
|
29
|
+
app: args.app,
|
|
30
|
+
path: args.rpc_path,
|
|
31
|
+
spec: role_grant_offer_create_action_spec,
|
|
32
|
+
params: { to_account_id: args.recipient.account.id, role: args.role },
|
|
33
|
+
headers: args.grantor.create_session_headers(),
|
|
34
|
+
});
|
|
35
|
+
assert.ok(create_res.ok, `role_grant_offer_create failed: ${create_res.ok ? '' : JSON.stringify(create_res.error)}`);
|
|
36
|
+
const { offer } = create_res.result;
|
|
37
|
+
const accept_res = await rpc_call_for_spec({
|
|
38
|
+
app: args.app,
|
|
39
|
+
path: args.rpc_path,
|
|
40
|
+
spec: role_grant_offer_accept_action_spec,
|
|
41
|
+
params: { offer_id: offer.id },
|
|
42
|
+
headers: args.recipient.create_session_headers(),
|
|
43
|
+
});
|
|
44
|
+
assert.ok(accept_res.ok, `role_grant_offer_accept failed: ${accept_res.ok ? '' : JSON.stringify(accept_res.error)}`);
|
|
45
|
+
return { offer_id: offer.id, role_grant_id: accept_res.result.role_grant_id };
|
|
46
|
+
};
|
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
import './assert_dev_env.js';
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
4
|
-
import type {
|
|
5
|
-
import { type DbFactory } from './db.js';
|
|
2
|
+
import type { BackendCapabilities } from './cross_backend/capabilities.js';
|
|
3
|
+
import type { SetupTest } from './cross_backend/setup.js';
|
|
4
|
+
import type { SurfaceSource } from './transports/surface_source.js';
|
|
6
5
|
/** Options for `describe_round_trip_validation`. */
|
|
7
6
|
export interface RoundTripTestOptions {
|
|
8
|
-
/**
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Per-test fixture-producing function. `describe_round_trip_validation`
|
|
9
|
+
* invokes this once in `beforeAll` (per-describe cadence — see module
|
|
10
|
+
* docstring) to share a single bootstrapped keeper + accounts across
|
|
11
|
+
* every route case.
|
|
12
|
+
*/
|
|
13
|
+
setup_test: SetupTest;
|
|
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.
|
|
18
|
+
*/
|
|
19
|
+
surface_source: SurfaceSource;
|
|
20
|
+
/** Backend capability declarations — see `cross_backend/capabilities.ts`. */
|
|
21
|
+
capabilities: BackendCapabilities;
|
|
16
22
|
/** Routes to skip, in `'METHOD /path'` format. */
|
|
17
23
|
skip_routes?: Array<string>;
|
|
18
24
|
/** Override generated bodies for specific routes (`'METHOD /path'` → body). */
|
|
@@ -25,11 +31,10 @@ export interface RoundTripTestOptions {
|
|
|
25
31
|
* 1. Resolve URL with valid params
|
|
26
32
|
* 2. Generate a valid request body (or use override)
|
|
27
33
|
* 3. Pick auth headers matching the route's auth requirement
|
|
28
|
-
* 4. Fire the request and validate the response
|
|
34
|
+
* 4. Fire the request through `fixture.transport` and validate the response
|
|
29
35
|
*
|
|
30
|
-
* SSE routes are skipped
|
|
31
|
-
*
|
|
32
|
-
* their declared error schemas.
|
|
36
|
+
* SSE routes are skipped by Content-Type sniff. Routes returning non-2xx
|
|
37
|
+
* with valid input are still validated against their declared error schemas.
|
|
33
38
|
*/
|
|
34
39
|
export declare const describe_round_trip_validation: (options: RoundTripTestOptions) => void;
|
|
35
40
|
//# sourceMappingURL=round_trip.d.ts.map
|
|
@@ -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;
|
|
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"}
|
|
@@ -2,21 +2,24 @@ import './assert_dev_env.js';
|
|
|
2
2
|
/**
|
|
3
3
|
* Schema-driven round-trip validation test suite.
|
|
4
4
|
*
|
|
5
|
-
* For every route spec
|
|
6
|
-
* and validates the response against
|
|
7
|
-
* DB-backed via
|
|
5
|
+
* For every route spec in the supplied `surface_source`, generates a
|
|
6
|
+
* valid request (auth, params, body) and validates the response against
|
|
7
|
+
* declared output or error schemas. DB-backed via the suite's
|
|
8
|
+
* `setup_test` fixture-producing callback.
|
|
9
|
+
*
|
|
10
|
+
* Cadence: per-describe `setup_test()` call. Each test in the suite
|
|
11
|
+
* fires one HTTP request against a shared fixture — no test mutates
|
|
12
|
+
* state in a way that contaminates the next, so the per-test cost of
|
|
13
|
+
* re-bootstrapping isn't justified here. Suites with state-isolation
|
|
14
|
+
* requirements (integration, admin_integration, audit_completeness)
|
|
15
|
+
* call `setup_test()` per test.
|
|
8
16
|
*
|
|
9
17
|
* @module
|
|
10
18
|
*/
|
|
11
|
-
import { describe, test, beforeAll
|
|
19
|
+
import { describe, test, beforeAll } from 'vitest';
|
|
12
20
|
import { ROLE_ADMIN } from '../auth/role_schema.js';
|
|
13
|
-
import { create_test_app } from './app_server.js';
|
|
14
|
-
import { create_pglite_factory } from './db.js';
|
|
15
21
|
import { assert_response_matches_spec, pick_auth_headers } from './integration_helpers.js';
|
|
16
22
|
import { resolve_valid_path, generate_valid_body } from './schema_generators.js';
|
|
17
|
-
import { run_migrations } from '../db/migrate.js';
|
|
18
|
-
import { auth_migration_ns } from '../auth/migrations.js';
|
|
19
|
-
import { create_stub_app_server_context } from './stubs.js';
|
|
20
23
|
/**
|
|
21
24
|
* Run schema-driven round-trip validation tests.
|
|
22
25
|
*
|
|
@@ -24,88 +27,64 @@ import { create_stub_app_server_context } from './stubs.js';
|
|
|
24
27
|
* 1. Resolve URL with valid params
|
|
25
28
|
* 2. Generate a valid request body (or use override)
|
|
26
29
|
* 3. Pick auth headers matching the route's auth requirement
|
|
27
|
-
* 4. Fire the request and validate the response
|
|
30
|
+
* 4. Fire the request through `fixture.transport` and validate the response
|
|
28
31
|
*
|
|
29
|
-
* SSE routes are skipped
|
|
30
|
-
*
|
|
31
|
-
* their declared error schemas.
|
|
32
|
+
* SSE routes are skipped by Content-Type sniff. Routes returning non-2xx
|
|
33
|
+
* with valid input are still validated against their declared error schemas.
|
|
32
34
|
*/
|
|
33
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;
|
|
34
41
|
const skip_set = new Set(options.skip_routes);
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
let test_app;
|
|
49
|
-
let authed_account;
|
|
50
|
-
let admin_account;
|
|
51
|
-
let db;
|
|
52
|
-
beforeAll(async () => {
|
|
53
|
-
db = await factory.create();
|
|
54
|
-
test_app = await create_test_app({
|
|
55
|
-
session_options: options.session_options,
|
|
56
|
-
create_route_specs: options.create_route_specs,
|
|
57
|
-
db,
|
|
58
|
-
app_options: options.app_options,
|
|
59
|
-
});
|
|
60
|
-
// Create accounts at each auth level
|
|
61
|
-
authed_account = await test_app.create_account({
|
|
62
|
-
username: 'round_trip_authed',
|
|
63
|
-
roles: [],
|
|
64
|
-
});
|
|
65
|
-
admin_account = await test_app.create_account({
|
|
66
|
-
username: 'round_trip_admin',
|
|
67
|
-
roles: [ROLE_ADMIN],
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
afterAll(async () => {
|
|
71
|
-
await test_app.cleanup();
|
|
72
|
-
await factory.close(db);
|
|
42
|
+
// `capabilities` is currently unused by this suite (no in-process-only
|
|
43
|
+
// reads, no transport-gated cases) but stays on the options for
|
|
44
|
+
// uniformity with the other Tier 1 suites.
|
|
45
|
+
void options.capabilities;
|
|
46
|
+
describe('round-trip validation', () => {
|
|
47
|
+
let fixture;
|
|
48
|
+
let authed_account;
|
|
49
|
+
let admin_account;
|
|
50
|
+
beforeAll(async () => {
|
|
51
|
+
fixture = await options.setup_test();
|
|
52
|
+
authed_account = await fixture.create_account({
|
|
53
|
+
username: 'round_trip_authed',
|
|
54
|
+
roles: [],
|
|
73
55
|
});
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
return;
|
|
78
|
-
// Resolve URL with valid param values
|
|
79
|
-
const url = resolve_valid_path(spec.path, spec.params);
|
|
80
|
-
// Generate or override request body
|
|
81
|
-
const override = options.input_overrides?.get(route_key);
|
|
82
|
-
const body = override ?? generate_valid_body(spec.input);
|
|
83
|
-
// Pick auth headers based on route auth requirement
|
|
84
|
-
const headers = pick_auth_headers(spec, test_app, authed_account, admin_account);
|
|
85
|
-
// Fire request
|
|
86
|
-
const request_init = {
|
|
87
|
-
method: spec.method,
|
|
88
|
-
headers: {
|
|
89
|
-
...headers,
|
|
90
|
-
...(body ? { 'content-type': 'application/json' } : {}),
|
|
91
|
-
},
|
|
92
|
-
...(body ? { body: JSON.stringify(body) } : {}),
|
|
93
|
-
};
|
|
94
|
-
const res = await test_app.app.request(url, request_init);
|
|
95
|
-
// Skip SSE responses — streaming bodies can't be parsed as JSON
|
|
96
|
-
if (res.headers.get('Content-Type')?.includes('text/event-stream')) {
|
|
97
|
-
await res.body?.cancel();
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
// Validate response against declared schemas
|
|
101
|
-
try {
|
|
102
|
-
await assert_response_matches_spec(test_app.route_specs, spec.method, url, res);
|
|
103
|
-
}
|
|
104
|
-
catch (e) {
|
|
105
|
-
// Re-throw with route context for easier debugging
|
|
106
|
-
throw new Error(`Round-trip validation failed for ${route_key} (status ${res.status}): ${e.message}`);
|
|
107
|
-
}
|
|
56
|
+
admin_account = await fixture.create_account({
|
|
57
|
+
username: 'round_trip_admin',
|
|
58
|
+
roles: [ROLE_ADMIN],
|
|
108
59
|
});
|
|
109
60
|
});
|
|
110
|
-
|
|
61
|
+
test.each(describe_time_specs)('$method $path produces schema-valid response', async (spec) => {
|
|
62
|
+
const route_key = `${spec.method} ${spec.path}`;
|
|
63
|
+
if (skip_set.has(route_key))
|
|
64
|
+
return;
|
|
65
|
+
const url = resolve_valid_path(spec.path, spec.params);
|
|
66
|
+
const override = options.input_overrides?.get(route_key);
|
|
67
|
+
const body = override ?? generate_valid_body(spec.input);
|
|
68
|
+
const headers = pick_auth_headers(spec, fixture, authed_account, admin_account);
|
|
69
|
+
const request_init = {
|
|
70
|
+
method: spec.method,
|
|
71
|
+
headers: {
|
|
72
|
+
...headers,
|
|
73
|
+
...(body ? { 'content-type': 'application/json' } : {}),
|
|
74
|
+
},
|
|
75
|
+
...(body ? { body: JSON.stringify(body) } : {}),
|
|
76
|
+
};
|
|
77
|
+
const res = await fixture.transport(url, request_init);
|
|
78
|
+
if (res.headers.get('Content-Type')?.includes('text/event-stream')) {
|
|
79
|
+
await res.body?.cancel();
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
await assert_response_matches_spec(describe_time_specs, spec.method, url, res);
|
|
84
|
+
}
|
|
85
|
+
catch (e) {
|
|
86
|
+
throw new Error(`Round-trip validation failed for ${route_key} (status ${res.status}): ${e.message}`);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
});
|
|
111
90
|
};
|
|
@@ -13,7 +13,8 @@ import type { SessionOptions } from '../auth/session_cookie.js';
|
|
|
13
13
|
* per-test `ctx.app_settings` / `ctx.deps` (e.g. the canonical
|
|
14
14
|
* `create_standard_rpc_actions(ctx.deps, {app_settings: ctx.app_settings})`
|
|
15
15
|
* pattern). `create_app_server` resolves either shape natively; test helpers
|
|
16
|
-
* forward the raw value to `
|
|
16
|
+
* forward the raw value to the top-level `rpc_endpoints` slot on
|
|
17
|
+
* `CreateTestAppOptions` for live dispatch.
|
|
17
18
|
*/
|
|
18
19
|
export type RpcEndpointsSuiteOption = Array<RpcEndpointSpec> | ((ctx: AppServerContext) => Array<RpcEndpointSpec>);
|
|
19
20
|
/**
|
|
@@ -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
|
|
1
|
+
{"version":3,"file":"rpc_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/rpc_helpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,32 +1,35 @@
|
|
|
1
1
|
import './assert_dev_env.js';
|
|
2
|
-
import type { RouteSpec } from '../http/route_spec.js';
|
|
3
|
-
import type { AppServerContext } from '../server/app_server.js';
|
|
4
|
-
import type { SessionOptions } from '../auth/session_cookie.js';
|
|
5
|
-
import { type SuiteAppOptions } from './app_server.js';
|
|
6
|
-
import { type DbFactory } from './db.js';
|
|
7
2
|
import { type RpcEndpointsSuiteOption } from './rpc_helpers.js';
|
|
3
|
+
import type { BackendCapabilities } from './cross_backend/capabilities.js';
|
|
4
|
+
import type { SetupTest } from './cross_backend/setup.js';
|
|
5
|
+
import type { SurfaceSource } from './transports/surface_source.js';
|
|
6
|
+
import type { SessionOptions } from '../auth/session_cookie.js';
|
|
8
7
|
/** Options for `describe_rpc_round_trip_tests`. */
|
|
9
8
|
export interface RpcRoundTripTestOptions {
|
|
10
|
-
/**
|
|
9
|
+
/** Per-test fixture-producing function (per-describe cadence). */
|
|
10
|
+
setup_test: SetupTest;
|
|
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.
|
|
15
|
+
*/
|
|
16
|
+
surface_source: SurfaceSource;
|
|
17
|
+
/** Backend capability declarations. */
|
|
18
|
+
capabilities: BackendCapabilities;
|
|
19
|
+
/**
|
|
20
|
+
* Session config — only needed to resolve factory-form `rpc_endpoints`
|
|
21
|
+
* against a stub `AppServerContext` at setup time (the actions' input
|
|
22
|
+
* schemas drive params generation; auth/dispatch run against the real
|
|
23
|
+
* backend through `fixture.transport`).
|
|
24
|
+
*/
|
|
11
25
|
session_options: SessionOptions<string>;
|
|
12
|
-
/** Route spec factory — same one used in production. */
|
|
13
|
-
create_route_specs: (ctx: AppServerContext) => Array<RouteSpec>;
|
|
14
26
|
/**
|
|
15
|
-
* RPC endpoint specs —
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* is required when action handlers must close over the per-test
|
|
20
|
-
* `ctx.app_settings` / `ctx.deps`. The factory must return the same
|
|
21
|
-
* endpoint `path` and `spec.method` list regardless of ctx — it is
|
|
22
|
-
* invoked once at setup (via a stub ctx) to enumerate methods and
|
|
23
|
-
* again per-test by `create_app_server` for live dispatch.
|
|
27
|
+
* RPC endpoint specs — eager array or factory. The factory must return
|
|
28
|
+
* the same endpoint `path` + `spec.method` list regardless of ctx
|
|
29
|
+
* (invoked once at setup with a stub ctx; the real per-test live
|
|
30
|
+
* dispatch goes through whatever the backend was started with).
|
|
24
31
|
*/
|
|
25
32
|
rpc_endpoints: RpcEndpointsSuiteOption;
|
|
26
|
-
/** Optional overrides for `AppServerOptions`. */
|
|
27
|
-
app_options?: SuiteAppOptions;
|
|
28
|
-
/** Database factories to run tests against. Default: pglite only. */
|
|
29
|
-
db_factories?: Array<DbFactory>;
|
|
30
33
|
/** Methods to skip, by name (e.g., `'zap_plan'`). */
|
|
31
34
|
skip_methods?: Array<string>;
|
|
32
35
|
/** Override generated params for specific methods (method name → params). */
|
|
@@ -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;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"}
|