@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.
Files changed (136) hide show
  1. package/dist/actions/CLAUDE.md +139 -24
  2. package/dist/actions/action_rpc.d.ts +10 -0
  3. package/dist/actions/action_rpc.d.ts.map +1 -1
  4. package/dist/actions/action_rpc.js +1 -1
  5. package/dist/actions/action_spec.d.ts +1 -1
  6. package/dist/actions/action_spec.js +1 -1
  7. package/dist/actions/connection_closer.d.ts +68 -0
  8. package/dist/actions/connection_closer.d.ts.map +1 -0
  9. package/dist/actions/connection_closer.js +41 -0
  10. package/dist/actions/perform_action.d.ts.map +1 -1
  11. package/dist/actions/perform_action.js +1 -0
  12. package/dist/actions/register_action_ws.d.ts.map +1 -1
  13. package/dist/actions/register_action_ws.js +23 -2
  14. package/dist/actions/register_ws_endpoint.d.ts +11 -9
  15. package/dist/actions/register_ws_endpoint.d.ts.map +1 -1
  16. package/dist/actions/register_ws_endpoint.js +5 -5
  17. package/dist/actions/transports_ws_auth_guard.d.ts +24 -8
  18. package/dist/actions/transports_ws_auth_guard.d.ts.map +1 -1
  19. package/dist/actions/transports_ws_auth_guard.js +23 -7
  20. package/dist/actions/ws_endpoint_spec.d.ts +119 -0
  21. package/dist/actions/ws_endpoint_spec.d.ts.map +1 -0
  22. package/dist/actions/ws_endpoint_spec.js +13 -0
  23. package/dist/auth/CLAUDE.md +124 -39
  24. package/dist/auth/account_action_specs.d.ts +7 -1
  25. package/dist/auth/account_action_specs.d.ts.map +1 -1
  26. package/dist/auth/account_action_specs.js +11 -4
  27. package/dist/auth/account_actions.d.ts +13 -0
  28. package/dist/auth/account_actions.d.ts.map +1 -1
  29. package/dist/auth/account_actions.js +40 -5
  30. package/dist/auth/account_routes.d.ts +12 -2
  31. package/dist/auth/account_routes.d.ts.map +1 -1
  32. package/dist/auth/account_routes.js +63 -12
  33. package/dist/auth/account_schema.d.ts +5 -5
  34. package/dist/auth/account_schema.js +2 -2
  35. package/dist/auth/actor_lookup_actions.d.ts +1 -1
  36. package/dist/auth/actor_lookup_actions.js +1 -1
  37. package/dist/auth/actor_lookup_queries.d.ts +1 -1
  38. package/dist/auth/actor_lookup_queries.js +1 -1
  39. package/dist/auth/actor_search_action_specs.d.ts +1 -1
  40. package/dist/auth/actor_search_action_specs.js +1 -1
  41. package/dist/auth/actor_search_actions.d.ts +1 -1
  42. package/dist/auth/actor_search_actions.js +1 -1
  43. package/dist/auth/actor_search_queries.d.ts +1 -1
  44. package/dist/auth/actor_search_queries.js +1 -1
  45. package/dist/auth/admin_action_specs.d.ts +8 -8
  46. package/dist/auth/admin_actions.d.ts +11 -0
  47. package/dist/auth/admin_actions.d.ts.map +1 -1
  48. package/dist/auth/admin_actions.js +25 -0
  49. package/dist/auth/all_action_spec_registries.d.ts +2 -2
  50. package/dist/auth/all_action_spec_registries.js +2 -2
  51. package/dist/auth/audit_emitter.d.ts +56 -12
  52. package/dist/auth/audit_emitter.d.ts.map +1 -1
  53. package/dist/auth/audit_emitter.js +38 -12
  54. package/dist/auth/audit_log_routes.d.ts +1 -1
  55. package/dist/auth/audit_log_routes.js +1 -1
  56. package/dist/auth/audit_log_schema.d.ts +30 -3
  57. package/dist/auth/audit_log_schema.d.ts.map +1 -1
  58. package/dist/auth/audit_log_schema.js +21 -3
  59. package/dist/auth/bootstrap_routes.d.ts +1 -1
  60. package/dist/auth/invite_schema.d.ts +2 -2
  61. package/dist/auth/request_context.d.ts +1 -1
  62. package/dist/auth/signup_routes.d.ts +1 -1
  63. package/dist/auth/standard_rpc_actions.d.ts +1 -0
  64. package/dist/auth/standard_rpc_actions.d.ts.map +1 -1
  65. package/dist/auth/standard_rpc_actions.js +1 -0
  66. package/dist/env/update_env_variable.js +1 -1
  67. package/dist/http/CLAUDE.md +42 -26
  68. package/dist/http/ip_canonical.d.ts +99 -0
  69. package/dist/http/ip_canonical.d.ts.map +1 -0
  70. package/dist/http/ip_canonical.js +191 -0
  71. package/dist/http/origin.d.ts +13 -5
  72. package/dist/http/origin.d.ts.map +1 -1
  73. package/dist/http/origin.js +13 -31
  74. package/dist/http/pending_effects.d.ts +1 -1
  75. package/dist/http/pending_effects.js +1 -1
  76. package/dist/http/proxy.d.ts +13 -5
  77. package/dist/http/proxy.d.ts.map +1 -1
  78. package/dist/http/proxy.js +15 -23
  79. package/dist/http/surface.d.ts +50 -0
  80. package/dist/http/surface.d.ts.map +1 -1
  81. package/dist/http/surface.js +27 -1
  82. package/dist/primitive_schemas.d.ts +20 -4
  83. package/dist/primitive_schemas.d.ts.map +1 -1
  84. package/dist/primitive_schemas.js +25 -4
  85. package/dist/realtime/sse_auth_guard.d.ts +16 -4
  86. package/dist/realtime/sse_auth_guard.d.ts.map +1 -1
  87. package/dist/realtime/sse_auth_guard.js +15 -3
  88. package/dist/server/app_backend.d.ts +66 -19
  89. package/dist/server/app_backend.d.ts.map +1 -1
  90. package/dist/server/app_backend.js +57 -34
  91. package/dist/server/app_server.d.ts +60 -0
  92. package/dist/server/app_server.d.ts.map +1 -1
  93. package/dist/server/app_server.js +95 -2
  94. package/dist/server/startup.d.ts.map +1 -1
  95. package/dist/server/startup.js +12 -0
  96. package/dist/testing/CLAUDE.md +91 -71
  97. package/dist/testing/admin_integration.d.ts.map +1 -1
  98. package/dist/testing/admin_integration.js +4 -5
  99. package/dist/testing/adversarial_headers.d.ts +6 -0
  100. package/dist/testing/adversarial_headers.d.ts.map +1 -1
  101. package/dist/testing/adversarial_headers.js +13 -5
  102. package/dist/testing/app_server.d.ts +33 -32
  103. package/dist/testing/app_server.d.ts.map +1 -1
  104. package/dist/testing/app_server.js +4 -13
  105. package/dist/testing/attack_surface.d.ts +8 -7
  106. package/dist/testing/attack_surface.d.ts.map +1 -1
  107. package/dist/testing/attack_surface.js +12 -8
  108. package/dist/testing/audit_completeness.d.ts.map +1 -1
  109. package/dist/testing/audit_completeness.js +20 -6
  110. package/dist/testing/audit_drift_guard.d.ts +116 -0
  111. package/dist/testing/audit_drift_guard.d.ts.map +1 -0
  112. package/dist/testing/audit_drift_guard.js +134 -0
  113. package/dist/testing/connection_closer_helpers.d.ts +44 -0
  114. package/dist/testing/connection_closer_helpers.d.ts.map +1 -0
  115. package/dist/testing/connection_closer_helpers.js +48 -0
  116. package/dist/testing/integration.d.ts.map +1 -1
  117. package/dist/testing/integration.js +7 -9
  118. package/dist/testing/rate_limiting.js +4 -4
  119. package/dist/testing/rpc_helpers.d.ts +2 -1
  120. package/dist/testing/rpc_helpers.d.ts.map +1 -1
  121. package/dist/testing/rpc_round_trip.d.ts.map +1 -1
  122. package/dist/testing/rpc_round_trip.js +6 -8
  123. package/dist/testing/sse_round_trip.d.ts.map +1 -1
  124. package/dist/testing/sse_round_trip.js +12 -6
  125. package/dist/testing/stubs.d.ts +11 -0
  126. package/dist/testing/stubs.d.ts.map +1 -1
  127. package/dist/testing/stubs.js +4 -0
  128. package/dist/testing/surface_invariants.d.ts +66 -1
  129. package/dist/testing/surface_invariants.d.ts.map +1 -1
  130. package/dist/testing/surface_invariants.js +103 -1
  131. package/dist/ui/CLAUDE.md +13 -18
  132. package/dist/ui/SurfaceExplorer.svelte +161 -2
  133. package/dist/ui/SurfaceExplorer.svelte.d.ts.map +1 -1
  134. package/dist/ui/keyed_async_slot.svelte.d.ts +1 -1
  135. package/dist/ui/keyed_async_slot.svelte.js +1 -1
  136. package/package.json +1 -1
