@fuzdev/fuz_app 0.64.0 → 0.66.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 +510 -946
- 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/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 +1 -4
- package/dist/actions/connection_closer.d.ts.map +1 -1
- package/dist/actions/connection_closer.js +1 -4
- package/dist/actions/register_action_ws.d.ts +2 -2
- package/dist/actions/register_ws_endpoint.d.ts +1 -1
- package/dist/actions/transports_ws_auth_guard.d.ts +1 -2
- package/dist/actions/transports_ws_auth_guard.d.ts.map +1 -1
- package/dist/actions/transports_ws_auth_guard.js +1 -2
- package/dist/auth/CLAUDE.md +570 -1871
- package/dist/auth/account_schema.d.ts +1 -1
- package/dist/auth/account_schema.d.ts.map +1 -1
- package/dist/auth/api_token_queries.js +1 -1
- 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.js +2 -2
- 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 +7 -1
- package/dist/auth/bootstrap_routes.d.ts.map +1 -1
- package/dist/auth/bootstrap_routes.js +15 -11
- 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/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 +47 -1
- package/dist/auth/signup_routes.d.ts.map +1 -1
- package/dist/auth/signup_routes.js +103 -52
- 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/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 +243 -522
- 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 +5 -4
- package/dist/http/ip_canonical.d.ts.map +1 -1
- package/dist/http/ip_canonical.js +8 -4
- 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/origin.d.ts +1 -1
- package/dist/http/origin.js +1 -1
- 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 +2 -2
- package/dist/server/app_server.d.ts +41 -10
- package/dist/server/app_server.d.ts.map +1 -1
- package/dist/server/app_server.js +10 -4
- 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/static.d.ts +4 -4
- package/dist/server/static.js +7 -7
- package/dist/testing/CLAUDE.md +740 -418
- 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 +230 -216
- package/dist/testing/app_server.d.ts +141 -39
- package/dist/testing/app_server.d.ts.map +1 -1
- package/dist/testing/app_server.js +157 -44
- package/dist/testing/audit_completeness.d.ts +25 -22
- package/dist/testing/audit_completeness.d.ts.map +1 -1
- package/dist/testing/audit_completeness.js +198 -159
- 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/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 +65 -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/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 +451 -0
- package/dist/testing/cross_backend/setup.d.ts.map +1 -0
- package/dist/testing/cross_backend/setup.js +581 -0
- 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 +11 -14
- package/dist/testing/data_exposure.d.ts.map +1 -1
- package/dist/testing/data_exposure.js +123 -146
- package/dist/testing/db_entities.d.ts +22 -1
- package/dist/testing/db_entities.d.ts.map +1 -1
- package/dist/testing/db_entities.js +24 -1
- package/dist/testing/integration.d.ts +56 -21
- package/dist/testing/integration.d.ts.map +1 -1
- package/dist/testing/integration.js +294 -319
- 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 +9 -0
- 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 +20 -16
- package/dist/testing/round_trip.d.ts.map +1 -1
- package/dist/testing/round_trip.js +61 -86
- 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 +24 -21
- package/dist/testing/rpc_round_trip.d.ts.map +1 -1
- package/dist/testing/rpc_round_trip.js +87 -104
- 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 +1 -68
- package/dist/testing/standard.d.ts +56 -25
- package/dist/testing/standard.d.ts.map +1 -1
- package/dist/testing/standard.js +62 -5
- package/dist/testing/stubs.d.ts +21 -6
- package/dist/testing/stubs.d.ts.map +1 -1
- package/dist/testing/stubs.js +33 -23
- 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 +10 -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":"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,WAAW,EAAC,MAAM,iBAAiB,CAAC;AAEjD;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAC3B,OAAO,KAAK,CAAC,SAAS,CAAC,EACvB,QAAQ,MAAM,EACd,MAAM,MAAM,KACV,SAAS,GAAG,SAad,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,iFAO3B,CAAC;AACX,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE5E;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe,GAC3B,OAAO,KAAK,CAAC,SAAS,CAAC,EACvB,QAAQ,mBAAmB,EAC3B,QAAQ,WAAW,KACjB,SAAS,GAAG,SAOd,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,4BAA4B,GACxC,aAAa,KAAK,CAAC,SAAS,CAAC,EAC7B,QAAQ,MAAM,EACd,MAAM,MAAM,EACZ,UAAU,QAAQ,KAChB,OAAO,CAAC,IAAI,CAmDd,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,0BAA0B,GACtC,SAAS,OAAO,EAChB,iBAAiB,cAAc,CAAC,MAAM,CAAC,KACrC,OAAO,CAAC,MAAM,CAGhB,CAAC;AAgCF;;;;;;;GAOG;AACH,eAAO,MAAM,2BAA2B,GAAI,MAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,KAAK,CAAC,MAAM,CAQvF,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,4BAA4B,GAAI,MAAM,OAAO,EAAE,SAAS,MAAM,KAAG,IAoB7E,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,oCAAoC,GAChD,UAAU,QAAQ,EAClB,MAAM;IAAC,WAAW,EAAE,MAAM,CAAA;CAAC,KACzB,IAUF,CAAC;AAIF,oEAAoE;AACpE,eAAO,MAAM,yBAAyB,EAAE,aAAa,CAAC,MAAM,CAAmC,CAAC;AAEhG,0EAA0E;AAC1E,eAAO,MAAM,0BAA0B,EAAE,aAAa,CAAC,MAAM,CAAgC,CAAC;AAE9F;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,GAAI,OAAO,OAAO,KAAG,GAAG,CAAC,MAAM,CAetE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,kCAAkC,GAC9C,MAAM,OAAO,EACb,WAAW,aAAa,CAAC,MAAM,CAAC,EAChC,SAAS,MAAM,KACb,IAKF,CAAC;AAEF;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACpC,sBAAsB,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnF,qBAAqB,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClF,2BAA2B,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACxF;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB,GAC7B,MAAM,SAAS,EACf,QAAQ,oBAAoB,EAC5B,gBAAgB,WAAW,EAC3B,eAAe,WAAW,KACxB,MAAM,CAAC,MAAM,EAAE,MAAM,CAevB,CAAC"}
|
|
@@ -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';
|
|
@@ -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,23 @@
|
|
|
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 { AppSurfaceSpec } from '../http/surface.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
|
+
* App surface (with route specs) for route iteration. Constructed in
|
|
16
|
+
* TS by the consumer; same shape for in-process and cross-process tests.
|
|
17
|
+
*/
|
|
18
|
+
surface_source: AppSurfaceSpec;
|
|
19
|
+
/** Backend capability declarations — see `cross_backend/capabilities.ts`. */
|
|
20
|
+
capabilities: BackendCapabilities;
|
|
16
21
|
/** Routes to skip, in `'METHOD /path'` format. */
|
|
17
22
|
skip_routes?: Array<string>;
|
|
18
23
|
/** Override generated bodies for specific routes (`'METHOD /path'` → body). */
|
|
@@ -25,11 +30,10 @@ export interface RoundTripTestOptions {
|
|
|
25
30
|
* 1. Resolve URL with valid params
|
|
26
31
|
* 2. Generate a valid request body (or use override)
|
|
27
32
|
* 3. Pick auth headers matching the route's auth requirement
|
|
28
|
-
* 4. Fire the request and validate the response
|
|
33
|
+
* 4. Fire the request through `fixture.transport` and validate the response
|
|
29
34
|
*
|
|
30
|
-
* SSE routes are skipped
|
|
31
|
-
*
|
|
32
|
-
* their declared error schemas.
|
|
35
|
+
* SSE routes are skipped by Content-Type sniff. Routes returning non-2xx
|
|
36
|
+
* with valid input are still validated against their declared error schemas.
|
|
33
37
|
*/
|
|
34
38
|
export declare const describe_round_trip_validation: (options: RoundTripTestOptions) => void;
|
|
35
39
|
//# 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,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"}
|
|
@@ -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,60 @@ 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
|
+
const describe_time_specs = options.surface_source.route_specs;
|
|
34
37
|
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);
|
|
38
|
+
// `capabilities` is currently unused by this suite (no in-process-only
|
|
39
|
+
// reads, no transport-gated cases) but stays on the options for
|
|
40
|
+
// uniformity with the other Tier 1 suites.
|
|
41
|
+
void options.capabilities;
|
|
42
|
+
describe('round-trip validation', () => {
|
|
43
|
+
let fixture;
|
|
44
|
+
let authed_account;
|
|
45
|
+
let admin_account;
|
|
46
|
+
beforeAll(async () => {
|
|
47
|
+
fixture = await options.setup_test();
|
|
48
|
+
authed_account = await fixture.create_account({
|
|
49
|
+
username: 'round_trip_authed',
|
|
50
|
+
roles: [],
|
|
73
51
|
});
|
|
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
|
-
}
|
|
52
|
+
admin_account = await fixture.create_account({
|
|
53
|
+
username: 'round_trip_admin',
|
|
54
|
+
roles: [ROLE_ADMIN],
|
|
108
55
|
});
|
|
109
56
|
});
|
|
110
|
-
|
|
57
|
+
test.each(describe_time_specs)('$method $path produces schema-valid response', async (spec) => {
|
|
58
|
+
const route_key = `${spec.method} ${spec.path}`;
|
|
59
|
+
if (skip_set.has(route_key))
|
|
60
|
+
return;
|
|
61
|
+
const url = resolve_valid_path(spec.path, spec.params);
|
|
62
|
+
const override = options.input_overrides?.get(route_key);
|
|
63
|
+
const body = override ?? generate_valid_body(spec.input);
|
|
64
|
+
const headers = pick_auth_headers(spec, fixture, authed_account, admin_account);
|
|
65
|
+
const request_init = {
|
|
66
|
+
method: spec.method,
|
|
67
|
+
headers: {
|
|
68
|
+
...headers,
|
|
69
|
+
...(body ? { 'content-type': 'application/json' } : {}),
|
|
70
|
+
},
|
|
71
|
+
...(body ? { body: JSON.stringify(body) } : {}),
|
|
72
|
+
};
|
|
73
|
+
const res = await fixture.transport(url, request_init);
|
|
74
|
+
if (res.headers.get('Content-Type')?.includes('text/event-stream')) {
|
|
75
|
+
await res.body?.cancel();
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
await assert_response_matches_spec(describe_time_specs, spec.method, url, res);
|
|
80
|
+
}
|
|
81
|
+
catch (e) {
|
|
82
|
+
throw new Error(`Round-trip validation failed for ${route_key} (status ${res.status}): ${e.message}`);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
});
|
|
111
86
|
};
|
|
@@ -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,32 +1,35 @@
|
|
|
1
1
|
import './assert_dev_env.js';
|
|
2
|
-
import type {
|
|
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';
|
|
2
|
+
import type { AppSurfaceSpec } from '../http/surface.js';
|
|
7
3
|
import { type RpcEndpointsSuiteOption } from './rpc_helpers.js';
|
|
4
|
+
import type { BackendCapabilities } from './cross_backend/capabilities.js';
|
|
5
|
+
import type { SetupTest } from './cross_backend/setup.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
|
+
* 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
|
+
*/
|
|
16
|
+
surface_source: AppSurfaceSpec;
|
|
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;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"}
|