@fuzdev/fuz_app 0.54.0 → 0.56.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 +214 -103
- package/dist/actions/action_bridge.d.ts +8 -5
- package/dist/actions/action_bridge.d.ts.map +1 -1
- package/dist/actions/action_bridge.js +1 -11
- package/dist/actions/action_codegen.d.ts +32 -0
- package/dist/actions/action_codegen.d.ts.map +1 -1
- package/dist/actions/action_codegen.js +35 -15
- package/dist/actions/action_registry.d.ts.map +1 -1
- package/dist/actions/action_registry.js +5 -2
- package/dist/actions/action_rpc.d.ts +141 -22
- package/dist/actions/action_rpc.d.ts.map +1 -1
- package/dist/actions/action_rpc.js +106 -187
- package/dist/actions/action_spec.d.ts +55 -16
- package/dist/actions/action_spec.d.ts.map +1 -1
- package/dist/actions/action_spec.js +16 -11
- package/dist/actions/action_types.d.ts +28 -60
- package/dist/actions/action_types.d.ts.map +1 -1
- package/dist/actions/action_types.js +13 -5
- package/dist/actions/broadcast_api.d.ts +2 -2
- package/dist/actions/broadcast_api.js +2 -2
- package/dist/actions/compile_action_registry.d.ts +50 -0
- package/dist/actions/compile_action_registry.d.ts.map +1 -0
- package/dist/actions/compile_action_registry.js +69 -0
- package/dist/actions/heartbeat.d.ts +8 -4
- package/dist/actions/heartbeat.d.ts.map +1 -1
- package/dist/actions/heartbeat.js +5 -4
- package/dist/actions/perform_action.d.ts +145 -0
- package/dist/actions/perform_action.d.ts.map +1 -0
- package/dist/actions/perform_action.js +258 -0
- package/dist/actions/register_action_ws.d.ts +46 -40
- package/dist/actions/register_action_ws.d.ts.map +1 -1
- package/dist/actions/register_action_ws.js +101 -159
- package/dist/actions/register_ws_endpoint.d.ts +15 -10
- package/dist/actions/register_ws_endpoint.d.ts.map +1 -1
- package/dist/actions/register_ws_endpoint.js +54 -7
- package/dist/actions/transports.d.ts.map +1 -1
- package/dist/actions/transports.js +0 -4
- package/dist/actions/transports_ws_auth_guard.d.ts +1 -1
- package/dist/actions/transports_ws_auth_guard.js +1 -1
- package/dist/actions/transports_ws_backend.d.ts +1 -1
- package/dist/actions/transports_ws_backend.js +1 -1
- package/dist/auth/CLAUDE.md +794 -410
- package/dist/auth/account_action_specs.d.ts +28 -7
- package/dist/auth/account_action_specs.d.ts.map +1 -1
- package/dist/auth/account_action_specs.js +7 -7
- package/dist/auth/account_actions.d.ts +7 -13
- package/dist/auth/account_actions.d.ts.map +1 -1
- package/dist/auth/account_actions.js +26 -35
- package/dist/auth/account_queries.d.ts +52 -16
- package/dist/auth/account_queries.d.ts.map +1 -1
- package/dist/auth/account_queries.js +87 -38
- package/dist/auth/account_routes.d.ts +9 -11
- package/dist/auth/account_routes.d.ts.map +1 -1
- package/dist/auth/account_routes.js +118 -46
- package/dist/auth/account_schema.d.ts +46 -35
- package/dist/auth/account_schema.d.ts.map +1 -1
- package/dist/auth/account_schema.js +21 -28
- package/dist/auth/admin_action_specs.d.ts +100 -32
- package/dist/auth/admin_action_specs.d.ts.map +1 -1
- package/dist/auth/admin_action_specs.js +64 -33
- package/dist/auth/admin_actions.d.ts +13 -19
- package/dist/auth/admin_actions.d.ts.map +1 -1
- package/dist/auth/admin_actions.js +37 -41
- package/dist/auth/audit_emitter.d.ts +160 -0
- package/dist/auth/audit_emitter.d.ts.map +1 -0
- package/dist/auth/audit_emitter.js +83 -0
- package/dist/auth/audit_log_queries.d.ts +17 -48
- package/dist/auth/audit_log_queries.d.ts.map +1 -1
- package/dist/auth/audit_log_queries.js +20 -56
- package/dist/auth/audit_log_routes.d.ts +1 -1
- package/dist/auth/audit_log_routes.d.ts.map +1 -1
- package/dist/auth/audit_log_routes.js +7 -3
- package/dist/auth/audit_log_schema.d.ts +92 -32
- package/dist/auth/audit_log_schema.d.ts.map +1 -1
- package/dist/auth/audit_log_schema.js +75 -46
- package/dist/auth/auth_guard_resolver.d.ts +44 -0
- package/dist/auth/auth_guard_resolver.d.ts.map +1 -0
- package/dist/auth/auth_guard_resolver.js +56 -0
- package/dist/auth/bearer_auth.d.ts +9 -7
- package/dist/auth/bearer_auth.d.ts.map +1 -1
- package/dist/auth/bearer_auth.js +13 -21
- package/dist/auth/bootstrap_account.d.ts +7 -7
- package/dist/auth/bootstrap_account.d.ts.map +1 -1
- package/dist/auth/bootstrap_account.js +7 -7
- package/dist/auth/bootstrap_routes.d.ts.map +1 -1
- package/dist/auth/bootstrap_routes.js +11 -10
- package/dist/auth/cleanup.d.ts +20 -26
- package/dist/auth/cleanup.d.ts.map +1 -1
- package/dist/auth/cleanup.js +33 -42
- package/dist/auth/credential_type_schema.d.ts +115 -0
- package/dist/auth/credential_type_schema.d.ts.map +1 -0
- package/dist/auth/credential_type_schema.js +127 -0
- package/dist/auth/daemon_token_middleware.d.ts +23 -11
- package/dist/auth/daemon_token_middleware.d.ts.map +1 -1
- package/dist/auth/daemon_token_middleware.js +28 -22
- package/dist/auth/ddl.d.ts +2 -2
- package/dist/auth/ddl.d.ts.map +1 -1
- package/dist/auth/ddl.js +6 -6
- package/dist/auth/deps.d.ts +7 -18
- package/dist/auth/deps.d.ts.map +1 -1
- package/dist/auth/grant_path_schema.d.ts +117 -0
- package/dist/auth/grant_path_schema.d.ts.map +1 -0
- package/dist/auth/grant_path_schema.js +137 -0
- package/dist/auth/invite_queries.d.ts +12 -1
- package/dist/auth/invite_queries.d.ts.map +1 -1
- package/dist/auth/invite_queries.js +12 -1
- package/dist/auth/invite_schema.d.ts +1 -1
- package/dist/auth/invite_schema.d.ts.map +1 -1
- package/dist/auth/invite_schema.js +1 -1
- package/dist/auth/middleware.d.ts.map +1 -1
- package/dist/auth/middleware.js +9 -4
- package/dist/auth/migrations.d.ts +37 -14
- package/dist/auth/migrations.d.ts.map +1 -1
- package/dist/auth/migrations.js +79 -32
- package/dist/auth/request_context.d.ts +331 -61
- package/dist/auth/request_context.d.ts.map +1 -1
- package/dist/auth/request_context.js +378 -95
- package/dist/auth/{permit_offer_action_specs.d.ts → role_grant_offer_action_specs.d.ts} +163 -94
- package/dist/auth/role_grant_offer_action_specs.d.ts.map +1 -0
- package/dist/auth/role_grant_offer_action_specs.js +262 -0
- package/dist/auth/role_grant_offer_actions.d.ts +104 -0
- package/dist/auth/role_grant_offer_actions.d.ts.map +1 -0
- package/dist/auth/role_grant_offer_actions.js +473 -0
- package/dist/auth/{permit_offer_notifications.d.ts → role_grant_offer_notifications.d.ts} +90 -70
- package/dist/auth/role_grant_offer_notifications.d.ts.map +1 -0
- package/dist/auth/role_grant_offer_notifications.js +182 -0
- package/dist/auth/role_grant_offer_queries.d.ts +242 -0
- package/dist/auth/role_grant_offer_queries.d.ts.map +1 -0
- package/dist/auth/role_grant_offer_queries.js +533 -0
- package/dist/auth/role_grant_offer_schema.d.ts +150 -0
- package/dist/auth/role_grant_offer_schema.d.ts.map +1 -0
- package/dist/auth/{permit_offer_schema.js → role_grant_offer_schema.js} +60 -36
- package/dist/auth/role_grant_queries.d.ts +231 -0
- package/dist/auth/role_grant_queries.d.ts.map +1 -0
- package/dist/auth/role_grant_queries.js +320 -0
- package/dist/auth/role_schema.d.ts +150 -40
- package/dist/auth/role_schema.d.ts.map +1 -1
- package/dist/auth/role_schema.js +144 -45
- package/dist/auth/scope_kind_schema.d.ts +96 -0
- package/dist/auth/scope_kind_schema.d.ts.map +1 -0
- package/dist/auth/scope_kind_schema.js +94 -0
- package/dist/auth/self_service_role_action_specs.d.ts +6 -1
- package/dist/auth/self_service_role_action_specs.d.ts.map +1 -1
- package/dist/auth/self_service_role_action_specs.js +3 -1
- package/dist/auth/self_service_role_actions.d.ts +34 -27
- package/dist/auth/self_service_role_actions.d.ts.map +1 -1
- package/dist/auth/self_service_role_actions.js +68 -48
- package/dist/auth/session_cookie.d.ts +43 -6
- package/dist/auth/session_cookie.d.ts.map +1 -1
- package/dist/auth/session_cookie.js +31 -5
- package/dist/auth/session_middleware.d.ts +37 -3
- package/dist/auth/session_middleware.d.ts.map +1 -1
- package/dist/auth/session_middleware.js +33 -7
- package/dist/auth/signup_routes.d.ts.map +1 -1
- package/dist/auth/signup_routes.js +48 -19
- package/dist/auth/standard_action_specs.d.ts +2 -2
- package/dist/auth/standard_action_specs.js +4 -4
- package/dist/auth/standard_rpc_actions.d.ts +23 -19
- package/dist/auth/standard_rpc_actions.d.ts.map +1 -1
- package/dist/auth/standard_rpc_actions.js +12 -12
- package/dist/db/migrate.d.ts +12 -8
- package/dist/db/migrate.d.ts.map +1 -1
- package/dist/db/migrate.js +10 -7
- package/dist/dev/setup.d.ts +2 -2
- package/dist/dev/setup.d.ts.map +1 -1
- package/dist/dev/setup.js +9 -7
- package/dist/env/load.d.ts +1 -1
- package/dist/env/load.js +1 -1
- package/dist/hono_context.d.ts +64 -5
- package/dist/hono_context.d.ts.map +1 -1
- package/dist/hono_context.js +38 -2
- package/dist/http/CLAUDE.md +264 -87
- package/dist/http/auth_shape.d.ts +191 -0
- package/dist/http/auth_shape.d.ts.map +1 -0
- package/dist/http/auth_shape.js +237 -0
- package/dist/http/common_routes.js +3 -3
- package/dist/http/db_routes.d.ts +4 -0
- package/dist/http/db_routes.d.ts.map +1 -1
- package/dist/http/db_routes.js +44 -7
- package/dist/http/error_schemas.d.ts +132 -19
- package/dist/http/error_schemas.d.ts.map +1 -1
- package/dist/http/error_schemas.js +132 -40
- package/dist/http/jsonrpc_errors.d.ts +27 -2
- package/dist/http/jsonrpc_errors.d.ts.map +1 -1
- package/dist/http/jsonrpc_errors.js +26 -2
- package/dist/http/pending_effects.d.ts +71 -18
- package/dist/http/pending_effects.d.ts.map +1 -1
- package/dist/http/pending_effects.js +87 -18
- package/dist/http/proxy.d.ts +52 -5
- package/dist/http/proxy.d.ts.map +1 -1
- package/dist/http/proxy.js +92 -14
- package/dist/http/route_spec.d.ts +113 -41
- package/dist/http/route_spec.d.ts.map +1 -1
- package/dist/http/route_spec.js +130 -52
- package/dist/http/schema_helpers.d.ts +3 -2
- package/dist/http/schema_helpers.d.ts.map +1 -1
- package/dist/http/schema_helpers.js +9 -2
- package/dist/http/surface.d.ts +2 -1
- package/dist/http/surface.d.ts.map +1 -1
- package/dist/http/surface.js +1 -2
- package/dist/http/surface_query.d.ts +39 -35
- package/dist/http/surface_query.d.ts.map +1 -1
- package/dist/http/surface_query.js +79 -36
- package/dist/primitive_schemas.d.ts +39 -0
- package/dist/primitive_schemas.d.ts.map +1 -0
- package/dist/primitive_schemas.js +40 -0
- package/dist/realtime/sse_auth_guard.d.ts +5 -5
- package/dist/realtime/sse_auth_guard.js +9 -9
- package/dist/runtime/mock.d.ts +1 -1
- package/dist/runtime/mock.js +1 -1
- package/dist/server/app_backend.d.ts +14 -11
- package/dist/server/app_backend.d.ts.map +1 -1
- package/dist/server/app_backend.js +12 -8
- package/dist/server/app_server.d.ts +7 -7
- package/dist/server/app_server.d.ts.map +1 -1
- package/dist/server/app_server.js +36 -31
- package/dist/server/validate_nginx.d.ts +1 -1
- package/dist/server/validate_nginx.js +1 -1
- package/dist/testing/CLAUDE.md +73 -55
- package/dist/testing/admin_integration.d.ts +5 -6
- package/dist/testing/admin_integration.d.ts.map +1 -1
- package/dist/testing/admin_integration.js +100 -96
- package/dist/testing/adversarial_headers.js +1 -1
- package/dist/testing/app_server.d.ts +11 -14
- package/dist/testing/app_server.d.ts.map +1 -1
- package/dist/testing/app_server.js +18 -17
- package/dist/testing/assertions.d.ts.map +1 -1
- package/dist/testing/assertions.js +2 -1
- package/dist/testing/attack_surface.d.ts.map +1 -1
- package/dist/testing/attack_surface.js +15 -9
- package/dist/testing/audit_completeness.d.ts +2 -2
- package/dist/testing/audit_completeness.d.ts.map +1 -1
- package/dist/testing/audit_completeness.js +53 -39
- package/dist/testing/auth_apps.d.ts +5 -4
- package/dist/testing/auth_apps.d.ts.map +1 -1
- package/dist/testing/auth_apps.js +28 -22
- package/dist/testing/data_exposure.d.ts.map +1 -1
- package/dist/testing/data_exposure.js +5 -5
- package/dist/testing/db.d.ts +1 -1
- package/dist/testing/db.d.ts.map +1 -1
- package/dist/testing/db.js +4 -4
- package/dist/testing/db_entities.d.ts +22 -0
- package/dist/testing/db_entities.d.ts.map +1 -0
- package/dist/testing/db_entities.js +28 -0
- package/dist/testing/entities.d.ts +10 -8
- package/dist/testing/entities.d.ts.map +1 -1
- package/dist/testing/entities.js +22 -18
- package/dist/testing/integration.d.ts.map +1 -1
- package/dist/testing/integration.js +13 -14
- package/dist/testing/integration_helpers.d.ts +8 -6
- package/dist/testing/integration_helpers.d.ts.map +1 -1
- package/dist/testing/integration_helpers.js +29 -23
- package/dist/testing/middleware.d.ts +15 -11
- package/dist/testing/middleware.d.ts.map +1 -1
- package/dist/testing/middleware.js +75 -32
- package/dist/testing/rpc_attack_surface.d.ts.map +1 -1
- package/dist/testing/rpc_attack_surface.js +40 -24
- package/dist/testing/rpc_helpers.d.ts.map +1 -1
- package/dist/testing/rpc_helpers.js +3 -1
- package/dist/testing/rpc_round_trip.d.ts +1 -1
- package/dist/testing/rpc_round_trip.d.ts.map +1 -1
- package/dist/testing/rpc_round_trip.js +14 -13
- package/dist/testing/sse_round_trip.d.ts +3 -4
- package/dist/testing/sse_round_trip.d.ts.map +1 -1
- package/dist/testing/sse_round_trip.js +7 -11
- package/dist/testing/standard.d.ts +1 -1
- package/dist/testing/stubs.d.ts +25 -0
- package/dist/testing/stubs.d.ts.map +1 -1
- package/dist/testing/stubs.js +43 -2
- package/dist/testing/surface_invariants.d.ts +2 -2
- package/dist/testing/ws_round_trip.d.ts +12 -13
- package/dist/testing/ws_round_trip.d.ts.map +1 -1
- package/dist/testing/ws_round_trip.js +24 -12
- package/dist/ui/AdminAccounts.svelte +23 -20
- package/dist/ui/AdminOverview.svelte +15 -13
- package/dist/ui/AdminOverview.svelte.d.ts.map +1 -1
- package/dist/ui/{AdminPermitHistory.svelte → AdminRoleGrantHistory.svelte} +12 -12
- package/dist/ui/AdminRoleGrantHistory.svelte.d.ts +4 -0
- package/dist/ui/AdminRoleGrantHistory.svelte.d.ts.map +1 -0
- package/dist/ui/BootstrapForm.svelte +1 -1
- package/dist/ui/CLAUDE.md +65 -59
- package/dist/ui/{PermitOfferForm.svelte → RoleGrantOfferForm.svelte} +37 -22
- package/dist/ui/RoleGrantOfferForm.svelte.d.ts +20 -0
- package/dist/ui/RoleGrantOfferForm.svelte.d.ts.map +1 -0
- package/dist/ui/{PermitOfferHistory.svelte → RoleGrantOfferHistory.svelte} +12 -12
- package/dist/ui/{PermitOfferHistory.svelte.d.ts → RoleGrantOfferHistory.svelte.d.ts} +4 -4
- package/dist/ui/RoleGrantOfferHistory.svelte.d.ts.map +1 -0
- package/dist/ui/{PermitOfferInbox.svelte → RoleGrantOfferInbox.svelte} +14 -14
- package/dist/ui/{PermitOfferInbox.svelte.d.ts → RoleGrantOfferInbox.svelte.d.ts} +4 -4
- package/dist/ui/RoleGrantOfferInbox.svelte.d.ts.map +1 -0
- package/dist/ui/SignupForm.svelte +1 -1
- package/dist/ui/SurfaceExplorer.svelte +35 -15
- package/dist/ui/SurfaceExplorer.svelte.d.ts.map +1 -1
- package/dist/ui/account_sessions_state.svelte.d.ts +2 -3
- package/dist/ui/account_sessions_state.svelte.d.ts.map +1 -1
- package/dist/ui/account_sessions_state.svelte.js +2 -3
- package/dist/ui/admin_accounts_state.svelte.d.ts +25 -18
- package/dist/ui/admin_accounts_state.svelte.d.ts.map +1 -1
- package/dist/ui/admin_accounts_state.svelte.js +28 -17
- package/dist/ui/admin_rpc_adapters.d.ts +20 -20
- package/dist/ui/admin_rpc_adapters.d.ts.map +1 -1
- package/dist/ui/admin_rpc_adapters.js +17 -17
- package/dist/ui/admin_sessions_state.svelte.d.ts +2 -2
- package/dist/ui/admin_sessions_state.svelte.js +2 -2
- package/dist/ui/audit_log_state.svelte.d.ts +7 -7
- package/dist/ui/audit_log_state.svelte.d.ts.map +1 -1
- package/dist/ui/audit_log_state.svelte.js +6 -6
- package/dist/ui/auth_state.svelte.d.ts +3 -3
- package/dist/ui/auth_state.svelte.d.ts.map +1 -1
- package/dist/ui/auth_state.svelte.js +6 -6
- package/dist/ui/format_scope.d.ts +2 -2
- package/dist/ui/format_scope.js +2 -2
- package/dist/ui/{permit_offers_state.svelte.d.ts → role_grant_offers_state.svelte.d.ts} +39 -31
- package/dist/ui/role_grant_offers_state.svelte.d.ts.map +1 -0
- package/dist/ui/{permit_offers_state.svelte.js → role_grant_offers_state.svelte.js} +25 -19
- package/dist/ui/ui_format.js +2 -2
- package/package.json +3 -3
- package/dist/auth/permit_offer_action_specs.d.ts.map +0 -1
- package/dist/auth/permit_offer_action_specs.js +0 -227
- package/dist/auth/permit_offer_actions.d.ts +0 -110
- package/dist/auth/permit_offer_actions.d.ts.map +0 -1
- package/dist/auth/permit_offer_actions.js +0 -452
- package/dist/auth/permit_offer_notifications.d.ts.map +0 -1
- package/dist/auth/permit_offer_notifications.js +0 -182
- package/dist/auth/permit_offer_queries.d.ts +0 -183
- package/dist/auth/permit_offer_queries.d.ts.map +0 -1
- package/dist/auth/permit_offer_queries.js +0 -408
- package/dist/auth/permit_offer_schema.d.ts +0 -103
- package/dist/auth/permit_offer_schema.d.ts.map +0 -1
- package/dist/auth/permit_queries.d.ts +0 -210
- package/dist/auth/permit_queries.d.ts.map +0 -1
- package/dist/auth/permit_queries.js +0 -294
- package/dist/auth/require_keeper.d.ts +0 -20
- package/dist/auth/require_keeper.d.ts.map +0 -1
- package/dist/auth/require_keeper.js +0 -35
- package/dist/auth/route_guards.d.ts +0 -21
- package/dist/auth/route_guards.d.ts.map +0 -1
- package/dist/auth/route_guards.js +0 -32
- package/dist/auth/session_lifecycle.d.ts +0 -37
- package/dist/auth/session_lifecycle.d.ts.map +0 -1
- package/dist/auth/session_lifecycle.js +0 -29
- package/dist/ui/AdminPermitHistory.svelte.d.ts +0 -4
- package/dist/ui/AdminPermitHistory.svelte.d.ts.map +0 -1
- package/dist/ui/PermitOfferForm.svelte.d.ts +0 -14
- package/dist/ui/PermitOfferForm.svelte.d.ts.map +0 -1
- package/dist/ui/PermitOfferHistory.svelte.d.ts.map +0 -1
- package/dist/ui/PermitOfferInbox.svelte.d.ts.map +0 -1
- package/dist/ui/permit_offers_state.svelte.d.ts.map +0 -1
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bound audit-emit capability.
|
|
3
|
+
*
|
|
4
|
+
* `AuditEmitter` closes over the pool-level `Db`, the `on_audit_event`
|
|
5
|
+
* subscriber chain, and the optional `AuditLogConfig` at backend-assembly
|
|
6
|
+
* time. Consumers reach for `deps.audit.emit(ctx, input)` and never see the
|
|
7
|
+
* pool — handlers cannot accidentally emit an audit event against the
|
|
8
|
+
* request's transactional `db` (which would be rolled back with the parent
|
|
9
|
+
* on a handler throw).
|
|
10
|
+
*
|
|
11
|
+
* Four methods cover every fan-out shape the auth domain needs:
|
|
12
|
+
*
|
|
13
|
+
* - `emit(ctx, input)` — fire-and-forget pool write. Pushes the in-flight
|
|
14
|
+
* promise onto `ctx.pending_effects` for post-response flushing. Errors are
|
|
15
|
+
* logged, never thrown. Returns `void` so callers don't pile up `void`
|
|
16
|
+
* keywords or accidentally `await` something whose handle is already in
|
|
17
|
+
* `pending_effects`.
|
|
18
|
+
* - `emit_role_grant_target(ctx, auth, input)` — wrapper that lifts the
|
|
19
|
+
* `actor_id` / `account_id` / `ip` boilerplate every role-grant-shape audit
|
|
20
|
+
* site repeated. Delegates to `emit`.
|
|
21
|
+
* - `emit_pool(input)` — awaitable pool write for code paths without a
|
|
22
|
+
* `pending_effects` queue (cleanup sweeps, ad-hoc maintenance scripts).
|
|
23
|
+
* Same write-then-notify semantics as `emit`, just synchronous-with-await.
|
|
24
|
+
* - `notify(event)` — fan out an already-written audit row (e.g. rows
|
|
25
|
+
* returned by `query_accept_offer` that were inserted in-transaction by
|
|
26
|
+
* the query layer). Runs every listener on the chain; per-listener throws
|
|
27
|
+
* are isolated.
|
|
28
|
+
*
|
|
29
|
+
* The chain is mutable so server assembly can append additional listeners
|
|
30
|
+
* (e.g. the audit-log SSE registry composed by `create_app_server`) after
|
|
31
|
+
* the backend is built but before the first request runs.
|
|
32
|
+
*
|
|
33
|
+
* @module
|
|
34
|
+
*/
|
|
35
|
+
import type { Logger } from '@fuzdev/fuz_util/log.js';
|
|
36
|
+
import type { Uuid } from '@fuzdev/fuz_util/id.js';
|
|
37
|
+
import type { Db } from '../db/db.js';
|
|
38
|
+
import type { RequestActorContext } from './request_context.js';
|
|
39
|
+
import { type AuditLogConfig, type AuditLogEvent, type AuditLogInput } from './audit_log_schema.js';
|
|
40
|
+
/**
|
|
41
|
+
* Per-request context required by `AuditEmitter.emit` — just the eager
|
|
42
|
+
* `pending_effects` queue. The bound emitter carries its own `log`
|
|
43
|
+
* reference inside the closure, so per-call contexts don't need one.
|
|
44
|
+
*
|
|
45
|
+
* Audit emits are eager-only by design: the bound emitter fires the
|
|
46
|
+
* pool write immediately and pushes the in-flight `Promise<void>` here.
|
|
47
|
+
* They never go through `emit_after_commit` — pool-routed audit writes
|
|
48
|
+
* are already rollback-resilient because they run outside the request
|
|
49
|
+
* transaction, so the post-commit timing the deferred queue provides
|
|
50
|
+
* would only delay forensic visibility without any safety benefit.
|
|
51
|
+
*
|
|
52
|
+
* Both `RouteContext` and `ActionContext` structurally satisfy this
|
|
53
|
+
* shape (they each carry `pending_effects`), so handlers pass `route`
|
|
54
|
+
* / `ctx` directly.
|
|
55
|
+
*/
|
|
56
|
+
export interface AuditEmitterContext {
|
|
57
|
+
pending_effects: Array<Promise<void>>;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Context required by `AuditEmitter.emit_role_grant_target` — adds
|
|
61
|
+
* `client_ip` so the helper can lift the `ip: ctx.client_ip`
|
|
62
|
+
* boilerplate every role-grant-shape emit site repeated.
|
|
63
|
+
*/
|
|
64
|
+
export interface AuditEmitRoleGrantContext extends AuditEmitterContext {
|
|
65
|
+
/** Resolved client IP from the trusted-proxy middleware — `'unknown'` if not resolved. */
|
|
66
|
+
client_ip: string;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Bound audit-emit capability. Built once at backend assembly via
|
|
70
|
+
* `create_audit_emitter`; lives on `AppDeps.audit` so factories never see
|
|
71
|
+
* the pool.
|
|
72
|
+
*/
|
|
73
|
+
export interface AuditEmitter {
|
|
74
|
+
/**
|
|
75
|
+
* Fire-and-forget audit write via the captured pool.
|
|
76
|
+
*
|
|
77
|
+
* The in-flight promise is pushed onto `ctx.pending_effects` so tests
|
|
78
|
+
* with `await_pending_effects: true` can assert side effects inline.
|
|
79
|
+
* Errors are logged, never thrown. Successful writes fan out to every
|
|
80
|
+
* listener on the chain (`notify`).
|
|
81
|
+
*
|
|
82
|
+
* Returns `void` deliberately — the in-flight promise is already on
|
|
83
|
+
* `ctx.pending_effects`, and exposing it would tempt callers to `await`
|
|
84
|
+
* (sequencing audit writes onto the response hot path) or sprinkle
|
|
85
|
+
* `void` to placate `no-floating-promises`. For awaitable writes from
|
|
86
|
+
* code paths without `pending_effects`, use `emit_pool`.
|
|
87
|
+
*
|
|
88
|
+
* @mutates `audit_log` table - inserts the row via the captured pool
|
|
89
|
+
* @mutates `ctx.pending_effects` - appends the in-flight settled promise
|
|
90
|
+
*/
|
|
91
|
+
emit<T extends string>(ctx: AuditEmitterContext, input: AuditLogInput<T>): void;
|
|
92
|
+
/**
|
|
93
|
+
* Emit a role-grant-shape audit event with `actor_id` / `account_id` /
|
|
94
|
+
* `ip` lifted from `auth` + `ctx`. Delegates to `emit`.
|
|
95
|
+
*
|
|
96
|
+
* Use for any event populating one of the `target_*_id` columns.
|
|
97
|
+
* Reach for the lower-level `emit` only when the event is non-role-grant
|
|
98
|
+
* shape (e.g. `app_settings_update`, bootstrap, signup).
|
|
99
|
+
*/
|
|
100
|
+
emit_role_grant_target<T extends string>(ctx: AuditEmitRoleGrantContext, auth: RequestActorContext, input: {
|
|
101
|
+
event_type: T;
|
|
102
|
+
target_account_id: Uuid | null;
|
|
103
|
+
target_actor_id: Uuid | null;
|
|
104
|
+
metadata: AuditLogInput<T>['metadata'];
|
|
105
|
+
outcome?: 'success' | 'failure';
|
|
106
|
+
}): void;
|
|
107
|
+
/**
|
|
108
|
+
* Awaitable pool write for code paths without a `pending_effects` queue.
|
|
109
|
+
*
|
|
110
|
+
* Same write-then-notify semantics as `emit`. Errors are logged and
|
|
111
|
+
* swallowed (resolved void), so callers can sequence sweeps with
|
|
112
|
+
* `await audit.emit_pool(...)` without try/catch boilerplate. The
|
|
113
|
+
* primary user is `auth/cleanup.ts` — sweeps have no per-request
|
|
114
|
+
* `pending_effects` to attach to.
|
|
115
|
+
*
|
|
116
|
+
* @mutates `audit_log` table - inserts the row via the captured pool
|
|
117
|
+
*/
|
|
118
|
+
emit_pool<T extends string>(input: AuditLogInput<T>): Promise<void>;
|
|
119
|
+
/**
|
|
120
|
+
* Fan out an already-written audit row to the listener chain.
|
|
121
|
+
*
|
|
122
|
+
* Use only when the row was inserted in-transaction by a query helper
|
|
123
|
+
* that returned the `AuditLogEvent` (e.g. `query_accept_offer.audit_events`).
|
|
124
|
+
* Per-listener exceptions are caught and logged; one failing listener
|
|
125
|
+
* does not starve siblings.
|
|
126
|
+
*/
|
|
127
|
+
notify(event: AuditLogEvent): void;
|
|
128
|
+
/**
|
|
129
|
+
* Mutable subscriber chain. Append at server assembly to compose the
|
|
130
|
+
* factory-managed audit-log SSE on top of the consumer's
|
|
131
|
+
* `on_audit_event` callback without shallow-copying `AppDeps`.
|
|
132
|
+
*/
|
|
133
|
+
readonly on_event_chain: Array<(event: AuditLogEvent) => void>;
|
|
134
|
+
}
|
|
135
|
+
/** Options for `create_audit_emitter`. */
|
|
136
|
+
export interface CreateAuditEmitterOptions {
|
|
137
|
+
/** Pool-level `Db`. Captured by every emit call. */
|
|
138
|
+
db: Db;
|
|
139
|
+
/** Logger for write + listener-callback failures. */
|
|
140
|
+
log: Logger;
|
|
141
|
+
/**
|
|
142
|
+
* Initial subscriber appended to `on_event_chain`. Omit for backends
|
|
143
|
+
* that compose listeners post-assembly (e.g. via `audit_log_sse`).
|
|
144
|
+
*/
|
|
145
|
+
on_audit_event?: ((event: AuditLogEvent) => void) | null;
|
|
146
|
+
/**
|
|
147
|
+
* Audit-log config. Defaults to `BUILTIN_AUDIT_LOG_CONFIG`. Consumer-
|
|
148
|
+
* extended configs from `create_audit_log_config({extra_events})` get
|
|
149
|
+
* registered here once at backend assembly.
|
|
150
|
+
*/
|
|
151
|
+
audit_log_config?: AuditLogConfig;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Build a bound `AuditEmitter`. Called once at `create_app_backend` time.
|
|
155
|
+
*
|
|
156
|
+
* @param options - pool, logger, optional initial subscriber, optional config
|
|
157
|
+
* @returns the bound emitter; closes over the pool + config + listener chain
|
|
158
|
+
*/
|
|
159
|
+
export declare const create_audit_emitter: (options: CreateAuditEmitterOptions) => AuditEmitter;
|
|
160
|
+
//# sourceMappingURL=audit_emitter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit_emitter.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/audit_emitter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AACpD,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,wBAAwB,CAAC;AAEjD,OAAO,KAAK,EAAC,EAAE,EAAC,MAAM,aAAa,CAAC;AACpC,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,sBAAsB,CAAC;AAE9D,OAAO,EAEN,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,MAAM,uBAAuB,CAAC;AAE/B;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,mBAAmB;IACnC,eAAe,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;CACtC;AAED;;;;GAIG;AACH,MAAM,WAAW,yBAA0B,SAAQ,mBAAmB;IACrE,0FAA0F;IAC1F,SAAS,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC5B;;;;;;;;;;;;;;;;OAgBG;IACH,IAAI,CAAC,CAAC,SAAS,MAAM,EAAE,GAAG,EAAE,mBAAmB,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAChF;;;;;;;OAOG;IACH,sBAAsB,CAAC,CAAC,SAAS,MAAM,EACtC,GAAG,EAAE,yBAAyB,EAC9B,IAAI,EAAE,mBAAmB,EACzB,KAAK,EAAE;QACN,UAAU,EAAE,CAAC,CAAC;QACd,iBAAiB,EAAE,IAAI,GAAG,IAAI,CAAC;QAC/B,eAAe,EAAE,IAAI,GAAG,IAAI,CAAC;QAC7B,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;QACvC,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;KAChC,GACC,IAAI,CAAC;IACR;;;;;;;;;;OAUG;IACH,SAAS,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE;;;;;;;OAOG;IACH,MAAM,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAAC;IACnC;;;;OAIG;IACH,QAAQ,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC,CAAC;CAC/D;AAED,0CAA0C;AAC1C,MAAM,WAAW,yBAAyB;IACzC,oDAAoD;IACpD,EAAE,EAAE,EAAE,CAAC;IACP,qDAAqD;IACrD,GAAG,EAAE,MAAM,CAAC;IACZ;;;OAGG;IACH,cAAc,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC;IACzD;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,cAAc,CAAC;CAClC;AAED;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,GAAI,SAAS,yBAAyB,KAAG,YAoDzE,CAAC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bound audit-emit capability.
|
|
3
|
+
*
|
|
4
|
+
* `AuditEmitter` closes over the pool-level `Db`, the `on_audit_event`
|
|
5
|
+
* subscriber chain, and the optional `AuditLogConfig` at backend-assembly
|
|
6
|
+
* time. Consumers reach for `deps.audit.emit(ctx, input)` and never see the
|
|
7
|
+
* pool — handlers cannot accidentally emit an audit event against the
|
|
8
|
+
* request's transactional `db` (which would be rolled back with the parent
|
|
9
|
+
* on a handler throw).
|
|
10
|
+
*
|
|
11
|
+
* Four methods cover every fan-out shape the auth domain needs:
|
|
12
|
+
*
|
|
13
|
+
* - `emit(ctx, input)` — fire-and-forget pool write. Pushes the in-flight
|
|
14
|
+
* promise onto `ctx.pending_effects` for post-response flushing. Errors are
|
|
15
|
+
* logged, never thrown. Returns `void` so callers don't pile up `void`
|
|
16
|
+
* keywords or accidentally `await` something whose handle is already in
|
|
17
|
+
* `pending_effects`.
|
|
18
|
+
* - `emit_role_grant_target(ctx, auth, input)` — wrapper that lifts the
|
|
19
|
+
* `actor_id` / `account_id` / `ip` boilerplate every role-grant-shape audit
|
|
20
|
+
* site repeated. Delegates to `emit`.
|
|
21
|
+
* - `emit_pool(input)` — awaitable pool write for code paths without a
|
|
22
|
+
* `pending_effects` queue (cleanup sweeps, ad-hoc maintenance scripts).
|
|
23
|
+
* Same write-then-notify semantics as `emit`, just synchronous-with-await.
|
|
24
|
+
* - `notify(event)` — fan out an already-written audit row (e.g. rows
|
|
25
|
+
* returned by `query_accept_offer` that were inserted in-transaction by
|
|
26
|
+
* the query layer). Runs every listener on the chain; per-listener throws
|
|
27
|
+
* are isolated.
|
|
28
|
+
*
|
|
29
|
+
* The chain is mutable so server assembly can append additional listeners
|
|
30
|
+
* (e.g. the audit-log SSE registry composed by `create_app_server`) after
|
|
31
|
+
* the backend is built but before the first request runs.
|
|
32
|
+
*
|
|
33
|
+
* @module
|
|
34
|
+
*/
|
|
35
|
+
import { query_audit_log } from './audit_log_queries.js';
|
|
36
|
+
import { BUILTIN_AUDIT_LOG_CONFIG, } from './audit_log_schema.js';
|
|
37
|
+
/**
|
|
38
|
+
* Build a bound `AuditEmitter`. Called once at `create_app_backend` time.
|
|
39
|
+
*
|
|
40
|
+
* @param options - pool, logger, optional initial subscriber, optional config
|
|
41
|
+
* @returns the bound emitter; closes over the pool + config + listener chain
|
|
42
|
+
*/
|
|
43
|
+
export const create_audit_emitter = (options) => {
|
|
44
|
+
const { db, log, audit_log_config = BUILTIN_AUDIT_LOG_CONFIG } = options;
|
|
45
|
+
const on_event_chain = [];
|
|
46
|
+
if (options.on_audit_event)
|
|
47
|
+
on_event_chain.push(options.on_audit_event);
|
|
48
|
+
const notify = (event) => {
|
|
49
|
+
for (const listener of on_event_chain) {
|
|
50
|
+
try {
|
|
51
|
+
listener(event);
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
log.error('Audit log listener failed:', err);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
const emit_pool = async (input) => {
|
|
59
|
+
try {
|
|
60
|
+
const event = await query_audit_log({ db }, input, audit_log_config);
|
|
61
|
+
notify(event);
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
log.error('Audit log write failed:', err);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
const emit = (ctx, input) => {
|
|
68
|
+
ctx.pending_effects.push(emit_pool(input));
|
|
69
|
+
};
|
|
70
|
+
const emit_role_grant_target = (ctx, auth, input) => {
|
|
71
|
+
emit(ctx, {
|
|
72
|
+
event_type: input.event_type,
|
|
73
|
+
actor_id: auth.actor.id,
|
|
74
|
+
account_id: auth.account.id,
|
|
75
|
+
outcome: input.outcome,
|
|
76
|
+
target_account_id: input.target_account_id,
|
|
77
|
+
target_actor_id: input.target_actor_id,
|
|
78
|
+
ip: ctx.client_ip,
|
|
79
|
+
metadata: input.metadata,
|
|
80
|
+
});
|
|
81
|
+
};
|
|
82
|
+
return { emit, emit_role_grant_target, emit_pool, notify, on_event_chain };
|
|
83
|
+
};
|
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Audit log database queries.
|
|
3
3
|
*
|
|
4
|
-
* Records and retrieves auth mutation events for security monitoring.
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
4
|
+
* Records and retrieves auth mutation events for security monitoring. The
|
|
5
|
+
* canonical fire-and-forget entry point is `AppDeps.audit.emit(ctx, input)`
|
|
6
|
+
* (see `auth/audit_emitter.ts`) — it closes over the pool so audit rows
|
|
7
|
+
* persist even when the request transaction rolls back. This module only
|
|
8
|
+
* exposes the in-transaction `query_*` primitives and the drift counters;
|
|
9
|
+
* the bound emitter writes through `query_audit_log` against its captured
|
|
10
|
+
* pool.
|
|
11
11
|
*
|
|
12
12
|
* @module
|
|
13
13
|
*/
|
|
14
14
|
import type { QueryDeps } from '../db/query_deps.js';
|
|
15
|
-
import type
|
|
16
|
-
import type { AppDeps } from './deps.js';
|
|
17
|
-
import { type AuditLogConfig, type AuditLogEvent, type AuditLogInput, type AuditLogListOptions, type AuditLogEventWithUsernamesJson, type PermitHistoryEventJson } from './audit_log_schema.js';
|
|
15
|
+
import { type AuditLogConfig, type AuditLogEvent, type AuditLogInput, type AuditLogListOptions, type AuditLogEventWithUsernamesJson, type RoleGrantHistoryEventJson } from './audit_log_schema.js';
|
|
18
16
|
/** Number of audit metadata validation failures observed since process start. */
|
|
19
17
|
export declare const get_audit_metadata_validation_failures: () => number;
|
|
20
18
|
/** Reset the counter — for tests only. */
|
|
@@ -32,6 +30,12 @@ export declare const reset_audit_unknown_event_type_failures: () => void;
|
|
|
32
30
|
* but write the row anyway. Consumers extend the recognized set via
|
|
33
31
|
* `create_audit_log_config({extra_events})`.
|
|
34
32
|
*
|
|
33
|
+
* In-transaction call site for query helpers that must atomically write the
|
|
34
|
+
* row alongside other mutations (e.g. `query_accept_offer`). Fire-and-forget
|
|
35
|
+
* call sites should reach for `AppDeps.audit.emit` instead — that wrapper
|
|
36
|
+
* closes over the pool so audit rows persist when the parent transaction
|
|
37
|
+
* rolls back.
|
|
38
|
+
*
|
|
35
39
|
* @param deps - query dependencies
|
|
36
40
|
* @param input - the audit event to record
|
|
37
41
|
* @param config - audit-log config. Defaults to `BUILTIN_AUDIT_LOG_CONFIG`.
|
|
@@ -57,22 +61,14 @@ export declare const query_audit_log_list: (deps: QueryDeps, options?: AuditLogL
|
|
|
57
61
|
*/
|
|
58
62
|
export declare const query_audit_log_list_with_usernames: (deps: QueryDeps, options?: AuditLogListOptions) => Promise<Array<AuditLogEventWithUsernamesJson>>;
|
|
59
63
|
/**
|
|
60
|
-
* List
|
|
61
|
-
*
|
|
62
|
-
* @param deps - query dependencies
|
|
63
|
-
* @param account_id - the account to query for
|
|
64
|
-
* @param limit - maximum entries to return
|
|
65
|
-
*/
|
|
66
|
-
export declare const query_audit_log_list_for_account: (deps: QueryDeps, account_id: string, limit?: number) => Promise<Array<AuditLogEvent>>;
|
|
67
|
-
/**
|
|
68
|
-
* List permit grant/revoke events with resolved usernames.
|
|
64
|
+
* List role_grant grant/revoke events with resolved usernames.
|
|
69
65
|
*
|
|
70
66
|
* @param deps - query dependencies
|
|
71
67
|
* @param limit - maximum entries to return
|
|
72
68
|
* @param offset - number of entries to skip
|
|
73
|
-
* @returns
|
|
69
|
+
* @returns role_grant history events with `username` and `target_username`
|
|
74
70
|
*/
|
|
75
|
-
export declare const
|
|
71
|
+
export declare const query_audit_log_list_role_grant_history: (deps: QueryDeps, limit?: number, offset?: number) => Promise<Array<RoleGrantHistoryEventJson>>;
|
|
76
72
|
/**
|
|
77
73
|
* Delete audit log entries older than the given date.
|
|
78
74
|
*
|
|
@@ -82,31 +78,4 @@ export declare const query_audit_log_list_permit_history: (deps: QueryDeps, limi
|
|
|
82
78
|
* @mutates `audit_log` table - deletes every row with `created_at < before`
|
|
83
79
|
*/
|
|
84
80
|
export declare const query_audit_log_cleanup_before: (deps: QueryDeps, before: Date) => Promise<number>;
|
|
85
|
-
/**
|
|
86
|
-
* Capabilities required by `audit_log_fire_and_forget`.
|
|
87
|
-
*
|
|
88
|
-
* Defined as a slice of `AppDeps` so call sites can pass the surrounding deps
|
|
89
|
-
* bundle directly without a structural-compatibility coincidence. The bundled
|
|
90
|
-
* shape replaces the prior `(log, on_audit_event, config?)` positional args
|
|
91
|
-
* — consumers that forgot the trailing `config` would silently fall back to
|
|
92
|
-
* `BUILTIN_AUDIT_LOG_CONFIG` and skip metadata validation for their own
|
|
93
|
-
* event types. `audit_log_config` is optional on `AppDeps` and defaults to
|
|
94
|
-
* `BUILTIN_AUDIT_LOG_CONFIG` inside `audit_log_fire_and_forget` when absent.
|
|
95
|
-
*/
|
|
96
|
-
export type AuditLogFireAndForgetDeps = Pick<AppDeps, 'log' | 'on_audit_event' | 'audit_log_config'>;
|
|
97
|
-
/**
|
|
98
|
-
* Log an audit event without blocking the caller.
|
|
99
|
-
*
|
|
100
|
-
* Errors are logged — audit logging never breaks auth flows. Uses
|
|
101
|
-
* `background_db` so entries persist even when the request transaction
|
|
102
|
-
* rolls back. Write and `on_audit_event` callback failures are logged separately.
|
|
103
|
-
*
|
|
104
|
-
* @param route - `background_db` and `pending_effects` from the route context
|
|
105
|
-
* @param input - the audit event to record
|
|
106
|
-
* @param deps - logger, `on_audit_event` callback, and optional `audit_log_config`
|
|
107
|
-
* @returns the settled promise (callers may ignore it)
|
|
108
|
-
* @mutates `audit_log` table - inserts a row via `background_db` (independent of the request transaction)
|
|
109
|
-
* @mutates `route.pending_effects` - pushes the in-flight settled promise for test flushing
|
|
110
|
-
*/
|
|
111
|
-
export declare const audit_log_fire_and_forget: <T extends string>(route: Pick<RouteContext, "background_db" | "pending_effects">, input: AuditLogInput<T>, deps: AuditLogFireAndForgetDeps) => Promise<void>;
|
|
112
81
|
//# sourceMappingURL=audit_log_queries.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit_log_queries.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/audit_log_queries.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,qBAAqB,CAAC;AAEnD,OAAO,
|
|
1
|
+
{"version":3,"file":"audit_log_queries.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/audit_log_queries.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,qBAAqB,CAAC;AAEnD,OAAO,EAGN,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,8BAA8B,EACnC,KAAK,yBAAyB,EAC9B,MAAM,uBAAuB,CAAC;AAa/B,iFAAiF;AACjF,eAAO,MAAM,sCAAsC,QAAO,MACvB,CAAC;AAEpC,0CAA0C;AAC1C,eAAO,MAAM,wCAAwC,QAAO,IAE3D,CAAC;AAYF,gFAAgF;AAChF,eAAO,MAAM,qCAAqC,QAAO,MACvB,CAAC;AAEnC,0CAA0C;AAC1C,eAAO,MAAM,uCAAuC,QAAO,IAE1D,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,eAAe,GAAU,CAAC,SAAS,MAAM,EACrD,MAAM,SAAS,EACf,OAAO,aAAa,CAAC,CAAC,CAAC,EACvB,SAAQ,cAAyC,KAC/C,OAAO,CAAC,aAAa,CAoCvB,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,GAChC,MAAM,SAAS,EACf,UAAU,mBAAmB,KAC3B,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,CAwC9B,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,mCAAmC,GAC/C,MAAM,SAAS,EACf,UAAU,mBAAmB,KAC3B,OAAO,CAAC,KAAK,CAAC,8BAA8B,CAAC,CA8C/C,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,uCAAuC,GACnD,MAAM,SAAS,EACf,cAA+B,EAC/B,eAAU,KACR,OAAO,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAY1C,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,8BAA8B,GAC1C,MAAM,SAAS,EACf,QAAQ,IAAI,KACV,OAAO,CAAC,MAAM,CAMhB,CAAC"}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Audit log database queries.
|
|
3
3
|
*
|
|
4
|
-
* Records and retrieves auth mutation events for security monitoring.
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
4
|
+
* Records and retrieves auth mutation events for security monitoring. The
|
|
5
|
+
* canonical fire-and-forget entry point is `AppDeps.audit.emit(ctx, input)`
|
|
6
|
+
* (see `auth/audit_emitter.ts`) — it closes over the pool so audit rows
|
|
7
|
+
* persist even when the request transaction rolls back. This module only
|
|
8
|
+
* exposes the in-transaction `query_*` primitives and the drift counters;
|
|
9
|
+
* the bound emitter writes through `query_audit_log` against its captured
|
|
10
|
+
* pool.
|
|
11
11
|
*
|
|
12
12
|
* @module
|
|
13
13
|
*/
|
|
@@ -53,6 +53,12 @@ export const reset_audit_unknown_event_type_failures = () => {
|
|
|
53
53
|
* but write the row anyway. Consumers extend the recognized set via
|
|
54
54
|
* `create_audit_log_config({extra_events})`.
|
|
55
55
|
*
|
|
56
|
+
* In-transaction call site for query helpers that must atomically write the
|
|
57
|
+
* row alongside other mutations (e.g. `query_accept_offer`). Fire-and-forget
|
|
58
|
+
* call sites should reach for `AppDeps.audit.emit` instead — that wrapper
|
|
59
|
+
* closes over the pool so audit rows persist when the parent transaction
|
|
60
|
+
* rolls back.
|
|
61
|
+
*
|
|
56
62
|
* @param deps - query dependencies
|
|
57
63
|
* @param input - the audit event to record
|
|
58
64
|
* @param config - audit-log config. Defaults to `BUILTIN_AUDIT_LOG_CONFIG`.
|
|
@@ -75,14 +81,15 @@ export const query_audit_log = async (deps, input, config = BUILTIN_AUDIT_LOG_CO
|
|
|
75
81
|
}
|
|
76
82
|
}
|
|
77
83
|
}
|
|
78
|
-
const rows = await deps.db.query(`INSERT INTO audit_log (event_type, outcome, actor_id, account_id, target_account_id, ip, metadata)
|
|
79
|
-
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
|
84
|
+
const rows = await deps.db.query(`INSERT INTO audit_log (event_type, outcome, actor_id, account_id, target_account_id, target_actor_id, ip, metadata)
|
|
85
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
|
80
86
|
RETURNING *`, [
|
|
81
87
|
input.event_type,
|
|
82
88
|
input.outcome ?? 'success',
|
|
83
89
|
input.actor_id ?? null,
|
|
84
90
|
input.account_id ?? null,
|
|
85
91
|
input.target_account_id ?? null,
|
|
92
|
+
input.target_actor_id ?? null,
|
|
86
93
|
input.ip ?? null,
|
|
87
94
|
input.metadata ? JSON.stringify(input.metadata) : null,
|
|
88
95
|
]);
|
|
@@ -171,33 +178,21 @@ export const query_audit_log_list_with_usernames = async (deps, options) => {
|
|
|
171
178
|
${where} ORDER BY al.seq DESC LIMIT $${param_index++} OFFSET $${param_index}`, [...params, limit, offset]);
|
|
172
179
|
};
|
|
173
180
|
/**
|
|
174
|
-
* List
|
|
175
|
-
*
|
|
176
|
-
* @param deps - query dependencies
|
|
177
|
-
* @param account_id - the account to query for
|
|
178
|
-
* @param limit - maximum entries to return
|
|
179
|
-
*/
|
|
180
|
-
export const query_audit_log_list_for_account = async (deps, account_id, limit = AUDIT_LOG_DEFAULT_LIMIT) => {
|
|
181
|
-
return deps.db.query(`SELECT * FROM audit_log
|
|
182
|
-
WHERE account_id = $1 OR target_account_id = $1
|
|
183
|
-
ORDER BY seq DESC LIMIT $2`, [account_id, limit]);
|
|
184
|
-
};
|
|
185
|
-
/**
|
|
186
|
-
* List permit grant/revoke events with resolved usernames.
|
|
181
|
+
* List role_grant grant/revoke events with resolved usernames.
|
|
187
182
|
*
|
|
188
183
|
* @param deps - query dependencies
|
|
189
184
|
* @param limit - maximum entries to return
|
|
190
185
|
* @param offset - number of entries to skip
|
|
191
|
-
* @returns
|
|
186
|
+
* @returns role_grant history events with `username` and `target_username`
|
|
192
187
|
*/
|
|
193
|
-
export const
|
|
188
|
+
export const query_audit_log_list_role_grant_history = async (deps, limit = AUDIT_LOG_DEFAULT_LIMIT, offset = 0) => {
|
|
194
189
|
return deps.db.query(`SELECT al.*,
|
|
195
190
|
a1.username AS username,
|
|
196
191
|
a2.username AS target_username
|
|
197
192
|
FROM audit_log al
|
|
198
193
|
LEFT JOIN account a1 ON a1.id = al.account_id
|
|
199
194
|
LEFT JOIN account a2 ON a2.id = al.target_account_id
|
|
200
|
-
WHERE al.event_type IN ('
|
|
195
|
+
WHERE al.event_type IN ('role_grant_create', 'role_grant_revoke')
|
|
201
196
|
ORDER BY al.seq DESC LIMIT $1 OFFSET $2`, [limit, offset]);
|
|
202
197
|
};
|
|
203
198
|
/**
|
|
@@ -212,34 +207,3 @@ export const query_audit_log_cleanup_before = async (deps, before) => {
|
|
|
212
207
|
const rows = await deps.db.query(`DELETE FROM audit_log WHERE created_at < $1 RETURNING id`, [before.toISOString()]);
|
|
213
208
|
return rows.length;
|
|
214
209
|
};
|
|
215
|
-
/**
|
|
216
|
-
* Log an audit event without blocking the caller.
|
|
217
|
-
*
|
|
218
|
-
* Errors are logged — audit logging never breaks auth flows. Uses
|
|
219
|
-
* `background_db` so entries persist even when the request transaction
|
|
220
|
-
* rolls back. Write and `on_audit_event` callback failures are logged separately.
|
|
221
|
-
*
|
|
222
|
-
* @param route - `background_db` and `pending_effects` from the route context
|
|
223
|
-
* @param input - the audit event to record
|
|
224
|
-
* @param deps - logger, `on_audit_event` callback, and optional `audit_log_config`
|
|
225
|
-
* @returns the settled promise (callers may ignore it)
|
|
226
|
-
* @mutates `audit_log` table - inserts a row via `background_db` (independent of the request transaction)
|
|
227
|
-
* @mutates `route.pending_effects` - pushes the in-flight settled promise for test flushing
|
|
228
|
-
*/
|
|
229
|
-
export const audit_log_fire_and_forget = (route, input, deps) => {
|
|
230
|
-
const { log, on_audit_event, audit_log_config = BUILTIN_AUDIT_LOG_CONFIG } = deps;
|
|
231
|
-
const p = query_audit_log({ db: route.background_db }, input, audit_log_config)
|
|
232
|
-
.then((event) => {
|
|
233
|
-
try {
|
|
234
|
-
on_audit_event(event);
|
|
235
|
-
}
|
|
236
|
-
catch (callback_err) {
|
|
237
|
-
log.error('Audit log on_audit_event callback failed:', callback_err);
|
|
238
|
-
}
|
|
239
|
-
})
|
|
240
|
-
.catch((err) => {
|
|
241
|
-
log.error('Audit log write failed:', err);
|
|
242
|
-
});
|
|
243
|
-
route.pending_effects.push(p);
|
|
244
|
-
return p;
|
|
245
|
-
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Audit log SSE stream route.
|
|
3
3
|
*
|
|
4
|
-
* The two list-reads (`audit_log_list`, `
|
|
4
|
+
* The two list-reads (`audit_log_list`, `audit_log_role_grant_history`) moved to
|
|
5
5
|
* RPC in `auth/admin_actions.ts`, and the admin session listing moved to
|
|
6
6
|
* `admin_session_list` on the same file. What remains here is the optional
|
|
7
7
|
* `GET /audit/stream` SSE route — streams aren't an action-kind, so they
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit_log_routes.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/audit_log_routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAEpD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAsB,KAAK,SAAS,EAAE,KAAK,eAAe,EAAC,MAAM,oBAAoB,CAAC;AAC7F,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"audit_log_routes.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/audit_log_routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAEpD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAsB,KAAK,SAAS,EAAE,KAAK,eAAe,EAAC,MAAM,oBAAoB,CAAC;AAC7F,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,oCAAoC,CAAC;AAQzE,yCAAyC;AACzC,MAAM,WAAW,oBAAoB;IACpC,+DAA+D;IAC/D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,MAAM,CAAC,EAAE;QACR,SAAS,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC,EAAE,gBAAgB,KAAK,MAAM,IAAI,CAAC;QAC1F,GAAG,EAAE,MAAM,CAAC;KACZ,CAAC;CACF;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,4BAA4B,GAAI,UAAU,oBAAoB,KAAG,KAAK,CAAC,SAAS,CAiC5F,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Audit log SSE stream route.
|
|
3
3
|
*
|
|
4
|
-
* The two list-reads (`audit_log_list`, `
|
|
4
|
+
* The two list-reads (`audit_log_list`, `audit_log_role_grant_history`) moved to
|
|
5
5
|
* RPC in `auth/admin_actions.ts`, and the admin session listing moved to
|
|
6
6
|
* `admin_session_list` on the same file. What remains here is the optional
|
|
7
7
|
* `GET /audit/stream` SSE route — streams aren't an action-kind, so they
|
|
@@ -15,6 +15,9 @@ import { z } from 'zod';
|
|
|
15
15
|
import { create_sse_response } from '../realtime/sse.js';
|
|
16
16
|
import { AUTH_SESSION_TOKEN_HASH_KEY, require_request_context } from './request_context.js';
|
|
17
17
|
import { AUDIT_LOG_CHANNEL } from '../realtime/sse_auth_guard.js';
|
|
18
|
+
import { ActingActor } from '../http/auth_shape.js';
|
|
19
|
+
/** Query schema for the audit-log SSE route — multi-actor admins pass `?acting=<uuid>`. */
|
|
20
|
+
const AuditStreamQuery = z.strictObject({ acting: ActingActor });
|
|
18
21
|
/**
|
|
19
22
|
* Create the optional audit-log SSE route spec.
|
|
20
23
|
*
|
|
@@ -33,15 +36,16 @@ export const create_audit_log_route_specs = (options) => {
|
|
|
33
36
|
{
|
|
34
37
|
method: 'GET',
|
|
35
38
|
path: '/audit/stream',
|
|
36
|
-
auth: {
|
|
39
|
+
auth: { account: 'required', actor: 'required', roles: [role] },
|
|
37
40
|
description: 'Subscribe to realtime audit log events',
|
|
41
|
+
query: AuditStreamQuery,
|
|
38
42
|
input: z.null(),
|
|
39
43
|
output: z.null(), // SSE — no JSON response
|
|
40
44
|
handler: (c) => {
|
|
41
45
|
const ctx = require_request_context(c);
|
|
42
46
|
// scope = session hash (capped → tabs-per-session limit and
|
|
43
47
|
// session-specific `session_revoke` close). groups = [account_id]
|
|
44
|
-
// (uncapped → coarse close on
|
|
48
|
+
// (uncapped → coarse close on role_grant_revoke / session_revoke_all
|
|
45
49
|
// / password_change).
|
|
46
50
|
const token_hash = c.get(AUTH_SESSION_TOKEN_HASH_KEY) ?? null;
|
|
47
51
|
const { response, stream } = create_sse_response(c, log);
|