@@ -1,12 +1,26 @@
1
1
  /**
2
2
  * WebSocket auth guard — bridges audit events to `BackendWebsocketTransport`.
3
3
  *
4
- * Mirror of `realtime/sse_auth_guard.ts` for the backend WebSocket transport.
5
- * Dispatches audit events to the right `close_sockets_for_*` method so
6
- * consumers do not re-implement the switch themselves.
4
+ * **Why this exists.** `register_action_ws` captures `account_id` and
5
+ * `credential_type` at upgrade time and reuses them for every message.
6
+ * `perform_action`'s per-message authorization phase reloads role_grants
7
+ * from the DB, but session and token VALIDITY are not re-queried — that
8
+ * trade-off keeps chatty WS connections fast. The cost: nothing in the
9
+ * dispatch path notices when a session is revoked or a token is rotated.
10
+ * This guard is the enforcement mechanism — it listens on the audit
11
+ * chain and closes affected sockets when revocation events fire, so
12
+ * revocation actually takes effect on existing connections. Without it,
13
+ * `session_revoke` / `token_revoke` are no-ops for open WS connections.
7
14
  *
8
- * Consumers wire it as `on_audit_event` on their `AppBackend` (or compose
9
- * it with other callbacks via `create_app_server`'s `audit_log_sse` path).
15
+ * Mirror of `realtime/sse_auth_guard.ts` for the backend WebSocket
16
+ * transport. Dispatches audit events to the right `close_sockets_for_*`
17
+ * method so consumers do not re-implement the switch themselves.
18
+ *
19
+ * For standard WS endpoints mounted via `AppServerOptions.ws_endpoints`,
20
+ * `create_app_server` composes the guard automatically per
21
+ * `WsEndpointSpec.auth_guard`. For custom wiring, append the handler
22
+ * inside the consumer's `audit_factory` body (or via
23
+ * `audit.on_event_chain.push(...)` post-assembly).
10
24
  *
11
25
  * @module
12
26
  */
@@ -14,7 +28,7 @@ import type { Logger } from '@fuzdev/fuz_util/log.js';
14
28
  import type { AuditLogEvent } from '../auth/audit_log_schema.js';
15
29
  import type { BackendWebsocketTransport } from './transports_ws_backend.js';
16
30
  /**
17
- * Audit-event callback shape — the function `CreateAppBackendOptions.on_audit_event`
31
+ * Audit-event callback shape — the function `CreateAuditEmitterOptions.on_audit_event`
18
32
  * accepts and that the helpers in this module return.
19
33
  *
20
34
  * Exported so consumers composing multiple handlers (typically
@@ -46,8 +60,10 @@ export declare const ws_disconnect_event_types: ReadonlySet<string>;
46
60
  * user close another user's socket by guessing a session hash or token id.
47
61
  *
48
62
  * @param log - logger for disconnect events (info level on non-zero closures)
49
- * @returns an `on_audit_event` callback suitable for `CreateAppBackendOptions`.
50
- * The returned callback mutates `transport` (closing matching sockets via
63
+ * @returns an `on_audit_event` callback suitable for `create_audit_emitter`'s
64
+ * `on_audit_event` slot, or for appending onto
65
+ * `audit.on_event_chain` post-assembly. The returned callback mutates
66
+ * `transport` (closing matching sockets via
51
67
  * `close_sockets_for_session` / `_token` / `_account`) on every relevant event.
52
68
  */
