@fuzdev/fuz_app 0.32.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.
@@ -538,13 +538,25 @@ lifecycle (via `permit_offer_create` + `permit_revoke` RPC flows —
538
538
  **not** REST; see `../auth/CLAUDE.md` for `permit_offer_action_specs.ts` + `permit_offer_actions.ts`), session / token management, audit log reads (RPC),
539
539
  admin-to-admin isolation, error coverage, response schema validation.
540
540
 
541
- Required options: `{session_options, create_route_specs, roles: RoleSchemaResult, rpc_endpoints: Array<RpcEndpointSpec>, admin_prefix?, app_options?, db_factories?}`.
542
-
543
- **Hard-fails via `require_rpc_endpoint_path(options.rpc_endpoints)`** at
544
- setup time when `rpc_endpoints` is empty admin permit grant/revoke
545
- plus session/token revoke-all plus audit-log list/history are all
546
- RPC-only since the 2026-04-22 migration. A confusing test failure
547
- mid-suite is worse than a clear setup error.
541
+ Required options: `{session_options, create_route_specs, roles: RoleSchemaResult, rpc_endpoints: RpcEndpointsSuiteOption, admin_prefix?, app_options?, db_factories?}`.
542
+
543
+ `rpc_endpoints` is `Array<RpcEndpointSpec> | ((ctx: AppServerContext) => Array<RpcEndpointSpec>)` —
544
+ the same `RpcEndpointsSuiteOption` union every DB-backed suite accepts
545
+ (`integration`, `admin_integration`, `audit_completeness`, `rate_limiting`,
546
+ `rpc_round_trip`, `sse_round_trip`). Prefer the factory form: it forwards
547
+ raw to `app_options.rpc_endpoints` so `create_app_server` resolves it per-test
548
+ with the real ctx — the only way action handlers can close over
549
+ `ctx.deps` / `ctx.app_settings` (e.g. `create_admin_rpc_actions(ctx.deps,
550
+ {app_settings: ctx.app_settings})`). Factory must return the same endpoint
551
+ `path` regardless of ctx — `resolve_rpc_endpoints_for_setup` invokes it
552
+ once with a stub ctx for path lookup and `create_app_server` invokes it
553
+ again per-test for live dispatch.
554
+
555
+ **Hard-fails via `require_rpc_endpoint_path`** at setup time when
556
+ `rpc_endpoints` is empty — admin permit grant/revoke plus session/token
557
+ revoke-all plus audit-log list/history are all RPC-only since the
558
+ 2026-04-22 migration. A confusing test failure mid-suite is worse than a
559
+ clear setup error.
548
560
 
549
561
  Error-coverage scope is narrowed to the REST suffixes still on the
550
562
  admin surface (`/sessions`, `/audit-log/stream`); the RPC surface is
@@ -569,9 +581,11 @@ provide the filesystem token state; covered separately in
569
581
 
570
582
  Convenience wrapper: always runs `describe_standard_integration_tests`;
571
583
  runs `describe_standard_admin_integration_tests` only when `roles` is
572
- provided. `rpc_endpoints` is a required field on `StandardTestOptions`
573
- — the admin suite's requirement is enforced at the type level, so a
574
- missing `rpc_endpoints` is a compile error rather than a runtime throw.
584
+ provided. `rpc_endpoints: RpcEndpointsSuiteOption` is a required field on
585
+ `StandardTestOptions` — the admin suite's requirement is enforced at the
586
+ type level, so a missing `rpc_endpoints` is a compile error rather than a
587
+ runtime throw. Round-trips the union through unchanged so consumers can
588
+ pass either an eager array or the factory form.
575
589
 
576
590
  ## RPC helpers
577
591
 
@@ -613,6 +627,8 @@ Registry lookups:
613
627
  - `find_rpc_action(rpc_endpoints, method)` — endpoint path + `RpcAction` source.
614
628
  - `find_rpc_method(rpc_endpoints, method)` — surface-shape lookup over `AppSurfaceRpcEndpoint[]` (generated by `generate_app_surface`).
