@fuzdev/fuz_app 0.62.0 → 0.64.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 +139 -24
- package/dist/actions/action_rpc.d.ts +10 -0
- package/dist/actions/action_rpc.d.ts.map +1 -1
- package/dist/actions/action_rpc.js +1 -1
- package/dist/actions/action_spec.d.ts +1 -1
- package/dist/actions/action_spec.js +1 -1
- package/dist/actions/connection_closer.d.ts +68 -0
- package/dist/actions/connection_closer.d.ts.map +1 -0
- package/dist/actions/connection_closer.js +41 -0
- package/dist/actions/perform_action.d.ts.map +1 -1
- package/dist/actions/perform_action.js +1 -0
- package/dist/actions/register_action_ws.d.ts.map +1 -1
- package/dist/actions/register_action_ws.js +23 -2
- package/dist/actions/register_ws_endpoint.d.ts +11 -9
- package/dist/actions/register_ws_endpoint.d.ts.map +1 -1
- package/dist/actions/register_ws_endpoint.js +5 -5
- package/dist/actions/transports_ws_auth_guard.d.ts +24 -8
- package/dist/actions/transports_ws_auth_guard.d.ts.map +1 -1
- package/dist/actions/transports_ws_auth_guard.js +23 -7
- package/dist/actions/ws_endpoint_spec.d.ts +119 -0
- package/dist/actions/ws_endpoint_spec.d.ts.map +1 -0
- package/dist/actions/ws_endpoint_spec.js +13 -0
- package/dist/auth/CLAUDE.md +124 -39
- package/dist/auth/account_action_specs.d.ts +7 -1
- package/dist/auth/account_action_specs.d.ts.map +1 -1
- package/dist/auth/account_action_specs.js +11 -4
- package/dist/auth/account_actions.d.ts +13 -0
- package/dist/auth/account_actions.d.ts.map +1 -1
- package/dist/auth/account_actions.js +40 -5
- package/dist/auth/account_routes.d.ts +12 -2
- package/dist/auth/account_routes.d.ts.map +1 -1
- package/dist/auth/account_routes.js +63 -12
- package/dist/auth/account_schema.d.ts +5 -5
- package/dist/auth/account_schema.js +2 -2
- package/dist/auth/actor_lookup_actions.d.ts +1 -1
- package/dist/auth/actor_lookup_actions.js +1 -1
- package/dist/auth/actor_lookup_queries.d.ts +1 -1
- package/dist/auth/actor_lookup_queries.js +1 -1
- package/dist/auth/actor_search_action_specs.d.ts +1 -1
- package/dist/auth/actor_search_action_specs.js +1 -1
- package/dist/auth/actor_search_actions.d.ts +1 -1
- package/dist/auth/actor_search_actions.js +1 -1
- package/dist/auth/actor_search_queries.d.ts +1 -1
- package/dist/auth/actor_search_queries.js +1 -1
- package/dist/auth/admin_action_specs.d.ts +8 -8
- package/dist/auth/admin_actions.d.ts +11 -0
- package/dist/auth/admin_actions.d.ts.map +1 -1
- package/dist/auth/admin_actions.js +25 -0
- package/dist/auth/all_action_spec_registries.d.ts +2 -2
- package/dist/auth/all_action_spec_registries.js +2 -2
- package/dist/auth/audit_emitter.d.ts +56 -12
- package/dist/auth/audit_emitter.d.ts.map +1 -1
- package/dist/auth/audit_emitter.js +38 -12
- package/dist/auth/audit_log_routes.d.ts +1 -1
- package/dist/auth/audit_log_routes.js +1 -1
- package/dist/auth/audit_log_schema.d.ts +30 -3
- package/dist/auth/audit_log_schema.d.ts.map +1 -1
- package/dist/auth/audit_log_schema.js +21 -3
- package/dist/auth/bootstrap_routes.d.ts +1 -1
- package/dist/auth/invite_schema.d.ts +2 -2
- package/dist/auth/request_context.d.ts +1 -1
- package/dist/auth/signup_routes.d.ts +1 -1
- package/dist/auth/standard_rpc_actions.d.ts +1 -0
- package/dist/auth/standard_rpc_actions.d.ts.map +1 -1
- package/dist/auth/standard_rpc_actions.js +1 -0
- package/dist/env/update_env_variable.js +1 -1
- package/dist/http/CLAUDE.md +42 -26
- package/dist/http/ip_canonical.d.ts +99 -0
- package/dist/http/ip_canonical.d.ts.map +1 -0
- package/dist/http/ip_canonical.js +191 -0
- package/dist/http/origin.d.ts +13 -5
- package/dist/http/origin.d.ts.map +1 -1
- package/dist/http/origin.js +13 -31
- package/dist/http/pending_effects.d.ts +1 -1
- package/dist/http/pending_effects.js +1 -1
- package/dist/http/proxy.d.ts +13 -5
- package/dist/http/proxy.d.ts.map +1 -1
- package/dist/http/proxy.js +15 -23
- package/dist/http/surface.d.ts +50 -0
- package/dist/http/surface.d.ts.map +1 -1
- package/dist/http/surface.js +27 -1
- package/dist/primitive_schemas.d.ts +20 -4
- package/dist/primitive_schemas.d.ts.map +1 -1
- package/dist/primitive_schemas.js +25 -4
- package/dist/realtime/sse_auth_guard.d.ts +16 -4
- package/dist/realtime/sse_auth_guard.d.ts.map +1 -1
- package/dist/realtime/sse_auth_guard.js +15 -3
- package/dist/server/app_backend.d.ts +66 -19
- package/dist/server/app_backend.d.ts.map +1 -1
- package/dist/server/app_backend.js +57 -34
- package/dist/server/app_server.d.ts +60 -0
- package/dist/server/app_server.d.ts.map +1 -1
- package/dist/server/app_server.js +95 -2
- package/dist/server/startup.d.ts.map +1 -1
- package/dist/server/startup.js +12 -0
- package/dist/testing/CLAUDE.md +91 -71
- package/dist/testing/admin_integration.d.ts.map +1 -1
- package/dist/testing/admin_integration.js +4 -5
- package/dist/testing/adversarial_headers.d.ts +6 -0
- package/dist/testing/adversarial_headers.d.ts.map +1 -1
- package/dist/testing/adversarial_headers.js +13 -5
- package/dist/testing/app_server.d.ts +33 -32
- package/dist/testing/app_server.d.ts.map +1 -1
- package/dist/testing/app_server.js +4 -13
- package/dist/testing/attack_surface.d.ts +8 -7
- package/dist/testing/attack_surface.d.ts.map +1 -1
- package/dist/testing/attack_surface.js +12 -8
- package/dist/testing/audit_completeness.d.ts.map +1 -1
- package/dist/testing/audit_completeness.js +20 -6
- package/dist/testing/audit_drift_guard.d.ts +116 -0
- package/dist/testing/audit_drift_guard.d.ts.map +1 -0
- package/dist/testing/audit_drift_guard.js +134 -0
- package/dist/testing/connection_closer_helpers.d.ts +44 -0
- package/dist/testing/connection_closer_helpers.d.ts.map +1 -0
- package/dist/testing/connection_closer_helpers.js +48 -0
- package/dist/testing/integration.d.ts.map +1 -1
- package/dist/testing/integration.js +7 -9
- package/dist/testing/rate_limiting.js +4 -4
- package/dist/testing/rpc_helpers.d.ts +2 -1
- package/dist/testing/rpc_helpers.d.ts.map +1 -1
- package/dist/testing/rpc_round_trip.d.ts.map +1 -1
- package/dist/testing/rpc_round_trip.js +6 -8
- package/dist/testing/sse_round_trip.d.ts.map +1 -1
- package/dist/testing/sse_round_trip.js +12 -6
- package/dist/testing/stubs.d.ts +11 -0
- package/dist/testing/stubs.d.ts.map +1 -1
- package/dist/testing/stubs.js +4 -0
- package/dist/testing/surface_invariants.d.ts +66 -1
- package/dist/testing/surface_invariants.d.ts.map +1 -1
- package/dist/testing/surface_invariants.js +103 -1
- package/dist/ui/CLAUDE.md +13 -18
- package/dist/ui/SurfaceExplorer.svelte +161 -2
- package/dist/ui/SurfaceExplorer.svelte.d.ts.map +1 -1
- package/dist/ui/keyed_async_slot.svelte.d.ts +1 -1
- package/dist/ui/keyed_async_slot.svelte.js +1 -1
- package/package.json +1 -1
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* @module
|
|
9
9
|
*/
|
|
10
10
|
import { Hono, type Context } from 'hono';
|
|
11
|
+
import type { UpgradeWebSocket } from 'hono/ws';
|
|
11
12
|
import { z } from 'zod';
|
|
12
13
|
import { type SessionOptions } from '../auth/session_cookie.js';
|
|
13
14
|
import type { BootstrapAccountSuccess } from '../auth/bootstrap_account.js';
|
|
@@ -25,6 +26,8 @@ import { type AppSurfaceSpec, type RpcEndpointSpec } from '../http/surface.js';
|
|
|
25
26
|
import { type RouteSpec } from '../http/route_spec.js';
|
|
26
27
|
import type { MiddlewareSpec } from '../http/middleware_spec.js';
|
|
27
28
|
import { type BootstrapStatus } from '../auth/bootstrap_routes.js';
|
|
29
|
+
import type { WsEndpointSpec } from '../actions/ws_endpoint_spec.js';
|
|
30
|
+
import { BackendWebsocketTransport } from '../actions/transports_ws_backend.js';
|
|
28
31
|
/**
|
|
29
32
|
* Context passed to `on_effect_error` when a pending effect rejects.
|
|
30
33
|
*/
|
|
@@ -163,6 +166,50 @@ export interface AppServerOptions {
|
|
|
163
166
|
* `create_standard_rpc_actions(ctx.deps, {app_settings: ctx.app_settings})`.
|
|
164
167
|
*/
|
|
165
168
|
rpc_endpoints?: Array<RpcEndpointSpec> | ((context: AppServerContext) => Array<RpcEndpointSpec>);
|
|
169
|
+
/**
|
|
170
|
+
* Hono adapter's `upgradeWebSocket` helper. Required whenever
|
|
171
|
+
* `ws_endpoints` resolves to a non-empty array — `create_app_server`
|
|
172
|
+
* throws at assembly otherwise. Omit (along with `ws_endpoints`)
|
|
173
|
+
* when the consumer doesn't mount any WS endpoints. The same
|
|
174
|
+
* adapter helper services every `WsEndpointSpec` mounted from
|
|
175
|
+
* `ws_endpoints` — one adapter per app.
|
|
176
|
+
*
|
|
177
|
+
* For Node, `import {upgradeWebSocket} from '@hono/node-ws'`. For
|
|
178
|
+
* Deno, `import {upgradeWebSocket} from 'hono/deno'`. Test harnesses
|
|
179
|
+
* use `create_stub_upgrade` from `$lib/testing/ws_round_trip.ts`.
|
|
180
|
+
*/
|
|
181
|
+
upgradeWebSocket?: UpgradeWebSocket;
|
|
182
|
+
/**
|
|
183
|
+
* WebSocket endpoint specs — single source of truth for both surface
|
|
184
|
+
* generation *and* live dispatch. Each entry is auto-mounted via
|
|
185
|
+
* `register_ws_endpoint` against the assembled Hono app, so
|
|
186
|
+
* consumers no longer call `register_ws_endpoint` themselves.
|
|
187
|
+
*
|
|
188
|
+
* Accepts either an array (evaluated eagerly) or a factory
|
|
189
|
+
* `(ctx: AppServerContext) => ReadonlyArray<WsEndpointSpec>`
|
|
190
|
+
* (evaluated after the server context is assembled). Use the factory
|
|
191
|
+
* form when action lists depend on `ctx.deps` /
|
|
192
|
+
* `ctx.action_*_rate_limiter` — e.g. when spreading
|
|
193
|
+
* `create_standard_rpc_actions(ctx.deps, ...)` over WS.
|
|
194
|
+
*
|
|
195
|
+
* When non-empty, `upgradeWebSocket` must be supplied (throws
|
|
196
|
+
* otherwise). A factory returning `[]` does NOT trip the check —
|
|
197
|
+
* feature-flag gated WS surfaces stay safe.
|
|
198
|
+
*
|
|
199
|
+
* Duplicate `path` values across two `WsEndpointSpec`s throw at
|
|
200
|
+
* mount time (Hono would silently shadow them otherwise).
|
|
201
|
+
*
|
|
202
|
+
* Each spec's `auth_guard?` defaults to `true` — the factory
|
|
203
|
+
* composes `create_ws_auth_guard` + `create_ws_logout_closer`
|
|
204
|
+
* against the mounted transport and appends them to
|
|
205
|
+
* `deps.audit.on_event_chain`. Wiring is deduped by transport
|
|
206
|
+
* **reference identity** so two specs sharing one
|
|
207
|
+
* `BackendWebsocketTransport` instance get a single pair of
|
|
208
|
+
* listeners; wrapped / proxied transports dedupe as separate
|
|
209
|
+
* entries (set `auth_guard: false` on duplicates and compose
|
|
210
|
+
* against the underlying transport once).
|
|
211
|
+
*/
|
|
212
|
+
ws_endpoints?: ReadonlyArray<WsEndpointSpec> | ((context: AppServerContext) => ReadonlyArray<WsEndpointSpec>);
|
|
166
213
|
/**
|
|
167
214
|
* Env schema for surface generation. Defaults to `BaseServerEnv` —
|
|
168
215
|
* pass an extended schema (typically `BaseServerEnv.extend({...})`)
|
|
@@ -241,6 +288,19 @@ export interface AppServer {
|
|
|
241
288
|
* Use `require_audit_sse(server)` to assert the invariant.
|
|
242
289
|
*/
|
|
243
290
|
audit_sse: AuditLogSse | null;
|
|
291
|
+
/**
|
|
292
|
+
* Path-keyed map of mounted WS endpoints. Each value is the
|
|
293
|
+
* `BackendWebsocketTransport` `create_app_server` registered
|
|
294
|
+
* connections against — supplied via `WsEndpointSpec.transport` or
|
|
295
|
+
* auto-created when omitted. Retain for broadcast / fan-out:
|
|
296
|
+
*
|
|
297
|
+
* ```ts
|
|
298
|
+
* app_server.ws_endpoints['/api/ws'].send_to_account(account_id, msg);
|
|
299
|
+
* ```
|
|
300
|
+
*
|
|
301
|
+
* Empty when no `ws_endpoints` were mounted.
|
|
302
|
+
*/
|
|
303
|
+
ws_endpoints: Readonly<Record<string, BackendWebsocketTransport>>;
|
|
244
304
|
/** Close the database connection. Propagated from `AppBackend`. */
|
|
245
305
|
close: () => Promise<void>;
|
|
246
306
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app_server.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/server/app_server.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"app_server.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/server/app_server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAC,IAAI,EAAE,KAAK,OAAO,EAAC,MAAM,MAAM,CAAC;AAGxC,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,SAAS,CAAC;AAC9C,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,OAAO,EAEN,KAAK,cAAc,EAEnB,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAC,uBAAuB,EAAC,MAAM,8BAA8B,CAAC;AAC1E,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAGN,KAAK,WAAW,EAChB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,gCAAgC,CAAC;AAEhE,OAAO,EAKN,KAAK,WAAW,EAChB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;AACtD,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAGjD,OAAO,oBAAoB,CAAC;AAE5B,OAAO,EAA2B,KAAK,kBAAkB,EAAC,MAAM,aAAa,CAAC;AAE9E,OAAO,EAEN,KAAK,cAAc,EAEnB,KAAK,eAAe,EACpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAIN,KAAK,SAAS,EACd,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAGN,KAAK,eAAe,EACpB,MAAM,6BAA6B,CAAC;AASrC,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,gCAAgC,CAAC;AAKnE,OAAO,EAAC,yBAAyB,EAAC,MAAM,qCAAqC,CAAC;AAE9E;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC,0DAA0D;IAC1D,MAAM,EAAE,MAAM,CAAC;IACf,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAC;CACb;AAED;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAChC,2DAA2D;IAC3D,OAAO,EAAE,UAAU,CAAC;IACpB,6CAA6C;IAC7C,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,sCAAsC;IACtC,eAAe,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAE/B,6BAA6B;IAC7B,KAAK,EAAE;QACN,eAAe,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QAC/B,iBAAiB,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,MAAM,GAAG,SAAS,CAAC;KACtD,CAAC;IAEF;;;;;OAKG;IACH,eAAe,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IACrC;;;;;OAKG;IACH,0BAA0B,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAChD;;;;;OAKG;IACH,2BAA2B,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IACjD;;;;OAIG;IACH,sBAAsB,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAC5C;;;;;;;;OAQG;IACH,sBAAsB,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAC5C;;;;;;;;OAQG;IACH,2BAA2B,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IACjD;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,2DAA2D;IAC3D,kBAAkB,CAAC,EAAE,gBAAgB,CAAC;IAEtC,yEAAyE;IACzE,SAAS,CAAC,EAAE;QACX,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,mEAAmE;QACnE,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB;;;WAGG;QACH,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,uBAAuB,EAAE,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;KAC9E,CAAC;IAEF;;;OAGG;IACH,aAAa,CAAC,EAAE,KAAK,CAAC;IAEtB;;;OAGG;IACH,kBAAkB,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,KAAK,CAAC,SAAS,CAAC,CAAC;IAEpE,4DAA4D;IAC5D,oBAAoB,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,KAAK,CAAC,cAAc,CAAC,CAAC;IAE/E;;;;;;;;;;;;;;OAcG;IACH,aAAa,CAAC,EAAE,IAAI,GAAG;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAC,CAAC;IAEvC,gFAAgF;IAChF,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAE/B;;;;;;;;;;;OAWG;IACH,aAAa,CAAC,EAAE,KAAK,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,gBAAgB,KAAK,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC;IAEjG;;;;;;;;;;;OAWG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IAEpC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;IACH,YAAY,CAAC,EACV,aAAa,CAAC,cAAc,CAAC,GAC7B,CAAC,CAAC,OAAO,EAAE,gBAAgB,KAAK,aAAa,CAAC,cAAc,CAAC,CAAC,CAAC;IAElE;;;;OAIG;IACH,UAAU,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;IAEzB,mFAAmF;IACnF,qBAAqB,CAAC,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;IAE9C,6DAA6D;IAC7D,cAAc,CAAC,EAAE;QAChB,YAAY,EAAE,kBAAkB,CAAC;QACjC,4DAA4D;QAC5D,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,gEAAgE;QAChE,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB;;;;WAIG;QACH,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;KACzC,CAAC;IAEF;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAEhC;;;;OAIG;IACH,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAExE,8CAA8C;IAC9C,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAED,8CAA8C;AAC9C,MAAM,WAAW,gBAAgB;IAChC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,UAAU,CAAC;IACpB,gBAAgB,EAAE,eAAe,CAAC;IAClC,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,yEAAyE;IACzE,eAAe,EAAE,WAAW,GAAG,IAAI,CAAC;IACpC,iFAAiF;IACjF,0BAA0B,EAAE,WAAW,GAAG,IAAI,CAAC;IAC/C,kFAAkF;IAClF,2BAA2B,EAAE,WAAW,GAAG,IAAI,CAAC;IAChD,uGAAuG;IACvG,sBAAsB,EAAE,WAAW,GAAG,IAAI,CAAC;IAC3C,0GAA0G;IAC1G,2BAA2B,EAAE,WAAW,GAAG,IAAI,CAAC;IAChD,2EAA2E;IAC3E,YAAY,EAAE,WAAW,CAAC;IAC1B;;;;OAIG;IACH,SAAS,EAAE,WAAW,GAAG,IAAI,CAAC;CAC9B;AAED,uCAAuC;AACvC,MAAM,WAAW,SAAS;IACzB,GAAG,EAAE,IAAI,CAAC;IACV,wEAAwE;IACxE,YAAY,EAAE,cAAc,CAAC;IAC7B,gBAAgB,EAAE,eAAe,CAAC;IAClC,2EAA2E;IAC3E,YAAY,EAAE,WAAW,CAAC;IAC1B,oGAAoG;IACpG,iBAAiB,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;IAClD;;;;OAIG;IACH,SAAS,EAAE,WAAW,GAAG,IAAI,CAAC;IAC9B;;;;;;;;;;;OAWG;IACH,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,yBAAyB,CAAC,CAAC,CAAC;IAClE,mEAAmE;IACnE,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,iBAAiB,GAAI,QAAQ;IAAC,SAAS,EAAE,WAAW,GAAG,IAAI,CAAA;CAAC,KAAG,WAO3E,CAAC;AAEF,gDAAgD;AAChD,eAAO,MAAM,qBAAqB,QAAc,CAAC;AAEjD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,iBAAiB,GAAU,SAAS,gBAAgB,KAAG,OAAO,CAAC,SAAS,CAqXpF,CAAC"}
|
|
@@ -32,6 +32,9 @@ import { fuz_auth_guard_resolver } from '../auth/auth_guard_resolver.js';
|
|
|
32
32
|
import { create_fuz_authorization_handler } from '../auth/request_context.js';
|
|
33
33
|
import { ERROR_PAYLOAD_TOO_LARGE } from '../http/error_schemas.js';
|
|
34
34
|
import { create_rpc_endpoint } from '../actions/action_rpc.js';
|
|
35
|
+
import { register_ws_endpoint } from '../actions/register_ws_endpoint.js';
|
|
36
|
+
import { create_ws_auth_guard, create_ws_logout_closer, } from '../actions/transports_ws_auth_guard.js';
|
|
37
|
+
import { BackendWebsocketTransport } from '../actions/transports_ws_backend.js';
|
|
35
38
|
/**
|
|
36
39
|
* Assert that `audit_sse` was wired by `create_app_server` and return it
|
|
37
40
|
* as a non-null `AuditLogSse`. Throws a labelled error when the
|
|
@@ -127,7 +130,15 @@ export const create_app_server = async (options) => {
|
|
|
127
130
|
const app_settings = await query_app_settings_load({ db: deps.db });
|
|
128
131
|
// Surface route ref — factory manages the circular ref
|
|
129
132
|
const surface_ref = {
|
|
130
|
-
surface: {
|
|
133
|
+
surface: {
|
|
134
|
+
middleware: [],
|
|
135
|
+
routes: [],
|
|
136
|
+
rpc_endpoints: [],
|
|
137
|
+
ws_endpoints: [],
|
|
138
|
+
env: [],
|
|
139
|
+
events: [],
|
|
140
|
+
diagnostics: [],
|
|
141
|
+
},
|
|
131
142
|
};
|
|
132
143
|
// Route specs (consumer routes + factory-managed routes)
|
|
133
144
|
const context = {
|
|
@@ -173,6 +184,15 @@ export const create_app_server = async (options) => {
|
|
|
173
184
|
}));
|
|
174
185
|
}
|
|
175
186
|
}
|
|
187
|
+
// WS endpoint resolution — done here (alongside RPC) so the captured
|
|
188
|
+
// array threads into surface generation below. Actual mount happens
|
|
189
|
+
// after `apply_route_specs` because `register_ws_endpoint` mutates the
|
|
190
|
+
// live Hono `app` (origin / auth / role / authorization middleware +
|
|
191
|
+
// the `app.get(path, ...)` upgrade route), and `app` does not exist
|
|
192
|
+
// until the assembly phase below.
|
|
193
|
+
const resolved_ws_endpoints = typeof options.ws_endpoints === 'function'
|
|
194
|
+
? options.ws_endpoints(context)
|
|
195
|
+
: options.ws_endpoints;
|
|
176
196
|
// Surface route (default: enabled)
|
|
177
197
|
if (options.surface_route !== false) {
|
|
178
198
|
factory_routes.push(create_surface_route_spec(surface_ref));
|
|
@@ -192,6 +212,7 @@ export const create_app_server = async (options) => {
|
|
|
192
212
|
env_schema: options.env_schema ?? BaseServerEnv,
|
|
193
213
|
event_specs: all_event_specs,
|
|
194
214
|
rpc_endpoints: resolved_rpc_endpoints,
|
|
215
|
+
ws_endpoints: resolved_ws_endpoints,
|
|
195
216
|
});
|
|
196
217
|
// Config-level diagnostics (concatenated after spec-level from generate_app_surface)
|
|
197
218
|
const config_diagnostics = [];
|
|
@@ -215,7 +236,7 @@ export const create_app_server = async (options) => {
|
|
|
215
236
|
config_diagnostics.push({
|
|
216
237
|
level: 'warning',
|
|
217
238
|
category: 'security',
|
|
218
|
-
message: 'Session cookie httpOnly=false — cookie accessible to
|
|
239
|
+
message: 'Session cookie httpOnly=false — cookie accessible to JS',
|
|
219
240
|
});
|
|
220
241
|
}
|
|
221
242
|
}
|
|
@@ -291,6 +312,77 @@ export const create_app_server = async (options) => {
|
|
|
291
312
|
apply_middleware_specs(app, middleware_specs);
|
|
292
313
|
const authorize = create_fuz_authorization_handler({ db: deps.db });
|
|
293
314
|
apply_route_specs(app, route_specs, fuz_auth_guard_resolver, log, deps.db, authorize);
|
|
315
|
+
// WS endpoint auto-mount — must run after `app` exists and
|
|
316
|
+
// `apply_route_specs` has registered the request routes. Each spec
|
|
317
|
+
// becomes a `register_ws_endpoint` call, plus optional `auth_guard`
|
|
318
|
+
// wiring onto the audit chain. `post_route_middleware` and static
|
|
319
|
+
// serving register after this loop, so WS upgrade routes sit
|
|
320
|
+
// adjacent to the consumer routes and ahead of the static fallback —
|
|
321
|
+
// matches the "WS mount is route registration" mental model.
|
|
322
|
+
const mounted_ws_endpoints = {};
|
|
323
|
+
if (resolved_ws_endpoints?.length) {
|
|
324
|
+
if (options.upgradeWebSocket === undefined) {
|
|
325
|
+
throw new Error('create_app_server: ws_endpoints resolved non-empty but upgradeWebSocket is missing. ' +
|
|
326
|
+
"Pass the Hono adapter's upgradeWebSocket helper as a top-level option.");
|
|
327
|
+
}
|
|
328
|
+
// Cross-surface collision: `register_ws_endpoint` mounts a `GET path`
|
|
329
|
+
// upgrade route. If a `RouteSpec` already registered `GET path`,
|
|
330
|
+
// Hono's last-wins semantics would silently shadow the consumer's
|
|
331
|
+
// GET route — fail fast instead.
|
|
332
|
+
const route_spec_get_paths = new Set();
|
|
333
|
+
for (const r of route_specs) {
|
|
334
|
+
if (r.method === 'GET')
|
|
335
|
+
route_spec_get_paths.add(r.path);
|
|
336
|
+
}
|
|
337
|
+
const seen_paths = new Set();
|
|
338
|
+
// Dedupe `auth_guard` wiring by transport reference — two specs
|
|
339
|
+
// sharing one transport instance get a single pair of listeners,
|
|
340
|
+
// otherwise revocation events would fire `close_sockets_for_*`
|
|
341
|
+
// twice per event (idempotent on the transport but log-spammy).
|
|
342
|
+
// Cross-spec OR-semantics: any spec with `auth_guard !== false`
|
|
343
|
+
// wires the guard for that transport; once wired, sibling specs
|
|
344
|
+
// (even with explicit `auth_guard: false`) cannot opt out. To
|
|
345
|
+
// disable, every spec sharing the transport must pass `auth_guard: false`.
|
|
346
|
+
const guarded_transports = new WeakSet();
|
|
347
|
+
for (const endpoint of resolved_ws_endpoints) {
|
|
348
|
+
if (seen_paths.has(endpoint.path)) {
|
|
349
|
+
throw new Error(`create_app_server: duplicate ws_endpoints path: ${endpoint.path}`);
|
|
350
|
+
}
|
|
351
|
+
if (route_spec_get_paths.has(endpoint.path)) {
|
|
352
|
+
throw new Error(`create_app_server: ws_endpoints path collides with a GET RouteSpec: ${endpoint.path}`);
|
|
353
|
+
}
|
|
354
|
+
seen_paths.add(endpoint.path);
|
|
355
|
+
const endpoint_transport = endpoint.transport ?? new BackendWebsocketTransport();
|
|
356
|
+
register_ws_endpoint({
|
|
357
|
+
app,
|
|
358
|
+
path: endpoint.path,
|
|
359
|
+
upgradeWebSocket: options.upgradeWebSocket,
|
|
360
|
+
allowed_origins: endpoint.allowed_origins,
|
|
361
|
+
db: deps.db,
|
|
362
|
+
actions: endpoint.actions,
|
|
363
|
+
transport: endpoint_transport,
|
|
364
|
+
heartbeat: endpoint.heartbeat,
|
|
365
|
+
artificial_delay: endpoint.artificial_delay,
|
|
366
|
+
on_socket_open: endpoint.on_socket_open,
|
|
367
|
+
on_socket_close: endpoint.on_socket_close,
|
|
368
|
+
log,
|
|
369
|
+
required_roles: endpoint.required_roles,
|
|
370
|
+
action_ip_rate_limiter,
|
|
371
|
+
action_account_rate_limiter,
|
|
372
|
+
});
|
|
373
|
+
mounted_ws_endpoints[endpoint.path] = endpoint_transport;
|
|
374
|
+
if (endpoint.auth_guard !== false && !guarded_transports.has(endpoint_transport)) {
|
|
375
|
+
guarded_transports.add(endpoint_transport);
|
|
376
|
+
deps.audit.on_event_chain.push(create_ws_auth_guard(endpoint_transport, log));
|
|
377
|
+
deps.audit.on_event_chain.push(create_ws_logout_closer(endpoint_transport, log));
|
|
378
|
+
}
|
|
379
|
+
if (endpoint.extra_audit_handlers?.length) {
|
|
380
|
+
for (const handler of endpoint.extra_audit_handlers) {
|
|
381
|
+
deps.audit.on_event_chain.push(handler);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
294
386
|
// Post-route middleware (before static serving)
|
|
295
387
|
if (options.post_route_middleware) {
|
|
296
388
|
apply_middleware_specs(app, options.post_route_middleware);
|
|
@@ -309,6 +401,7 @@ export const create_app_server = async (options) => {
|
|
|
309
401
|
app_settings,
|
|
310
402
|
migration_results: backend.migration_results,
|
|
311
403
|
audit_sse,
|
|
404
|
+
ws_endpoints: mounted_ws_endpoints,
|
|
312
405
|
close: backend.close,
|
|
313
406
|
};
|
|
314
407
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"startup.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/server/startup.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAGpD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,oBAAoB,CAAC;AAEnD;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB,GAC/B,SAAS,UAAU,EACnB,KAAK,MAAM,EACX,aAAa,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAClC,
|
|
1
|
+
{"version":3,"file":"startup.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/server/startup.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAGpD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,oBAAoB,CAAC;AAEnD;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB,GAC/B,SAAS,UAAU,EACnB,KAAK,MAAM,EACX,aAAa,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAClC,IAkDF,CAAC"}
|
package/dist/server/startup.js
CHANGED
|
@@ -17,6 +17,18 @@ import { format_env_display_value } from '../env/mask.js';
|
|
|
17
17
|
*/
|
|
18
18
|
export const log_startup_summary = (surface, log, env_values) => {
|
|
19
19
|
log.info(`Surface: ${surface.routes.length} routes, ${surface.middleware.length} middleware layers`);
|
|
20
|
+
// Endpoint surfaces — logged when non-empty so operators can confirm
|
|
21
|
+
// auto-mount picked up the expected actions (and so a factory that
|
|
22
|
+
// silently returns `[]` is loud at boot instead of a method_not_found
|
|
23
|
+
// at first call).
|
|
24
|
+
if (surface.rpc_endpoints.length) {
|
|
25
|
+
const rpc_method_count = surface.rpc_endpoints.reduce((sum, ep) => sum + ep.methods.length, 0);
|
|
26
|
+
log.info(`RPC: ${surface.rpc_endpoints.length} endpoint(s), ${rpc_method_count} method(s)`);
|
|
27
|
+
}
|
|
28
|
+
if (surface.ws_endpoints.length) {
|
|
29
|
+
const ws_method_count = surface.ws_endpoints.reduce((sum, ep) => sum + ep.methods.length, 0);
|
|
30
|
+
log.info(`WS: ${surface.ws_endpoints.length} endpoint(s), ${ws_method_count} method(s)`);
|
|
31
|
+
}
|
|
20
32
|
if (surface.env.length) {
|
|
21
33
|
const required = surface.env.filter((e) => !e.optional);
|
|
22
34
|
const secret = surface.env.filter((e) => e.sensitivity === 'secret');
|
package/dist/testing/CLAUDE.md
CHANGED
|
@@ -6,43 +6,37 @@ round-trip harnesses. Consumers import these to assemble their own test suites
|
|
|
6
6
|
against a fuz_app-derived server.
|
|
7
7
|
|
|
8
8
|
For narrative wiring examples (how to call these from a consumer's vitest
|
|
9
|
-
setup), see
|
|
10
|
-
conventions
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
setup), see ../../../docs/testing.md. For fuz_app's own test suite
|
|
10
|
+
conventions, see ../../test/CLAUDE.md. For shared testing conventions
|
|
11
|
+
(`.db.test.ts`, `assert` from vitest, `assert_rejects`, `vi.mock` caveats),
|
|
12
|
+
see Skill(fuz-stack) testing-patterns. This file is a reference index for
|
|
13
|
+
the helpers themselves.
|
|
13
14
|
|
|
14
15
|
## Production guard — always the first import
|
|
15
16
|
|
|
16
|
-
Every module
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
bundles. SvelteKit and Vite set `DEV` correctly for dev + tests; the
|
|
20
|
-
production code path explodes at the first testing-module import.
|
|
21
|
-
|
|
22
|
-
When adding a new module to this directory, make this import the first
|
|
23
|
-
line. The convention is enforced by grep, not by a linter — break it and
|
|
24
|
-
the production bundle still builds, then crashes at runtime on first
|
|
25
|
-
module load.
|
|
17
|
+
Every module here starts with `import './assert_dev_env.js';` — reads `DEV`
|
|
18
|
+
from `esm-env` and throws if false, preventing production-bundle inclusion.
|
|
19
|
+
Enforced by grep, not a linter; make this the first line in new modules.
|
|
26
20
|
|
|
27
21
|
## Stubs, factories, mocks
|
|
28
22
|
|
|
29
23
|
### `stubs.ts` — `AppDeps` + `AppServerContext` stubs
|
|
30
24
|
|
|
31
|
-
| Helper | Role
|
|
32
|
-
| ----------------------------------------------------- |
|
|
33
|
-
| `create_throwing_stub<T>(label)` | Proxy whose every property access throws `Throwing stub 'label' — unexpected access to 'prop'`; JS-internal probes return `undefined`; `toJSON` returns `"[throwing_stub:label]"` so accidental serialization is visible rather than `{}`.
|
|
34
|
-
| `create_noop_stub<T>(label, overrides?)` | Proxy whose every method returns `async () => undefined`; `overrides` lets callers pin specific props.
|
|
35
|
-
| `stub` | Pre-built throwing stub labelled `'stub'`.
|
|
36
|
-
| `create_stub_db()` | Returns a real `Db` whose `client.query` yields `{rows: []}` and whose `transaction(fn)` synchronously calls `fn(inner_stub_db)`. Safe for `apply_route_specs`'s declarative transaction wrapper.
|
|
37
|
-
| `stub_handler()` | Returns a fresh `Response('stub')`.
|
|
38
|
-
| `stub_mw` | Pass-through middleware handler (`async (_c, next) => next()`).
|
|
39
|
-
| `stub_app_deps` | Frozen `AppDeps` — every capability is a throwing stub, `audit` is a no-op `AuditEmitter` from `create_test_audit_emitter`.
|
|
40
|
-
| `create_stub_app_deps()` | Factory returning fresh `AppDeps` with no-op FS/keyring/password, a `create_noop_stub` DB, silent `Logger`, no-op `audit`.
|
|
41
|
-
| `create_test_audit_emitter()` | No-op `AuditEmitter` for tests that don't assert on audit fan-out. `emit` / `emit_role_grant_target` are no-ops; `emit_pool` resolves immediately; `notify` is a no-op; `on_event_chain` is empty.
|
|
42
|
-
| `create_stub_audit_sse()` | No-op `AuditLogSse` for surface-test wiring without booting real SSE. `subscribe` returns a no-op cleanup; `on_audit_event` is a no-op; the `registry` is a fresh `SubscriberRegistry` (live `.size` / `.close_*` for tests touching registry state, isolated per call). For real SSE plumbing, build via `create_audit_log_sse` against `create_test_app`.
|
|
43
|
-
| `create_stub_api_middleware({include_daemon_token?})` | Stub `MiddlewareSpec[]` matching `create_auth_middleware_specs`'s output (origin/session/request_context/bearer_auth, optional daemon_token) for surface generation without booting real auth. See
|
|
44
|
-
| `create_stub_app_server_context(session_options)` | Stub `AppServerContext` — rate limiters null, `bootstrap_status.available: false`, `app_settings.open_signup: false`.
|
|
45
|
-
| `create_test_app_surface_spec(options)` | Builds an `AppSurfaceSpec` that mirrors `create_app_server`'s route assembly: consumer routes + factory-managed bootstrap routes (prefixed via `bootstrap_route_prefix`, default `'/api/account'`) + stub middleware + surface generation. `CreateTestAppSurfaceSpecOptions` accepts `session_options`, `create_route_specs`, `env_schema?`, `event_specs?`, `rpc_endpoints?`, `transform_middleware?`, `bootstrap_route_prefix?`. Single source of truth for attack-surface tests — track `create_app_server` wiring changes here. |
|
|
25
|
+
| Helper | Role |
|
|
26
|
+
| ----------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
27
|
+
| `create_throwing_stub<T>(label)` | Proxy whose every property access throws `Throwing stub 'label' — unexpected access to 'prop'`; JS-internal probes return `undefined`; `toJSON` returns `"[throwing_stub:label]"` so accidental serialization is visible rather than `{}`. |
|
|
28
|
+
| `create_noop_stub<T>(label, overrides?)` | Proxy whose every method returns `async () => undefined`; `overrides` lets callers pin specific props. |
|
|
29
|
+
| `stub` | Pre-built throwing stub labelled `'stub'`. |
|
|
30
|
+
| `create_stub_db()` | Returns a real `Db` whose `client.query` yields `{rows: []}` and whose `transaction(fn)` synchronously calls `fn(inner_stub_db)`. Safe for `apply_route_specs`'s declarative transaction wrapper. |
|
|
31
|
+
| `stub_handler()` | Returns a fresh `Response('stub')`. |
|
|
32
|
+
| `stub_mw` | Pass-through middleware handler (`async (_c, next) => next()`). |
|
|
33
|
+
| `stub_app_deps` | Frozen `AppDeps` — every capability is a throwing stub, `audit` is a no-op `AuditEmitter` from `create_test_audit_emitter`. |
|
|
34
|
+
| `create_stub_app_deps()` | Factory returning fresh `AppDeps` with no-op FS/keyring/password, a `create_noop_stub` DB, silent `Logger`, no-op `audit`. |
|
|
35
|
+
| `create_test_audit_emitter()` | No-op `AuditEmitter` for tests that don't assert on audit fan-out. `emit` / `emit_role_grant_target` are no-ops; `emit_pool` resolves immediately; `notify` is a no-op; `on_event_chain` is empty. |
|
|
36
|
+
| `create_stub_audit_sse()` | No-op `AuditLogSse` for surface-test wiring without booting real SSE. `subscribe` returns a no-op cleanup; `on_audit_event` is a no-op; the `registry` is a fresh `SubscriberRegistry` (live `.size` / `.close_*` for tests touching registry state, isolated per call). For real SSE plumbing, build via `create_audit_log_sse` against `create_test_app`. |
|
|
37
|
+
| `create_stub_api_middleware({include_daemon_token?})` | Stub `MiddlewareSpec[]` matching `create_auth_middleware_specs`'s output (origin/session/request_context/bearer_auth, optional daemon_token) for surface generation without booting real auth. See `auth/CLAUDE.md` §Middleware for the real stack. |
|
|
38
|
+
| `create_stub_app_server_context(session_options)` | Stub `AppServerContext` — rate limiters null, `bootstrap_status.available: false`, `app_settings.open_signup: false`. |
|
|
39
|
+
| `create_test_app_surface_spec(options)` | Builds an `AppSurfaceSpec` that mirrors `create_app_server`'s route assembly: consumer routes + factory-managed bootstrap routes (prefixed via `bootstrap_route_prefix`, default `'/api/account'`) + stub middleware + surface generation. `CreateTestAppSurfaceSpecOptions` accepts `session_options`, `create_route_specs`, `env_schema?`, `event_specs?`, `rpc_endpoints?`, `ws_endpoints?`, `transform_middleware?`, `bootstrap_route_prefix?`. Single source of truth for attack-surface tests — track `create_app_server` wiring changes here. |
|
|
46
40
|
|
|
47
41
|
Throwing stubs surface mock escape: a test that accidentally reaches into
|
|
48
42
|
stub territory breaks immediately with a label-scoped error rather than
|
|
@@ -88,6 +82,25 @@ DB rows but not a full session/token bundle. For tests that also need
|
|
|
88
82
|
an API token + session cookie + role_grants, use `bootstrap_test_account`
|
|
89
83
|
from `app_server.ts` instead.
|
|
90
84
|
|
|
85
|
+
### `audit_drift_guard.ts` — audit-emission validation
|
|
86
|
+
|
|
87
|
+
| Helper | Role |
|
|
88
|
+
| ------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
89
|
+
| `install_audit_drift_guard()` | `beforeEach` resets + `afterEach` zero-checks the `audit_metadata_validation_failures` + `audit_unknown_event_type_failures` counters from `auth/audit_log_queries.ts`. Call once at the top of any `describe_db` block that fires audit emits — production validation is fail-open, so without this any regression that ships a typo'd `event_type` or an undeclared metadata field is silent. Pair with `await_pending_effects: true` (the `create_test_app` default) so fire-and-forget audit writes have completed by response time. |
|
|
90
|
+
| `create_emit_ordering_audit_factory<E>(seq_ref, events_ref, build_inner)` | Returns an `AuditFactory` that wraps the result of `build_inner({db, log})` so every `emit` call pushes `{kind: 'emit', at: seq.value++}` into a shared sequence + events array. Pass through `create_test_app({audit_factory: …})` — the test backend invokes it with its constructed `{db, log}` and lands the wrapped emitter on `deps.audit`. Generic `E extends {kind: string; at: number}` so the events array typechecks against the caller's own `close` / custom marker shape. Pair with `create_recording_closer(seq_ref)` (in `connection_closer_helpers.ts`) for close-vs-emit ordering tests. Scope is `emit` only — `emit_role_grant_target`, `emit_pool`, `notify` forward to the inner emitter unwrapped (same caveat as the previous `patch_audit_emit_capture`). |
|
|
91
|
+
| `AuditEmitMarker` | `{kind: 'emit'; at: number}` — the type of marker `create_emit_ordering_audit_factory` pushes. |
|
|
92
|
+
| `create_recording_audit_emitter(calls_ref?)` | Build a no-op `AuditEmitter` that pushes every `emit` and `emit_pool` call into `calls`. Pass `calls_ref` to write into a caller-owned array; omit to let the helper allocate one. Returns `{emitter, calls}` — destructure `emitter` as the `audit` dep and read `calls` to assert on captured metadata. Replaces per-file capturing emitters previously duplicated across `password_change.test.ts`, `audit_log.test.ts`, etc. |
|
|
93
|
+
| `RecordingAuditEmitter` | `{emitter: AuditEmitter; calls: Array<AuditLogInput>}` — return shape of `create_recording_audit_emitter`. |
|
|
94
|
+
|
|
95
|
+
### `connection_closer_helpers.ts` — `ConnectionCloser` test doubles
|
|
96
|
+
|
|
97
|
+
| Helper | Role |
|
|
98
|
+
| ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
99
|
+
| `create_recording_closer(seq_ref?)` | Returns `{closer, calls}` where every method on `closer` records `{method, id, at}` into `calls`. Pass `seq_ref` to share the sequence counter with `create_emit_ordering_audit_factory` so close + emit markers compose for ordering tests. |
|
|
100
|
+
| `assert_close_call(call, method, id)` | Pins `{method, id}` on a single recorded close call without baking in the `at: N` sequence number. Use at every "did the closer fire?" assertion site; reserve `at: N` assertions for the dedicated ordering test paired with the capture helper. |
|
|
101
|
+
| `RecordedClose` | `{method: 'session' \| 'token' \| 'account', id, at}` — recorded shape pushed by the closer. |
|
|
102
|
+
| `RecordingCloser` | `{closer, calls}` — return shape of `create_recording_closer`. |
|
|
103
|
+
|
|
91
104
|
## Database — `db.ts`
|
|
92
105
|
|
|
93
106
|
Factory builders for parameterized DB tests. Consumer projects pass their
|
|
@@ -146,13 +159,13 @@ Key module-scope values:
|
|
|
146
159
|
"insert account + actor + roles + API token + session + cookie" flow.
|
|
147
160
|
Takes `{db, keyring, session_options, password, username?, password_value?, roles?}`.
|
|
148
161
|
|
|
149
|
-
| Type | Shape
|
|
150
|
-
| --------------------------------------------------- |
|
|
151
|
-
| `TestAppServer extends AppBackend` | Adds `account`, `actor`, `api_token`, `session_cookie`, `keyring`, `cleanup()`.
|
|
152
|
-
| `TestAppServerOptions` | `session_options` (required), optional `db`, `db_type`, `password`, `username`, `password_value`, `roles`, `on_audit_event`, `audit_log_config
|
|
153
|
-
| `CreateTestAppOptions extends TestAppServerOptions` | Adds `create_route_specs` (required)
|
|
154
|
-
| `TestAccount` | `{account, actor, session_cookie, api_token, create_session_headers, create_bearer_headers}`.
|
|
155
|
-
| `TestApp` | `{app, backend, surface_spec, surface, route_specs, create_session_headers, create_bearer_headers, create_daemon_token_headers, create_account, cleanup}`.
|
|
162
|
+
| Type | Shape |
|
|
163
|
+
| --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
164
|
+
| `TestAppServer extends AppBackend` | Adds `account`, `actor`, `api_token`, `session_cookie`, `keyring`, `cleanup()`. |
|
|
165
|
+
| `TestAppServerOptions` | `session_options` (required), optional `db`, `db_type`, `password`, `username`, `password_value`, `roles`, `audit_factory`. The optional `audit_factory` defaults to `default_audit_factory` (no-listener `create_audit_emitter` over the test backend's `{db, log}`); pass a custom factory to compose `on_audit_event` / `audit_log_config`, wrap with `emit_decorator` (via `create_emit_ordering_audit_factory`), or otherwise replace the emitter. Mirrors `CreateAppBackendOptions` end-to-end — the previous `on_audit_event` / `audit_log_config` sugar was removed alongside the production rename. |
|
|
166
|
+
| `CreateTestAppOptions extends TestAppServerOptions` | Adds `create_route_specs` (required), `rpc_endpoints?: RpcEndpointsSuiteOption` (top-level only — single source of truth, symmetric with the suite-level option), and `app_options?: SuiteAppOptions` (`Partial<AppServerOptions>` excluding the four fields the helper manages: `backend`, `session_options`, `create_route_specs`, `rpc_endpoints`). |
|
|
167
|
+
| `TestAccount` | `{account, actor, session_cookie, api_token, create_session_headers, create_bearer_headers}`. |
|
|
168
|
+
| `TestApp` | `{app, backend, surface_spec, surface, route_specs, create_session_headers, create_bearer_headers, create_daemon_token_headers, create_account, cleanup}`. |
|
|
156
169
|
|
|
157
170
|
`create_test_app` hard-codes the test-friendly `AppServerOptions`:
|
|
158
171
|
`allowed_origins: [/^http:\/\/localhost/]`, stub proxy pinned to
|
|
@@ -219,6 +232,21 @@ Structural invariants (options-free, apply universally):
|
|
|
219
232
|
| `assert_error_code_status_consistency` | The same `z.literal()` error code never appears at two different HTTP statuses. |
|
|
220
233
|
| `assert_404_schemas_use_specific_errors` | Routes with params declaring 404 must use `z.literal()` or `z.enum()`, not generic `z.string()`. |
|
|
221
234
|
|
|
235
|
+
RPC / WS structural invariants (options-free, apply universally over
|
|
236
|
+
`surface.rpc_endpoints` + `surface.ws_endpoints`):
|
|
237
|
+
|
|
238
|
+
| Assertion | Checks |
|
|
239
|
+
| ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
|
|
240
|
+
| `assert_rpc_method_descriptions_present` | Every RPC method on every endpoint has a non-empty `description`. |
|
|
241
|
+
| `assert_ws_method_descriptions_present` | Every WS method on every endpoint has a non-empty `description`. |
|
|
242
|
+
| `assert_ws_endpoints_include_protocol_actions` | Every WS endpoint includes `heartbeat` + `cancel` (the `protocol_actions` spread from `actions/protocol.js`). |
|
|
243
|
+
| `assert_ws_notifications_have_null_auth` | WS method `kind === 'remote_notification' ⟺ auth === null` — guards against drift between spec union and surface emitter. |
|
|
244
|
+
|
|
245
|
+
Per-endpoint duplicate method names and the auth-shape biconditional are
|
|
246
|
+
already enforced at startup by `compile_action_registry` (see
|
|
247
|
+
`actions/CLAUDE.md` §Registry compile) — these assertions only cover
|
|
248
|
+
contract-surface concerns a runtime registration check cannot reach.
|
|
249
|
+
|
|
222
250
|
Policy invariants (configurable, sensible defaults):
|
|
223
251
|
|
|
224
252
|
| Assertion | Checks |
|
|
@@ -254,7 +282,8 @@ Tightness audit:
|
|
|
254
282
|
|
|
255
283
|
Aggregate runners (called by the standard attack-surface suite):
|
|
256
284
|
|
|
257
|
-
- `assert_surface_invariants(surface)` — runs all structural assertions.
|
|
285
|
+
- `assert_surface_invariants(surface)` — runs all route-level structural assertions.
|
|
286
|
+
- `assert_rpc_ws_surface_invariants(surface)` — runs all RPC/WS structural assertions.
|
|
258
287
|
- `assert_surface_security_policy(surface, options?)` — runs all policy assertions.
|
|
259
288
|
|
|
260
289
|
### `error_coverage.ts` — reachability tracking
|
|
@@ -337,7 +366,7 @@ Single-call bundle of 5 top-level groups (10 named tests + every
|
|
|
337
366
|
adversarial case per route):
|
|
338
367
|
|
|
339
368
|
1. **attack surface snapshot** — `matches committed snapshot`, `is deterministic`.
|
|
340
|
-
2. **attack surface structure** — `only expected public routes`, `full middleware stack on API routes`, `surface invariants`, `security policy`, `error schema tightness` (logs counts and asserts against `default_error_schema_tightness` by default; pass an override config or `null` via `error_schema_tightness`).
|
|
369
|
+
2. **attack surface structure** — `only expected public routes`, `full middleware stack on API routes`, `surface invariants`, `rpc/ws surface invariants`, `security policy`, `error schema tightness` (logs counts and asserts against `default_error_schema_tightness` by default; pass an override config or `null` via `error_schema_tightness`).
|
|
341
370
|
3. **adversarial HTTP auth enforcement** — `unauthenticated → 401`, `wrong role → 403` × roles, `authenticated without role → 403`, `keeper routes reject session credential → 403`, `correct auth passes guard`.
|
|
342
371
|
4. **adversarial input validation** — delegated to `describe_adversarial_input`.
|
|
343
372
|
5. **adversarial 404 response validation** — delegated to `describe_adversarial_404`.
|
|
@@ -390,8 +419,8 @@ body matches the declared 404 Zod schema. No DB needed.
|
|
|
390
419
|
3. no auth headers → passes through
|
|
391
420
|
4. bearer + empty Origin → 403 `ERROR_FORBIDDEN_ORIGIN` (defense-in-depth)
|
|
392
421
|
5. lowercase `bearer` scheme → RFC 7235 §2.1 soft-fail
|
|
393
|
-
6. bearer + rogue Referer →
|
|
394
|
-
7. bearer + allowed Referer → bearer silently discarded
|
|
422
|
+
6. bearer + rogue Referer (no Origin) → passes origin check (Origin-only posture), bearer silently discarded (Referer is still a browser-context indicator for bearer auth)
|
|
423
|
+
7. bearer + allowed Referer (no Origin) → bearer silently discarded (browser context)
|
|
395
424
|
|
|
396
425
|
Each case declares `validate_expectation: 'called' | 'not_called'` so the
|
|
397
426
|
suite asserts that short-circuit middleware actually fires before token
|
|
@@ -572,7 +601,7 @@ Options: `{session_options, create_route_specs, app_options?, db_factories?}`.
|
|
|
572
601
|
|
|
573
602
|
7 test groups covering admin surface: account listing, role_grant grant
|
|
574
603
|
lifecycle (via `role_grant_offer_create` + `role_grant_revoke` RPC flows —
|
|
575
|
-
**not** REST; see
|
|
604
|
+
**not** REST; see `auth/CLAUDE.md` for `role_grant_offer_action_specs.ts` + `role_grant_offer_actions.ts`), session / token management, audit log reads (RPC),
|
|
576
605
|
admin-to-admin isolation, error coverage, response schema validation.
|
|
577
606
|
|
|
578
607
|
Required options: `{session_options, create_route_specs, roles: RoleSchemaResult, rpc_endpoints: RpcEndpointsSuiteOption, admin_prefix?, app_options?, db_factories?}`.
|
|
@@ -581,8 +610,9 @@ Required options: `{session_options, create_route_specs, roles: RoleSchemaResult
|
|
|
581
610
|
the same `RpcEndpointsSuiteOption` union every DB-backed suite accepts
|
|
582
611
|
(`integration`, `admin_integration`, `audit_completeness`, `rate_limiting`,
|
|
583
612
|
`rpc_round_trip`, `sse_round_trip`). Prefer the factory form: it forwards
|
|
584
|
-
raw to `
|
|
585
|
-
with the real ctx — the only way
|
|
613
|
+
raw to the top-level `rpc_endpoints` slot on `CreateTestAppOptions` so
|
|
614
|
+
`create_app_server` resolves it per-test with the real ctx — the only way
|
|
615
|
+
action handlers can close over
|
|
586
616
|
`ctx.deps` / `ctx.app_settings` (e.g. `create_standard_rpc_actions(ctx.deps,
|
|
587
617
|
{app_settings: ctx.app_settings})`). Factory must return the same endpoint
|
|
588
618
|
`path` regardless of ctx — `resolve_rpc_endpoints_for_setup` invokes it
|
|
@@ -688,7 +718,7 @@ Registry lookups:
|
|
|
688
718
|
- unauthenticated → `unauthenticated` (code -32001)
|
|
689
719
|
- wrong role → `forbidden` (-32002)
|
|
690
720
|
- authenticated without role → `forbidden`
|
|
691
|
-
- **keeper rejects non-daemon credentials** — session and api_token credentials are rejected even when the account has the keeper role (only `daemon_token` passes). The credential-type gate fires before the role gate (see
|
|
721
|
+
- **keeper rejects non-daemon credentials** — session and api_token credentials are rejected even when the account has the keeper role (only `daemon_token` passes). The credential-type gate fires before the role gate (see `auth/CLAUDE.md` §`request_context.ts` for `require_credential_types`).
|
|
692
722
|
- correct auth passes (not 401/403)
|
|
693
723
|
- GET unauthenticated for `side_effects: false` reads
|
|
694
724
|
2. **RPC adversarial envelopes** — fixed set exercising dispatcher steps 1–2: non-JSON body, wrong `jsonrpc` version, missing `jsonrpc` / `method` / `id`, batch array, unknown method, GET missing `method`/`id`, GET invalid JSON params, GET non-object params, GET mutation method → `invalid_request`.
|
|
@@ -705,42 +735,32 @@ not folded into `create_standard_rpc_actions` (today `self_service_role_actions`
|
|
|
705
735
|
/ round-trip coverage from `describe_rpc_attack_surface_tests` +
|
|
706
736
|
`describe_rpc_round_trip_tests` unless the consumer ships a
|
|
707
737
|
`<module>.rpc_suites.db.test.ts` mounting the opt-in factory on the RPC
|
|
708
|
-
endpoint and calling both suites. See
|
|
738
|
+
endpoint and calling both suites. See ../../test/CLAUDE.md §Composable
|
|
709
739
|
Test Suites for the obligation note; existing
|
|
710
|
-
|
|
740
|
+
../../test/auth/\*.rpc_suites.db.test.ts files are templates.
|
|
711
741
|
|
|
712
742
|
## Cross-cutting conventions
|
|
713
743
|
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
-
|
|
718
|
-
|
|
719
|
-
`create_pglite_factory`). The suffix opts the file into the `db`
|
|
720
|
-
vitest project (`isolate: false`, `fileParallelism: false`) so the
|
|
721
|
-
PGlite WASM cache is shared across every DB test file.
|
|
744
|
+
Shared conventions (`.db.test.ts` suffix, `isolate: false` semantics,
|
|
745
|
+
`assert` from vitest, `assert_rejects`, `vi.mock` avoidance under
|
|
746
|
+
`isolate: false`) live in Skill(fuz-stack) testing-patterns.
|
|
747
|
+
fuz_app-specific points:
|
|
748
|
+
|
|
722
749
|
- **`await_pending_effects: true`** is set by `create_test_app`.
|
|
723
750
|
Fire-and-forget effects (audit logs, session touches, WS fan-out via
|
|
724
751
|
`emit_after_commit`) resolve before the response returns, so tests
|
|
725
752
|
can assert on side effects inline without manual flushing.
|
|
726
|
-
- **
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
ship one.
|
|
735
|
-
- **DI via small `*Deps` interfaces.** Stub factories here accept the
|
|
736
|
-
same narrow `*Deps` contracts production code uses — never
|
|
737
|
-
`Pick<GodType, ...>`. New helpers that need env/fs/logger access
|
|
738
|
-
should take `EnvDeps` / `FsReadDeps` / `Logger` from
|
|
739
|
-
`runtime/deps.ts` or `@fuzdev/fuz_util/log.js`.
|
|
753
|
+
- **Deep-path imports only.** Import from the canonical module
|
|
754
|
+
(`testing/db.js`, `testing/rpc_helpers.js`, etc.); fuz_app's `dist/` ships no
|
|
755
|
+
barrel.
|
|
756
|
+
- **DI via small `*Deps` interfaces.** Stub factories accept the same
|
|
757
|
+
narrow `*Deps` contracts production code uses — never
|
|
758
|
+
`Pick<GodType, ...>`. New helpers needing env/fs/logger take
|
|
759
|
+
`EnvDeps` / `FsReadDeps` / `Logger` from `runtime/deps.ts` or
|
|
760
|
+
`@fuzdev/fuz_util/log.js`.
|
|
740
761
|
- **Keep the shared echo routes in sync with public surface.** When
|
|
741
762
|
middleware or public API gains a new context variable, header, or
|
|
742
763
|
field, update the echo in `middleware.ts`
|
|
743
764
|
(`create_bearer_auth_test_app`, `create_test_middleware_stack_app`)
|
|
744
|
-
alongside the assertions in `src/test/auth/*.test.ts`.
|
|
745
|
-
|
|
746
|
-
test failure.
|
|
765
|
+
alongside the assertions in `src/test/auth/*.test.ts`. Drift surfaces
|
|
766
|
+
as a missed assertion, not a test failure.
|
|
@@ -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,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAA0B,KAAK,gBAAgB,EAAC,MAAM,wBAAwB,CAAC;AAGtF,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;AAoB1B;;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;
|
|
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,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAA0B,KAAK,gBAAgB,EAAC,MAAM,wBAAwB,CAAC;AAGtF,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;AAoB1B;;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;AAiCD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,yCAAyC,GACrD,SAAS,mCAAmC,KAC1C,IAg2BF,CAAC"}
|
|
@@ -61,10 +61,8 @@ const build_admin_test_app_options = (options, db, roles) => ({
|
|
|
61
61
|
create_route_specs: options.create_route_specs,
|
|
62
62
|
db,
|
|
63
63
|
roles: roles ?? [ROLE_KEEPER, ROLE_ADMIN],
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
rpc_endpoints: options.rpc_endpoints,
|
|
67
|
-
},
|
|
64
|
+
rpc_endpoints: options.rpc_endpoints,
|
|
65
|
+
app_options: options.app_options,
|
|
68
66
|
});
|
|
69
67
|
/**
|
|
70
68
|
* Standard admin integration test suite for fuz_app admin routes.
|
|
@@ -84,7 +82,8 @@ export const describe_standard_admin_integration_tests = (options) => {
|
|
|
84
82
|
// Hard-fail early so consumers see a clear setup error instead of a
|
|
85
83
|
// confusing test failure when `rpc_endpoints` is missing. Factory-form
|
|
86
84
|
// callers are resolved with a stub ctx purely to extract the endpoint
|
|
87
|
-
// path; real handlers run per-test via `
|
|
85
|
+
// path; real handlers run per-test via the top-level `rpc_endpoints`
|
|
86
|
+
// slot on `CreateTestAppOptions`.
|
|
88
87
|
const rpc_endpoints_for_setup = resolve_rpc_endpoints_for_setup(options.rpc_endpoints, options.session_options);
|
|
89
88
|
const rpc_path = require_rpc_endpoint_path(rpc_endpoints_for_setup);
|
|
90
89
|
const init_schema = async (db) => {
|