53
69
  export declare const create_ws_auth_guard: (transport: BackendWebsocketTransport, log: Logger) => AuditEventHandler;
@@ -1 +1 @@
1
- {"version":3,"file":"transports_ws_auth_guard.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/transports_ws_auth_guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAEpD,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,6BAA6B,CAAC;AAC/D,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,4BAA4B,CAAC;AAE1E;;;;;;;;GAQG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;AAE/D;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,yBAAyB,EAAE,WAAW,CAAC,MAAM,CAMxD,CAAC;AAEH;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,oBAAoB,GAChC,WAAW,yBAAyB,EACpC,KAAK,MAAM,KACT,iBA6CF,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,eAAO,MAAM,uBAAuB,GACnC,WAAW,yBAAyB,EACpC,KAAK,MAAM,KACT,iBAaF,CAAC"}
1
+ {"version":3,"file":"transports_ws_auth_guard.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/transports_ws_auth_guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAEpD,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,6BAA6B,CAAC;AAC/D,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,4BAA4B,CAAC;AAE1E;;;;;;;;GAQG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;AAE/D;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,yBAAyB,EAAE,WAAW,CAAC,MAAM,CAMxD,CAAC;AAEH;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,oBAAoB,GAChC,WAAW,yBAAyB,EACpC,KAAK,MAAM,KACT,iBA6CF,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,eAAO,MAAM,uBAAuB,GACnC,WAAW,yBAAyB,EACpC,KAAK,MAAM,KACT,iBAaF,CAAC"}
@@ -1,12 +1,26 @@
1
1
  /**
2
2
  * WebSocket auth guard — bridges audit events to `BackendWebsocketTransport`.
3
3
  *
4
- * Mirror of `realtime/sse_auth_guard.ts` for the backend WebSocket transport.
5
- * Dispatches audit events to the right `close_sockets_for_*` method so
6
- * consumers do not re-implement the switch themselves.
4
+ * **Why this exists.** `register_action_ws` captures `account_id` and
5
+ * `credential_type` at upgrade time and reuses them for every message.
6
+ * `perform_action`'s per-message authorization phase reloads role_grants
7
+ * from the DB, but session and token VALIDITY are not re-queried — that
8
+ * trade-off keeps chatty WS connections fast. The cost: nothing in the
9
+ * dispatch path notices when a session is revoked or a token is rotated.
10
+ * This guard is the enforcement mechanism — it listens on the audit
11
+ * chain and closes affected sockets when revocation events fire, so
12
+ * revocation actually takes effect on existing connections. Without it,
13
+ * `session_revoke` / `token_revoke` are no-ops for open WS connections.
7
14
  *
8
- * Consumers wire it as `on_audit_event` on their `AppBackend` (or compose
9
- * it with other callbacks via `create_app_server`'s `audit_log_sse` path).
15
+ * Mirror of `realtime/sse_auth_guard.ts` for the backend WebSocket
16
+ * transport. Dispatches audit events to the right `close_sockets_for_*`
17
+ * method so consumers do not re-implement the switch themselves.
18
+ *
19
+ * For standard WS endpoints mounted via `AppServerOptions.ws_endpoints`,
20
+ * `create_app_server` composes the guard automatically per
21
+ * `WsEndpointSpec.auth_guard`. For custom wiring, append the handler
22
+ * inside the consumer's `audit_factory` body (or via
23
+ * `audit.on_event_chain.push(...)` post-assembly).
10
24
  *
11
25
  * @module
12
26
  */