615
629
  - `require_rpc_endpoint_path(rpc_endpoints)` — returns the single endpoint path; throws descriptively on zero or multiple endpoints. Used by the admin/audit suites to hard-fail at setup.
630
+ - `RpcEndpointsSuiteOption` — union `Array<RpcEndpointSpec> | ((ctx: AppServerContext) => Array<RpcEndpointSpec>)` accepted by every DB-backed suite's `rpc_endpoints` field.
631
+ - `resolve_rpc_endpoints_for_setup(rpc_endpoints, session_options)` — resolves the union to an array for setup-time inspection (path lookup, `find_rpc_action` presence checks). Factory form is invoked once with a stub `AppServerContext`; the produced actions are discarded because `create_app_server` invokes the factory a second time per-test with its real ctx. Safe when the factory is pure wrt endpoint `path` and action `spec.method` list.
616
632
 
617
633
  ### `rpc_attack_surface.ts` — `describe_rpc_attack_surface_tests`
618
634
 
@@ -1,10 +1,11 @@
1
1
  import './assert_dev_env.js';
2
2
  import type { SessionOptions } from '../auth/session_cookie.js';
3
- import type { AppServerContext, AppServerOptions } from '../server/app_server.js';
3
+ import type { AppServerContext } from '../server/app_server.js';
4
4
  import type { RouteSpec } from '../http/route_spec.js';
5
5
  import { type RoleSchemaResult } from '../auth/role_schema.js';
6
+ import { type SuiteAppOptions } from './app_server.js';
6
7
  import { type DbFactory } from './db.js';
7
- import type { RpcEndpointSpec } from '../http/surface.js';
8
+ import { type RpcEndpointsSuiteOption } from './rpc_helpers.js';
8
9
  /**
9
10
  * Configuration for `describe_standard_admin_integration_tests`.
10
11
  */
