@fuzdev/fuz_app 0.111.0 → 0.112.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions/CLAUDE.md +15 -11
- package/dist/actions/action_rpc.d.ts +1 -1
- package/dist/actions/action_rpc.d.ts.map +1 -1
- package/dist/actions/action_rpc.js +4 -6
- package/dist/actions/peer_ping.d.ts +8 -0
- package/dist/actions/peer_ping.d.ts.map +1 -1
- package/dist/actions/peer_ping.js +8 -0
- package/dist/actions/peer_request.d.ts +1 -1
- package/dist/actions/peer_request.js +1 -1
- package/dist/actions/perform_action.d.ts +16 -9
- package/dist/actions/perform_action.d.ts.map +1 -1
- package/dist/actions/perform_action.js +30 -21
- package/dist/actions/register_action_ws.d.ts +1 -1
- package/dist/actions/register_action_ws.d.ts.map +1 -1
- package/dist/actions/register_action_ws.js +88 -21
- package/dist/auth/CLAUDE.md +37 -7
- package/dist/auth/account_actions.d.ts.map +1 -1
- package/dist/auth/account_actions.js +10 -1
- package/dist/auth/account_queries.d.ts.map +1 -1
- package/dist/auth/account_queries.js +36 -16
- package/dist/auth/account_schema.d.ts +20 -0
- package/dist/auth/account_schema.d.ts.map +1 -1
- package/dist/auth/account_schema.js +22 -1
- package/dist/auth/actor_search_actions.d.ts +3 -3
- package/dist/auth/actor_search_actions.d.ts.map +1 -1
- package/dist/auth/actor_search_actions.js +10 -6
- package/dist/auth/api_token_queries.d.ts.map +1 -1
- package/dist/auth/api_token_queries.js +11 -5
- package/dist/auth/app_settings_queries.d.ts.map +1 -1
- package/dist/auth/app_settings_queries.js +6 -4
- package/dist/auth/audit_log_queries.d.ts +6 -0
- package/dist/auth/audit_log_queries.d.ts.map +1 -1
- package/dist/auth/audit_log_queries.js +11 -5
- package/dist/auth/cell_actions.d.ts.map +1 -1
- package/dist/auth/cell_actions.js +3 -8
- package/dist/auth/cell_audit_actions.d.ts.map +1 -1
- package/dist/auth/cell_audit_actions.js +1 -1
- package/dist/auth/cell_field_actions.js +1 -1
- package/dist/auth/cell_grant_actions.js +1 -1
- package/dist/auth/cell_item_actions.js +1 -1
- package/dist/auth/invite_queries.d.ts.map +1 -1
- package/dist/auth/invite_queries.js +10 -8
- package/dist/auth/role_grant_offer_ddl.d.ts +11 -0
- package/dist/auth/role_grant_offer_ddl.d.ts.map +1 -1
- package/dist/auth/role_grant_offer_ddl.js +20 -2
- package/dist/auth/role_grant_offer_queries.d.ts.map +1 -1
- package/dist/auth/role_grant_offer_queries.js +29 -15
- package/dist/auth/role_grant_queries.d.ts.map +1 -1
- package/dist/auth/role_grant_queries.js +21 -7
- package/dist/auth/session_queries.d.ts.map +1 -1
- package/dist/auth/session_queries.js +9 -4
- package/dist/db/CLAUDE.md +21 -2
- package/dist/db/cell_audit_queries.js +2 -2
- package/dist/db/cell_field_queries.d.ts +1 -1
- package/dist/db/cell_field_queries.d.ts.map +1 -1
- package/dist/db/cell_field_queries.js +8 -6
- package/dist/db/cell_grant_queries.d.ts +1 -1
- package/dist/db/cell_grant_queries.d.ts.map +1 -1
- package/dist/db/cell_grant_queries.js +12 -10
- package/dist/db/cell_item_queries.d.ts +1 -1
- package/dist/db/cell_item_queries.d.ts.map +1 -1
- package/dist/db/cell_item_queries.js +9 -7
- package/dist/db/cell_queries.d.ts +3 -3
- package/dist/db/cell_queries.d.ts.map +1 -1
- package/dist/db/cell_queries.js +6 -4
- package/dist/db/fact_queries.d.ts.map +1 -1
- package/dist/db/fact_queries.js +9 -3
- package/dist/db/sql_columns.d.ts +80 -3
- package/dist/db/sql_columns.d.ts.map +1 -1
- package/dist/db/sql_columns.js +91 -4
- package/dist/http/CLAUDE.md +3 -1
- package/dist/http/jsonrpc_helpers.d.ts +13 -0
- package/dist/http/jsonrpc_helpers.d.ts.map +1 -1
- package/dist/http/jsonrpc_helpers.js +13 -0
- package/dist/server/serve_fact_route.d.ts.map +1 -1
- package/dist/server/serve_fact_route.js +7 -2
- package/dist/testing/CLAUDE.md +53 -27
- package/dist/testing/admin_integration.d.ts +0 -3
- package/dist/testing/admin_integration.d.ts.map +1 -1
- package/dist/testing/admin_integration.js +0 -1
- package/dist/testing/adversarial_404.d.ts.map +1 -1
- package/dist/testing/adversarial_404.js +4 -1
- package/dist/testing/adversarial_input.d.ts.map +1 -1
- package/dist/testing/adversarial_input.js +5 -4
- package/dist/testing/app_server.d.ts +4 -3
- package/dist/testing/app_server.d.ts.map +1 -1
- package/dist/testing/app_server.js +11 -5
- package/dist/testing/attack_surface.d.ts +16 -0
- package/dist/testing/attack_surface.d.ts.map +1 -1
- package/dist/testing/attack_surface.js +36 -13
- package/dist/testing/audit_completeness.d.ts +0 -3
- package/dist/testing/audit_completeness.d.ts.map +1 -1
- package/dist/testing/audit_completeness.js +0 -1
- package/dist/testing/auth_apps.d.ts +9 -2
- package/dist/testing/auth_apps.d.ts.map +1 -1
- package/dist/testing/auth_apps.js +9 -2
- package/dist/testing/cross_backend/account_lifecycle.d.ts +5 -4
- package/dist/testing/cross_backend/account_lifecycle.d.ts.map +1 -1
- package/dist/testing/cross_backend/account_lifecycle.js +7 -0
- package/dist/testing/cross_backend/action_manifest.d.ts +19 -3
- package/dist/testing/cross_backend/action_manifest.d.ts.map +1 -1
- package/dist/testing/cross_backend/action_manifest.js +10 -4
- package/dist/testing/cross_backend/action_manifest_parity.d.ts +9 -3
- package/dist/testing/cross_backend/action_manifest_parity.d.ts.map +1 -1
- package/dist/testing/cross_backend/action_manifest_parity.js +6 -0
- package/dist/testing/cross_backend/actor_lookup.d.ts +3 -2
- package/dist/testing/cross_backend/actor_lookup.d.ts.map +1 -1
- package/dist/testing/cross_backend/body_size.d.ts +4 -2
- package/dist/testing/cross_backend/body_size.d.ts.map +1 -1
- package/dist/testing/cross_backend/body_size.js +1 -1
- package/dist/testing/cross_backend/cell_crud.d.ts +2 -2
- package/dist/testing/cross_backend/cell_crud.d.ts.map +1 -1
- package/dist/testing/cross_backend/cell_crud.js +10 -0
- package/dist/testing/cross_backend/cell_gated_create.d.ts +3 -3
- package/dist/testing/cross_backend/cell_gated_create.d.ts.map +1 -1
- package/dist/testing/cross_backend/cell_grant_role.d.ts +2 -2
- package/dist/testing/cross_backend/cell_grant_role.d.ts.map +1 -1
- package/dist/testing/cross_backend/cell_relations.d.ts +2 -2
- package/dist/testing/cross_backend/cell_relations.d.ts.map +1 -1
- package/dist/testing/cross_backend/fact_serving.d.ts +2 -2
- package/dist/testing/cross_backend/fact_serving.d.ts.map +1 -1
- package/dist/testing/cross_backend/make_cross_backend_project.d.ts +17 -2
- package/dist/testing/cross_backend/make_cross_backend_project.d.ts.map +1 -1
- package/dist/testing/cross_backend/make_cross_backend_project.js +23 -3
- package/dist/testing/cross_backend/origin.d.ts +4 -2
- package/dist/testing/cross_backend/origin.d.ts.map +1 -1
- package/dist/testing/cross_backend/origin.js +1 -1
- package/dist/testing/cross_backend/peer_ping_ws.d.ts.map +1 -1
- package/dist/testing/cross_backend/peer_ping_ws.js +11 -7
- package/dist/testing/cross_backend/query_shape.d.ts +6 -5
- package/dist/testing/cross_backend/query_shape.d.ts.map +1 -1
- package/dist/testing/cross_backend/ready.d.ts +2 -2
- package/dist/testing/cross_backend/ready.d.ts.map +1 -1
- package/dist/testing/cross_backend/role_grant_offer_enumeration.d.ts.map +1 -1
- package/dist/testing/cross_backend/role_grant_offer_enumeration.js +7 -1
- package/dist/testing/cross_backend/setup.d.ts +26 -6
- package/dist/testing/cross_backend/setup.d.ts.map +1 -1
- package/dist/testing/cross_backend/standard.d.ts +5 -1
- package/dist/testing/cross_backend/standard.d.ts.map +1 -1
- package/dist/testing/cross_backend/standard.js +1 -5
- package/dist/testing/cross_backend/testing_backdoor.js +1 -1
- package/dist/testing/cross_backend/testing_reset_actions.d.ts +5 -0
- package/dist/testing/cross_backend/testing_reset_actions.d.ts.map +1 -1
- package/dist/testing/cross_backend/token_lifetime.d.ts.map +1 -1
- package/dist/testing/cross_backend/token_lifetime.js +6 -0
- package/dist/testing/cross_backend/token_scope_surface.d.ts +2 -2
- package/dist/testing/cross_backend/token_scope_surface.d.ts.map +1 -1
- package/dist/testing/cross_backend/wire_shapes.d.ts +22 -0
- package/dist/testing/cross_backend/wire_shapes.d.ts.map +1 -0
- package/dist/testing/cross_backend/wire_shapes.js +41 -0
- package/dist/testing/data_exposure.d.ts +0 -3
- package/dist/testing/data_exposure.d.ts.map +1 -1
- package/dist/testing/data_exposure.js +0 -1
- package/dist/testing/db.d.ts +44 -7
- package/dist/testing/db.d.ts.map +1 -1
- package/dist/testing/db.js +62 -27
- package/dist/testing/integration.d.ts.map +1 -1
- package/dist/testing/integration.js +15 -2
- package/dist/testing/round_trip.d.ts +0 -3
- package/dist/testing/round_trip.d.ts.map +1 -1
- package/dist/testing/round_trip.js +0 -4
- package/dist/testing/rpc_attack_surface.js +2 -2
- package/dist/testing/rpc_round_trip.d.ts +0 -3
- package/dist/testing/rpc_round_trip.d.ts.map +1 -1
- package/dist/testing/rpc_round_trip.js +0 -1
- package/dist/testing/schema_generators.d.ts +15 -0
- package/dist/testing/schema_generators.d.ts.map +1 -1
- package/dist/testing/schema_generators.js +45 -11
- package/dist/testing/standard.d.ts +5 -1
- package/dist/testing/standard.d.ts.map +1 -1
- package/dist/testing/standard.js +2 -7
- package/dist/timestamp.d.ts +58 -0
- package/dist/timestamp.d.ts.map +1 -0
- package/dist/timestamp.js +57 -0
- package/dist/ui/RoleGrantOfferHistory.svelte +3 -1
- package/dist/ui/RoleGrantOfferHistory.svelte.d.ts.map +1 -1
- package/dist/ui/role_grant_offers_state.svelte.d.ts.map +1 -1
- package/dist/ui/role_grant_offers_state.svelte.js +6 -2
- package/package.json +1 -1
package/dist/db/sql_columns.js
CHANGED
|
@@ -10,7 +10,16 @@
|
|
|
10
10
|
* client-safe subset — rather than spelling a second column list, so the
|
|
11
11
|
* drift guard on the base const (`assert_columns_match_live` in
|
|
12
12
|
* `testing/db.ts`) covers every derived projection too. Twin of the Rust
|
|
13
|
-
* spine's `*_COLUMNS` consts + `fuz_db::qualify_columns`.
|
|
13
|
+
* spine's `*_COLUMNS` consts + `fuz_db::qualify_columns` / `omit_columns`.
|
|
14
|
+
*
|
|
15
|
+
* A read that needs a column rendered as something other than the bare
|
|
16
|
+
* reference passes a `ColumnExpr` — the `expr` override, twin of the third
|
|
17
|
+
* argument to `fuz_db::qualify_columns`. Every timestamp that reaches the
|
|
18
|
+
* wire projects through `iso8601_timestamp_column` so both spines serialize
|
|
19
|
+
* the same instant to the same bytes; each query module builds its override
|
|
20
|
+
* with `iso8601_timestamp_expr` over its table const. An override costs one
|
|
21
|
+
* rule — a projected `ORDER BY` must qualify its column — stated on
|
|
22
|
+
* `qualify_columns`.
|
|
14
23
|
*
|
|
15
24
|
* Placement rule: a const lives in its table's query module. When two query
|
|
16
25
|
* modules project the same table (the revoke cascades in
|
|
@@ -27,13 +36,78 @@
|
|
|
27
36
|
* @module
|
|
28
37
|
*/
|
|
29
38
|
import { assert_valid_sql_identifier } from './sql_identifier.js';
|
|
39
|
+
/**
|
|
40
|
+
* Build a `to_char({alias}.{column} AT TIME ZONE 'UTC',
|
|
41
|
+
* 'YYYY-MM-DD"T"HH24:MI:SS"Z"')` fragment for embedding in a SELECT
|
|
42
|
+
* projection, via a `ColumnExpr` override.
|
|
43
|
+
*
|
|
44
|
+
* The format literal is the spine's canonical timestamp wire shape —
|
|
45
|
+
* second-precision UTC ISO-8601, exactly 20 characters — byte-identical to
|
|
46
|
+
* `fuz_db::iso8601_timestamp_column`, so the two backends serialize the same
|
|
47
|
+
* instant to the same bytes. `to_iso8601_seconds` (`timestamp.ts`) is the
|
|
48
|
+
* same shape for stamps minted in TS rather than read from Postgres.
|
|
49
|
+
*
|
|
50
|
+
* @param alias - the table alias or name to qualify the column with, or the
|
|
51
|
+
* empty string for an unqualified reference
|
|
52
|
+
* @param column - the timestamp column name
|
|
53
|
+
* @returns the `to_char(…)` fragment
|
|
54
|
+
*/
|
|
55
|
+
export const iso8601_timestamp_column = (alias, column) => alias === ''
|
|
56
|
+
? `to_char(${column} AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')`
|
|
57
|
+
: `to_char(${alias}.${column} AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')`;
|
|
58
|
+
/**
|
|
59
|
+
* Build a table's timestamp override: a `ColumnExpr` factory that projects
|
|
60
|
+
* each of `timestamp_columns` through `iso8601_timestamp_column` and declines
|
|
61
|
+
* every other column. The result takes the row qualifier — the empty string
|
|
62
|
+
* for a bare-table read, the alias for a JOIN — so one definition per query
|
|
63
|
+
* module serves every read in it.
|
|
64
|
+
*
|
|
65
|
+
* `timestamp_columns` is typed against `columns` (and checked at build time),
|
|
66
|
+
* so a misspelled name is a compile error and a stale one throws at module
|
|
67
|
+
* load rather than silently leaving a column projected as a `Date`.
|
|
68
|
+
*
|
|
69
|
+
* @param columns - the table's `*_COLUMNS` const
|
|
70
|
+
* @param timestamp_columns - the members of `columns` that carry timestamps
|
|
71
|
+
* @returns `(alias) => ColumnExpr`
|
|
72
|
+
* @throws Error when a name in `timestamp_columns` is not in `columns`
|
|
73
|
+
*/
|
|
74
|
+
export const iso8601_timestamp_expr = (columns, timestamp_columns) => {
|
|
75
|
+
for (const t of timestamp_columns) {
|
|
76
|
+
if (!columns.includes(t)) {
|
|
77
|
+
throw new Error(`iso8601_timestamp_expr: "${t}" is not in the column list "${columns.join(', ')}"`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return (alias) => (column) => timestamp_columns.includes(column)
|
|
81
|
+
? iso8601_timestamp_column(alias, column)
|
|
82
|
+
: undefined;
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Render one projection entry — the `expr` override aliased back to its
|
|
86
|
+
* column name, or `fallback` when the override declines the column
|
|
87
|
+
* (`undefined`, and only `undefined` — see `ColumnExpr`).
|
|
88
|
+
*
|
|
89
|
+
* The alias this adds is what makes the `ORDER BY` rule on `qualify_columns`
|
|
90
|
+
* necessary.
|
|
91
|
+
*
|
|
92
|
+
* @param column - the column name, and the output name an override is aliased to
|
|
93
|
+
* @param fallback - what to project when the override declines — the bare
|
|
94
|
+
* column, or the alias-qualified reference
|
|
95
|
+
* @param expr - the per-column expression override, if the read has one
|
|
96
|
+
* @returns the projection entry, `<expr> AS <column>` or `fallback`
|
|
97
|
+
*/
|
|
98
|
+
const render_column = (column, fallback, expr) => {
|
|
99
|
+
const override = expr?.(column);
|
|
100
|
+
return override === undefined ? fallback : `${override} AS ${column}`;
|
|
101
|
+
};
|
|
30
102
|
/**
|
|
31
103
|
* Render a `*_COLUMNS` const as a SQL select list, in projection order.
|
|
32
104
|
*
|
|
33
105
|
* @param columns - the column names
|
|
106
|
+
* @param expr - optional per-column expression override; an overridden
|
|
107
|
+
* column is aliased back to its own name
|
|
34
108
|
* @returns `a, b, c`
|
|
35
109
|
*/
|
|
36
|
-
export const columns_sql = (columns) => columns.join(', ');
|
|
110
|
+
export const columns_sql = (columns, expr) => columns.map((c) => render_column(c, c, expr)).join(', ');
|
|
37
111
|
/**
|
|
38
112
|
* Render a `*_COLUMNS` const as a SQL select list with every column qualified
|
|
39
113
|
* by a table alias, for reads that alias the table (JOINs, the `c`-aliased
|
|
@@ -44,14 +118,27 @@ export const columns_sql = (columns) => columns.join(', ');
|
|
|
44
118
|
* alias through gets a thrown error instead of a malformed (or injectable)
|
|
45
119
|
* projection.
|
|
46
120
|
*
|
|
121
|
+
* **An `expr` override costs one rule: an `ORDER BY` in a projected SELECT
|
|
122
|
+
* must qualify its column.** An override is aliased back to its own name
|
|
123
|
+
* (`… AS created_at`), and Postgres resolves a bare `ORDER BY created_at`
|
|
124
|
+
* against the *output* names first, so it would sort on the `to_char(…)`
|
|
125
|
+
* text — collapsing sub-second order into ties and losing the btree index (a
|
|
126
|
+
* `Sort` node over the expression instead of an `Index Scan`). Writing
|
|
127
|
+
* `ORDER BY <alias>.created_at` (or `<table>.created_at`) names the input
|
|
128
|
+
* column and both go away. The Rust twin needs no such rule: it decodes
|
|
129
|
+
* positionally, so `fuz_db::qualify_columns` emits no alias and its bare
|
|
130
|
+
* `ORDER BY created_at` already means the column.
|
|
131
|
+
*
|
|
47
132
|
* @param columns - the column names
|
|
48
133
|
* @param alias - the table alias or name to prefix each column with
|
|
134
|
+
* @param expr - optional per-column expression override; an overridden
|
|
135
|
+
* column is aliased back to its own name
|
|
49
136
|
* @returns `alias.a, alias.b, alias.c`
|
|
50
137
|
* @throws Error when `alias` is not a valid SQL identifier
|
|
51
138
|
*/
|
|
52
|
-
export const qualify_columns = (columns, alias) => {
|
|
139
|
+
export const qualify_columns = (columns, alias, expr) => {
|
|
53
140
|
assert_valid_sql_identifier(alias);
|
|
54
|
-
return
|
|
141
|
+
return columns.map((c) => render_column(c, `${alias}.${c}`, expr)).join(', ');
|
|
55
142
|
};
|
|
56
143
|
/**
|
|
57
144
|
* Drop named columns from a `*_COLUMNS` const, preserving projection order —
|
package/dist/http/CLAUDE.md
CHANGED
|
@@ -107,7 +107,9 @@ wrapper). See `auth/signup_routes.ts`.
|
|
|
107
107
|
|
|
108
108
|
**Ordering: 401 → authz → 403 → 400 → handler.** Mirrors the RPC dispatcher
|
|
109
109
|
(`actions/action_rpc.ts`) so HTTP RPC and REST fail with the same priority, and
|
|
110
|
-
matches the Rust spine, which validates handler-side
|
|
110
|
+
matches the Rust spine, which validates handler-side — with the one difference
|
|
111
|
+
that the dispatcher carries a per-action rate-limit phase (429) between 403 and
|
|
112
|
+
400 that REST has no equivalent of. Body validation runs last
|
|
111
113
|
so a caller the authority gates refuse learns nothing about the route's input
|
|
112
114
|
shape — a 400 would confirm the route exists and describe how to call it.
|
|
113
115
|
Params and query still validate first: they are part of addressing the route,
|
|
@@ -43,6 +43,19 @@ export declare const is_jsonrpc_error_response: (message: unknown) => message is
|
|
|
43
43
|
* Returns `null` if no valid id can be extracted.
|
|
44
44
|
*/
|
|
45
45
|
export declare const to_jsonrpc_message_id: (message_or_id: unknown) => JsonrpcRequestId | null;
|
|
46
|
+
/**
|
|
47
|
+
* The id an error response to a rejected envelope can echo: the frame's
|
|
48
|
+
* `id` when the frame is an object carrying a valid one, else `null`.
|
|
49
|
+
*
|
|
50
|
+
* Unlike `to_jsonrpc_message_id`, a scalar frame (`5`, `"x"`) is never read
|
|
51
|
+
* as its own id — a non-object body has no id to echo, which is the Rust
|
|
52
|
+
* twin's `classify` answer too. Both transports use this for the
|
|
53
|
+
* `invalid_request` reply.
|
|
54
|
+
*
|
|
55
|
+
* @param frame - the parsed body, of any shape
|
|
56
|
+
* @returns the echoable id, or `null`
|
|
57
|
+
*/
|
|
58
|
+
export declare const to_jsonrpc_envelope_id: (frame: unknown) => JsonrpcRequestId | null;
|
|
46
59
|
/**
|
|
47
60
|
* Normalizes input to JSON-RPC params format.
|
|
48
61
|
* Returns `undefined` for null/undefined, wraps primitives in `{value}`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jsonrpc_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/jsonrpc_helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,EACN,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,EAC9B,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,cAAc,EAEnB,eAAe,EACf,MAAM,cAAc,CAAC;AAKtB,0CAA0C;AAC1C,eAAO,MAAM,sBAAsB,GAClC,QAAQ,aAAa,EACrB,QAAQ,oBAAoB,GAAG,SAAS,EACxC,IAAI,gBAAgB,KAClB,cAUF,CAAC;AAEF,mDAAmD;AACnD,eAAO,MAAM,uBAAuB,GACnC,IAAI,gBAAgB,EACpB,QAAQ,aAAa,KACnB,eAID,CAAC;AAEH,6EAA6E;AAC7E,eAAO,MAAM,2BAA2B,GACvC,QAAQ,aAAa,EACrB,QAAQ,yBAAyB,GAAG,SAAS,KAC3C,mBASF,CAAC;AAEF,iDAAiD;AACjD,eAAO,MAAM,6BAA6B,GACzC,IAAI,oBAAoB,CAAC,IAAI,CAAC,EAC9B,OAAO,oBAAoB,CAAC,OAAO,CAAC,KAClC,oBAID,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,yCAAyC,GACrD,IAAI,gBAAgB,GAAG,IAAI,EAC3B,OAAO,OAAO,KACZ,oBAyBF,CAAC;AAIF,kFAAkF;AAClF,eAAO,MAAM,qBAAqB,GAAI,IAAI,OAAO,KAAG,EAAE,IAAI,gBAGzD,CAAC;AAEF,qEAAqE;AACrE,eAAO,MAAM,iBAAiB,GAC7B,SAAS,OAAO,KACd,OAAO,IAAI;IAAE,OAAO,EAAE,OAAO,eAAe,CAAA;CAIF,CAAC;AAE9C,sEAAsE;AACtE,eAAO,MAAM,kBAAkB,GAC9B,SAAS,OAAO,KACd,OAAO,IAAI,cAAc,GAAG,KAAK,CAAC,cAAc,CAGrB,CAAC;AAE/B,iEAAiE;AACjE,eAAO,MAAM,kBAAkB,GAAI,SAAS,OAAO,KAAG,OAAO,IAAI,cACI,CAAC;AAEtE,wEAAwE;AACxE,eAAO,MAAM,uBAAuB,GAAI,SAAS,OAAO,KAAG,OAAO,IAAI,mBACE,CAAC;AAEzE,0EAA0E;AAC1E,eAAO,MAAM,mBAAmB,GAAI,SAAS,OAAO,KAAG,OAAO,IAAI,eACG,CAAC;AAEtE,uEAAuE;AACvE,eAAO,MAAM,yBAAyB,GAAI,SAAS,OAAO,KAAG,OAAO,IAAI,oBACJ,CAAC;AAIrE;;;GAGG;AACH,eAAO,MAAM,qBAAqB,GAAI,eAAe,OAAO,KAAG,gBAAgB,GAAG,IAOjF,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAAI,OAAO,OAAO,KAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAQxE,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAAI,QAAQ,OAAO,KAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAQrE,CAAC"}
|
|
1
|
+
{"version":3,"file":"jsonrpc_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/jsonrpc_helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,EACN,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,EAC9B,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,cAAc,EAEnB,eAAe,EACf,MAAM,cAAc,CAAC;AAKtB,0CAA0C;AAC1C,eAAO,MAAM,sBAAsB,GAClC,QAAQ,aAAa,EACrB,QAAQ,oBAAoB,GAAG,SAAS,EACxC,IAAI,gBAAgB,KAClB,cAUF,CAAC;AAEF,mDAAmD;AACnD,eAAO,MAAM,uBAAuB,GACnC,IAAI,gBAAgB,EACpB,QAAQ,aAAa,KACnB,eAID,CAAC;AAEH,6EAA6E;AAC7E,eAAO,MAAM,2BAA2B,GACvC,QAAQ,aAAa,EACrB,QAAQ,yBAAyB,GAAG,SAAS,KAC3C,mBASF,CAAC;AAEF,iDAAiD;AACjD,eAAO,MAAM,6BAA6B,GACzC,IAAI,oBAAoB,CAAC,IAAI,CAAC,EAC9B,OAAO,oBAAoB,CAAC,OAAO,CAAC,KAClC,oBAID,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,yCAAyC,GACrD,IAAI,gBAAgB,GAAG,IAAI,EAC3B,OAAO,OAAO,KACZ,oBAyBF,CAAC;AAIF,kFAAkF;AAClF,eAAO,MAAM,qBAAqB,GAAI,IAAI,OAAO,KAAG,EAAE,IAAI,gBAGzD,CAAC;AAEF,qEAAqE;AACrE,eAAO,MAAM,iBAAiB,GAC7B,SAAS,OAAO,KACd,OAAO,IAAI;IAAE,OAAO,EAAE,OAAO,eAAe,CAAA;CAIF,CAAC;AAE9C,sEAAsE;AACtE,eAAO,MAAM,kBAAkB,GAC9B,SAAS,OAAO,KACd,OAAO,IAAI,cAAc,GAAG,KAAK,CAAC,cAAc,CAGrB,CAAC;AAE/B,iEAAiE;AACjE,eAAO,MAAM,kBAAkB,GAAI,SAAS,OAAO,KAAG,OAAO,IAAI,cACI,CAAC;AAEtE,wEAAwE;AACxE,eAAO,MAAM,uBAAuB,GAAI,SAAS,OAAO,KAAG,OAAO,IAAI,mBACE,CAAC;AAEzE,0EAA0E;AAC1E,eAAO,MAAM,mBAAmB,GAAI,SAAS,OAAO,KAAG,OAAO,IAAI,eACG,CAAC;AAEtE,uEAAuE;AACvE,eAAO,MAAM,yBAAyB,GAAI,SAAS,OAAO,KAAG,OAAO,IAAI,oBACJ,CAAC;AAIrE;;;GAGG;AACH,eAAO,MAAM,qBAAqB,GAAI,eAAe,OAAO,KAAG,gBAAgB,GAAG,IAOjF,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,sBAAsB,GAAI,OAAO,OAAO,KAAG,gBAAgB,GAAG,IACX,CAAC;AAEjE;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAAI,OAAO,OAAO,KAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAQxE,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAAI,QAAQ,OAAO,KAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAQrE,CAAC"}
|
|
@@ -110,6 +110,19 @@ export const to_jsonrpc_message_id = (message_or_id) => {
|
|
|
110
110
|
const maybe_id = typeof message_or_id === 'object' ? message_or_id.id : message_or_id;
|
|
111
111
|
return is_jsonrpc_request_id(maybe_id) ? maybe_id : null;
|
|
112
112
|
};
|
|
113
|
+
/**
|
|
114
|
+
* The id an error response to a rejected envelope can echo: the frame's
|
|
115
|
+
* `id` when the frame is an object carrying a valid one, else `null`.
|
|
116
|
+
*
|
|
117
|
+
* Unlike `to_jsonrpc_message_id`, a scalar frame (`5`, `"x"`) is never read
|
|
118
|
+
* as its own id — a non-object body has no id to echo, which is the Rust
|
|
119
|
+
* twin's `classify` answer too. Both transports use this for the
|
|
120
|
+
* `invalid_request` reply.
|
|
121
|
+
*
|
|
122
|
+
* @param frame - the parsed body, of any shape
|
|
123
|
+
* @returns the echoable id, or `null`
|
|
124
|
+
*/
|
|
125
|
+
export const to_jsonrpc_envelope_id = (frame) => typeof frame === 'object' ? to_jsonrpc_message_id(frame) : null;
|
|
113
126
|
/**
|
|
114
127
|
* Normalizes input to JSON-RPC params format.
|
|
115
128
|
* Returns `undefined` for null/undefined, wraps primitives in `{value}`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serve_fact_route.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/server/serve_fact_route.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwFG;AAMH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAetD,OAAO,EAAuC,KAAK,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAE5F,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAM/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"serve_fact_route.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/server/serve_fact_route.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwFG;AAMH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAetD,OAAO,EAAuC,KAAK,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAE5F,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAM/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAkEjD,MAAM,WAAW,+BAA+B;IAC/C;;;;;;OAMG;IACH,IAAI,EAAE,OAAO,CAAC;IACd,kFAAkF;IAClF,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,GAAG,EAAE,MAAM,CAAC;CACZ;AAgHD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,iCAAiC,GAC7C,SAAS,+BAA+B,KACtC,SAgDF,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,4BAA4B,GACxC,SAAS,+BAA+B,KACtC,SA0CF,CAAC"}
|
|
@@ -150,11 +150,16 @@ const cell_fact_params_schema = z.strictObject({
|
|
|
150
150
|
cell_id: Uuid,
|
|
151
151
|
hash: FactHashSchema
|
|
152
152
|
});
|
|
153
|
-
/**
|
|
153
|
+
/**
|
|
154
|
+
* Shared error-schema entry: tighten the auto-derived 400 to the literal
|
|
155
|
+
* emitted by params validation. `issues` is optional because the framework
|
|
156
|
+
* emits it through `dev_only` — a production body carries the `error`
|
|
157
|
+
* literal alone.
|
|
158
|
+
*/
|
|
154
159
|
const params_400_error = {
|
|
155
160
|
400: z.looseObject({
|
|
156
161
|
error: z.literal(ERROR_INVALID_ROUTE_PARAMS),
|
|
157
|
-
issues: z.array(z.unknown())
|
|
162
|
+
issues: z.array(z.unknown()).optional()
|
|
158
163
|
})
|
|
159
164
|
};
|
|
160
165
|
/**
|
package/dist/testing/CLAUDE.md
CHANGED
|
@@ -121,7 +121,8 @@ factories accept any migration namespace set.
|
|
|
121
121
|
- `IS_CI` — `process.env.CI === 'true'`.
|
|
122
122
|
- `DbFactory` — `{name, create, close, skip, skip_reason?}`.
|
|
123
123
|
- `reset_pglite(db)` — `DROP SCHEMA public CASCADE` + recreate. Reuses a live PGlite instance.
|
|
124
|
-
- `create_pglite_factory(init_schema)` — in-memory; no external deps; `skip: false`. See WASM caching below.
|
|
124
|
+
- `create_pglite_factory(init_schema, options?)` — in-memory; no external deps; `skip: false`. `options.substitutable: false` pins the call site to PGlite when a substitute is installed. See WASM caching below.
|
|
125
|
+
- `set_substitute_db_factory(create_factory | null)` — install a `DbFactoryBuilder` that stands in for `create_pglite_factory`, so a suite written against PGlite runs on another driver without being edited. Injected rather than selected here: the drivers a substitute wraps live in test-side code this shipped module can't import. fuz_app's own switch is `src/test/db_substitute.ts`.
|
|
125
126
|
- `create_pg_factory(init_schema, test_url?)` — PostgreSQL; `skip: true` when `test_url` missing. Drops `schema_version` before `init_schema` so migrations re-evaluate against actual tables (prevents stale tracker rows from skipping migrations when DDL changes between sessions). Pool reused + cleaned up across `create()` calls.
|
|
126
127
|
- `auth_truncate_tables` — `['invite', 'api_token', 'auth_session', 'role_grant', 'role_grant_offer', 'actor', 'account']` in FK-safe order. Excludes `audit_log` — unit DB tests don't need to truncate it.
|
|
127
128
|
- `auth_integration_truncate_tables` — `auth_truncate_tables + ['audit_log']` for integration suites that exercise the audit path.
|
|
@@ -131,14 +132,13 @@ factories accept any migration namespace set.
|
|
|
131
132
|
- `assert_columns_match_live(db, table, columns)` — the named-projection drift guard: asserts a `*_COLUMNS` const (`ACCOUNT_COLUMNS`, `CELL_COLUMNS`, a consumer's own) names exactly the live `public`-schema columns of `table`, via `query_public_columns(db, {table})`. Per module, or iterated from a table → const registry (fuz_app's own: `src/test/db/column_projections.db.test.ts`).
|
|
132
133
|
|
|
133
134
|
**PGlite WASM caching.** `create_pglite_factory` shares a single PGlite
|
|
134
|
-
instance in a module-level ref (`module_db`) across
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
cost again. Each vitest file runs in its own worker, so no cross-file
|
|
138
|
-
contamination — but inside a file, suites share state until the schema is
|
|
135
|
+
instance in a module-level ref (`module_db`) across the PGlite factories it builds.
|
|
136
|
+
Subsequent `create()` calls `DROP SCHEMA public CASCADE` instead of paying the
|
|
137
|
+
~500–700ms WASM cold-start cost again, so suites share state until the next
|
|
139
138
|
reset. The `db` vitest project (opted into by the `.db.test.ts` suffix) runs
|
|
140
139
|
with `isolate: false` + `fileParallelism: false` to amortize WASM boot across
|
|
141
|
-
every DB test file
|
|
140
|
+
every DB test file — which also makes that one instance the whole run's; a
|
|
141
|
+
project that isolates its files gets one per worker instead.
|
|
142
142
|
|
|
143
143
|
## Test app assembly
|
|
144
144
|
|
|
@@ -207,7 +207,7 @@ test-only by construction.
|
|
|
207
207
|
- `AuthTestApps` — `{public, authed, keeper, by_role: Map<string, Hono>}`.
|
|
208
208
|
- `create_auth_test_apps(specs, roles)` — builds one app per auth level. Keeper app uses `credential_type: 'daemon_token'` so `require_credential_types(['daemon_token'])` passes.
|
|
209
209
|
- `select_auth_app(apps, auth)` — map `RouteAuth` → matching Hono app. Throws for missing `role:*` entries.
|
|
210
|
-
- `
|
|
210
|
+
- `create_route_skip_filter(skip_routes)` — the `'METHOD /path'` skip predicate the three adversarial sub-suites apply from their `skip_routes` option.
|
|
211
211
|
|
|
212
212
|
## Cross-impl schema parity
|
|
213
213
|
|
|
@@ -237,8 +237,10 @@ per-method auth shape.
|
|
|
237
237
|
- `cross_backend/action_manifest.ts` — `ActionManifest` / `ActionManifestEntry`
|
|
238
238
|
Zod schema (the `_testing_action_manifest` wire validator) + `build_action_manifest(specs)`,
|
|
239
239
|
which normalizes each spec to `{method, side_effects, account, actor, roles,
|
|
240
|
-
credential_types}` (auth axes pass through; `roles` /
|
|
241
|
-
to sorted arrays
|
|
240
|
+
credential_types, rate_limit}` (auth axes pass through; `roles` /
|
|
241
|
+
`credential_types` flatten to sorted arrays; `rate_limit` is the declared
|
|
242
|
+
class or an explicit `null`, so a missing key reads as drift rather than a
|
|
243
|
+
default). Twin of `schema_introspect.ts`. Excludes the protocol actions
|
|
242
244
|
(`heartbeat` / `cancel` / `peer/ping`) — `create_testing_action_manifest_action`
|
|
243
245
|
filters them via the `protocol_action_specs` method set (Rust drops
|
|
244
246
|
`PROTOCOL_ACTION_SPECS`); the two impls organize them differently (`peer/ping`
|
|
@@ -247,6 +249,8 @@ credential_types}` (auth axes pass through; `roles` / `credential_types` flatten
|
|
|
247
249
|
- `cross_backend/action_manifest_parity.ts` — `diff_action_manifests` /
|
|
248
250
|
`format_action_manifest_diffs` / `assert_action_manifests_equal` (twin of
|
|
249
251
|
`schema_parity.ts`) — asserts exact method-set + per-method auth-shape parity.
|
|
252
|
+
`ActionManifestDiff` kinds: `method_only_in`, `side_effects_differ`,
|
|
253
|
+
`rate_limit_differs`, `auth_field_differs`, `auth_list_differs`.
|
|
250
254
|
- `cross_backend/setup.ts` `capture_action_manifest(handle)` — dumps a backend's
|
|
251
255
|
manifest over the daemon-token `_testing_action_manifest` channel (twin of
|
|
252
256
|
`capture_schema_snapshot`).
|
|
@@ -255,9 +259,9 @@ It runs under the same dual-spawn `cross_backend_parity` project (one TS-spine +
|
|
|
255
259
|
Rust-stub spawn serves both gates). It complements the in-repo
|
|
256
260
|
`spine_method_coverage` reconciliation gate (which proves _mounted ⟹ covered_);
|
|
257
261
|
this proves _TS-mount-set ≡ Rust-mount-set_. The gate asserts **exact** parity —
|
|
258
|
-
every mounted method and its full auth shape (side-effects
|
|
259
|
-
must match across the two impls, with no allowlisted
|
|
260
|
-
`action_manifest_parity.cross.test.ts`).
|
|
262
|
+
every mounted method and its full auth shape (side-effects, the four auth axes,
|
|
263
|
+
the rate-limit class) must match across the two impls, with no allowlisted
|
|
264
|
+
divergences (see `action_manifest_parity.cross.test.ts`).
|
|
261
265
|
|
|
262
266
|
**Cross-impl gate pattern** — a dual-impl consumer running two backends
|
|
263
267
|
(a TS Hono server and a Rust spine server) against a shared schema, plus
|
|
@@ -367,7 +371,7 @@ Walks Zod schemas to generate valid values for adversarial/round-trip tests.
|
|
|
367
371
|
|
|
368
372
|
- `detect_format(field_schema)` — reads `format` / `pattern` from the JSON Schema representation.
|
|
369
373
|
- `generate_valid_value(field, field_schema)` — base-type switch producing a valid sample (UUIDs → nil UUID, strings → `'xxxxxxxxxx'`, numbers → `1`, objects → recurse, enums → first entry, etc.). For branded-string refinements, walks a fallback chain synthesized from the `pattern` string the JSON Schema representation exposes: fixed-length hex (`^[0-9a-f]{N}$` — blake3 / sha256 / md5 digests; `0`.repeat(N)), prefix-lengthed slug (`^<prefix>_[A-Za-z0-9_-]{N}$` — `ApiTokenId`-style ids; `<prefix>_` + `x`.repeat(N)), absolute path prefix, URL prefix. First candidate that `safeParse` accepts is used.
|
|
370
|
-
- `resolve_valid_path(path, params_schema?)` — swaps `:param` for
|
|
374
|
+
- `resolve_valid_path(path, params_schema?)` — swaps `:param` for a value the params schema accepts. Prefers `test_<name>` wherever the field schema admits it (the param name keeps failure messages readable); otherwise a UUID param takes the nil UUID and anything else is synthesized from the schema, percent-encoded. A synthesized value containing `/` is refused (it would route elsewhere) and falls back to `test_<name>`.
|
|
371
375
|
- `generate_valid_body(input_schema) => Record<string, unknown> | undefined` — builds a body satisfying the input schema. Throws with Zod `issues` if the generated body fails validation — surfaces broken generation logic with a descriptive error rather than a confusing 400 downstream.
|
|
372
376
|
|
|
373
377
|
### `integration_helpers.ts` — route lookup + body checks
|
|
@@ -398,7 +402,16 @@ case per route):
|
|
|
398
402
|
4. **adversarial input validation** — delegated to `describe_adversarial_input`.
|
|
399
403
|
5. **adversarial 404 response validation** — delegated to `describe_adversarial_404`.
|
|
400
404
|
|
|
401
|
-
Options: `{build: () => AppSurfaceSpec, snapshot_path, expected_public_routes, expected_api_middleware, roles, api_path_prefix?, security_policy?, error_schema_tightness?}`.
|
|
405
|
+
Options: `{build: () => AppSurfaceSpec, snapshot_path, expected_public_routes, expected_api_middleware, roles, api_path_prefix?, security_policy?, error_schema_tightness?, skip_routes?}`.
|
|
406
|
+
|
|
407
|
+
`skip_routes` is a list of `'METHOD /path'` surface keys the three
|
|
408
|
+
adversarial sub-suites drop, forwarded to each of them (it also sits on
|
|
409
|
+
`AdversarialTestOptions` for the standalone `describe_adversarial_auth` /
|
|
410
|
+
`describe_adversarial_input` / `describe_adversarial_404` calls). It is the
|
|
411
|
+
escape hatch for a route that cannot be driven generically at all — a
|
|
412
|
+
handler needing real seeded state, a path segment no schema describes. A
|
|
413
|
+
route whose params merely carry a format needs no entry: `resolve_valid_path`
|
|
414
|
+
synthesizes a segment the route accepts.
|
|
402
415
|
|
|
403
416
|
Also exported: `describe_adversarial_auth(options)` (group 3 on its own) and
|
|
404
417
|
`build_error_schema_lookup(specs, middleware_specs?)` (pre-built
|
|
@@ -480,7 +493,7 @@ For every route spec, fires a valid request with matching auth and validates
|
|
|
480
493
|
the response against declared schemas. DB-backed via `create_test_app`.
|
|
481
494
|
Per-route test (`test.each`) — one line per route in the vitest output.
|
|
482
495
|
|
|
483
|
-
Options: `{setup_test, surface_source,
|
|
496
|
+
Options: `{setup_test, surface_source, skip_routes?, input_overrides?, success_fixtures?}`.
|
|
484
497
|
`input_overrides` is a `Map<"METHOD /path", body>` — override generated
|
|
485
498
|
bodies for routes whose input schema can't round-trip cleanly (e.g. fields
|
|
486
499
|
that must reference DB state).
|
|
@@ -493,7 +506,7 @@ picks them up separately.
|
|
|
493
506
|
DB-backed round-trip for RPC: one POST test for all methods, one GET test
|
|
494
507
|
for `side_effects: false` methods. Successful responses validate against
|
|
495
508
|
`action.spec.output`; error responses validate as well-formed JSON-RPC error
|
|
496
|
-
envelopes. Options: `{setup_test, surface_source,
|
|
509
|
+
envelopes. Options: `{setup_test, surface_source, session_options, rpc_endpoints, skip_methods?, input_overrides?, success_fixtures?}`.
|
|
497
510
|
The admin RPC auth test picks a session-based identity (`authed` / `admin` /
|
|
498
511
|
bootstrapped keeper) based on `method.auth`; keeper uses the daemon token.
|
|
499
512
|
|
|
@@ -568,7 +581,7 @@ Support functions: `collect_json_schema_property_names(schema)` (walks
|
|
|
568
581
|
`assert_output_schemas_no_sensitive_fields(surface, fields?)`,
|
|
569
582
|
`assert_non_admin_schemas_no_admin_fields(surface, fields?)`.
|
|
570
583
|
|
|
571
|
-
Options: `{setup_test, surface_source,
|
|
584
|
+
Options: `{setup_test, surface_source, sensitive_fields?, admin_only_fields?, skip_routes?}`.
|
|
572
585
|
|
|
573
586
|
### `rate_limiting.ts` — `describe_rate_limiting_tests`
|
|
574
587
|
|
|
@@ -626,7 +639,7 @@ Override with
|
|
|
626
639
|
minimal route sets whose declared error codes outpace the suite's
|
|
627
640
|
denial-path drivers).
|
|
628
641
|
|
|
629
|
-
Options: `{setup_test, surface_source,
|
|
642
|
+
Options: `{setup_test, surface_source, session_options, rpc_endpoints, error_coverage_min?}`.
|
|
630
643
|
|
|
631
644
|
### `admin_integration.ts` — `describe_standard_admin_integration_tests`
|
|
632
645
|
|
|
@@ -646,7 +659,7 @@ header/account mismatch. Direct-grant fixtures (test focuses on revoke or
|
|
|
646
659
|
isolation, not the consent path) go through `create_test_role_grant_direct`
|
|
647
660
|
from `db_entities.ts`.
|
|
648
661
|
|
|
649
|
-
Required options: `{setup_test, surface_source,
|
|
662
|
+
Required options: `{setup_test, surface_source, session_options, rpc_endpoints: RpcEndpointsSuiteOption, roles: RoleSchemaResult, admin_prefix?}`.
|
|
650
663
|
|
|
651
664
|
`rpc_endpoints` is `Array<RpcEndpointSpec> | ((ctx: AppServerContext) => Array<RpcEndpointSpec>)` —
|
|
652
665
|
the same `RpcEndpointsSuiteOption` union every DB-backed suite accepts
|
|
@@ -1179,10 +1192,23 @@ never sees them). Both parse every success response against the verb's Zod
|
|
|
1179
1192
|
**output** schema, so a TS↔Rust envelope drift fails the suite — not just a
|
|
1180
1193
|
payload-field drift. Call-site primitives (`cross_rpc_call` / `error_reason` /
|
|
1181
1194
|
`expect_output`) live in `cross_backend/cell_cross_helpers.ts`; the shared
|
|
1182
|
-
options shape is `
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1195
|
+
options shape is `RpcPathCapabilityGatedCrossSuiteOptions` from
|
|
1196
|
+
`cross_backend/setup.ts`. `cross_backend/wire_shapes.ts` carries
|
|
1197
|
+
`assert_iso8601_seconds` / `assert_iso8601_seconds_nullable` — the byte-level
|
|
1198
|
+
gate on the canonical second-precision UTC timestamp shape, which a
|
|
1199
|
+
`z.string()` output schema can't catch (a millisecond stamp parses fine).
|
|
1200
|
+
The shared suites pin it on the account-status account + role grants, a
|
|
1201
|
+
session, a minted + listed API token, a cell's `created_at` / `updated_at`,
|
|
1202
|
+
an audit row, an admin account listing, and an offer's `created_at` /
|
|
1203
|
+
`expires_at`. `cross_backend/setup.ts` carries the four bases every
|
|
1204
|
+
imperative cross suite aliases: `CrossSuiteOptions` (`setup_test` alone),
|
|
1205
|
+
`CapabilityGatedCrossSuiteOptions` (+ `capabilities` — `ready`),
|
|
1206
|
+
`RpcPathCrossSuiteOptions` (+ `rpc_path?` — origin, body-size, actor
|
|
1207
|
+
lookup/search, app settings, testing backdoor), and the intersection
|
|
1208
|
+
`RpcPathCapabilityGatedCrossSuiteOptions` (every `cell_*` suite, query-shape,
|
|
1209
|
+
token-scope surface, fact-serving, account lifecycle). A suite takes the
|
|
1210
|
+
capability-carrying variant only when it actually gates cases on a flag, so
|
|
1211
|
+
the option type states whether the bundle is read.
|
|
1186
1212
|
|
|
1187
1213
|
- **`describe_cell_crud_cross_tests`** (gates on `capabilities.cell_crud`) —
|
|
1188
1214
|
the create → get → update → delete → list lifecycle threading the id, plus
|
|
@@ -1387,7 +1413,7 @@ censuses). Cross-process only; fuz_app's own wiring is
|
|
|
1387
1413
|
|
|
1388
1414
|
### Origin verification parity — `cross_backend/origin.ts`
|
|
1389
1415
|
|
|
1390
|
-
`describe_origin_cross_tests({setup_test,
|
|
1416
|
+
`describe_origin_cross_tests({setup_test, rpc_path?})` — the
|
|
1391
1417
|
imperative Origin-verification suite: disallowed `Origin` → 403 `forbidden_origin` (refused
|
|
1392
1418
|
before dispatch), absent `Origin` → request passes (non-browser direct access).
|
|
1393
1419
|
Imperative (not a conformance-table row) because origin rejection is
|
|
@@ -1461,7 +1487,7 @@ drift-guarded by `src/test/cross_backend/spine_expected_schema.db.test.ts`
|
|
|
1461
1487
|
|
|
1462
1488
|
### Testing-backdoor credential gate — `cross_backend/testing_backdoor.ts`
|
|
1463
1489
|
|
|
1464
|
-
`describe_testing_backdoor_cross_tests({setup_test,
|
|
1490
|
+
`describe_testing_backdoor_cross_tests({setup_test, rpc_path?})` —
|
|
1465
1491
|
the negative-credential parity suite for the `_testing_*` backdoor actions.
|
|
1466
1492
|
For each of `_testing_reset` / `_testing_mint_session` / `_testing_put_fact` /
|
|
1467
1493
|
`_testing_schema_snapshot` (the three privileged writes plus the schema-dump
|
|
@@ -1471,7 +1497,7 @@ proving the daemon-token gate that fences each backdoor action holds end-to-end
|
|
|
1471
1497
|
on the real dispatcher (the spec-derived `describe_rpc_attack_surface_tests`
|
|
1472
1498
|
never enumerates them because they're off the declared surface). Each method is
|
|
1473
1499
|
sent with **valid** params so each case varies only the credential (validation
|
|
1474
|
-
runs after the gates — order is 401 → authz → 403 → 400); the handler never
|
|
1500
|
+
runs after the gates — order is 401 → authz → 403 → 429 → 400); the handler never
|
|
1475
1501
|
runs. Cited property: `docs/security.md`
|
|
1476
1502
|
§Test Backdoor Actions. Cross-process only (the `_testing_*` actions are
|
|
1477
1503
|
mounted on the spawned binary, not the in-process app — like the ws/sse
|
|
@@ -3,7 +3,6 @@ import type { SessionOptions } from '../auth/session_cookie.js';
|
|
|
3
3
|
import { type RoleSchemaResult } from '../auth/role_schema.js';
|
|
4
4
|
import { type RpcEndpointsSuiteOption } from './rpc_helpers.js';
|
|
5
5
|
import type { AppSurfaceSpec } from '../http/surface.js';
|
|
6
|
-
import type { BackendCapabilities } from './cross_backend/capabilities.js';
|
|
7
6
|
import type { SetupTest } from './cross_backend/setup.js';
|
|
8
7
|
/**
|
|
9
8
|
* Configuration for `describe_standard_admin_integration_tests`.
|
|
@@ -21,8 +20,6 @@ export interface StandardAdminIntegrationTestOptions {
|
|
|
21
20
|
* shape for in-process and cross-process tests).
|
|
22
21
|
*/
|
|
23
22
|
surface_source: AppSurfaceSpec;
|
|
24
|
-
/** Backend capability declarations. */
|
|
25
|
-
capabilities: BackendCapabilities;
|
|
26
23
|
/** Session config — needed for cookie_name + factory-form rpc_endpoints resolution. */
|
|
27
24
|
session_options: SessionOptions<string>;
|
|
28
25
|
/** Role schema result from `create_role_schema()` — used to determine valid/invalid/web-grantable roles. */
|
|
@@ -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;AAgC7B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAc,KAAK,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAW3E,OAAO,EAKN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AAmB1B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"admin_integration.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/admin_integration.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAgC7B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAc,KAAK,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAW3E,OAAO,EAKN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AAmB1B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,SAAS,EAAe,MAAM,0BAA0B,CAAC;AAYvE;;GAEG;AACH,MAAM,WAAW,mCAAmC;IACnD;;;;OAIG;IACH,UAAU,EAAE,SAAS,CAAC;IACtB;;;;OAIG;IACH,cAAc,EAAE,cAAc,CAAC;IAC/B,uFAAuF;IACvF,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,4GAA4G;IAC5G,KAAK,EAAE,gBAAgB,CAAC;IACxB;;;OAGG;IACH,aAAa,EAAE,uBAAuB,CAAC;IACvC;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB;AAiBD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,yCAAyC,GACrD,SAAS,mCAAmC,KAC1C,IAk5BF,CAAC"}
|
|
@@ -77,7 +77,6 @@ export const describe_standard_admin_integration_tests = (options) => {
|
|
|
77
77
|
// confusing test failure when `rpc_endpoints` is missing.
|
|
78
78
|
const rpc_endpoints_for_setup = resolve_rpc_endpoints_for_setup(options.rpc_endpoints, options.session_options);
|
|
79
79
|
const rpc_path = require_rpc_endpoint_path(rpc_endpoints_for_setup);
|
|
80
|
-
void options.capabilities;
|
|
81
80
|
describe('standard_admin_integration', () => {
|
|
82
81
|
const { cookie_name } = options.session_options;
|
|
83
82
|
const { role_specs } = options.roles;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adversarial_404.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/adversarial_404.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAoB7B,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAyBlE;;;;;;;;GAQG;AACH,eAAO,MAAM,wBAAwB,GAAI,SAAS,sBAAsB,KAAG,
|
|
1
|
+
{"version":3,"file":"adversarial_404.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/adversarial_404.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAoB7B,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAyBlE;;;;;;;;GAQG;AACH,eAAO,MAAM,wBAAwB,GAAI,SAAS,sBAAsB,KAAG,IA6E1E,CAAC"}
|
|
@@ -13,7 +13,7 @@ import './assert_dev_env.js';
|
|
|
13
13
|
import { test, assert, describe } from 'vitest';
|
|
14
14
|
import { z } from 'zod';
|
|
15
15
|
import { is_null_schema } from '../http/schema_helpers.js';
|
|
16
|
-
import { create_auth_test_apps, select_auth_app } from './auth_apps.js';
|
|
16
|
+
import { create_auth_test_apps, create_route_skip_filter, select_auth_app } from './auth_apps.js';
|
|
17
17
|
import { resolve_valid_path, generate_valid_body } from './schema_generators.js';
|
|
18
18
|
/**
|
|
19
19
|
* Extract the error code from a 404 Zod schema for use in the stub handler.
|
|
@@ -51,6 +51,7 @@ const extract_404_error_code = (schema) => {
|
|
|
51
51
|
export const describe_adversarial_404 = (options) => {
|
|
52
52
|
const { build, roles } = options;
|
|
53
53
|
const { surface, route_specs } = build();
|
|
54
|
+
const is_skipped = create_route_skip_filter(options.skip_routes);
|
|
54
55
|
// Build spec lookup for Zod schema access
|
|
55
56
|
const spec_lookup = new Map();
|
|
56
57
|
for (const spec of route_specs) {
|
|
@@ -63,6 +64,8 @@ export const describe_adversarial_404 = (options) => {
|
|
|
63
64
|
continue;
|
|
64
65
|
if (!route.error_schemas || !('404' in route.error_schemas))
|
|
65
66
|
continue;
|
|
67
|
+
if (is_skipped(route))
|
|
68
|
+
continue;
|
|
66
69
|
const key = `${route.method} ${route.path}`;
|
|
67
70
|
const spec = spec_lookup.get(key);
|
|
68
71
|
if (!spec?.params || !spec.errors?.[404])
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adversarial_input.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/adversarial_input.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAiB7B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAUxB,OAAO,EAEN,0BAA0B,EAC1B,uBAAuB,EAGvB,MAAM,0BAA0B,CAAC;AAElC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AA8ClE,UAAU,aAAa;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,cAAc,EAAE,OAAO,0BAA0B,GAAG,OAAO,uBAAuB,CAAC;CACnF;AAED,UAAU,cAAc;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B;AAED,UAAU,aAAa;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAID;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,yBAAyB,GAAI,cAAc,CAAC,CAAC,OAAO,KAAG,KAAK,CAAC,aAAa,CAsMtF,CAAC;AAIF;;;;;;GAMG;AACH,eAAO,MAAM,0BAA0B,GAAI,eAAe,CAAC,CAAC,SAAS,KAAG,KAAK,CAAC,cAAc,CA+B3F,CAAC;AAIF;;;;;;GAMG;AACH,eAAO,MAAM,yBAAyB,GAAI,cAAc,CAAC,CAAC,SAAS,KAAG,KAAK,CAAC,aAAa,CA4CxF,CAAC;AAqBF;;;;;;GAMG;AACH,eAAO,MAAM,0BAA0B,GAAI,SAAS,sBAAsB,KAAG,
|
|
1
|
+
{"version":3,"file":"adversarial_input.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/adversarial_input.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAiB7B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAUxB,OAAO,EAEN,0BAA0B,EAC1B,uBAAuB,EAGvB,MAAM,0BAA0B,CAAC;AAElC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AA8ClE,UAAU,aAAa;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,cAAc,EAAE,OAAO,0BAA0B,GAAG,OAAO,uBAAuB,CAAC;CACnF;AAED,UAAU,cAAc;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B;AAED,UAAU,aAAa;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAID;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,yBAAyB,GAAI,cAAc,CAAC,CAAC,OAAO,KAAG,KAAK,CAAC,aAAa,CAsMtF,CAAC;AAIF;;;;;;GAMG;AACH,eAAO,MAAM,0BAA0B,GAAI,eAAe,CAAC,CAAC,SAAS,KAAG,KAAK,CAAC,cAAc,CA+B3F,CAAC;AAIF;;;;;;GAMG;AACH,eAAO,MAAM,yBAAyB,GAAI,cAAc,CAAC,CAAC,SAAS,KAAG,KAAK,CAAC,aAAa,CA4CxF,CAAC;AAqBF;;;;;;GAMG;AACH,eAAO,MAAM,0BAA0B,GAAI,SAAS,sBAAsB,KAAG,IAmN5E,CAAC"}
|
|
@@ -18,7 +18,7 @@ import { zod_unwrap_to_object, zod_extract_fields } from '@fuzdev/fuz_util/zod.t
|
|
|
18
18
|
import { is_null_schema } from '../http/schema_helpers.js';
|
|
19
19
|
import { filter_routes_with_input, filter_routes_with_params, filter_routes_with_query } from '../http/surface_query.js';
|
|
20
20
|
import { ValidationError, ERROR_INVALID_REQUEST_BODY, ERROR_INVALID_JSON_BODY, ERROR_INVALID_ROUTE_PARAMS, ERROR_INVALID_QUERY_PARAMS } from '../http/error_schemas.js';
|
|
21
|
-
import { create_auth_test_apps, select_auth_app } from './auth_apps.js';
|
|
21
|
+
import { create_auth_test_apps, create_route_skip_filter, select_auth_app } from './auth_apps.js';
|
|
22
22
|
import { detect_format, generate_valid_value, resolve_valid_path } from './schema_generators.js';
|
|
23
23
|
// --- Payload generation ---
|
|
24
24
|
/** One wrong-type value per base type — one representative is sufficient. */
|
|
@@ -374,9 +374,10 @@ const build_query_url = (path, query) => {
|
|
|
374
374
|
export const describe_adversarial_input = (options) => {
|
|
375
375
|
const { build, roles } = options;
|
|
376
376
|
const { surface, route_specs } = build();
|
|
377
|
-
const
|
|
378
|
-
const
|
|
379
|
-
const
|
|
377
|
+
const is_skipped = create_route_skip_filter(options.skip_routes);
|
|
378
|
+
const routes_with_input = filter_routes_with_input(surface).filter((r) => !is_skipped(r));
|
|
379
|
+
const routes_with_params = filter_routes_with_params(surface).filter((r) => !is_skipped(r));
|
|
380
|
+
const routes_with_query = filter_routes_with_query(surface).filter((r) => !is_skipped(r));
|
|
380
381
|
if (routes_with_input.length === 0 &&
|
|
381
382
|
routes_with_params.length === 0 &&
|
|
382
383
|
routes_with_query.length === 0)
|
|
@@ -3,8 +3,9 @@ import './assert_dev_env.js';
|
|
|
3
3
|
* Bootstrapped app server factory for integration tests.
|
|
4
4
|
*
|
|
5
5
|
* Creates a keeper account, API token, and signed session cookie on a
|
|
6
|
-
* database. By default uses a cached in-memory PGlite (shared WASM instance
|
|
7
|
-
* per
|
|
6
|
+
* database. By default uses a cached in-memory PGlite (one shared WASM instance
|
|
7
|
+
* per loaded copy of `testing/db.ts` — once per run under the `db` project's
|
|
8
|
+
* `isolate: false` + `fileParallelism: false`); pass `db` to use
|
|
8
9
|
* an existing database (any driver) instead.
|
|
9
10
|
*
|
|
10
11
|
* Also provides `create_test_app` — a combined helper that creates both
|
|
@@ -312,7 +313,7 @@ export interface TestApp {
|
|
|
312
313
|
*
|
|
313
314
|
* A fresh Hono app is created each call — middleware closures bind to the
|
|
314
315
|
* server's deps (db, keyring), so reuse across servers is unsafe.
|
|
315
|
-
* The expensive resource (PGlite WASM) is cached separately in `
|
|
316
|
+
* The expensive resource (PGlite WASM) is cached separately in `testing/db.ts`.
|
|
316
317
|
*
|
|
317
318
|
* @param options - test app configuration
|
|
318
319
|
* @returns a `TestApp` ready for HTTP testing
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app_server.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/app_server.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAE7B
|
|
1
|
+
{"version":3,"file":"app_server.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/app_server.ts"],"names":[],"mappings":"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"}
|
|
@@ -31,8 +31,8 @@ export const stub_password_deps = {
|
|
|
31
31
|
/** 64-hex-char test cookie secret — deterministic, never used in production. */
|
|
32
32
|
export const TEST_COOKIE_SECRET = 'a'.repeat(64);
|
|
33
33
|
// Module-level PGlite factory for create_test_app_server when no db is provided.
|
|
34
|
-
// Shares the WASM instance cache from
|
|
35
|
-
// within
|
|
34
|
+
// Shares the WASM instance cache from `testing/db.ts`, avoiding redundant cold starts
|
|
35
|
+
// within one loaded copy of that module. Schema is reset on each create() call.
|
|
36
36
|
const fallback_pglite_factory = create_pglite_factory(async (db) => {
|
|
37
37
|
await run_migrations(db, [auth_migration_ns]);
|
|
38
38
|
});
|
|
@@ -205,10 +205,16 @@ const _build_test_backend = async (options) => {
|
|
|
205
205
|
};
|
|
206
206
|
}
|
|
207
207
|
else {
|
|
208
|
-
// In-memory PGlite via cached factory — reuses the WASM instance from
|
|
208
|
+
// In-memory PGlite via cached factory — reuses the WASM instance from `testing/db.ts`
|
|
209
209
|
// instead of creating a new PGlite each time. Schema is reset and migrations re-run
|
|
210
|
-
// on each call, but the expensive WASM cold start only happens once per
|
|
210
|
+
// on each call, but the expensive WASM cold start only happens once per loaded
|
|
211
|
+
// copy of `testing/db.ts` — under the `db` project's `isolate: false` +
|
|
212
|
+
// `fileParallelism: false` that is once for the whole run.
|
|
211
213
|
// `migration_namespaces` selects an auth+extras factory; auth-only is the default.
|
|
214
|
+
// `db_type` below names PGlite unconditionally: a run that installs a substitute
|
|
215
|
+
// factory (`set_substitute_db_factory`) before this module loads gets that driver
|
|
216
|
+
// here, and no caller reads this field to pick behavior — it is reported, not
|
|
217
|
+
// dispatched on.
|
|
212
218
|
const db = await resolve_fallback_factory(migration_namespaces).create();
|
|
213
219
|
const audit = audit_factory({ db, log: test_log });
|
|
214
220
|
backend = {
|
|
@@ -255,7 +261,7 @@ export const create_test_app_server = async (options) => {
|
|
|
255
261
|
*
|
|
256
262
|
* A fresh Hono app is created each call — middleware closures bind to the
|
|
257
263
|
* server's deps (db, keyring), so reuse across servers is unsafe.
|
|
258
|
-
* The expensive resource (PGlite WASM) is cached separately in `
|
|
264
|
+
* The expensive resource (PGlite WASM) is cached separately in `testing/db.ts`.
|
|
259
265
|
*
|
|
260
266
|
* @param options - test app configuration
|
|
261
267
|
* @returns a `TestApp` ready for HTTP testing
|