@@ -39,8 +53,10 @@ export const ws_disconnect_event_types = new Set([
39
53
  * user close another user's socket by guessing a session hash or token id.
40
54
  *
41
55
  * @param log - logger for disconnect events (info level on non-zero closures)
42
- * @returns an `on_audit_event` callback suitable for `CreateAppBackendOptions`.
43
- * The returned callback mutates `transport` (closing matching sockets via
56
+ * @returns an `on_audit_event` callback suitable for `create_audit_emitter`'s
57
+ * `on_audit_event` slot, or for appending onto
58
+ * `audit.on_event_chain` post-assembly. The returned callback mutates
59
+ * `transport` (closing matching sockets via
44
60
  * `close_sockets_for_session` / `_token` / `_account`) on every relevant event.
45
61
  */
46
62
  export const create_ws_auth_guard = (transport, log) => {
@@ -0,0 +1,119 @@
1
+ /**
2
+ * `WsEndpointSpec` — the canonical WebSocket endpoint declaration consumed
3
+ * by `create_app_server`'s `ws_endpoints` option (mirror of `RpcEndpointSpec`
4
+ * for HTTP RPC).
5
+ *
6
+ * Lives in its own module so both `server/app_server.ts` (which mounts
7
+ * endpoints from these specs) and `http/surface.ts` (which threads the
8
+ * resolved spec list into surface generation) can import it without a
9
+ * cycle between the two.
10
+ *
11
+ * @module
12
+ */
13
+ import type { Action } from './action_types.js';
14
+ import type { RoleName } from '../auth/role_schema.js';
15
+ import type { BackendWebsocketTransport } from './transports_ws_backend.js';
16
+ import type { ServerHeartbeatOptions, SocketCloseContext, SocketOpenContext } from './register_action_ws.js';
17
+ import type { AuditEventHandler } from './transports_ws_auth_guard.js';
18
+ /**
19
+ * Declarative description of a WebSocket endpoint to be auto-mounted by
20
+ * `create_app_server`.
21
+ *
22
+ * Single source of truth for mount + surface — the same array drives
23
+ * `register_ws_endpoint`-style upgrade wiring AND the `surface.ws_endpoints`
24
+ * slot emitted into `AppSurface`, so consumers cannot drift their declared
25
+ * actions from what dispatch actually serves.
26
+ */
27
+ export interface WsEndpointSpec {
28
+ /** Hono mount path (e.g. `/api/ws`). */
29
+ path: string;
30
+ /**
31
+ * Origin allowlist regexes — typically parsed via `parse_allowed_origins`.
32
+ * Passed straight to `verify_request_source` on upgrade.
33
+ */
34
+ allowed_origins: ReadonlyArray<RegExp>;
35
+ /**
36
+ * The actions registered on this endpoint. Spread `protocol_actions`
37
+ * from `actions/protocol.ts` first to complete the
38
+ * disconnect-detection + per-request cancel pairing with the frontend
39
+ * client.
40
+ */
41
+ actions: ReadonlyArray<Action>;
42
+ /**
43
+ * Roles permitted to upgrade — any-of disjunction. Omit (or pass `[]`)
44
+ * to skip the upgrade-time role gate; per-action `auth` on each spec
45
+ * still applies at dispatch time via `perform_action`. Pass
46
+ * `[ROLE_ADMIN]` for a zap-style admin-only WS endpoint.
47
+ */
48
+ required_roles?: ReadonlyArray<RoleName>;
49
+ /**
50
+ * Existing transport to register connections with. Auto-created when
51
+ * omitted. Either way the mounted transport is reachable on
52
+ * `AppServer.ws_endpoints[path]` for broadcast / fan-out.
53
+ */
54
+ transport?: BackendWebsocketTransport;
55
+ /**
56
+ * Server-side heartbeat policy. Default-on (60s receive-silence
57
+ * timeout). Set `false` only when an upstream stack (TCP keepalive,
58
+ * Cloudflare idle timeout) already owns disconnect detection.
59
+ */
60
+ heartbeat?: boolean | ServerHeartbeatOptions;
61
+ /** Optional per-message delay for testing loading states. */
62
+ artificial_delay?: number;
63
+ /**
64
+ * Called once per socket after `transport.add_connection` but before
65
+ * the first message dispatches. See
66
+ * `RegisterActionWsOptions.on_socket_open`.
67
+ */
68
+ on_socket_open?: (ctx: SocketOpenContext) => void | Promise<void>;
69
+ /**
70
+ * Called once per socket on close, before `transport.remove_connection`.
71
+ * See `RegisterActionWsOptions.on_socket_close`.
72
+ */
73
+ on_socket_close?: (ctx: SocketCloseContext) => void | Promise<void>;
74
+ /**
75
+ * Default `true` — auto-composes `create_ws_auth_guard` +
76
+ * `create_ws_logout_closer` against this endpoint's transport and
77
+ * appends them to `deps.audit.on_event_chain`. Wiring is deduped by
78
+ * transport **reference identity** (`WeakSet<BackendWebsocketTransport>`),
79
+ * so two `WsEndpointSpec`s sharing the exact same instance get a
80
+ * single pair of listeners.
81
+ *
82
+ * **Shared-transport OR-semantics.** When multiple `WsEndpointSpec`s
83
+ * share one transport, the guard is wired iff **any** of those specs
84
+ * has `auth_guard !== false`. To opt out for a shared transport,
85
+ * every sibling spec must pass `auth_guard: false`. The default is
86
+ * "fail safe" — easier to enable than disable, and predictable
87
+ * regardless of spec order.
88
+ *
89
+ * Reference-identity dedupe means **wrapped or proxied transports
90
+ * dedupe as separate entries** — a consumer threading every
91
+ * transport through a tracing / DI / metrics shim will get a fresh
92
+ * pair of listeners per shimmed reference, even when the underlying
93
+ * transport is the same. If you wrap or proxy, set `auth_guard:
94
+ * false` on the duplicate `WsEndpointSpec`s and compose
95
+ * `create_ws_auth_guard` / `create_ws_logout_closer` against the
96
+ * underlying transport once.
97
+ *
98
+ * Set `false` when a consumer needs to compose their own callback
99
+ * from scratch — or to opt out of the auto-wiring entirely.
100
+ *
101
+ * NOTE: does NOT close sockets on `role_grant_revoke` — that omission
102
+ * is deliberate (per-connection role tracking is out of scope). A user
103
+ * whose admin role is revoked keeps their socket open; the next message
104
+ * gets `forbidden` from the per-message authorization phase. Consumers
105
+ * wanting role-revoke disconnection use `extra_audit_handlers`.
106
+ */
107
+ auth_guard?: boolean;
108
+ /**
109
+ * Extra audit-event handlers appended to `deps.audit.on_event_chain`
110
+ * AFTER the standard `auth_guard` wiring (when enabled). By the time
111
+ * these run, the standard guards may have already closed sockets. Use
112
+ * for role-revoke disconnection, custom analytics, etc.
113
+ *
114
+ * Never deduped — consumer-owned; pass the same handler twice and it
115
+ * fires twice.
116
+ */
117
+ extra_audit_handlers?: ReadonlyArray<AuditEventHandler>;
118
+ }
119
+ //# sourceMappingURL=ws_endpoint_spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ws_endpoint_spec.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/actions/ws_endpoint_spec.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,mBAAmB,CAAC;AAC9C,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,wBAAwB,CAAC;AACrD,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,4BAA4B,CAAC;AAC1E,OAAO,KAAK,EACX,sBAAsB,EACtB,kBAAkB,EAClB,iBAAiB,EACjB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,+BAA+B,CAAC;AAErE;;;;;;;;GAQG;AACH,MAAM,WAAW,cAAc;IAC9B,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,eAAe,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACvC;;;;;OAKG;IACH,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC/B;;;;;OAKG;IACH,cAAc,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;IACzC;;;;OAIG;IACH,SAAS,CAAC,EAAE,yBAAyB,CAAC;IACtC;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,GAAG,sBAAsB,CAAC;IAC7C,6DAA6D;IAC7D,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,iBAAiB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClE;;;OAGG;IACH,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,kBAAkB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAgCG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;;;;OAQG;IACH,oBAAoB,CAAC,EAAE,aAAa,CAAC,iBAAiB,CAAC,CAAC;CACxD"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * `WsEndpointSpec` — the canonical WebSocket endpoint declaration consumed
3
+ * by `create_app_server`'s `ws_endpoints` option (mirror of `RpcEndpointSpec`
4
+ * for HTTP RPC).
5
+ *
6
+ * Lives in its own module so both `server/app_server.ts` (which mounts
7
+ * endpoints from these specs) and `http/surface.ts` (which threads the
8
+ * resolved spec list into surface generation) can import it without a
9
+ * cycle between the two.
10
+ *
11
+ * @module
12
+ */
13
+ export {};
@@ -2,16 +2,18 @@
2
2
 
3
3
  > Auth domain: identity, crypto primitives, schema + DDL, queries, middleware, routes, RPC actions, cleanup.
4
4
 
5
- Grouped below by theme. For design rationale and threat
6
- model, see `../../../docs/identity.md` and `../../../docs/security.md`. For the
5
+ Grouped below by theme. For design rationale and threat model, see
6
+ ../../../docs/identity.md and ../../../docs/security.md. For the
7
7
  subsystem's place in server assembly and middleware ordering, see
8
- `../../../docs/architecture.md` and the root `../../../CLAUDE.md`.
8
+ ../../../docs/architecture.md and the root ../../../CLAUDE.md. For
9
+ the workspace-wide DI vocabulary (capabilities / options / runtime
10
+ state), see Skill(fuz-stack) dependency-injection.
9
11
 
10
- The DI vocabulary is the stack standard: stateless capabilities in
11
- `AppDeps` / `RouteFactoryDeps`; static config in `*Options`; runtime state
12
- (e.g. `DaemonTokenState`, mutable `AppSettings` ref, `BootstrapStatus`) is
13
- inline, never in `deps`. All `query_*` functions take `deps: QueryDeps = {db}`
14
- as their first arg.
12
+ Auth-specific instances: stateless capabilities in `AppDeps` /
13
+ `RouteFactoryDeps`; static config in `*Options`; runtime state
14
+ (`DaemonTokenState`, mutable `AppSettings` ref, `BootstrapStatus`) is
15
+ inline, never in `deps`. All `query_*` functions take
16
+ `deps: QueryDeps = {db}` as their first arg.
15
17
 
16
18
  ## Crypto primitives
17
19
 
@@ -373,10 +375,11 @@ Zod enum; `AuditOutcome` is `'success' | 'failure'`.
373
375
  - **Consumer extensibility**: `create_audit_log_config({extra_events})`
374
376
  builds an `AuditLogConfig` merging builtins with consumer event-type
375
377
  strings keyed to a Zod schema (validates metadata) or `null` (registers
376
- without validation). Pass the result to `create_app_backend({audit_log_config})`
377
- it gets captured inside the bound `AppDeps.audit` emitter, and every
378
- call to `audit.emit` validates against it (defaults to
379
- `builtin_audit_log_config` when absent). `query_audit_log` still accepts
378
+ without validation). Pass the result into the consumer's `audit_factory`
379
+ body typically `({db, log}) => create_audit_emitter({db, log,
380
+ audit_log_config, on_audit_event})` so it gets captured inside the
381
+ bound `AppDeps.audit` emitter; every call to `audit.emit` validates
382
+ against it (defaults to `builtin_audit_log_config` when absent). `query_audit_log` still accepts
380
383
  the trailing `config` positional arg for in-transaction emit sites that
381
384
  hold a transaction-scoped DB only. Builtin collisions and
382
385
  `AuditEventTypeName` format failures throw at construction. The DB
@@ -754,7 +757,9 @@ run'` if the seed somehow missed (defensive — migrations always seed).
754
757
  - `query_audit_log_list_role_grant_history` (filters to `role_grant_create` / `role_grant_revoke`).
755
758
  - `query_audit_log_cleanup_before`.
756
759
  - **Audit fan-out runs through `AppDeps.audit`** (the bound emitter built
757
- by `create_audit_emitter` at backend assembly — see §`audit_emitter.ts`).
760
+ by the consumer's `audit_factory` callback on `CreateAppBackendOptions`,
761
+ typically a one-liner over `create_audit_emitter` — see
762
+ §`audit_emitter.ts`).
758
763
  `audit.emit(ctx, input)` writes via the captured pool, so audit entries
759
764
  persist even when the request transaction rolls back. The emitter
760
765
  closes over `on_audit_event` + `audit_log_config` so handlers can never
@@ -765,7 +770,11 @@ run'` if the seed somehow missed (defensive — migrations always seed).
765
770
  ### `audit_emitter.ts`
766
771
 
767
772
  `AuditEmitter` is the bound capability that lives on `AppDeps.audit`,
768
- built once at `create_app_backend` time.
773
+ built once by the consumer's `audit_factory` callback on
774
+ `CreateAppBackendOptions`. `create_app_backend` invokes the callback
775
+ with its constructed `{db, log}` after migrations run; the canonical
776
+ body is `({db, log}) => create_audit_emitter({db, log, on_audit_event,
777
+ audit_log_config})`.
769
778
 
770
779
  Four methods:
771
780
 
@@ -789,7 +798,7 @@ Per-call `ctx` shape:
789
798
  - `emit` requires `{pending_effects: Array<Promise<void>>}` — the eager
790
799
  queue only. Both `RouteContext` and `ActionContext` satisfy this
791
800
  structurally; `audit.emit` pushes its in-flight pool-write promise
792
- onto the eager queue. See `../http/CLAUDE.md` §Pending Effects for
801
+ onto the eager queue. See `http/CLAUDE.md` §Pending Effects for
793
802
  the eager / deferred split.
794
803
  - `emit_role_grant_target` adds `client_ip: string` (also on `ActionContext`;
795
804
  REST handlers pass `{pending_effects, client_ip: get_client_ip(c)}`).
@@ -919,7 +928,7 @@ consciously violate the contract.
919
928
 
920
929
  ## Middleware
921
930
 
922
- See the root `../../../CLAUDE.md` §Middleware Ordering for the canonical
931
+ See the root ../../../CLAUDE.md §Middleware Ordering for the canonical
923
932
  assembly order. Two-phase identity:
924
933
 
925
934
  - **Authentication** runs in middleware (session / bearer / daemon
@@ -974,7 +983,7 @@ assembly order. Two-phase identity:
974
983
  actor row was deleted between credential validation and the
975
984
  follow-up read). The named per-error shape `AuthorizationFailureBody`
976
985
  is still exported for callers that want to bind the failure body
977
- by type. See the root `../../../CLAUDE.md` § Cleanest architecture
986
+ by type. See the root ../../../CLAUDE.md §Cleanest architecture
978
987
  takes priority for the rationale.
979
988
 
980
989
  Session parsing is separate from auth enforcement — login / bootstrap
@@ -1141,6 +1150,8 @@ Session-based auth route specs. Factory: `create_account_route_specs(deps, optio
1141
1150
  - `POST /logout` — revokes session by hash, clears cookie.
1142
1151
  - **`POST /password`** — `current_password: PasswordProvided` +
1143
1152
  `new_password: Password`. Per-IP + per-account rate limited.
1153
+ Declares `credential_types: ['session']` (see
1154
+ `docs/security.md` §Credential-channel gating).
1144
1155
  **Revokes all sessions + all API tokens** (force re-auth everywhere);
1145
1156
  clears cookie.
1146
1157
  - **`GET /verify`** — empty-body session-validity probe for nginx
@@ -1212,7 +1223,7 @@ gets `require_auth` when `account === 'required'` or `actor === 'required'`;
1212
1223
  `post_authorization` gets `require_credential_types(types)` when
1213
1224
  `credential_types?.length` and `require_role(roles)` when `roles?.length`.
1214
1225
  Injected into `apply_route_specs` so the generic HTTP framework stays
1215
- auth-agnostic (see `../http/CLAUDE.md` §Validation pipeline for where it plugs in).
1226
+ auth-agnostic (see `http/CLAUDE.md` §Validation pipeline for where it plugs in).
1216
1227
 
1217
1228
  ### `audit_log_routes.ts`
1218
1229
 
@@ -1232,7 +1243,7 @@ module produces is now just the optional SSE stream:
1232
1243
  ## RPC actions (SAES)
1233
1244
 
1234
1245
  Three action surfaces that mount on a consumer's JSON-RPC endpoint via
1235
- `create_rpc_endpoint` (see `../actions/CLAUDE.md` §Single JSON-RPC 2.0 endpoint).
1246
+ `create_rpc_endpoint` (see `actions/CLAUDE.md` §Single JSON-RPC 2.0 endpoint).
1236
1247
  Each surface is split across two files:
1237
1248
 
1238
1249
  - `*_action_specs.ts` — Input/Output Zod schemas (paired with `z.infer` type
@@ -1327,6 +1338,19 @@ Closure state:
1327
1338
  When absent, those two specs are still present in `all_admin_action_specs`
1328
1339
  (surface-wise) but the handlers are not wired — RPC dispatch returns
1329
1340
  `method_not_found`.
1341
+ - `options.connection_closer?: ConnectionCloser | null` — when set,
1342
+ `admin_session_revoke_all` and `admin_token_revoke_all` handlers
1343
+ eagerly close the target account's live WS sockets via
1344
+ `close_sockets_for_account(input.account_id)` BEFORE emitting the
1345
+ audit event. Failure outcomes (404 account-not-found) skip the
1346
+ eager close. Listener-based close
1347
+ (`transports_ws_auth_guard` on `audit.on_event_chain`) stays as a
1348
+ fail-safe; primitives are idempotent. Symmetric with the
1349
+ self-service surface (see `AccountActionOptions.connection_closer`
1350
+ below). `BackendWebsocketTransport` satisfies the interface
1351
+ structurally. Mirrors `zzz_server`'s parity pass — fuz_app widens
1352
+ to admin-side too (Rust port's catch-up tracked in
1353
+ `~/dev/zzz/TODO_RUST_SERVER_DETAILS.md`).
1330
1354
 
1331
1355
  `all_admin_action_specs: Array<RequestResponseActionSpec>` — codegen-ready
1332
1356
  registry of all eleven specs (always includes the two app-settings specs).
@@ -1413,16 +1437,16 @@ Error reason constants (exported as `as const` literals):
1413
1437
  - `ERROR_ROLE_GRANT_OFFER_ACTOR_MISMATCH` (`'role_grant_offer_actor_mismatch'` —
1414
1438
  actor-targeted offer was accepted by an actor other than `to_actor_id`)
1415
1439
 
1416
- Plus re-uses from `../http/error_schemas.ts`: `ERROR_ROLE_GRANT_NOT_FOUND`,
1440
+ Plus re-uses from `http/error_schemas.ts`: `ERROR_ROLE_GRANT_NOT_FOUND`,
1417
1441
  `ERROR_ROLE_NOT_WEB_GRANTABLE`, `ERROR_INSUFFICIENT_PERMISSIONS`,
1418
1442
  `ERROR_ACCOUNT_NOT_FOUND`.
1419
1443
 
1420
1444
  Each spec declares the reason codes its handler may surface (see
1421
- `../actions/CLAUDE.md` §Action specs for the field semantics). Only
1445
+ `actions/CLAUDE.md` §Action specs for the field semantics). Only
1422
1446
  domain reasons returned via `error.data.reason` are listed; standard
1423
1447
  transport errors (validation, auth, rate-limit) stay implicit. Drift
1424
1448
  between declared reasons and handler throws is caught by
1425
- `../../test/auth/role_grant_offer_actions.error_reasons.test.ts`.
1449
+ ../../test/auth/role_grant_offer_actions.error_reasons.test.ts.
1426
1450
 
1427
1451
  Failure-outcome audit events emitted (success and failure rows both carry
1428
1452
  `ip: ctx.client_ip` — uniform with the admin and self-service surfaces):
@@ -1442,8 +1466,8 @@ Failure-outcome audit events emitted (success and failure rows both carry
1442
1466
  role_grant).
1443
1467
 
1444
1468
  WS notifications (post-commit via `emit_after_commit` from
1445
- `../http/pending_effects.js` — swallows exceptions so one failed send
1446
- can't starve others; see `../http/CLAUDE.md` §Pending Effects):
1469
+ `http/pending_effects.js` — swallows exceptions so one failed send
1470
+ can't starve others; see `http/CLAUDE.md` §Pending Effects):
1447
1471
 
1448
1472
  - Create → `role_grant_offer_received` to recipient.
1449
1473
  - Retract → `role_grant_offer_retracted` to recipient.
@@ -1490,6 +1514,8 @@ surface drop down to the per-domain factories directly.
1490
1514
  Option routing: `roles` is shared between admin and role-grant-offer;
1491
1515
  `app_settings` flows to admin only; `default_ttl_ms` and `authorize`
1492
1516
  flow to role-grant-offer only; `max_tokens` flows to account only;
1517
+ `connection_closer` is shared between admin and account (handler-side
1518
+ eager WS close on revoke; role-grant-offer ignores);
1493
1519
  `notification_sender` is wired through to role-grant-offer (admin +
1494
1520
  account ignore it).
1495
1521
 
@@ -1506,7 +1532,7 @@ Pair this with `create_app_server`'s `rpc_endpoints` factory form
1506
1532
  (`(ctx) => Array<RpcEndpointSpec>`) so the combined action list gets
1507
1533
  `ctx.deps` + `ctx.app_settings` — `create_app_server` auto-mounts the
1508
1534
  endpoint via `create_rpc_endpoint`, so consumers don't need to mount it
1509
- again in `create_route_specs`. See `../../../docs/usage.md` §Server
1535
+ again in `create_route_specs`. See ../../../docs/usage.md §Server
1510
1536
  Assembly.
1511
1537
 
1512
1538
  Pre-bundle consumers spread `create_admin_actions` and
@@ -1519,20 +1545,43 @@ consumer wiring the admin surface without account actions will hit
1519
1545
  `method not found` on first admin-suite run.
1520
1546
 
1521
1547
  Frontend mirror: `all_standard_action_specs` (in
1522
- `./standard_action_specs.ts`) bundles `all_admin_action_specs +
1548
+ `auth/standard_action_specs.ts`) bundles `all_admin_action_specs +
1523
1549
  all_role_grant_offer_action_specs + all_account_action_specs` into one