@@ -18,8 +19,17 @@ export interface StandardAdminIntegrationTestOptions {
18
19
  /**
19
20
  * RPC endpoint specs — the source `RpcAction` arrays. Required; permit
20
21
  * grant/revoke are RPC-only and the suite hard-fails without them.
22
+ *
23
+ * Accepts either an array (eager) or a factory
24
+ * `(ctx: AppServerContext) => Array<RpcEndpointSpec>` — the factory form
25
+ * is required when action handlers must close over the per-test
26
+ * `ctx.app_settings` / `ctx.deps` (e.g. the canonical
27
+ * `create_admin_rpc_actions(ctx.deps, {app_settings: ctx.app_settings})`
28
+ * pattern). The factory must return the same endpoint `path` regardless
29
+ * of ctx — it is invoked once at setup with a stub ctx for path lookup
30
+ * and again per-test by `create_app_server` for live dispatch.
21
31
  */
22
- rpc_endpoints: Array<RpcEndpointSpec>;
32
+ rpc_endpoints: RpcEndpointsSuiteOption;
23
33
  /**
24
34
  * Path prefix where admin routes are mounted (e.g., `'/api/admin'`).
25
35
  * Used by the schema validation test to scope to fuz_app admin routes only,
@@ -28,7 +38,7 @@ export interface StandardAdminIntegrationTestOptions {
28
38
  */
29
39
  admin_prefix?: string;
30
40
  /** Optional overrides for `AppServerOptions`. */
31
- app_options?: Partial<Omit<AppServerOptions, 'backend' | 'session_options' | 'create_route_specs'>>;
41
+ app_options?: SuiteAppOptions;
32
42
  /**
33
43
  * Database factories to run tests against. Default: pglite only.
34
44
  * Pass consumer factories (e.g. `[pglite_factory, pg_factory]`) to also test against PostgreSQL.
@@ -1 +1 @@
1
- {"version":3,"file":"admin_integration.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/admin_integration.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAkB7B,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;AAErD,OAAO,EAA0B,KAAK,gBAAgB,EAAC,MAAM,wBAAwB,CAAC;AAGtF,OAAO,EAIN,KAAK,SAAS,EACd,MAAM,SAAS,CAAC;AASjB,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,oBAAoB,CAAC;AAsBxD;;GAEG;AACH,MAAM,WAAW,mCAAmC;IACnD,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,4GAA4G;IAC5G,KAAK,EAAE,gBAAgB,CAAC;IACxB;;;OAGG;IACH,aAAa,EAAE,KAAK,CAAC,eAAe,CAAC,CAAC;IACtC;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iDAAiD;IACjD,WAAW,CAAC,EAAE,OAAO,CACpB,IAAI,CAAC,gBAAgB,EAAE,SAAS,GAAG,iBAAiB,GAAG,oBAAoB,CAAC,CAC5E,CAAC;IACF;;;OAGG;IACH,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;CAChC;AAgCD;;;;;;;;GAQG;AACH,eAAO,MAAM,yCAAyC,GACrD,SAAS,mCAAmC,KAC1C,IAo2BF,CAAC"}
1
+ {"version":3,"file":"admin_integration.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/admin_integration.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAkB7B,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;AAErD,OAAO,EAA0B,KAAK,gBAAgB,EAAC,MAAM,wBAAwB,CAAC;AAEtF,OAAO,EAA6C,KAAK,eAAe,EAAC,MAAM,iBAAiB,CAAC;AACjG,OAAO,EAIN,KAAK,SAAS,EACd,MAAM,SAAS,CAAC;AASjB,OAAO,EAKN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AAqB1B;;GAEG;AACH,MAAM,WAAW,mCAAmC;IACnD,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,4GAA4G;IAC5G,KAAK,EAAE,gBAAgB,CAAC;IACxB;;;;;;;;;;;;OAYG;IACH,aAAa,EAAE,uBAAuB,CAAC;IACvC;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iDAAiD;IACjD,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B;;;OAGG;IACH,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;CAChC;AAgCD;;;;;;;;GAQG;AACH,eAAO,MAAM,yCAAyC,GACrD,SAAS,mCAAmC,KAC1C,IA02BF,CAAC"}
@@ -20,7 +20,7 @@ import { create_pglite_factory, create_describe_db, AUTH_INTEGRATION_TRUNCATE_TA
20
20
  import { find_auth_route, assert_response_matches_spec } from './integration_helpers.js';
21
21
  import { run_migrations } from '../db/migrate.js';
22
22
  import { ErrorCoverageCollector, assert_error_coverage, DEFAULT_INTEGRATION_ERROR_COVERAGE, } from './error_coverage.js';
23
- import { rpc_call, rpc_call_non_browser, require_rpc_endpoint_path } from './rpc_helpers.js';
23
+ import { rpc_call, rpc_call_non_browser, require_rpc_endpoint_path, resolve_rpc_endpoints_for_setup, } from './rpc_helpers.js';
24
24
  import { permit_offer_create_action_spec, permit_revoke_action_spec, } from '../auth/permit_offer_action_specs.js';
25
25
  import { admin_account_list_action_spec, admin_session_list_action_spec, admin_session_revoke_all_action_spec, admin_token_revoke_all_action_spec, audit_log_list_action_spec, audit_log_permit_history_action_spec, } from '../auth/admin_action_specs.js';
26
26
  import { account_token_create_action_spec, account_verify_action_spec, } from '../auth/account_action_specs.js';
@@ -46,8 +46,8 @@ const build_admin_test_app_options = (options, db, roles) => ({
46
46
  db,
47
47
  roles: roles ?? [ROLE_KEEPER, ROLE_ADMIN],
48
48
  app_options: {
49
- rpc_endpoints: options.rpc_endpoints,
50
49
  ...options.app_options,
50
+ rpc_endpoints: options.rpc_endpoints,
51
51
  },
52
52
  });
53
53
  /**
@@ -61,8 +61,11 @@ const build_admin_test_app_options = (options, db, roles) => ({
61
61
  */
62
62
  export const describe_standard_admin_integration_tests = (options) => {
63
63
  // Hard-fail early so consumers see a clear setup error instead of a
64
- // confusing test failure when `rpc_endpoints` is missing.
65
- const rpc_path = require_rpc_endpoint_path(options.rpc_endpoints);
64
+ // confusing test failure when `rpc_endpoints` is missing. Factory-form
65
+ // callers are resolved with a stub ctx purely to extract the endpoint
66
+ // path; real handlers run per-test via `app_options.rpc_endpoints`.
67
+ const rpc_endpoints_for_setup = resolve_rpc_endpoints_for_setup(options.rpc_endpoints, options.session_options);
68
+ const rpc_path = require_rpc_endpoint_path(rpc_endpoints_for_setup);
66
69
  const init_schema = async (db) => {
67
70
  await run_migrations(db, [AUTH_MIGRATION_NS]);
68
71
  };
@@ -121,6 +121,16 @@ export interface CreateTestAppOptions extends TestAppServerOptions {
121
121
  /** Optional overrides for `AppServerOptions` (backend, session_options, and create_route_specs are managed). */
122
122
  app_options?: Partial<Omit<AppServerOptions, 'backend' | 'session_options' | 'create_route_specs'>>;
123
123
  }
124
+ /**
125
+ * `app_options` shape accepted by DB-backed suite helpers
126
+ * (`describe_standard_integration_tests`, `describe_audit_completeness_tests`,
127
+ * etc.). Excludes `rpc_endpoints` on top of the fields `CreateTestAppOptions`
128
+ * excludes — suites require `rpc_endpoints` at the suite level (hard-failed
129
+ * by `require_rpc_endpoint_path`) so setup-time path lookup and runtime
130
+ * dispatch read from one source of truth. Low-level `create_test_app`
131
+ * callers still pass `rpc_endpoints` via `app_options`.
132
+ */
133
+ export type SuiteAppOptions = Partial<Omit<AppServerOptions, 'backend' | 'session_options' | 'create_route_specs' | 'rpc_endpoints'>>;
124
134
  /**
125
135
  * A bootstrapped test account with credentials.
126
136
  */
@@ -1 +1 @@
1
- {"version":3,"file":"app_server.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/app_server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"app_server.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/app_server.ts"],"names":[],"mappings":"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"}
@@ -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, AppServerOptions } from '../server/app_server.js';
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 { RpcEndpointSpec } from '../http/surface.js';
7
+ import { type RpcEndpointsSuiteOption } from './rpc_helpers.js';
7
8
  /**
8
9
  * Configuration for `describe_audit_completeness_tests`.
9
10
  */
@@ -20,10 +21,13 @@ export interface AuditCompletenessTestOptions {
20
21
  * `(ctx: AppServerContext) => Array<RpcEndpointSpec>` — the factory form
21
22
  * is required when action handlers must close over the per-test
22
23
  * `ctx.app_settings` / `ctx.deps` (e.g. exercising `app_settings_update`).
24
+ * The factory must return the same endpoint `path` regardless of ctx —
25
+ * it is invoked once at setup with a stub ctx for path lookup and again
26
+ * per-test by `create_app_server` for live dispatch.
23
27
  */
24
- rpc_endpoints: Array<RpcEndpointSpec> | ((ctx: AppServerContext) => Array<RpcEndpointSpec>);
28
+ rpc_endpoints: RpcEndpointsSuiteOption;
25
29
  /** Optional overrides for `AppServerOptions`. */
26
- app_options?: Partial<Omit<AppServerOptions, 'backend' | 'session_options' | 'create_route_specs'>>;
30
+ app_options?: SuiteAppOptions;
27
31
  /** Database factories to run tests against. Default: pglite only. */
28
32
  db_factories?: Array<DbFactory>;
29
33
  }
@@ -1 +1 @@
1
- {"version":3,"file":"audit_completeness.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/audit_completeness.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAkB7B,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;AAMrD,OAAO,EAIN,KAAK,SAAS,EACd,MAAM,SAAS,CAAC;AAOjB,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,oBAAoB,CAAC;AAsBxD;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC5C,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;;;;;;;;OAQG;IACH,aAAa,EAAE,KAAK,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,gBAAgB,KAAK,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC;IAC5F,iDAAiD;IACjD,WAAW,CAAC,EAAE,OAAO,CACpB,IAAI,CAAC,gBAAgB,EAAE,SAAS,GAAG,iBAAiB,GAAG,oBAAoB,CAAC,CAC5E,CAAC;IACF,qEAAqE;IACrE,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;CAChC;AAoDD;;;;;;;;GAQG;AACH,eAAO,MAAM,iCAAiC,GAAI,SAAS,4BAA4B,KAAG,IA2ezF,CAAC"}
1
+ {"version":3,"file":"audit_completeness.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/audit_completeness.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAkB7B,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;AAKrD,OAAO,EAGN,KAAK,eAAe,EAEpB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAIN,KAAK,SAAS,EACd,MAAM,SAAS,CAAC;AAKjB,OAAO,EAIN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AAsB1B;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC5C,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;;;;;;;;;;;OAWG;IACH,aAAa,EAAE,uBAAuB,CAAC;IACvC,iDAAiD;IACjD,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,qEAAqE;IACrE,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;CAChC;AAoDD;;;;;;;;GAQG;AACH,eAAO,MAAM,iCAAiC,GAAI,SAAS,4BAA4B,KAAG,IAsezF,CAAC"}
@@ -16,13 +16,12 @@ import { describe, test, assert } from 'vitest';
16
16
  import { ROLE_KEEPER, ROLE_ADMIN } from '../auth/role_schema.js';
17
17
  import { AUDIT_EVENT_TYPES } from '../auth/audit_log_schema.js';
18
18
  import { AUTH_MIGRATION_NS } from '../auth/migrations.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, create_describe_db, AUTH_INTEGRATION_TRUNCATE_TABLES, } from './db.js';
21
21
  import { find_auth_route } from './integration_helpers.js';
22
22
  import { run_migrations } from '../db/migrate.js';
23
23
  import { query_accept_offer } from '../auth/permit_offer_queries.js';
24
- import { rpc_call, require_rpc_endpoint_path } from './rpc_helpers.js';
25
- import { create_stub_app_server_context } from './stubs.js';
24
+ import { rpc_call, require_rpc_endpoint_path, resolve_rpc_endpoints_for_setup, } from './rpc_helpers.js';
26
25
  import { permit_offer_create_action_spec, permit_revoke_action_spec, } from '../auth/permit_offer_action_specs.js';
27
26
  import { admin_session_revoke_all_action_spec, admin_token_revoke_all_action_spec, app_settings_update_action_spec, invite_create_action_spec, invite_delete_action_spec, } from '../auth/admin_action_specs.js';
28
27
  import { account_session_list_action_spec, account_session_revoke_action_spec, account_session_revoke_all_action_spec, account_token_create_action_spec, account_token_list_action_spec, account_token_revoke_action_spec, } from '../auth/account_action_specs.js';
@@ -42,8 +41,8 @@ const build_options = (options, db) => ({
42
41
  db,
43
42
  roles: [ROLE_KEEPER, ROLE_ADMIN],
44
43
  app_options: {
45
- rpc_endpoints: options.rpc_endpoints,
46
44
  ...options.app_options,
45
+ rpc_endpoints: options.rpc_endpoints,
47
46
  },
48
47
  });
49
48
  /** Headers for unauthenticated JSON requests (login, signup). */
@@ -68,17 +67,10 @@ const json_session_headers = (test_app, extra) => test_app.create_session_header
68
67
  */
69
68
  export const describe_audit_completeness_tests = (options) => {
70
69
  // Hard-fail early so consumers see a clear setup error instead of a
71
- // confusing test failure when `rpc_endpoints` is missing. For the
72
- // factory form we invoke the factory once here with a stub ctx purely
73
- // to extract the endpoint path (a stable string like `/api/rpc`); the
74
- // resulting actions array is discarded. `create_app_server` invokes
75
- // the factory a second time inside each test with its real ctx, and
76
- // those are the handlers that actually serve requests. Safe as long
77
- // as the factory is pure — the stock helpers (e.g.
78
- // `create_admin_rpc_actions`) are.
79
- const rpc_endpoints_for_setup = typeof options.rpc_endpoints === 'function'
80
- ? options.rpc_endpoints(create_stub_app_server_context(options.session_options))
81
- : options.rpc_endpoints;
70
+ // confusing test failure when `rpc_endpoints` is missing. Factory-form
71
+ // callers are resolved with a stub ctx purely to extract the endpoint
72
+ // path; real handlers run per-test via `app_options.rpc_endpoints`.
73
+ const rpc_endpoints_for_setup = resolve_rpc_endpoints_for_setup(options.rpc_endpoints, options.session_options);
82
74
  const rpc_path = require_rpc_endpoint_path(rpc_endpoints_for_setup);
83
75
  const init_schema = async (db) => {
84
76
  await run_migrations(db, [AUTH_MIGRATION_NS]);
@@ -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, AppServerOptions } from '../server/app_server.js';
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 { RpcEndpointSpec } from '../http/surface.js';
7
+ import { type RpcEndpointsSuiteOption } from './rpc_helpers.js';
7
8
  /**
8
9
  * Configuration for `describe_standard_integration_tests`.
9
10
  */
@@ -13,7 +14,7 @@ export interface StandardIntegrationTestOptions {
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?: Partial<Omit<AppServerOptions, 'backend' | 'session_options' | 'create_route_specs'>>;
17
+ app_options?: SuiteAppOptions;
17
18
  /**
18
19
  * Database factories to run tests against. Default: pglite only.
19
20
  * Pass consumer factories (e.g. `[pglite_factory, pg_factory]`) to also test against PostgreSQL.
@@ -26,8 +27,17 @@ export interface StandardIntegrationTestOptions {
26
27
  * nginx shim with no payload). Hard-fails via
27
28
  * `require_rpc_endpoint_path` on setup so consumer projects see a
28
29
  * clear setup error instead of confusing test failures.
30
+ *
31
+ * Accepts either an array (eager) or a factory
32
+ * `(ctx: AppServerContext) => Array<RpcEndpointSpec>` — the factory form
33
+ * is required when action handlers must close over the per-test
34
+ * `ctx.app_settings` / `ctx.deps` (e.g. the canonical
35
+ * `create_admin_rpc_actions(ctx.deps, {app_settings: ctx.app_settings})`
36
+ * pattern). The factory must return the same endpoint `path` regardless
37
+ * of ctx — it is invoked once at setup with a stub ctx for path lookup
38
+ * and again per-test by `create_app_server` for live dispatch.
29
39
  */
30
- rpc_endpoints: Array<RpcEndpointSpec>;
40
+ rpc_endpoints: RpcEndpointsSuiteOption;
31
41
  }
32
42
  /**
33
43
  * Standard integration test suite for fuz_app auth routes.
@@ -1 +1 @@
1
- {"version":3,"file":"integration.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/integration.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAsB7B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAC,gBAAgB,EAAE,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAChF,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAGrD,OAAO,EAIN,KAAK,SAAS,EACd,MAAM,SAAS,CAAC;AAsBjB,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,oBAAoB,CAAC;AAYxD;;GAEG;AACH,MAAM,WAAW,8BAA8B;IAC9C,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;;;OAGG;IACH,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAChC;;;;;;;OAOG;IACH,aAAa,EAAE,KAAK,CAAC,eAAe,CAAC,CAAC;CACtC;AAeD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,mCAAmC,GAC/C,SAAS,8BAA8B,KACrC,IAm3CF,CAAC"}
1
+ {"version":3,"file":"integration.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/integration.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAsB7B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAErD,OAAO,EAA6C,KAAK,eAAe,EAAC,MAAM,iBAAiB,CAAC;AACjG,OAAO,EAIN,KAAK,SAAS,EACd,MAAM,SAAS,CAAC;AAOjB,OAAO,EAMN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AAqB1B;;GAEG;AACH,MAAM,WAAW,8BAA8B;IAC9C,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;;;OAGG;IACH,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAChC;;;;;;;;;;;;;;;;OAgBG;IACH,aAAa,EAAE,uBAAuB,CAAC;CACvC;AAsBD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,mCAAmC,GAC/C,SAAS,8BAA8B,KACrC,IAy3CF,CAAC"}
@@ -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: options.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
- const rpc_path = require_rpc_endpoint_path(options.rpc_endpoints);
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(options.rpc_endpoints, invite_create_action_spec.method))
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(options.rpc_endpoints, invite_create_action_spec.method))
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, AppServerOptions } from '../server/app_server.js';
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 { RpcEndpointSpec } from '../http/surface.js';
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?: Partial<Omit<AppServerOptions, 'backend' | 'session_options' | 'create_route_specs'>>;
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: Array<RpcEndpointSpec>;
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,EAAE,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAChF,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAKrD,OAAO,EAIN,KAAK,SAAS,EACd,MAAM,SAAS,CAAC;AAKjB,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,oBAAoB,CAAC;AAGxD;;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,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,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,aAAa,EAAE,KAAK,CAAC,eAAe,CAAC,CAAC;CACtC;AAED;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,4BAA4B,GAAI,SAAS,uBAAuB,KAAG,IAqP/E,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;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
- const rpc_path = require_rpc_endpoint_path(options.rpc_endpoints);
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":"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"}
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, AppServerOptions } from '../server/app_server.js';
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 { RpcEndpointSpec } from '../http/surface.js';
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
- /** RPC endpoint specs — the source `RpcAction` arrays for params generation. */
14
- rpc_endpoints: Array<RpcEndpointSpec>;
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?: Partial<Omit<AppServerOptions, 'backend' | 'session_options' | 'create_route_specs'>>;
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,EAAE,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAChF,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAG9D,OAAO,EAAwB,KAAK,SAAS,EAAC,MAAM,SAAS,CAAC;AAK9D,OAAO,KAAK,EAAC,eAAe,EAAsB,MAAM,oBAAoB,CAAC;AAQ7E,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,gFAAgF;IAChF,aAAa,EAAE,KAAK,CAAC,eAAe,CAAC,CAAC;IACtC,iDAAiD;IACjD,WAAW,CAAC,EAAE,OAAO,CACpB,IAAI,CAAC,gBAAgB,EAAE,SAAS,GAAG,iBAAiB,GAAG,oBAAoB,CAAC,CAC5E,CAAC;IACF,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,IAqIhF,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;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 options.rpc_endpoints) {
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 options.rpc_endpoints) {
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, AppServerOptions } from '../server/app_server.js';
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 { RpcEndpointSpec } from '../http/surface.js';
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?: Partial<Omit<AppServerOptions, 'backend' | 'session_options' | 'create_route_specs'>>;
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: Array<RpcEndpointSpec>;
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,EAAE,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAChF,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,EAAkB,KAAK,OAAO,EAAE,KAAK,WAAW,EAAC,MAAM,iBAAiB,CAAC;AAChF,OAAO,EAAwB,KAAK,SAAS,EAAC,MAAM,SAAS,CAAC;AAM9D,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,oBAAoB,CAAC;AAGxD,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,OAAO,CACpB,IAAI,CAAC,gBAAgB,EAAE,SAAS,GAAG,iBAAiB,GAAG,oBAAoB,CAAC,CAC5E,CAAC;IACF,qEAAqE;IACrE,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAChC;;;;;OAKG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAChD;;;;;OAKG;IACH,aAAa,EAAE,KAAK,CAAC,eAAe,CAAC,CAAC;IACtC,8BAA8B;IAC9B,MAAM,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC;CAChC;AAyHD;;;;;;;;GAQG;AACH,eAAO,MAAM,wBAAwB,GAAI,SAAS,mBAAmB,KAAG,IAkHvE,CAAC"}
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
- const rpc_path = require_rpc_endpoint_path(options.rpc_endpoints);
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: options.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 { RpcEndpointSpec } from '../http/surface.js';
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: Array<RpcEndpointSpec>;
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,eAAe,EAAC,MAAM,oBAAoB,CAAC;AAExD;;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;;;;;OAKG;IACH,aAAa,EAAE,KAAK,CAAC,eAAe,CAAC,CAAC;IACtC;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,uBAAuB,GAAI,SAAS,mBAAmB,KAAG,IAStE,CAAC"}
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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fuzdev/fuz_app",
3
- "version": "0.32.0",
3
+ "version": "0.33.0",
4
4
  "description": "fullstack app library",
5
5
  "glyph": "🗝",
6
6
  "logo": "logo.svg",