@fuzdev/fuz_app 0.31.0 → 0.33.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/rpc_client.d.ts +29 -0
- package/dist/actions/rpc_client.d.ts.map +1 -1
- package/dist/actions/rpc_client.js +31 -0
- package/dist/auth/CLAUDE.md +22 -0
- package/dist/auth/admin_rpc_actions.d.ts +49 -0
- package/dist/auth/admin_rpc_actions.d.ts.map +1 -0
- package/dist/auth/admin_rpc_actions.js +32 -0
- package/dist/server/app_server.d.ts +13 -2
- package/dist/server/app_server.d.ts.map +1 -1
- package/dist/server/app_server.js +12 -1
- package/dist/testing/CLAUDE.md +26 -10
- package/dist/testing/admin_integration.d.ts +14 -4
- package/dist/testing/admin_integration.d.ts.map +1 -1
- package/dist/testing/admin_integration.js +7 -4
- package/dist/testing/app_server.d.ts +10 -0
- package/dist/testing/app_server.d.ts.map +1 -1
- package/dist/testing/audit_completeness.d.ts +13 -4
- package/dist/testing/audit_completeness.d.ts.map +1 -1
- package/dist/testing/audit_completeness.js +8 -5
- package/dist/testing/integration.d.ts +14 -4
- package/dist/testing/integration.d.ts.map +1 -1
- package/dist/testing/integration.js +16 -6
- package/dist/testing/rate_limiting.d.ts +13 -4
- package/dist/testing/rate_limiting.d.ts.map +1 -1
- package/dist/testing/rate_limiting.js +9 -3
- package/dist/testing/rpc_helpers.d.ts +29 -0
- package/dist/testing/rpc_helpers.d.ts.map +1 -1
- package/dist/testing/rpc_helpers.js +20 -0
- package/dist/testing/rpc_round_trip.d.ts +16 -5
- package/dist/testing/rpc_round_trip.d.ts.map +1 -1
- package/dist/testing/rpc_round_trip.js +11 -5
- package/dist/testing/sse_round_trip.d.ts +13 -5
- package/dist/testing/sse_round_trip.d.ts.map +1 -1
- package/dist/testing/sse_round_trip.js +11 -5
- package/dist/testing/standard.d.ts +7 -2
- package/dist/testing/standard.d.ts.map +1 -1
- package/dist/testing/stubs.d.ts +10 -2
- package/dist/testing/stubs.d.ts.map +1 -1
- package/dist/testing/stubs.js +17 -2
- package/dist/ui/CLAUDE.md +12 -0
- package/dist/ui/admin_rpc_adapters.d.ts +94 -0
- package/dist/ui/admin_rpc_adapters.d.ts.map +1 -0
- package/dist/ui/admin_rpc_adapters.js +100 -0
- package/package.json +1 -1
|
@@ -21,7 +21,7 @@ import { AUTH_MIGRATION_NS } from '../auth/migrations.js';
|
|
|
21
21
|
import { create_test_app } from './app_server.js';
|
|
22
22
|
import { create_pglite_factory, create_describe_db, AUTH_INTEGRATION_TRUNCATE_TABLES, } from './db.js';
|
|
23
23
|
import { find_auth_route, assert_response_matches_spec, create_expired_test_cookie, assert_no_error_info_leakage, } from './integration_helpers.js';
|
|
24
|
-
import { find_rpc_action, rpc_call, rpc_call_non_browser, require_rpc_endpoint_path, } from './rpc_helpers.js';
|
|
24
|
+
import { find_rpc_action, rpc_call, rpc_call_non_browser, require_rpc_endpoint_path, resolve_rpc_endpoints_for_setup, } from './rpc_helpers.js';
|
|
25
25
|
import { RateLimiter } from '../rate_limiter.js';
|
|
26
26
|
import { run_migrations } from '../db/migrate.js';
|
|
27
27
|
import { ErrorCoverageCollector, assert_error_coverage, DEFAULT_INTEGRATION_ERROR_COVERAGE, } from './error_coverage.js';
|
|
@@ -30,12 +30,19 @@ import { account_verify_action_spec, account_session_list_action_spec, account_s
|
|
|
30
30
|
import { invite_create_action_spec } from '../auth/admin_action_specs.js';
|
|
31
31
|
/**
|
|
32
32
|
* Build `CreateTestAppOptions` from standard options plus a database.
|
|
33
|
+
* Forwards `options.rpc_endpoints` to `app_options.rpc_endpoints` so
|
|
34
|
+
* `create_app_server` auto-mounts it per-test with the real ctx.
|
|
35
|
+
* `SuiteAppOptions` excludes `rpc_endpoints` so there's no way for
|
|
36
|
+
* `options.app_options` to collide with the suite-level field.
|
|
33
37
|
*/
|
|
34
38
|
const build_test_app_options = (options, db) => ({
|
|
35
39
|
session_options: options.session_options,
|
|
36
40
|
create_route_specs: options.create_route_specs,
|
|
37
41
|
db,
|
|
38
|
-
app_options:
|
|
42
|
+
app_options: {
|
|
43
|
+
...options.app_options,
|
|
44
|
+
rpc_endpoints: options.rpc_endpoints,
|
|
45
|
+
},
|
|
39
46
|
});
|
|
40
47
|
/**
|
|
41
48
|
* Standard integration test suite for fuz_app auth routes.
|
|
@@ -53,8 +60,11 @@ const build_test_app_options = (options, db) => ({
|
|
|
53
60
|
*/
|
|
54
61
|
export const describe_standard_integration_tests = (options) => {
|
|
55
62
|
// Hard-fail early so consumers see a clear setup error instead of a
|
|
56
|
-
// confusing test failure when `rpc_endpoints` is missing.
|
|
57
|
-
|
|
63
|
+
// confusing test failure when `rpc_endpoints` is missing. Factory-form
|
|
64
|
+
// callers are resolved with a stub ctx purely to extract the endpoint
|
|
65
|
+
// path; real handlers run per-test via `app_options.rpc_endpoints`.
|
|
66
|
+
const rpc_endpoints_for_setup = resolve_rpc_endpoints_for_setup(options.rpc_endpoints, options.session_options);
|
|
67
|
+
const rpc_path = require_rpc_endpoint_path(rpc_endpoints_for_setup);
|
|
58
68
|
const init_schema = async (db) => {
|
|
59
69
|
await run_migrations(db, [AUTH_MIGRATION_NS]);
|
|
60
70
|
};
|
|
@@ -1021,7 +1031,7 @@ export const describe_standard_integration_tests = (options) => {
|
|
|
1021
1031
|
// `invite_create` became RPC-only in the 2026-04-23 migration.
|
|
1022
1032
|
// Consumers that don't wire admin RPC actions can't exercise invites;
|
|
1023
1033
|
// skip the test rather than fail.
|
|
1024
|
-
if (!find_rpc_action(
|
|
1034
|
+
if (!find_rpc_action(rpc_endpoints_for_setup, invite_create_action_spec.method))
|
|
1025
1035
|
return;
|
|
1026
1036
|
// Create an admin to manage invites
|
|
1027
1037
|
const admin = await test_app.create_account({
|
|
@@ -1066,7 +1076,7 @@ export const describe_standard_integration_tests = (options) => {
|
|
|
1066
1076
|
return; // signup is optional
|
|
1067
1077
|
// `invite_create` became RPC-only in the 2026-04-23 migration.
|
|
1068
1078
|
// Consumers that don't wire admin RPC actions can't exercise invites.
|
|
1069
|
-
if (!find_rpc_action(
|
|
1079
|
+
if (!find_rpc_action(rpc_endpoints_for_setup, invite_create_action_spec.method))
|
|
1070
1080
|
return;
|
|
1071
1081
|
// We need admin access — create an admin account
|
|
1072
1082
|
const admin = await test_app.create_account({
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import './assert_dev_env.js';
|
|
2
2
|
import type { SessionOptions } from '../auth/session_cookie.js';
|
|
3
|
-
import type { AppServerContext
|
|
3
|
+
import type { AppServerContext } from '../server/app_server.js';
|
|
4
4
|
import type { RouteSpec } from '../http/route_spec.js';
|
|
5
|
+
import { type SuiteAppOptions } from './app_server.js';
|
|
5
6
|
import { type DbFactory } from './db.js';
|
|
6
|
-
import type
|
|
7
|
+
import { type RpcEndpointsSuiteOption } from './rpc_helpers.js';
|
|
7
8
|
/**
|
|
8
9
|
* Configuration for `describe_rate_limiting_tests`.
|
|
9
10
|
*/
|
|
@@ -13,7 +14,7 @@ export interface RateLimitingTestOptions {
|
|
|
13
14
|
/** Route spec factory — same one used in production. */
|
|
14
15
|
create_route_specs: (ctx: AppServerContext) => Array<RouteSpec>;
|
|
15
16
|
/** Optional overrides for `AppServerOptions`. */
|
|
16
|
-
app_options?:
|
|
17
|
+
app_options?: SuiteAppOptions;
|
|
17
18
|
/**
|
|
18
19
|
* Database factories to run tests against. Default: pglite only.
|
|
19
20
|
*/
|
|
@@ -27,8 +28,16 @@ export interface RateLimitingTestOptions {
|
|
|
27
28
|
* RPC endpoint specs — required so the bearer-auth rate limiting test
|
|
28
29
|
* can probe an authenticated method via the `account_verify` RPC
|
|
29
30
|
* action. Hard-fails via `require_rpc_endpoint_path` on setup.
|
|
31
|
+
*
|
|
32
|
+
* Accepts either an array (eager) or a factory
|
|
33
|
+
* `(ctx: AppServerContext) => Array<RpcEndpointSpec>` — the factory form
|
|
34
|
+
* is required when action handlers must close over the per-test
|
|
35
|
+
* `ctx.app_settings` / `ctx.deps`. The factory must return the same
|
|
36
|
+
* endpoint `path` regardless of ctx — it is invoked once at setup with
|
|
37
|
+
* a stub ctx for path lookup and again per-test by `create_app_server`
|
|
38
|
+
* for live dispatch.
|
|
30
39
|
*/
|
|
31
|
-
rpc_endpoints:
|
|
40
|
+
rpc_endpoints: RpcEndpointsSuiteOption;
|
|
32
41
|
}
|
|
33
42
|
/**
|
|
34
43
|
* Standard rate limiting integration test suite.
|
|
@@ -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;AAiB7B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAC,gBAAgB,
|
|
1
|
+
{"version":3,"file":"rate_limiting.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/rate_limiting.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAiB7B,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;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,4BAA4B,GAAI,SAAS,uBAAuB,KAAG,IA8P/E,CAAC"}
|
|
@@ -18,7 +18,7 @@ import { AUTH_MIGRATION_NS } from '../auth/migrations.js';
|
|
|
18
18
|
import { create_test_app } from './app_server.js';
|
|
19
19
|
import { create_pglite_factory, create_describe_db, AUTH_INTEGRATION_TRUNCATE_TABLES, } from './db.js';
|
|
20
20
|
import { find_auth_route, assert_rate_limit_retry_after_header } from './integration_helpers.js';
|
|
21
|
-
import { rpc_call_non_browser, require_rpc_endpoint_path } from './rpc_helpers.js';
|
|
21
|
+
import { rpc_call_non_browser, require_rpc_endpoint_path, resolve_rpc_endpoints_for_setup, } from './rpc_helpers.js';
|
|
22
22
|
import { run_migrations } from '../db/migrate.js';
|
|
23
23
|
import { account_verify_action_spec } from '../auth/account_action_specs.js';
|
|
24
24
|
/**
|
|
@@ -40,8 +40,11 @@ import { account_verify_action_spec } from '../auth/account_action_specs.js';
|
|
|
40
40
|
export const describe_rate_limiting_tests = (options) => {
|
|
41
41
|
const max_attempts = options.max_attempts ?? 2;
|
|
42
42
|
// Hard-fail early so consumers see a clear setup error instead of a
|
|
43
|
-
// confusing test failure when `rpc_endpoints` is missing.
|
|
44
|
-
|
|
43
|
+
// confusing test failure when `rpc_endpoints` is missing. Factory-form
|
|
44
|
+
// callers are resolved with a stub ctx purely to extract the endpoint
|
|
45
|
+
// path; real handlers run per-test via `app_options.rpc_endpoints`.
|
|
46
|
+
const rpc_endpoints_for_setup = resolve_rpc_endpoints_for_setup(options.rpc_endpoints, options.session_options);
|
|
47
|
+
const rpc_path = require_rpc_endpoint_path(rpc_endpoints_for_setup);
|
|
45
48
|
const init_schema = async (db) => {
|
|
46
49
|
await run_migrations(db, [AUTH_MIGRATION_NS]);
|
|
47
50
|
};
|
|
@@ -61,6 +64,7 @@ export const describe_rate_limiting_tests = (options) => {
|
|
|
61
64
|
db: get_db(),
|
|
62
65
|
app_options: {
|
|
63
66
|
...options.app_options,
|
|
67
|
+
rpc_endpoints: options.rpc_endpoints,
|
|
64
68
|
ip_rate_limiter,
|
|
65
69
|
login_account_rate_limiter: null,
|
|
66
70
|
bearer_ip_rate_limiter: null,
|
|
@@ -113,6 +117,7 @@ export const describe_rate_limiting_tests = (options) => {
|
|
|
113
117
|
db: get_db(),
|
|
114
118
|
app_options: {
|
|
115
119
|
...options.app_options,
|
|
120
|
+
rpc_endpoints: options.rpc_endpoints,
|
|
116
121
|
ip_rate_limiter: null,
|
|
117
122
|
login_account_rate_limiter,
|
|
118
123
|
bearer_ip_rate_limiter: null,
|
|
@@ -177,6 +182,7 @@ export const describe_rate_limiting_tests = (options) => {
|
|
|
177
182
|
db: get_db(),
|
|
178
183
|
app_options: {
|
|
179
184
|
...options.app_options,
|
|
185
|
+
rpc_endpoints: options.rpc_endpoints,
|
|
180
186
|
ip_rate_limiter: null,
|
|
181
187
|
login_account_rate_limiter: null,
|
|
182
188
|
bearer_ip_rate_limiter,
|
|
@@ -4,6 +4,35 @@ import { type JsonrpcErrorCode } from '../http/jsonrpc.js';
|
|
|
4
4
|
import type { RequestResponseActionSpec } from '../actions/action_spec.js';
|
|
5
5
|
import type { RpcAction } from '../actions/action_rpc.js';
|
|
6
6
|
import type { AppSurfaceRpcEndpoint, AppSurfaceRpcMethod, RpcEndpointSpec } from '../http/surface.js';
|
|
7
|
+
import type { AppServerContext } from '../server/app_server.js';
|
|
8
|
+
import type { SessionOptions } from '../auth/session_cookie.js';
|
|
9
|
+
/**
|
|
10
|
+
* Union accepted by the suite-level `rpc_endpoints` option — eager array or
|
|
11
|
+
* a factory that takes an `AppServerContext` and returns endpoint specs. The
|
|
12
|
+
* factory form is required when action handlers must close over the
|
|
13
|
+
* per-test `ctx.app_settings` / `ctx.deps` (e.g. the canonical
|
|
14
|
+
* `create_admin_rpc_actions(ctx.deps, {app_settings: ctx.app_settings})`
|
|
15
|
+
* pattern). `create_app_server` resolves either shape natively; test helpers
|
|
16
|
+
* forward the raw value to `app_options.rpc_endpoints` for live dispatch.
|
|
17
|
+
*/
|
|
18
|
+
export type RpcEndpointsSuiteOption = Array<RpcEndpointSpec> | ((ctx: AppServerContext) => Array<RpcEndpointSpec>);
|
|
19
|
+
/**
|
|
20
|
+
* Resolve a suite's `rpc_endpoints` option to an array for setup-time
|
|
21
|
+
* inspection (path lookup, action presence checks).
|
|
22
|
+
*
|
|
23
|
+
* For the factory form this invokes the factory once with a stub
|
|
24
|
+
* `AppServerContext` purely to materialize its return shape — the produced
|
|
25
|
+
* actions are discarded. `create_app_server` invokes the factory a second
|
|
26
|
+
* time inside each test with its real ctx, and those are the handlers that
|
|
27
|
+
* actually serve requests.
|
|
28
|
+
*
|
|
29
|
+
* Safe as long as the factory is pure with respect to the endpoint `path`
|
|
30
|
+
* and the action `spec.method` list — the canonical helpers
|
|
31
|
+
* (`create_admin_rpc_actions`, `create_account_actions`, etc.) are. Factories
|
|
32
|
+
* that return a different `path` based on `ctx` will produce a setup/runtime
|
|
33
|
+
* mismatch; don't do that.
|
|
34
|
+
*/
|
|
35
|
+
export declare const resolve_rpc_endpoints_for_setup: (rpc_endpoints: RpcEndpointsSuiteOption, session_options: SessionOptions<string>) => Array<RpcEndpointSpec>;
|
|
7
36
|
/**
|
|
8
37
|
* Create a `RequestInit` for a JSON-RPC POST request.
|
|
9
38
|
*
|
|
@@ -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;
|
|
1
|
+
{"version":3,"file":"rpc_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/rpc_helpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,6 +11,26 @@ import './assert_dev_env.js';
|
|
|
11
11
|
import { assert } from 'vitest';
|
|
12
12
|
import { z } from 'zod';
|
|
13
13
|
import { JSONRPC_VERSION, JsonrpcErrorResponse, JsonrpcResponse, } from '../http/jsonrpc.js';
|
|
14
|
+
import { create_stub_app_server_context } from './stubs.js';
|
|
15
|
+
/**
|
|
16
|
+
* Resolve a suite's `rpc_endpoints` option to an array for setup-time
|
|
17
|
+
* inspection (path lookup, action presence checks).
|
|
18
|
+
*
|
|
19
|
+
* For the factory form this invokes the factory once with a stub
|
|
20
|
+
* `AppServerContext` purely to materialize its return shape — the produced
|
|
21
|
+
* actions are discarded. `create_app_server` invokes the factory a second
|
|
22
|
+
* time inside each test with its real ctx, and those are the handlers that
|
|
23
|
+
* actually serve requests.
|
|
24
|
+
*
|
|
25
|
+
* Safe as long as the factory is pure with respect to the endpoint `path`
|
|
26
|
+
* and the action `spec.method` list — the canonical helpers
|
|
27
|
+
* (`create_admin_rpc_actions`, `create_account_actions`, etc.) are. Factories
|
|
28
|
+
* that return a different `path` based on `ctx` will produce a setup/runtime
|
|
29
|
+
* mismatch; don't do that.
|
|
30
|
+
*/
|
|
31
|
+
export const resolve_rpc_endpoints_for_setup = (rpc_endpoints, session_options) => typeof rpc_endpoints === 'function'
|
|
32
|
+
? rpc_endpoints(create_stub_app_server_context(session_options))
|
|
33
|
+
: rpc_endpoints;
|
|
14
34
|
/**
|
|
15
35
|
* Create a `RequestInit` for a JSON-RPC POST request.
|
|
16
36
|
*
|
|
@@ -1,19 +1,30 @@
|
|
|
1
1
|
import './assert_dev_env.js';
|
|
2
2
|
import type { RouteSpec } from '../http/route_spec.js';
|
|
3
|
-
import type { AppServerContext
|
|
3
|
+
import type { AppServerContext } from '../server/app_server.js';
|
|
4
4
|
import type { SessionOptions } from '../auth/session_cookie.js';
|
|
5
|
+
import { type SuiteAppOptions } from './app_server.js';
|
|
5
6
|
import { type DbFactory } from './db.js';
|
|
6
|
-
import type
|
|
7
|
+
import { type RpcEndpointsSuiteOption } from './rpc_helpers.js';
|
|
7
8
|
/** Options for `describe_rpc_round_trip_tests`. */
|
|
8
9
|
export interface RpcRoundTripTestOptions {
|
|
9
10
|
/** Session config for cookie-based auth. */
|
|
10
11
|
session_options: SessionOptions<string>;
|
|
11
12
|
/** Route spec factory — same one used in production. */
|
|
12
13
|
create_route_specs: (ctx: AppServerContext) => Array<RouteSpec>;
|
|
13
|
-
/**
|
|
14
|
-
|
|
14
|
+
/**
|
|
15
|
+
* RPC endpoint specs — the source `RpcAction` arrays for params generation.
|
|
16
|
+
*
|
|
17
|
+
* Accepts either an array (eager) or a factory
|
|
18
|
+
* `(ctx: AppServerContext) => Array<RpcEndpointSpec>` — the factory form
|
|
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.
|
|
24
|
+
*/
|
|
25
|
+
rpc_endpoints: RpcEndpointsSuiteOption;
|
|
15
26
|
/** Optional overrides for `AppServerOptions`. */
|
|
16
|
-
app_options?:
|
|
27
|
+
app_options?: SuiteAppOptions;
|
|
17
28
|
/** Database factories to run tests against. Default: pglite only. */
|
|
18
29
|
db_factories?: Array<DbFactory>;
|
|
19
30
|
/** Methods to skip, by name (e.g., `'tx_plan'`). */
|
|
@@ -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;AAe7B,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAC,gBAAgB,
|
|
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;AAe7B,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAE9D,OAAO,EAEN,KAAK,eAAe,EAGpB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAwB,KAAK,SAAS,EAAC,MAAM,SAAS,CAAC;AAM9D,OAAO,EAMN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AAE1B,mDAAmD;AACnD,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;;;;;;;;;;OAUG;IACH,aAAa,EAAE,uBAAuB,CAAC;IACvC,iDAAiD;IACjD,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,qEAAqE;IACrE,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAChC,oDAAoD;IACpD,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;AA2BD;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,6BAA6B,GAAI,SAAS,uBAAuB,KAAG,IA8IhF,CAAC"}
|
|
@@ -11,12 +11,12 @@ import './assert_dev_env.js';
|
|
|
11
11
|
*/
|
|
12
12
|
import { describe, test, beforeAll, afterAll } from 'vitest';
|
|
13
13
|
import { ROLE_ADMIN } from '../auth/role_schema.js';
|
|
14
|
-
import { create_test_app } from './app_server.js';
|
|
14
|
+
import { create_test_app, } from './app_server.js';
|
|
15
15
|
import { create_pglite_factory } from './db.js';
|
|
16
16
|
import { generate_valid_body } from './schema_generators.js';
|
|
17
17
|
import { run_migrations } from '../db/migrate.js';
|
|
18
18
|
import { AUTH_MIGRATION_NS } from '../auth/migrations.js';
|
|
19
|
-
import { create_rpc_post_init, create_rpc_get_url, assert_jsonrpc_error_response, assert_jsonrpc_success_response, } from './rpc_helpers.js';
|
|
19
|
+
import { create_rpc_post_init, create_rpc_get_url, assert_jsonrpc_error_response, assert_jsonrpc_success_response, resolve_rpc_endpoints_for_setup, } from './rpc_helpers.js';
|
|
20
20
|
/**
|
|
21
21
|
* Pick auth headers matching an RPC method's auth requirement.
|
|
22
22
|
*/
|
|
@@ -54,6 +54,12 @@ const pick_rpc_auth_headers = (method, test_app, authed_account, admin_account)
|
|
|
54
54
|
*/
|
|
55
55
|
export const describe_rpc_round_trip_tests = (options) => {
|
|
56
56
|
const skip_set = new Set(options.skip_methods);
|
|
57
|
+
// Resolve factory-form endpoints once for setup-time iteration (method
|
|
58
|
+
// enumeration, surface lookup). Real handlers run per-test via
|
|
59
|
+
// `app_options.rpc_endpoints` — `action.spec.method` / `.input` /
|
|
60
|
+
// `.output` are ctx-independent, so the stub-resolved specs match
|
|
61
|
+
// what the live dispatcher serves.
|
|
62
|
+
const rpc_endpoints_for_setup = resolve_rpc_endpoints_for_setup(options.rpc_endpoints, options.session_options);
|
|
57
63
|
const init_schema = async (db) => {
|
|
58
64
|
await run_migrations(db, [AUTH_MIGRATION_NS]);
|
|
59
65
|
};
|
|
@@ -72,8 +78,8 @@ export const describe_rpc_round_trip_tests = (options) => {
|
|
|
72
78
|
create_route_specs: options.create_route_specs,
|
|
73
79
|
db,
|
|
74
80
|
app_options: {
|
|
75
|
-
rpc_endpoints: options.rpc_endpoints,
|
|
76
81
|
...options.app_options,
|
|
82
|
+
rpc_endpoints: options.rpc_endpoints,
|
|
77
83
|
},
|
|
78
84
|
});
|
|
79
85
|
authed_account = await test_app.create_account({
|
|
@@ -90,7 +96,7 @@ export const describe_rpc_round_trip_tests = (options) => {
|
|
|
90
96
|
await factory.close(db);
|
|
91
97
|
});
|
|
92
98
|
test('all RPC methods produce valid JSON-RPC responses (POST)', async () => {
|
|
93
|
-
for (const ep_spec of
|
|
99
|
+
for (const ep_spec of rpc_endpoints_for_setup) {
|
|
94
100
|
const surface_ep = test_app.surface_spec.surface.rpc_endpoints.find((e) => e.path === ep_spec.path);
|
|
95
101
|
if (!surface_ep)
|
|
96
102
|
continue;
|
|
@@ -126,7 +132,7 @@ export const describe_rpc_round_trip_tests = (options) => {
|
|
|
126
132
|
}
|
|
127
133
|
});
|
|
128
134
|
test('all read RPC methods produce valid JSON-RPC responses (GET)', async () => {
|
|
129
|
-
for (const ep_spec of
|
|
135
|
+
for (const ep_spec of rpc_endpoints_for_setup) {
|
|
130
136
|
const surface_ep = test_app.surface_spec.surface.rpc_endpoints.find((e) => e.path === ep_spec.path);
|
|
131
137
|
if (!surface_ep)
|
|
132
138
|
continue;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import './assert_dev_env.js';
|
|
2
2
|
import type { RouteSpec } from '../http/route_spec.js';
|
|
3
|
-
import type { AppServerContext
|
|
3
|
+
import type { AppServerContext } from '../server/app_server.js';
|
|
4
4
|
import type { SessionOptions } from '../auth/session_cookie.js';
|
|
5
5
|
import { type EventSpec } from '../realtime/sse.js';
|
|
6
6
|
import type { AuditLogEvent } from '../auth/audit_log_schema.js';
|
|
7
|
-
import { type TestApp, type TestAccount } from './app_server.js';
|
|
7
|
+
import { type SuiteAppOptions, type TestApp, type TestAccount } from './app_server.js';
|
|
8
8
|
import { type DbFactory } from './db.js';
|
|
9
|
-
import type
|
|
9
|
+
import { type RpcEndpointsSuiteOption } from './rpc_helpers.js';
|
|
10
10
|
/** Config for a single SSE route under test. */
|
|
11
11
|
export interface SseRouteTestSpec {
|
|
12
12
|
/** Full HTTP path of the SSE endpoint (e.g., `'/api/tx/subscribe'`). */
|
|
@@ -39,7 +39,7 @@ export interface SseRouteTestOptions {
|
|
|
39
39
|
/** Route spec factory — same shape as production. */
|
|
40
40
|
create_route_specs: (ctx: AppServerContext) => Array<RouteSpec>;
|
|
41
41
|
/** Optional overrides for `AppServerOptions`. */
|
|
42
|
-
app_options?:
|
|
42
|
+
app_options?: SuiteAppOptions;
|
|
43
43
|
/** Database factories to run tests against. Default: pglite only. */
|
|
44
44
|
db_factories?: Array<DbFactory>;
|
|
45
45
|
/**
|
|
@@ -54,8 +54,16 @@ export interface SseRouteTestOptions {
|
|
|
54
54
|
* dispatch `account_session_revoke_all` via RPC (the former REST route
|
|
55
55
|
* `POST /api/account/sessions/revoke-all` was removed in the 2026-04-23
|
|
56
56
|
* migration). Hard-fails via `require_rpc_endpoint_path` on setup.
|
|
57
|
+
*
|
|
58
|
+
* Accepts either an array (eager) or a factory
|
|
59
|
+
* `(ctx: AppServerContext) => Array<RpcEndpointSpec>` — the factory form
|
|
60
|
+
* is required when action handlers must close over the per-test
|
|
61
|
+
* `ctx.app_settings` / `ctx.deps`. The factory must return the same
|
|
62
|
+
* endpoint `path` regardless of ctx — it is invoked once at setup with
|
|
63
|
+
* a stub ctx for path lookup and again per-test by `create_app_server`
|
|
64
|
+
* for live dispatch.
|
|
57
65
|
*/
|
|
58
|
-
rpc_endpoints:
|
|
66
|
+
rpc_endpoints: RpcEndpointsSuiteOption;
|
|
59
67
|
/** SSE routes to exercise. */
|
|
60
68
|
routes: Array<SseRouteTestSpec>;
|
|
61
69
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sse_round_trip.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/sse_round_trip.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAmB7B,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAC,gBAAgB,
|
|
1
|
+
{"version":3,"file":"sse_round_trip.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/sse_round_trip.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAmB7B,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAwB,KAAK,SAAS,EAAuB,MAAM,oBAAoB,CAAC;AAE/F,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAEN,KAAK,eAAe,EACpB,KAAK,OAAO,EACZ,KAAK,WAAW,EAChB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAwB,KAAK,SAAS,EAAC,MAAM,SAAS,CAAC;AAE9D,OAAO,EAIN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AAM1B,gDAAgD;AAChD,MAAM,WAAW,gBAAgB;IAChC,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,OAAO,EAAE,CAAC,GAAG,EAAE;QAAC,QAAQ,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,WAAW,CAAA;KAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3E;;;OAGG;IACH,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAC/B;;;;OAIG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;CAClC;AAED,8CAA8C;AAC9C,MAAM,WAAW,mBAAmB;IACnC,4CAA4C;IAC5C,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,qDAAqD;IACrD,kBAAkB,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,KAAK,CAAC,SAAS,CAAC,CAAC;IAChE,iDAAiD;IACjD,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,qEAAqE;IACrE,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAChC;;;;;OAKG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAChD;;;;;;;;;;;;;OAaG;IACH,aAAa,EAAE,uBAAuB,CAAC;IACvC,8BAA8B;IAC9B,MAAM,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC;CAChC;AAyHD;;;;;;;;GAQG;AACH,eAAO,MAAM,wBAAwB,GAAI,SAAS,mBAAmB,KAAG,IA2HvE,CAAC"}
|
|
@@ -16,10 +16,10 @@ import './assert_dev_env.js';
|
|
|
16
16
|
import { describe, test, beforeAll, afterAll, assert } from 'vitest';
|
|
17
17
|
import { SSE_CONNECTED_COMMENT } from '../realtime/sse.js';
|
|
18
18
|
import { ROLE_ADMIN } from '../auth/role_schema.js';
|
|
19
|
-
import { create_test_app } from './app_server.js';
|
|
19
|
+
import { create_test_app, } from './app_server.js';
|
|
20
20
|
import { create_pglite_factory } from './db.js';
|
|
21
21
|
import { find_route_spec, pick_auth_headers } from './integration_helpers.js';
|
|
22
|
-
import { rpc_call, require_rpc_endpoint_path } from './rpc_helpers.js';
|
|
22
|
+
import { rpc_call, require_rpc_endpoint_path, resolve_rpc_endpoints_for_setup, } from './rpc_helpers.js';
|
|
23
23
|
import { run_migrations } from '../db/migrate.js';
|
|
24
24
|
import { AUTH_MIGRATION_NS } from '../auth/migrations.js';
|
|
25
25
|
import { account_session_revoke_all_action_spec } from '../auth/account_action_specs.js';
|
|
@@ -130,8 +130,11 @@ const parse_and_validate_sse_payload = (frame, event_specs, route_path) => {
|
|
|
130
130
|
*/
|
|
131
131
|
export const describe_sse_route_tests = (options) => {
|
|
132
132
|
// Hard-fail early so consumers see a clear setup error instead of a
|
|
133
|
-
// confusing test failure when `rpc_endpoints` is missing.
|
|
134
|
-
|
|
133
|
+
// confusing test failure when `rpc_endpoints` is missing. Factory-form
|
|
134
|
+
// callers are resolved with a stub ctx purely to extract the endpoint
|
|
135
|
+
// path; real handlers run per-test via `app_options.rpc_endpoints`.
|
|
136
|
+
const rpc_endpoints_for_setup = resolve_rpc_endpoints_for_setup(options.rpc_endpoints, options.session_options);
|
|
137
|
+
const rpc_path = require_rpc_endpoint_path(rpc_endpoints_for_setup);
|
|
135
138
|
const init_schema = async (db) => {
|
|
136
139
|
await run_migrations(db, [AUTH_MIGRATION_NS]);
|
|
137
140
|
};
|
|
@@ -152,7 +155,10 @@ export const describe_sse_route_tests = (options) => {
|
|
|
152
155
|
session_options: options.session_options,
|
|
153
156
|
create_route_specs: options.create_route_specs,
|
|
154
157
|
db,
|
|
155
|
-
app_options:
|
|
158
|
+
app_options: {
|
|
159
|
+
...options.app_options,
|
|
160
|
+
rpc_endpoints: options.rpc_endpoints,
|
|
161
|
+
},
|
|
156
162
|
on_audit_event: options.on_audit_event,
|
|
157
163
|
});
|
|
158
164
|
authed_account = await test_app.create_account({
|
|
@@ -13,7 +13,7 @@ import type { AppServerContext, AppServerOptions } from '../server/app_server.js
|
|
|
13
13
|
import type { RouteSpec } from '../http/route_spec.js';
|
|
14
14
|
import type { RoleSchemaResult } from '../auth/role_schema.js';
|
|
15
15
|
import type { DbFactory } from './db.js';
|
|
16
|
-
import type {
|
|
16
|
+
import type { RpcEndpointsSuiteOption } from './rpc_helpers.js';
|
|
17
17
|
/**
|
|
18
18
|
* Configuration for `describe_standard_tests`.
|
|
19
19
|
*/
|
|
@@ -38,8 +38,13 @@ export interface StandardTestOptions {
|
|
|
38
38
|
* `account_verify`, `account_session_*`, `account_token_*` through the
|
|
39
39
|
* RPC surface (and admin tests, when wired, drive permit grant/revoke
|
|
40
40
|
* through it too).
|
|
41
|
+
*
|
|
42
|
+
* Accepts either an array (eager) or a factory
|
|
43
|
+
* `(ctx: AppServerContext) => Array<RpcEndpointSpec>`. Round-tripped
|
|
44
|
+
* to both sub-suites unchanged — see their docstrings for the full
|
|
45
|
+
* factory-form contract.
|
|
41
46
|
*/
|
|
42
|
-
rpc_endpoints:
|
|
47
|
+
rpc_endpoints: RpcEndpointsSuiteOption;
|
|
43
48
|
/**
|
|
44
49
|
* Path prefix where admin routes are mounted.
|
|
45
50
|
* Default `'/api/admin'`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"standard.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/standard.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAE7B;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAC,gBAAgB,EAAE,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAChF,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,SAAS,CAAC;AAGvC,OAAO,KAAK,EAAC,
|
|
1
|
+
{"version":3,"file":"standard.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/standard.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAE7B;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAC,gBAAgB,EAAE,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAChF,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,SAAS,CAAC;AAGvC,OAAO,KAAK,EAAC,uBAAuB,EAAC,MAAM,kBAAkB,CAAC;AAE9D;;GAEG;AACH,MAAM,WAAW,mBAAmB;IACnC,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,OAAO,CACpB,IAAI,CAAC,gBAAgB,EAAE,SAAS,GAAG,iBAAiB,GAAG,oBAAoB,CAAC,CAC5E,CAAC;IACF;;OAEG;IACH,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAChC;;;OAGG;IACH,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB;;;;;;;;;;OAUG;IACH,aAAa,EAAE,uBAAuB,CAAC;IACvC;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,uBAAuB,GAAI,SAAS,mBAAmB,KAAG,IAStE,CAAC"}
|
package/dist/testing/stubs.d.ts
CHANGED
|
@@ -76,8 +76,16 @@ export interface CreateTestAppSurfaceSpecOptions {
|
|
|
76
76
|
env_schema?: z.ZodObject;
|
|
77
77
|
/** SSE event specs for surface generation. */
|
|
78
78
|
event_specs?: Array<EventSpec>;
|
|
79
|
-
/**
|
|
80
|
-
|
|
79
|
+
/**
|
|
80
|
+
* RPC endpoint specs for surface generation.
|
|
81
|
+
*
|
|
82
|
+
* Accepts either an array (eager) or a factory
|
|
83
|
+
* `(ctx: AppServerContext) => Array<RpcEndpointSpec>` — symmetric with
|
|
84
|
+
* `create_app_server`'s `rpc_endpoints` option, so consumers can pass
|
|
85
|
+
* the same factory to both entry points. The factory runs once against
|
|
86
|
+
* the stub `AppServerContext` this helper already builds.
|
|
87
|
+
*/
|
|
88
|
+
rpc_endpoints?: Array<RpcEndpointSpec> | ((ctx: AppServerContext) => Array<RpcEndpointSpec>);
|
|
81
89
|
/** Transform middleware array (e.g., tx's `extend_middleware_for_tx_binary`). */
|
|
82
90
|
transform_middleware?: (specs: Array<MiddlewareSpec>) => Array<MiddlewareSpec>;
|
|
83
91
|
/** Bootstrap route prefix (default: `'/api/account'`). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stubs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/stubs.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAa7B,OAAO,KAAK,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAE3B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,4BAA4B,CAAC;AAE/D,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAC,EAAE,EAAC,MAAM,aAAa,CAAC;AAC/B,OAAO,EAAqB,KAAK,SAAS,EAAC,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"stubs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/stubs.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAa7B,OAAO,KAAK,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAE3B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,4BAA4B,CAAC;AAE/D,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAC,EAAE,EAAC,MAAM,aAAa,CAAC;AAC/B,OAAO,EAAqB,KAAK,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAGzE,OAAO,EAEN,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,oBAAoB,CAAC;AAKlD;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,GAAI,CAAC,GAAG,GAAG,EAAE,OAAO,MAAM,KAAG,CAqBtD,CAAC;AAET;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB,GAAI,CAAC,GAAG,GAAG,EAAE,QAAQ,MAAM,EAAE,YAAY,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,CAOxF,CAAC;AAET,iEAAiE;AACjE,eAAO,MAAM,IAAI,EAAE,GAAkC,CAAC;AAEtD;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,QAAO,EAI/B,CAAC;AAEJ,gDAAgD;AAChD,eAAO,MAAM,YAAY,QAAO,QAAgC,CAAC;AAEjE,2CAA2C;AAC3C,eAAO,MAAM,OAAO,GAAU,IAAI,GAAG,EAAE,MAAM,GAAG,KAAG,OAAO,CAAC,IAAI,CAAW,CAAC;AAI3E,2EAA2E;AAC3E,eAAO,MAAM,aAAa,EAAE,OAS3B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,QAAO,OAStC,CAAC;AAEH,2FAA2F;AAC3F,eAAO,MAAM,0BAA0B,GAAI,UAAU;IACpD,iDAAiD;IACjD,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAC/B,KAAG,KAAK,CAAC,cAAc,CAqBvB,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,8BAA8B,GAC1C,iBAAiB,cAAc,CAAC,MAAM,CAAC,KACrC,gBAmBF,CAAC;AAEF,kDAAkD;AAClD,MAAM,WAAW,+BAA+B;IAC/C,6DAA6D;IAC7D,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,qFAAqF;IACrF,kBAAkB,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,KAAK,CAAC,SAAS,CAAC,CAAC;IAChE,oEAAoE;IACpE,UAAU,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;IACzB,8CAA8C;IAC9C,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAC/B;;;;;;;;OAQG;IACH,aAAa,CAAC,EAAE,KAAK,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,gBAAgB,KAAK,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC;IAC7F,iFAAiF;IACjF,oBAAoB,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,KAAK,CAAC,cAAc,CAAC,CAAC;IAC/E,0DAA0D;IAC1D,sBAAsB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,4BAA4B,GACxC,SAAS,+BAA+B,KACtC,cA2CF,CAAC"}
|
package/dist/testing/stubs.js
CHANGED
|
@@ -12,6 +12,7 @@ import { ApiError, RateLimitError } from '../http/error_schemas.js';
|
|
|
12
12
|
import { Db } from '../db/db.js';
|
|
13
13
|
import { prefix_route_specs } from '../http/route_spec.js';
|
|
14
14
|
import { create_bootstrap_route_specs } from '../auth/bootstrap_routes.js';
|
|
15
|
+
import { create_rpc_endpoint } from '../actions/action_rpc.js';
|
|
15
16
|
import { create_app_surface_spec, } from '../http/surface.js';
|
|
16
17
|
import { BaseServerEnv } from '../server/env.js';
|
|
17
18
|
/* eslint-disable @typescript-eslint/require-await */
|
|
@@ -178,7 +179,21 @@ export const create_test_app_surface_spec = (options) => {
|
|
|
178
179
|
ip_rate_limiter: null,
|
|
179
180
|
});
|
|
180
181
|
const prefix = options.bootstrap_route_prefix ?? '/api/account';
|
|
181
|
-
|
|
182
|
+
// Auto-mount rpc endpoints (mirrors create_app_server) so consumer
|
|
183
|
+
// `create_route_specs` does not need to call `create_rpc_endpoint`.
|
|
184
|
+
const resolved_rpc_endpoints = typeof options.rpc_endpoints === 'function'
|
|
185
|
+
? options.rpc_endpoints(ctx)
|
|
186
|
+
: options.rpc_endpoints;
|
|
187
|
+
const rpc_route_specs = resolved_rpc_endpoints?.flatMap((endpoint) => create_rpc_endpoint({
|
|
188
|
+
path: endpoint.path,
|
|
189
|
+
actions: endpoint.actions,
|
|
190
|
+
log: ctx.deps.log,
|
|
191
|
+
})) ?? [];
|
|
192
|
+
const route_specs = [
|
|
193
|
+
...consumer_routes,
|
|
194
|
+
...rpc_route_specs,
|
|
195
|
+
...prefix_route_specs(prefix, bootstrap_routes),
|
|
196
|
+
];
|
|
182
197
|
let middleware_specs = create_stub_api_middleware();
|
|
183
198
|
if (options.transform_middleware) {
|
|
184
199
|
middleware_specs = options.transform_middleware(middleware_specs);
|
|
@@ -188,6 +203,6 @@ export const create_test_app_surface_spec = (options) => {
|
|
|
188
203
|
route_specs,
|
|
189
204
|
env_schema: options.env_schema ?? BaseServerEnv,
|
|
190
205
|
event_specs: options.event_specs,
|
|
191
|
-
rpc_endpoints:
|
|
206
|
+
rpc_endpoints: resolved_rpc_endpoints,
|
|
192
207
|
});
|
|
193
208
|
};
|
package/dist/ui/CLAUDE.md
CHANGED
|
@@ -266,6 +266,18 @@ destructive actions.
|
|
|
266
266
|
`Loadable` + `app_settings_rpc_context` + narrow `AppSettingsRpc`
|
|
267
267
|
(`get`, `update`). Fields: `settings`, `updating`. Single mutation
|
|
268
268
|
`update_open_signup(boolean)`.
|
|
269
|
+
- `admin_rpc_adapters.ts` (plain `.ts`, no reactive state) — bundled
|
|
270
|
+
wiring for the four admin RPC contexts. `create_admin_rpc_adapters(rpc_call)`
|
|
271
|
+
takes a single `AdminRpcCall` closure (alias of `ThrowingRpcCall` from
|
|
272
|
+
`../actions/rpc_client.ts`) and returns `{admin_accounts, admin_invites,
|
|
273
|
+
audit_log, app_settings}` adapter objects. `provide_admin_rpc_contexts(adapters)`
|
|
274
|
+
calls `set` on all four contexts in one shot. Pair with
|
|
275
|
+
`create_throwing_rpc_call(api)` from `../actions/rpc_client.ts` to turn a
|
|
276
|
+
typed `create_rpc_client` Proxy into the throw-on-error `rpc_call`
|
|
277
|
+
signature — two lines at the admin shell layout. Method-name mapping is
|
|
278
|
+
in the module TSDoc (`grant_permit` → `permit_offer_create`,
|
|
279
|
+
`retract_offer` → `permit_offer_retract`, etc.) and the
|
|
280
|
+
`admin_rpc_adapters.test.ts` fixtures.
|
|
269
281
|
|
|
270
282
|
## RPC adapter contexts
|
|
271
283
|
|