1524
1550
  `ReadonlyArray<RequestResponseActionSpec>` for typed-client codegen
1525
1551
  and `create_frontend_rpc_client({specs})` wiring. Self-service role
1526
1552
  specs are not included (opt-in, app-specific `eligible_roles`) —
1527
1553
  spread `all_self_service_role_action_specs` separately when needed.
1528
1554
 
1555
+ To expose the standard surface over WebSocket as well as HTTP RPC,
1556
+ spread `protocol_actions` and `create_standard_rpc_actions(ctx.deps,
1557
+ opts)` into `create_app_server`'s `ws_endpoints` factory alongside the
1558
+ matching `rpc_endpoints` entry:
1559
+
1560
+ ```ts
1561
+ ws_endpoints: (ctx) => [{
1562
+ path: '/api/ws',
1563
+ allowed_origins,
1564
+ actions: [
1565
+ ...protocol_actions,
1566
+ ...create_standard_rpc_actions(ctx.deps, opts),
1567
+ ...consumer_local_actions,
1568
+ ],
1569
+ }],
1570
+ ```
1571
+
1572
+ The same action factory powers both surfaces; per-message authorization
1573
+ and rate limiting fire identically across HTTP RPC and WS. With both
1574
+ endpoints mounted, a typed frontend client can route per-method via
1575
+ `transport_for_method` (e.g. `account_*` over WS for live revocation
1576
+ detection, admin reads over HTTP).
1577
+
1529
1578
  ### `all_action_spec_registries.ts` — walker-only registry-of-registries
1530
1579
 
1531
1580
  `all_fuz_auth_action_spec_registries` — walker/codegen entry for every
1532
1581
  fuz-auth action-spec bundle (`admin`, `role_grant_offer`, `account`,
1533
1582
  `self_service_role`, `actor_lookup`, `actor_search`). Not a mounting
1534
1583
  surface; protocol specs are excluded. Iterated by registry-wide
1535
- invariant tests in `../../test/auth/`.
1584
+ invariant tests in ../../test/auth/.
1536
1585
 
1537
1586
  ### `account_action_specs.ts` + `account_actions.ts` — seven self-service RPC actions
1538
1587
 
@@ -1553,6 +1602,18 @@ operations are account-scoped via `query_session_revoke_for_account` /
1553
1602
  or token id returns `revoked: false` rather than revealing whether the id
1554
1603
  exists.
1555
1604
 
1605
+ **Credential-channel gating** — `account_token_create`,
1606
+ `account_token_revoke`, `account_session_revoke`, and
1607
+ `account_session_revoke_all` declare `credential_types: ['session']`
1608
+ on their `auth` axis (same gate as REST `POST /password`).
1609
+ `account_session_revoke` is gated alongside `_revoke_all` because a
1610
+ leaked bearer can otherwise compose `account_session_list` + N×revoke
1611
+ to reach the same lockout. Admin token/session revoke specs in
1612
+ `admin_action_specs.ts` deliberately stay unrestricted (admin
1613
+ scripting from CLI/bearer is legitimate operator workflow). For the
1614
+ threat model, the trust-bar rationale, and the defense-in-depth audit
1615
+ metadata see `docs/security.md` §Credential-channel gating.
1616
+
1556
1617
  | Spec | Side effects | Rate limit | Input | Output |
1557
1618
  | ---------------------------------------- | ------------ | ----------- | -------------- | ----------------------- |
1558
1619
  | `account_verify_action_spec` | false | | `z.void()` | `SessionAccountJson` |
@@ -1577,11 +1638,31 @@ vector, so rate caps are symmetry-only and skipped.
1577
1638
  Audit events emitted (via `deps.audit.emit` with `ip: ctx.client_ip`):
1578
1639
  `session_revoke`, `session_revoke_all`, `token_create`, `token_revoke`. The
1579
1640
  IP is the resolved trusted-proxy value from `ActionContext.client_ip`,
1580
- matching the REST handler convention.
1641
+ matching the REST handler convention. Every gated event additionally
1642
+ records `credential_type` (read from `ActionContext.credential_type`)
1643
+ in metadata — defense in depth so forensics survive if the
1644
+ `credential_types: ['session']` spec gate is ever loosened or bypassed.
1645
+ The REST `password_change` audit row mirrors the same field on all
1646
+ three outcomes (success, wrong-password, concurrent-change).
1581
1647
 
1582
1648
  Deps: `Pick<RouteFactoryDeps, 'log' | 'audit'>`.
1583
- Options: `{max_tokens?: number | null}` defaults to `DEFAULT_MAX_TOKENS`
1584
- from `account_routes.ts`; `null` disables the cap.
1649
+ Options: `{max_tokens?: number | null, connection_closer?: ConnectionCloser | null}`.
1650
+ `max_tokens` defaults to `DEFAULT_MAX_TOKENS` from `account_routes.ts`;
1651
+ `null` disables the cap. `connection_closer` (from
1652
+ `actions/connection_closer.ts`) wires handler-side eager WS socket
1653
+ closure: `account_session_revoke` calls `close_sockets_for_session(input.session_id)`,
1654
+ `_session_revoke_all` calls `close_sockets_for_account(account.id)`,
1655
+ `account_token_revoke` calls `close_sockets_for_token(input.token_id)` —
1656
+ each fires synchronously BEFORE the audit emit so revocation lands even
1657
+ when the audit INSERT fails. Listener-based close
1658
+ (`transports_ws_auth_guard` on `audit.on_event_chain`) stays as a
1659
+ fail-safe; close primitives are idempotent. Failure outcomes
1660
+ (`revoked: false`) skip the eager close — mirrors the listener's
1661
+ `outcome === 'failure'` guard so attacker-guessable ids can't be used to
1662
+ target arbitrary sockets. `BackendWebsocketTransport` satisfies
1663
+ `ConnectionCloser` structurally — consumers pass the WS transport
1664
+ instance directly. Mirrors `zzz_server::handlers/account.rs` (landed
1665
+ 2026-05-16).
1585
1666
 
1586
1667
  `all_account_action_specs: Array<RequestResponseActionSpec>` — codegen-ready
1587
1668
  registry of all seven specs.
@@ -1698,7 +1779,7 @@ One static `request_response` action — `actor_search({query, scope_ids?, limit
1698
1779
  powers person-target pickers. Sibling to `actor_lookup`: that resolves a
1699
1780
  batch of known ids to labels; this resolves a partial name to candidate
1700
1781
  actors. Reuses `ActorLookupEntryJson` from
1701
- `./actor_lookup_action_specs.ts` so the labels arc on the consumer side
1782
+ `auth/actor_lookup_action_specs.ts` so the labels arc on the consumer side
1702
1783
  stays uniform. Default limit `ACTOR_SEARCH_LIMIT_DEFAULT = 20`, hard cap
1703
1784
  `ACTOR_SEARCH_LIMIT_MAX = 50`. Query string capped at
1704
1785
  `ACTOR_SEARCH_QUERY_LENGTH_MAX = 50`.
@@ -1789,15 +1870,19 @@ resulting role_grant.
1789
1870
  - `db: Db` — pool-level instance (middleware uses this; route handlers
1790
1871
  get a transaction-scoped `Db` via `RouteContext`).
1791
1872
  - `log: Logger`.
1792
- - `audit: AuditEmitter` — bound emitter built once at `create_app_backend`
1793
- via `create_audit_emitter`. Closes over the pool, the
1873
+ - `audit: AuditEmitter` — bound emitter built once by the consumer's
1874
+ `audit_factory` callback on `CreateAppBackendOptions`. The factory
1875
+ runs after `create_db` resolves and migrations apply;
1876
+ `create_app_backend` invokes it with `{db, log}` and lands the
1877
+ returned emitter on `deps.audit`. The canonical body is one line
1878
+ over `create_audit_emitter` (closes over the pool, the
1794
1879
  `on_audit_event` subscriber chain, and the optional
1795
- `AuditLogConfig` so handlers reach `audit.emit(ctx, input)` /
1880
+ `AuditLogConfig`); consumers wrap or replace it for tests. Handlers
1881
+ reach `audit.emit(ctx, input)` /
1796
1882
  `audit.emit_role_grant_target(ctx, auth, input)` and never see the
1797
- pool. Pass `on_audit_event` and `audit_log_config` to
1798
- `create_app_backend` both fold into `audit`'s closure and the slot
1799
- is the single seam for SSE/WS fan-out (additional listeners append
1800
- via `audit.on_event_chain.push(...)` at server assembly).
1883
+ pool. The slot is the single seam for SSE/WS fan-out — additional
1884
+ listeners append via `audit.on_event_chain.push(...)` at server
1885
+ assembly.
1801
1886
  - **`RouteFactoryDeps = Omit<AppDeps, 'db'>`** — for route factories. Route
1802
1887
  handlers receive DB access via `RouteContext`, so factories don't capture
1803
1888
  a pool-level `Db`.
@@ -1805,5 +1890,5 @@ resulting role_grant.
1805
1890
  Action factories take `Pick<RouteFactoryDeps, 'log' | 'audit'>` directly
1806
1891
  (role-grant-offer adds `notification_sender?` inline).
1807
1892
 
1808
- See root `../../../CLAUDE.md` §AppDeps Vocabulary for the
1893
+ See root ../../../CLAUDE.md §AppDeps Vocabulary for the
1809
1894
  capability / options / runtime-state split across the whole project.
@@ -98,7 +98,7 @@ export declare const account_verify_action_spec: {
98
98
  input: z.ZodVoid;
99
99
  output: z.ZodObject<{
100
100
  id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
101
- username: z.ZodString;
101
+ username: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
102
102
  email: z.ZodNullable<z.ZodEmail>;
103
103
  email_verified: z.ZodBoolean;
104
104
  created_at: z.ZodString;
@@ -135,6 +135,7 @@ export declare const account_session_revoke_action_spec: {
135
135
  auth: {
136
136
  account: "required";
137
137
  actor: "none";
138
+ credential_types: string[];
138
139
  };
139
140
  side_effects: true;
140
141
  input: z.ZodObject<{
@@ -154,6 +155,7 @@ export declare const account_session_revoke_all_action_spec: {
154
155
  auth: {
155
156
  account: "required";
156
157
  actor: "none";
158
+ credential_types: string[];
157
159
  };
158
160
  side_effects: true;
159
161
  input: z.ZodVoid;
@@ -165,6 +167,8 @@ export declare const account_session_revoke_all_action_spec: {
165
167
  description: string;
166
168
  };
167
169
  /**
170
+ * `credential_types: ['session']` — see `docs/security.md` §Credential-channel gating.
171
+ *
168
172
  * `rate_limit: 'account'` bounds the burn rate of API-token creates. The
169
173
  * outstanding-token count is already capped by `max_tokens` (via
170
174
  * `query_api_token_enforce_limit`), but the per-account *rate* of churn
@@ -179,6 +183,7 @@ export declare const account_token_create_action_spec: {
179
183
  auth: {
180
184
  account: "required";
181
185
  actor: "none";
186
+ credential_types: string[];
182
187
  };
183
188
  side_effects: true;
184
189
  input: z.ZodPrefault<z.ZodObject<{
@@ -225,6 +230,7 @@ export declare const account_token_revoke_action_spec: {
225
230
  auth: {
226
231
  account: "required";
227
232
  actor: "none";
233
+ credential_types: string[];
228
234
  };
229
235
  side_effects: true;
230
236
  input: z.ZodObject<{
@@ -1 +1 @@
1
- {"version":3,"file":"account_action_specs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/account_action_specs.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"account_action_specs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/account_action_specs.ts"],"names":[],"mappings":"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"}