@fuzdev/fuz_app 0.117.1 → 0.119.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 +301 -73
- package/dist/actions/action_rpc.d.ts.map +1 -1
- package/dist/actions/action_rpc.js +16 -1
- package/dist/actions/connection_closer.d.ts +136 -51
- package/dist/actions/connection_closer.d.ts.map +1 -1
- package/dist/actions/connection_closer.js +133 -34
- package/dist/actions/register_action_ws.d.ts +176 -24
- package/dist/actions/register_action_ws.d.ts.map +1 -1
- package/dist/actions/register_action_ws.js +581 -241
- package/dist/actions/register_ws_endpoint.d.ts +1 -0
- package/dist/actions/register_ws_endpoint.d.ts.map +1 -1
- package/dist/actions/register_ws_endpoint.js +1 -0
- package/dist/actions/socket.svelte.d.ts +43 -9
- package/dist/actions/socket.svelte.d.ts.map +1 -1
- package/dist/actions/socket.svelte.js +59 -8
- package/dist/actions/transports.d.ts +55 -1
- package/dist/actions/transports.d.ts.map +1 -1
- package/dist/actions/transports.js +55 -1
- package/dist/actions/transports_ws_auth_guard.d.ts +53 -67
- package/dist/actions/transports_ws_auth_guard.d.ts.map +1 -1
- package/dist/actions/transports_ws_auth_guard.js +87 -111
- package/dist/actions/transports_ws_backend.d.ts +212 -30
- package/dist/actions/transports_ws_backend.d.ts.map +1 -1
- package/dist/actions/transports_ws_backend.js +327 -70
- package/dist/actions/ws_endpoint_spec.d.ts +26 -13
- package/dist/actions/ws_endpoint_spec.d.ts.map +1 -1
- package/dist/auth/CLAUDE.md +125 -31
- package/dist/auth/account_actions.d.ts +12 -18
- package/dist/auth/account_actions.d.ts.map +1 -1
- package/dist/auth/account_actions.js +47 -33
- package/dist/auth/account_routes.d.ts +5 -11
- package/dist/auth/account_routes.d.ts.map +1 -1
- package/dist/auth/account_routes.js +40 -36
- package/dist/auth/account_schema.d.ts +27 -0
- package/dist/auth/account_schema.d.ts.map +1 -1
- package/dist/auth/account_schema.js +22 -0
- package/dist/auth/admin_actions.d.ts +8 -17
- package/dist/auth/admin_actions.d.ts.map +1 -1
- package/dist/auth/admin_actions.js +33 -21
- package/dist/auth/api_token_queries.d.ts +23 -2
- package/dist/auth/api_token_queries.d.ts.map +1 -1
- package/dist/auth/api_token_queries.js +39 -3
- package/dist/auth/audit_emitter.d.ts +72 -44
- package/dist/auth/audit_emitter.d.ts.map +1 -1
- package/dist/auth/audit_emitter.js +60 -16
- package/dist/auth/audit_log_route_schema.js +7 -7
- package/dist/auth/audit_log_routes.d.ts +31 -6
- package/dist/auth/audit_log_routes.d.ts.map +1 -1
- package/dist/auth/audit_log_routes.js +85 -11
- package/dist/auth/audit_log_schema.d.ts +48 -0
- package/dist/auth/audit_log_schema.d.ts.map +1 -1
- package/dist/auth/audit_log_schema.js +58 -0
- package/dist/auth/bootstrap_account.d.ts +3 -2
- package/dist/auth/bootstrap_account.d.ts.map +1 -1
- package/dist/auth/bootstrap_account.js +3 -3
- package/dist/auth/cleanup.d.ts +219 -30
- package/dist/auth/cleanup.d.ts.map +1 -1
- package/dist/auth/cleanup.js +260 -45
- package/dist/auth/deps.d.ts +29 -1
- package/dist/auth/deps.d.ts.map +1 -1
- package/dist/auth/migrations.d.ts.map +1 -1
- package/dist/auth/migrations.js +27 -0
- package/dist/auth/resolved_auth.d.ts +105 -0
- package/dist/auth/resolved_auth.d.ts.map +1 -0
- package/dist/auth/resolved_auth.js +124 -0
- package/dist/auth/role_grant_offer_ddl.d.ts +4 -2
- package/dist/auth/role_grant_offer_ddl.d.ts.map +1 -1
- package/dist/auth/role_grant_offer_ddl.js +10 -3
- package/dist/auth/role_grant_offer_queries.d.ts +16 -7
- package/dist/auth/role_grant_offer_queries.d.ts.map +1 -1
- package/dist/auth/role_grant_offer_queries.js +33 -15
- package/dist/auth/role_grant_offer_schema.d.ts +9 -0
- package/dist/auth/role_grant_offer_schema.d.ts.map +1 -1
- package/dist/auth/session_middleware.d.ts +8 -1
- package/dist/auth/session_middleware.d.ts.map +1 -1
- package/dist/auth/session_middleware.js +9 -3
- package/dist/auth/session_queries.d.ts +31 -6
- package/dist/auth/session_queries.d.ts.map +1 -1
- package/dist/auth/session_queries.js +31 -6
- package/dist/auth/standard_rpc_actions.d.ts +9 -9
- package/dist/auth/standard_rpc_actions.d.ts.map +1 -1
- package/dist/auth/standard_rpc_actions.js +3 -3
- package/dist/db/CLAUDE.md +7 -1
- package/dist/db/migrate.d.ts +8 -13
- package/dist/db/migrate.d.ts.map +1 -1
- package/dist/db/migrate.js +9 -38
- package/dist/db/status.d.ts +58 -7
- package/dist/db/status.d.ts.map +1 -1
- package/dist/db/status.js +205 -97
- package/dist/http/CLAUDE.md +7 -3
- package/dist/http/db_routes.d.ts +6 -2
- package/dist/http/db_routes.d.ts.map +1 -1
- package/dist/http/db_routes.js +2 -2
- package/dist/periodic.d.ts +80 -0
- package/dist/periodic.d.ts.map +1 -0
- package/dist/periodic.js +122 -0
- package/dist/realtime/sse_auth_guard.d.ts +79 -49
- package/dist/realtime/sse_auth_guard.d.ts.map +1 -1
- package/dist/realtime/sse_auth_guard.js +103 -73
- package/dist/realtime/subscriber_registry.d.ts +119 -8
- package/dist/realtime/subscriber_registry.d.ts.map +1 -1
- package/dist/realtime/subscriber_registry.js +184 -25
- package/dist/runtime/deno.d.ts.map +1 -1
- package/dist/runtime/deno.js +9 -6
- package/dist/runtime/deps.d.ts +3 -2
- package/dist/runtime/deps.d.ts.map +1 -1
- package/dist/runtime/secure_file.d.ts +23 -9
- package/dist/runtime/secure_file.d.ts.map +1 -1
- package/dist/runtime/secure_file.js +29 -10
- package/dist/server/app_backend.d.ts +13 -2
- package/dist/server/app_backend.d.ts.map +1 -1
- package/dist/server/app_backend.js +5 -2
- package/dist/server/app_server.d.ts +55 -15
- package/dist/server/app_server.d.ts.map +1 -1
- package/dist/server/app_server.js +41 -13
- package/dist/testing/CLAUDE.md +140 -48
- package/dist/testing/app_server.d.ts +2 -2
- package/dist/testing/app_server.d.ts.map +1 -1
- package/dist/testing/app_server.js +11 -2
- package/dist/testing/audit_drift_guard.d.ts +3 -52
- package/dist/testing/audit_drift_guard.d.ts.map +1 -1
- package/dist/testing/audit_drift_guard.js +2 -46
- package/dist/testing/connection_closer_helpers.d.ts +9 -22
- package/dist/testing/connection_closer_helpers.d.ts.map +1 -1
- package/dist/testing/connection_closer_helpers.js +11 -17
- package/dist/testing/cross_backend/capabilities.d.ts +67 -13
- package/dist/testing/cross_backend/capabilities.d.ts.map +1 -1
- package/dist/testing/cross_backend/capabilities.js +27 -12
- package/dist/testing/cross_backend/default_backend_configs.d.ts.map +1 -1
- package/dist/testing/cross_backend/default_backend_configs.js +21 -0
- package/dist/testing/cross_backend/expected_schema.json +1 -0
- package/dist/testing/cross_backend/role_grant_offer_notification_ws.d.ts.map +1 -1
- package/dist/testing/cross_backend/role_grant_offer_notification_ws.js +13 -4
- package/dist/testing/cross_backend/rust_spine_stub_backend_config.d.ts.map +1 -1
- package/dist/testing/cross_backend/rust_spine_stub_backend_config.js +4 -1
- package/dist/testing/cross_backend/session_cap.d.ts +13 -0
- package/dist/testing/cross_backend/session_cap.d.ts.map +1 -1
- package/dist/testing/cross_backend/session_cap.js +55 -19
- package/dist/testing/cross_backend/sse_round_trip.d.ts +10 -2
- package/dist/testing/cross_backend/sse_round_trip.d.ts.map +1 -1
- package/dist/testing/cross_backend/sse_round_trip.js +93 -26
- package/dist/testing/cross_backend/testing_server_bun.js +4 -4
- package/dist/testing/cross_backend/ts_spine_backend_config.d.ts.map +1 -1
- package/dist/testing/cross_backend/ts_spine_backend_config.js +10 -2
- package/dist/testing/cross_backend/ws_connection_cap.d.ts +35 -0
- package/dist/testing/cross_backend/ws_connection_cap.d.ts.map +1 -0
- package/dist/testing/cross_backend/ws_connection_cap.js +131 -0
- package/dist/testing/cross_backend/ws_round_trip.d.ts +2 -1
- package/dist/testing/cross_backend/ws_round_trip.d.ts.map +1 -1
- package/dist/testing/cross_backend/ws_round_trip.js +156 -19
- package/dist/testing/sse_round_trip.d.ts +6 -4
- package/dist/testing/sse_round_trip.d.ts.map +1 -1
- package/dist/testing/stubs.d.ts +1 -1
- package/dist/testing/stubs.d.ts.map +1 -1
- package/dist/testing/stubs.js +6 -4
- package/dist/testing/transports/sse_transport.d.ts +1 -1
- package/dist/testing/transports/ws_client.d.ts +7 -0
- package/dist/testing/transports/ws_client.d.ts.map +1 -1
- package/dist/testing/transports/ws_raw_client.d.ts +51 -0
- package/dist/testing/transports/ws_raw_client.d.ts.map +1 -0
- package/dist/testing/transports/ws_raw_client.js +156 -0
- package/dist/testing/transports/ws_transport.d.ts +28 -0
- package/dist/testing/transports/ws_transport.d.ts.map +1 -1
- package/dist/testing/transports/ws_transport.js +45 -1
- package/dist/testing/ws_round_trip.d.ts +8 -3
- package/dist/testing/ws_round_trip.d.ts.map +1 -1
- package/dist/testing/ws_round_trip.js +19 -4
- package/dist/ui/AdminAccounts.svelte +4 -3
- package/dist/ui/AdminAccounts.svelte.d.ts.map +1 -1
- package/dist/ui/AdminOverview.svelte +3 -1
- package/dist/ui/AdminOverview.svelte.d.ts.map +1 -1
- package/dist/ui/CLAUDE.md +22 -6
- package/dist/ui/admin_accounts_state.svelte.d.ts +15 -1
- package/dist/ui/admin_accounts_state.svelte.d.ts.map +1 -1
- package/dist/ui/admin_accounts_state.svelte.js +16 -0
- package/dist/ui/auth_state.svelte.d.ts +25 -1
- package/dist/ui/auth_state.svelte.d.ts.map +1 -1
- package/dist/ui/auth_state.svelte.js +28 -1
- package/package.json +2 -2
|
@@ -121,6 +121,33 @@ export declare const is_role_grant_active: (p: {
|
|
|
121
121
|
revoked_at?: string | null;
|
|
122
122
|
expires_at: string | null;
|
|
123
123
|
}, now?: Date) => boolean;
|
|
124
|
+
/**
|
|
125
|
+
* Whether `role_grants` holds a live global grant of `role` — `scope_id` is
|
|
126
|
+
* `null` and the grant passes `is_role_grant_active`.
|
|
127
|
+
*
|
|
128
|
+
* This is the question a role gate asks. A scoped grant confers its role on
|
|
129
|
+
* one resource only, and a scoped grant of a builtin role (`admin`, `keeper`)
|
|
130
|
+
* confers nothing, so matching on the role name alone would read a grant for
|
|
131
|
+
* one resource as authority everywhere. Server-side the same rule is
|
|
132
|
+
* `has_scoped_role(ctx, role, null)` over a request context and
|
|
133
|
+
* `query_account_has_global_role` in SQL; this is the form for a bare list of
|
|
134
|
+
* grants — `AuthState.role_grants`, an admin listing row.
|
|
135
|
+
*
|
|
136
|
+
* The scope match is `scope_id === null`, so a grant decoded without the
|
|
137
|
+
* field is not read as global. Client-side the answer shapes the UI and
|
|
138
|
+
* nothing else: the server re-checks every request.
|
|
139
|
+
*
|
|
140
|
+
* @param role_grants - the grants to search, e.g. `AuthState.role_grants`
|
|
141
|
+
* @param role - the role to check
|
|
142
|
+
* @param now - current time (defaults to `new Date()`, pass for testability)
|
|
143
|
+
* @returns `true` iff a live grant of `role` with no scope is present
|
|
144
|
+
*/
|
|
145
|
+
export declare const has_global_role: (role_grants: ReadonlyArray<{
|
|
146
|
+
role: string;
|
|
147
|
+
scope_id: string | null;
|
|
148
|
+
revoked_at?: string | null;
|
|
149
|
+
expires_at: string | null;
|
|
150
|
+
}>, role: string, now?: Date) => boolean;
|
|
124
151
|
/**
|
|
125
152
|
* A session's storage key — the blake3 hash of its raw token, branded so a
|
|
126
153
|
* bare `string` can't stand in for one. `Blake3Hash` (`hash_schemas.ts`) is
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"account_schema.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/account_schema.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"account_schema.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/account_schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -49,6 +49,28 @@ export const ROLE_GRANT_REVOKED_REASON_LENGTH_MAX = 500;
|
|
|
49
49
|
* @returns `true` when the grant is neither revoked nor expired
|
|
50
50
|
*/
|
|
51
51
|
export const is_role_grant_active = (p, now = new Date()) => !p.revoked_at && (!p.expires_at || is_iso8601_seconds_live(p.expires_at, now.getTime()));
|
|
52
|
+
/**
|
|
53
|
+
* Whether `role_grants` holds a live global grant of `role` — `scope_id` is
|
|
54
|
+
* `null` and the grant passes `is_role_grant_active`.
|
|
55
|
+
*
|
|
56
|
+
* This is the question a role gate asks. A scoped grant confers its role on
|
|
57
|
+
* one resource only, and a scoped grant of a builtin role (`admin`, `keeper`)
|
|
58
|
+
* confers nothing, so matching on the role name alone would read a grant for
|
|
59
|
+
* one resource as authority everywhere. Server-side the same rule is
|
|
60
|
+
* `has_scoped_role(ctx, role, null)` over a request context and
|
|
61
|
+
* `query_account_has_global_role` in SQL; this is the form for a bare list of
|
|
62
|
+
* grants — `AuthState.role_grants`, an admin listing row.
|
|
63
|
+
*
|
|
64
|
+
* The scope match is `scope_id === null`, so a grant decoded without the
|
|
65
|
+
* field is not read as global. Client-side the answer shapes the UI and
|
|
66
|
+
* nothing else: the server re-checks every request.
|
|
67
|
+
*
|
|
68
|
+
* @param role_grants - the grants to search, e.g. `AuthState.role_grants`
|
|
69
|
+
* @param role - the role to check
|
|
70
|
+
* @param now - current time (defaults to `new Date()`, pass for testability)
|
|
71
|
+
* @returns `true` iff a live grant of `role` with no scope is present
|
|
72
|
+
*/
|
|
73
|
+
export const has_global_role = (role_grants, role, now = new Date()) => role_grants.some((p) => p.role === role && p.scope_id === null && is_role_grant_active(p, now));
|
|
52
74
|
/**
|
|
53
75
|
* A session's storage key — the blake3 hash of its raw token, branded so a
|
|
54
76
|
* bare `string` can't stand in for one. `Blake3Hash` (`hash_schemas.ts`) is
|
|
@@ -29,9 +29,8 @@
|
|
|
29
29
|
* @module
|
|
30
30
|
*/
|
|
31
31
|
import { type RpcAction } from '../actions/action_rpc.js';
|
|
32
|
-
import type { ConnectionCloser } from '../actions/connection_closer.js';
|
|
33
32
|
import { type RoleSchemaResult } from './role_schema.js';
|
|
34
|
-
import type {
|
|
33
|
+
import type { RevokingActionFactoryDeps } from './deps.js';
|
|
35
34
|
/** Options for `create_admin_actions`. */
|
|
36
35
|
export interface AdminActionOptions {
|
|
37
36
|
/**
|
|
@@ -41,26 +40,18 @@ export interface AdminActionOptions {
|
|
|
41
40
|
* `admin_account_list`.
|
|
42
41
|
*/
|
|
43
42
|
roles?: RoleSchemaResult;
|
|
44
|
-
/**
|
|
45
|
-
* Live-connection closer — when set, `admin_session_revoke_all` and
|
|
46
|
-
* `admin_token_revoke_all` handlers eagerly close affected WebSocket
|
|
47
|
-
* sockets for the target account BEFORE emitting the corresponding
|
|
48
|
-
* audit event. Mirrors the self-service surface (see
|
|
49
|
-
* `AccountActionOptions.connection_closer`). `BackendWebsocketTransport`
|
|
50
|
-
* satisfies this interface structurally. When absent, only the
|
|
51
|
-
* listener-based close (`transports_ws_auth_guard`) runs.
|
|
52
|
-
*/
|
|
53
|
-
connection_closer?: ConnectionCloser | null;
|
|
54
43
|
}
|
|
55
44
|
/**
|
|
56
45
|
* Create the admin-only RPC actions.
|
|
57
46
|
*
|
|
58
|
-
* @param deps - `
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
* `AuditLogConfig`.
|
|
47
|
+
* @param deps - `RevokingActionFactoryDeps` (`log`, `audit`,
|
|
48
|
+
* `connection_closer`). `log` drives RPC-internal error logging;
|
|
49
|
+
* `audit.emit` writes audit rows via the captured pool. The bound emitter
|
|
50
|
+
* encapsulates listener fan-out and the optional `AuditLogConfig`.
|
|
51
|
+
* `connection_closer` closes the target account's live connections after a
|
|
52
|
+
* revoke-all, delete, or purge commits.
|
|
62
53
|
* @param options - role schema for `grantable_roles` derivation
|
|
63
54
|
* @returns the `RpcAction` array to spread into a `create_rpc_endpoint` call
|
|
64
55
|
*/
|
|
65
|
-
export declare const create_admin_actions: (deps:
|
|
56
|
+
export declare const create_admin_actions: (deps: RevokingActionFactoryDeps, options?: AdminActionOptions) => Array<RpcAction>;
|
|
66
57
|
//# sourceMappingURL=admin_actions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin_actions.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/admin_actions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,EAAuC,KAAK,SAAS,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"admin_actions.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/admin_actions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,EAAuC,KAAK,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAG/F,OAAO,EAKN,KAAK,gBAAgB,EACrB,MAAM,kBAAkB,CAAC;AAyC1B,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,WAAW,CAAC;AA0D3D,0CAA0C;AAC1C,MAAM,WAAW,kBAAkB;IAClC;;;;;OAKG;IACH,KAAK,CAAC,EAAE,gBAAgB,CAAC;CACzB;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,oBAAoB,GAChC,MAAM,yBAAyB,EAC/B,UAAS,kBAAuB,KAC9B,KAAK,CAAC,SAAS,CAogBjB,CAAC"}
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
* @module
|
|
30
30
|
*/
|
|
31
31
|
import { rpc_action } from '../actions/action_rpc.js';
|
|
32
|
+
import { queue_connection_close } from '../actions/connection_closer.js';
|
|
32
33
|
import { jsonrpc_errors } from '../http/jsonrpc_errors.js';
|
|
33
34
|
import { builtin_role_specs_by_name, list_roles_with_grant_path, ROLE_ADMIN, ROLE_KEEPER } from './role_schema.js';
|
|
34
35
|
import { has_scoped_role } from './request_context.js';
|
|
@@ -47,17 +48,19 @@ import { admin_account_list_action_spec, admin_session_list_action_spec, admin_s
|
|
|
47
48
|
/**
|
|
48
49
|
* Create the admin-only RPC actions.
|
|
49
50
|
*
|
|
50
|
-
* @param deps - `
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
* `AuditLogConfig`.
|
|
51
|
+
* @param deps - `RevokingActionFactoryDeps` (`log`, `audit`,
|
|
52
|
+
* `connection_closer`). `log` drives RPC-internal error logging;
|
|
53
|
+
* `audit.emit` writes audit rows via the captured pool. The bound emitter
|
|
54
|
+
* encapsulates listener fan-out and the optional `AuditLogConfig`.
|
|
55
|
+
* `connection_closer` closes the target account's live connections after a
|
|
56
|
+
* revoke-all, delete, or purge commits.
|
|
54
57
|
* @param options - role schema for `grantable_roles` derivation
|
|
55
58
|
* @returns the `RpcAction` array to spread into a `create_rpc_endpoint` call
|
|
56
59
|
*/
|
|
57
60
|
export const create_admin_actions = (deps, options = {}) => {
|
|
58
61
|
const role_specs = options.roles?.role_specs ?? builtin_role_specs_by_name;
|
|
59
62
|
const grantable_roles = list_roles_with_grant_path(role_specs, GRANT_PATH_ADMIN);
|
|
60
|
-
const connection_closer =
|
|
63
|
+
const { connection_closer } = deps;
|
|
61
64
|
const account_list_handler = async (input, ctx) => {
|
|
62
65
|
const accounts = await query_admin_account_list(ctx, {
|
|
63
66
|
limit: input.limit,
|
|
@@ -91,15 +94,15 @@ export const create_admin_actions = (deps, options = {}) => {
|
|
|
91
94
|
throw jsonrpc_errors.not_found('account', { reason: ERROR_ACCOUNT_NOT_FOUND });
|
|
92
95
|
}
|
|
93
96
|
const count = await query_session_revoke_all_for_account(ctx, input.account_id);
|
|
94
|
-
//
|
|
95
|
-
//
|
|
96
|
-
//
|
|
97
|
-
//
|
|
98
|
-
// out-of-band emit sites. Idempotent — see
|
|
97
|
+
// Close the target account's live connections once the revoke has
|
|
98
|
+
// committed — queued, so it never runs before the commit or on
|
|
99
|
+
// rollback, and it does not depend on the audit write below. Queued at
|
|
100
|
+
// every `count`, zero included. See
|
|
99
101
|
// `account_actions.ts::session_revoke_handler`.
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
102
|
+
queue_connection_close(ctx, connection_closer, {
|
|
103
|
+
kind: 'account',
|
|
104
|
+
account_id: input.account_id
|
|
105
|
+
});
|
|
103
106
|
// TOCTOU window — admin B hard-deletes `input.account_id` between the
|
|
104
107
|
// pre-check above and this emit; the FK rejects the row, the audit
|
|
105
108
|
// emitter logs + swallows, and the operation goes unaudited. Bounded
|
|
@@ -138,10 +141,11 @@ export const create_admin_actions = (deps, options = {}) => {
|
|
|
138
141
|
throw jsonrpc_errors.not_found('account', { reason: ERROR_ACCOUNT_NOT_FOUND });
|
|
139
142
|
}
|
|
140
143
|
const count = await query_revoke_all_api_tokens_for_account(ctx, input.account_id);
|
|
141
|
-
//
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
144
|
+
// Post-commit close — see `session_revoke_all_handler`.
|
|
145
|
+
queue_connection_close(ctx, connection_closer, {
|
|
146
|
+
kind: 'account',
|
|
147
|
+
account_id: input.account_id
|
|
148
|
+
});
|
|
145
149
|
// TOCTOU window — see `session_revoke_all_handler` for the rationale on
|
|
146
150
|
// keeping `target_account_id` populated rather than switching to the
|
|
147
151
|
// failure-shape.
|
|
@@ -314,8 +318,12 @@ export const create_admin_actions = (deps, options = {}) => {
|
|
|
314
318
|
}
|
|
315
319
|
await query_session_revoke_all_for_account(ctx, target_account_id);
|
|
316
320
|
await query_revoke_all_api_tokens_for_account(ctx, target_account_id);
|
|
317
|
-
|
|
318
|
-
|
|
321
|
+
// The tombstone ends every credential of the account; its connections
|
|
322
|
+
// close once that has committed.
|
|
323
|
+
queue_connection_close(ctx, connection_closer, {
|
|
324
|
+
kind: 'account',
|
|
325
|
+
account_id: target_account_id
|
|
326
|
+
});
|
|
319
327
|
deps.audit.emit(ctx, {
|
|
320
328
|
event_type: 'account_delete',
|
|
321
329
|
actor_id: auth.actor.id,
|
|
@@ -366,8 +374,12 @@ export const create_admin_actions = (deps, options = {}) => {
|
|
|
366
374
|
});
|
|
367
375
|
throw jsonrpc_errors.not_found('account', { reason: ERROR_ACCOUNT_NOT_FOUND });
|
|
368
376
|
}
|
|
369
|
-
|
|
370
|
-
|
|
377
|
+
// The cascade removed every credential of the account; its connections
|
|
378
|
+
// close once that has committed.
|
|
379
|
+
queue_connection_close(ctx, connection_closer, {
|
|
380
|
+
kind: 'account',
|
|
381
|
+
account_id: input.account_id
|
|
382
|
+
});
|
|
371
383
|
deps.log.warn(`account hard-purged (irreversible cascading delete): ${input.account_id} by actor ${auth.actor.id}`);
|
|
372
384
|
deps.audit.emit(ctx, {
|
|
373
385
|
event_type: 'account_purge',
|
|
@@ -47,6 +47,22 @@ export declare const query_create_api_token: (deps: QueryDeps, id: string, accou
|
|
|
47
47
|
* @mutates `pending_effects` - pushes the in-flight tracking promise when provided
|
|
48
48
|
*/
|
|
49
49
|
export declare const query_validate_api_token: (deps: ApiTokenQueryDeps, raw_token: string, ip: string | undefined, pending_effects: Array<Promise<void>> | undefined) => Promise<ApiToken | undefined>;
|
|
50
|
+
/**
|
|
51
|
+
* Look up the owning account of a live API token — one that still exists and
|
|
52
|
+
* has not expired — by its public id.
|
|
53
|
+
*
|
|
54
|
+
* The by-id counterpart of `query_validate_api_token`, for re-checking a token
|
|
55
|
+
* that already authenticated (`revalidate_resolved_auth`): no hash, no scope
|
|
56
|
+
* decode, and no touch of `last_used_at` / `last_used_ip` — a re-check is not
|
|
57
|
+
* a use. "Live" is the same predicate in both (`API_TOKEN_IS_LIVE`). The scope
|
|
58
|
+
* document is not re-read: the resolved credential carries the scope it was
|
|
59
|
+
* admitted with, and nothing rewrites the column after the mint.
|
|
60
|
+
*
|
|
61
|
+
* @param deps - query dependencies
|
|
62
|
+
* @param id - the public token id (e.g. `tok_abc123`)
|
|
63
|
+
* @returns the owning account id, or `undefined` when the token is gone or expired
|
|
64
|
+
*/
|
|
65
|
+
export declare const query_api_token_live_account: (deps: QueryDeps, id: string) => Promise<string | undefined>;
|
|
50
66
|
/**
|
|
51
67
|
* Revoke all tokens for an account.
|
|
52
68
|
*
|
|
@@ -91,11 +107,16 @@ export declare const query_api_token_list_for_account: (deps: QueryDeps, account
|
|
|
91
107
|
* caveat, as `query_session_enforce_limit` — deterministic survivors under a
|
|
92
108
|
* `created_at` tie, not a guarantee that the row just inserted survives.
|
|
93
109
|
*
|
|
110
|
+
* Deleting a token row does not end the connections it opened, so the
|
|
111
|
+
* returned ids are what the caller closes once the transaction commits
|
|
112
|
+
* (`queue_connection_close` with a `token` target) — `account_token_create`
|
|
113
|
+
* does.
|
|
114
|
+
*
|
|
94
115
|
* @param deps - query dependencies (must be transaction-scoped)
|
|
95
116
|
* @param account_id - the account to enforce the limit for
|
|
96
117
|
* @param max_tokens - maximum number of tokens to keep
|
|
97
|
-
* @returns the
|
|
118
|
+
* @returns the evicted tokens' ids, empty when nothing was evicted
|
|
98
119
|
* @mutates `api_token` table - deletes the oldest rows past the cap
|
|
99
120
|
*/
|
|
100
|
-
export declare const query_api_token_enforce_limit: (deps: QueryDeps, account_id: string, max_tokens: number) => Promise<
|
|
121
|
+
export declare const query_api_token_enforce_limit: (deps: QueryDeps, account_id: string, max_tokens: number) => Promise<Array<string>>;
|
|
101
122
|
//# sourceMappingURL=api_token_queries.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api_token_queries.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/api_token_queries.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAGrD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAE,KAAK,UAAU,EAAmD,MAAM,kBAAkB,CAAC;AAEpG,yEAAyE;AACzE,MAAM,WAAW,iBAAkB,SAAQ,SAAS;IACnD,GAAG,EAAE,MAAM,CAAC;CACZ;AAED;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,0HAUoB,CAAC;
|
|
1
|
+
{"version":3,"file":"api_token_queries.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/api_token_queries.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAGrD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAE,KAAK,UAAU,EAAmD,MAAM,kBAAkB,CAAC;AAEpG,yEAAyE;AACzE,MAAM,WAAW,iBAAkB,SAAQ,SAAS;IACnD,GAAG,EAAE,MAAM,CAAC;CACZ;AAED;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,0HAUoB,CAAC;AA6BnD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,sBAAsB,GAClC,MAAM,SAAS,EACf,IAAI,MAAM,EACV,YAAY,MAAM,EAClB,MAAM,MAAM,EACZ,YAAY,MAAM,EAClB,OAAO,UAAU,EACjB,aAAa,IAAI,GAAG,IAAI,KACtB,OAAO,CAAC,QAAQ,CAelB,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,wBAAwB,GACpC,MAAM,iBAAiB,EACvB,WAAW,MAAM,EACjB,IAAI,MAAM,GAAG,SAAS,EACtB,iBAAiB,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,SAAS,KAC/C,OAAO,CAAC,QAAQ,GAAG,SAAS,CAgC9B,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,4BAA4B,GACxC,MAAM,SAAS,EACf,IAAI,MAAM,KACR,OAAO,CAAC,MAAM,GAAG,SAAS,CAM5B,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,uCAAuC,GACnD,MAAM,SAAS,EACf,YAAY,MAAM,KAChB,OAAO,CAAC,MAAM,CAMhB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,kCAAkC,GAC9C,MAAM,SAAS,EACf,IAAI,MAAM,EACV,YAAY,MAAM,KAChB,OAAO,CAAC,OAAO,CAMjB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,gCAAgC,GAC5C,MAAM,SAAS,EACf,YAAY,MAAM,KAChB,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAM7C,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,6BAA6B,GACzC,MAAM,SAAS,EACf,YAAY,MAAM,EAClB,YAAY,MAAM,KAChB,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAYvB,CAAC"}
|
|
@@ -36,6 +36,18 @@ const api_token_expr = iso8601_timestamp_expr(API_TOKEN_COLUMNS, [
|
|
|
36
36
|
'last_used_at',
|
|
37
37
|
'created_at'
|
|
38
38
|
])('');
|
|
39
|
+
/**
|
|
40
|
+
* The `WHERE` fragment that makes an `api_token` row **live**: not expired (an
|
|
41
|
+
* eternal token has no expiry).
|
|
42
|
+
*
|
|
43
|
+
* One definition for every query that decides whether a token authenticates —
|
|
44
|
+
* the resolve path's `query_validate_api_token` and the re-check's
|
|
45
|
+
* `query_api_token_live_account` — so a condition added to one is added to
|
|
46
|
+
* both, and the re-check can never admit a token resolution would refuse. A
|
|
47
|
+
* new liveness condition (a `revoked_at`, a `disabled` flag) goes here. The
|
|
48
|
+
* twin of the Rust spine's `API_TOKEN_IS_LIVE`.
|
|
49
|
+
*/
|
|
50
|
+
const API_TOKEN_IS_LIVE = '(expires_at IS NULL OR expires_at > NOW())';
|
|
39
51
|
/**
|
|
40
52
|
* Store a new API token (the hash, not the raw token).
|
|
41
53
|
*
|
|
@@ -80,7 +92,7 @@ export const query_validate_api_token = async (deps, raw_token, ip, pending_effe
|
|
|
80
92
|
const token_hash = hash_api_token(raw_token);
|
|
81
93
|
const row = await deps.db.query_one(`SELECT ${columns_sql(API_TOKEN_COLUMNS, api_token_expr)} FROM api_token
|
|
82
94
|
WHERE token_hash = $1
|
|
83
|
-
AND
|
|
95
|
+
AND ${API_TOKEN_IS_LIVE}`, [token_hash]);
|
|
84
96
|
if (!row)
|
|
85
97
|
return undefined;
|
|
86
98
|
// **Fail-closed on an unreadable scope**: refuse the credential, the same
|
|
@@ -104,6 +116,25 @@ export const query_validate_api_token = async (deps, raw_token, ip, pending_effe
|
|
|
104
116
|
pending_effects?.push(p);
|
|
105
117
|
return row;
|
|
106
118
|
};
|
|
119
|
+
/**
|
|
120
|
+
* Look up the owning account of a live API token — one that still exists and
|
|
121
|
+
* has not expired — by its public id.
|
|
122
|
+
*
|
|
123
|
+
* The by-id counterpart of `query_validate_api_token`, for re-checking a token
|
|
124
|
+
* that already authenticated (`revalidate_resolved_auth`): no hash, no scope
|
|
125
|
+
* decode, and no touch of `last_used_at` / `last_used_ip` — a re-check is not
|
|
126
|
+
* a use. "Live" is the same predicate in both (`API_TOKEN_IS_LIVE`). The scope
|
|
127
|
+
* document is not re-read: the resolved credential carries the scope it was
|
|
128
|
+
* admitted with, and nothing rewrites the column after the mint.
|
|
129
|
+
*
|
|
130
|
+
* @param deps - query dependencies
|
|
131
|
+
* @param id - the public token id (e.g. `tok_abc123`)
|
|
132
|
+
* @returns the owning account id, or `undefined` when the token is gone or expired
|
|
133
|
+
*/
|
|
134
|
+
export const query_api_token_live_account = async (deps, id) => {
|
|
135
|
+
const row = await deps.db.query_one(`SELECT account_id FROM api_token WHERE id = $1 AND ${API_TOKEN_IS_LIVE}`, [id]);
|
|
136
|
+
return row?.account_id;
|
|
137
|
+
};
|
|
107
138
|
/**
|
|
108
139
|
* Revoke all tokens for an account.
|
|
109
140
|
*
|
|
@@ -157,10 +188,15 @@ export const query_api_token_list_for_account = async (deps, account_id) => {
|
|
|
157
188
|
* caveat, as `query_session_enforce_limit` — deterministic survivors under a
|
|
158
189
|
* `created_at` tie, not a guarantee that the row just inserted survives.
|
|
159
190
|
*
|
|
191
|
+
* Deleting a token row does not end the connections it opened, so the
|
|
192
|
+
* returned ids are what the caller closes once the transaction commits
|
|
193
|
+
* (`queue_connection_close` with a `token` target) — `account_token_create`
|
|
194
|
+
* does.
|
|
195
|
+
*
|
|
160
196
|
* @param deps - query dependencies (must be transaction-scoped)
|
|
161
197
|
* @param account_id - the account to enforce the limit for
|
|
162
198
|
* @param max_tokens - maximum number of tokens to keep
|
|
163
|
-
* @returns the
|
|
199
|
+
* @returns the evicted tokens' ids, empty when nothing was evicted
|
|
164
200
|
* @mutates `api_token` table - deletes the oldest rows past the cap
|
|
165
201
|
*/
|
|
166
202
|
export const query_api_token_enforce_limit = async (deps, account_id, max_tokens) => {
|
|
@@ -171,5 +207,5 @@ export const query_api_token_enforce_limit = async (deps, account_id, max_tokens
|
|
|
171
207
|
ORDER BY created_at DESC, id DESC
|
|
172
208
|
OFFSET $2
|
|
173
209
|
) RETURNING id`, [account_id, max_tokens]);
|
|
174
|
-
return rows.
|
|
210
|
+
return rows.map((row) => row.id);
|
|
175
211
|
};
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
* transactional `db` (which would be rolled back with the parent on a
|
|
12
12
|
* handler throw).
|
|
13
13
|
*
|
|
14
|
-
*
|
|
14
|
+
* These methods cover every fan-out shape the auth domain needs
|
|
15
|
+
* (`add_listener` and `listener_count` manage the listener chain):
|
|
15
16
|
*
|
|
16
17
|
* - `emit(ctx, input)` — fire-and-forget pool write. Pushes the in-flight
|
|
17
18
|
* promise onto `ctx.pending_effects` for post-response flushing. Errors are
|
|
@@ -22,49 +23,71 @@
|
|
|
22
23
|
* `actor_id` / `account_id` / `ip` boilerplate every role-grant-shape audit
|
|
23
24
|
* site repeated. Delegates to `emit`.
|
|
24
25
|
* - `emit_pool(input)` — awaitable pool write for code paths without a
|
|
25
|
-
*
|
|
26
|
-
* Same write-then-notify semantics as `emit`, just synchronous-with-await.
|
|
26
|
+
* request context (ad-hoc maintenance scripts). Writes, then notifies.
|
|
27
27
|
* - `notify(event)` — fan out an already-written audit row (e.g. rows
|
|
28
28
|
* returned by `query_accept_offer` that were inserted in-transaction by
|
|
29
|
-
* the query layer
|
|
30
|
-
*
|
|
29
|
+
* the query layer, or the offer-expiry rows `auth/cleanup.ts` writes in
|
|
30
|
+
* its sweep transaction). Runs every registered listener; per-listener
|
|
31
|
+
* throws are isolated.
|
|
32
|
+
*
|
|
33
|
+
* ## When listeners hear about a row
|
|
34
|
+
*
|
|
35
|
+
* `emit` writes the row at once, on the pool, whatever its outcome — the write
|
|
36
|
+
* is outside the request's transaction, so it survives a rollback. Listener
|
|
37
|
+
* fan-out is a separate step, and it depends on the outcome:
|
|
38
|
+
*
|
|
39
|
+
* - A **failure** row is announced as soon as it is written. It records an
|
|
40
|
+
* attempt, which happened whether or not the request's transaction commits.
|
|
41
|
+
* - A **success** row is announced only after the request's transaction
|
|
42
|
+
* commits, and never when the handler throws: the fan-out is queued on
|
|
43
|
+
* `ctx.post_commit_effects` and awaits the write. A success row reports a
|
|
44
|
+
* state change, and the listeners act on it — the revocation listeners close
|
|
45
|
+
* connections, the audit stream broadcasts it. Announced before the commit,
|
|
46
|
+
* a close could run while the revoked credential still reads as valid, and a
|
|
47
|
+
* rolled-back revocation would close connections anyway.
|
|
48
|
+
*
|
|
49
|
+
* A success row emitted by a handler that later throws is still in the table —
|
|
50
|
+
* the write is outside the transaction — but is never announced.
|
|
51
|
+
*
|
|
52
|
+
* The Rust spine reaches the same order by writing a success row inside the
|
|
53
|
+
* transaction and queueing its fan-out behind the commit.
|
|
31
54
|
*
|
|
32
55
|
* Listeners are a documented registration seam — `create_app_server`
|
|
33
56
|
* registers additional listeners via `add_listener` after the backend is
|
|
34
|
-
* built (the factory-managed audit-log SSE, per-endpoint WS auth guards
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
57
|
+
* built (the factory-managed audit-log SSE, per-endpoint WS auth guards, any
|
|
58
|
+
* `extra_audit_handlers` on a `WsEndpointSpec`) before the first request
|
|
59
|
+
* runs. Consumers can also register listeners directly on the emitter they
|
|
60
|
+
* return from `audit_factory` for setups that don't pass through
|
|
61
|
+
* `create_app_server`.
|
|
39
62
|
*
|
|
40
63
|
* @module
|
|
41
64
|
*/
|
|
42
65
|
import type { Logger } from '@fuzdev/fuz_util/log.ts';
|
|
43
66
|
import type { Uuid } from '@fuzdev/fuz_util/id.ts';
|
|
44
67
|
import type { Db } from '../db/db.js';
|
|
68
|
+
import { type EmitAfterCommitContext } from '../http/pending_effects.js';
|
|
45
69
|
import type { RequestActorContext } from './request_context.js';
|
|
46
70
|
import { type AuditLogConfig, type AuditLogEvent, type AuditLogInput } from './audit_log_schema.js';
|
|
47
71
|
/**
|
|
48
|
-
* Per-request context required by `AuditEmitter.emit` —
|
|
49
|
-
*
|
|
50
|
-
*
|
|
72
|
+
* Per-request context required by `AuditEmitter.emit` — the request's two
|
|
73
|
+
* side-effect queues. The bound emitter carries its own `log` reference
|
|
74
|
+
* inside the closure, so per-call contexts don't need one.
|
|
75
|
+
*
|
|
76
|
+
* The write is eager: the bound emitter fires the pool write immediately and
|
|
77
|
+
* pushes the in-flight `Promise<void>` onto `pending_effects`. Deferring it
|
|
78
|
+
* would only delay forensic visibility, since a pool-routed write is already
|
|
79
|
+
* rollback-resilient. A success row's listener fan-out goes on
|
|
80
|
+
* `post_commit_effects` instead (module doc, "When listeners hear about a
|
|
81
|
+
* row").
|
|
51
82
|
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
* pool-routed writes are already rollback-resilient because they run
|
|
56
|
-
* outside the request transaction, so deferring them would only delay
|
|
57
|
-
* forensic visibility without any safety benefit. The exception is a
|
|
58
|
-
* **success-only** event paired with a state mutation (the
|
|
59
|
-
* `db_admin_row_delete` emit in `http/db_routes.ts`): there the caller
|
|
60
|
-
* wraps the emit in `emit_after_commit` so the trail can't claim a
|
|
61
|
-
* mutation whose transaction failed at COMMIT.
|
|
83
|
+
* One success-only event also defers its *write*: the `db_admin_row_delete`
|
|
84
|
+
* emit in `http/db_routes.ts` wraps the whole emit in `emit_after_commit`, so
|
|
85
|
+
* the trail can't claim a mutation whose transaction failed at COMMIT.
|
|
62
86
|
*
|
|
63
87
|
* Both `RouteContext` and `ActionContext` structurally satisfy this
|
|
64
|
-
* shape
|
|
65
|
-
* / `ctx` directly.
|
|
88
|
+
* shape, so handlers pass `route` / `ctx` directly.
|
|
66
89
|
*/
|
|
67
|
-
export interface AuditEmitterContext {
|
|
90
|
+
export interface AuditEmitterContext extends EmitAfterCommitContext {
|
|
68
91
|
pending_effects: Array<Promise<void>>;
|
|
69
92
|
}
|
|
70
93
|
/**
|
|
@@ -87,8 +110,10 @@ export interface AuditEmitter {
|
|
|
87
110
|
*
|
|
88
111
|
* The in-flight promise is pushed onto `ctx.pending_effects` so tests
|
|
89
112
|
* with `await_pending_effects: true` can assert side effects inline.
|
|
90
|
-
* Errors are logged, never thrown.
|
|
91
|
-
* listener on the chain (`notify`)
|
|
113
|
+
* Errors are logged, never thrown. A written row fans out to every
|
|
114
|
+
* listener on the chain (`notify`): a failure row as soon as it is
|
|
115
|
+
* written, a success row from `ctx.post_commit_effects` — after the
|
|
116
|
+
* request's transaction commits, and never when the handler throws.
|
|
92
117
|
*
|
|
93
118
|
* Returns `void` deliberately — the in-flight promise is already on
|
|
94
119
|
* `ctx.pending_effects`, and exposing it would tempt callers to `await`
|
|
@@ -98,6 +123,7 @@ export interface AuditEmitter {
|
|
|
98
123
|
*
|
|
99
124
|
* @mutates `audit_log` table - inserts the row via the captured pool
|
|
100
125
|
* @mutates `ctx.pending_effects` - appends the in-flight settled promise
|
|
126
|
+
* @mutates `ctx.post_commit_effects` - appends a success row's listener fan-out
|
|
101
127
|
*/
|
|
102
128
|
emit<T extends string>(ctx: AuditEmitterContext, input: AuditLogInput<T>): void;
|
|
103
129
|
/**
|
|
@@ -116,13 +142,18 @@ export interface AuditEmitter {
|
|
|
116
142
|
outcome?: 'success' | 'failure';
|
|
117
143
|
}): void;
|
|
118
144
|
/**
|
|
119
|
-
* Awaitable pool write for code paths without a
|
|
145
|
+
* Awaitable pool write for code paths without a request context.
|
|
146
|
+
*
|
|
147
|
+
* Writes, then notifies the listeners, whatever the outcome — there is no
|
|
148
|
+
* request transaction to order the fan-out against. Errors are logged and
|
|
149
|
+
* swallowed (resolved void), so callers can sequence writes with
|
|
150
|
+
* `await audit.emit_pool(...)` without try/catch boilerplate.
|
|
120
151
|
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
* `
|
|
152
|
+
* Not for a success audit paired with a state mutation: the pool write
|
|
153
|
+
* can't roll back with the state, and a swallowed error leaves the
|
|
154
|
+
* mutation unaudited. Write those in the mutation's transaction
|
|
155
|
+
* (`query_audit_log` against the tx) and `notify` after the commit — the
|
|
156
|
+
* shape `auth/cleanup.ts`'s offer sweep and `query_accept_offer` use.
|
|
126
157
|
*
|
|
127
158
|
* @mutates `audit_log` table - inserts the row via the captured pool
|
|
128
159
|
*/
|
|
@@ -138,11 +169,11 @@ export interface AuditEmitter {
|
|
|
138
169
|
notify(event: AuditLogEvent): void;
|
|
139
170
|
/**
|
|
140
171
|
* Register an audit-event listener. Append-only — listeners fire in
|
|
141
|
-
* registration order
|
|
172
|
+
* registration order for every row `emit` / `emit_pool` wrote and on
|
|
142
173
|
* every `notify`.
|
|
143
174
|
*
|
|
144
175
|
* `create_app_server` registers the factory-managed audit-log SSE
|
|
145
|
-
* listener and per-endpoint WS auth guards
|
|
176
|
+
* listener and per-endpoint WS auth guards here so
|
|
146
177
|
* SSE + WS fan-out compose on top of the consumer's `on_audit_event`
|
|
147
178
|
* callback without shallow-copying `AppDeps`. Consumers can also
|
|
148
179
|
* register listeners directly for setups that don't run through
|
|
@@ -164,15 +195,13 @@ export type AuditEmitFn = <T extends string>(ctx: AuditEmitterContext, input: Au
|
|
|
164
195
|
/**
|
|
165
196
|
* Wrap the bound `emit` before it gets captured by `emit_role_grant_target`'s
|
|
166
197
|
* closure and exposed on the returned `AuditEmitter`. Test instrumentation
|
|
167
|
-
* uses this to record `emit`
|
|
168
|
-
*
|
|
169
|
-
* without paying the freeze-breaking footgun the pre-decorator
|
|
170
|
-
* `patch_audit_emit_capture` hot-patcher had.
|
|
198
|
+
* uses this to record `emit` invocations against external markers on a
|
|
199
|
+
* frozen emitter, whose slots can't be patched after construction.
|
|
171
200
|
*
|
|
172
201
|
* Because the inner closure captures the decorated function (not the
|
|
173
202
|
* outer slot reference), `emit_role_grant_target` also routes through
|
|
174
|
-
* the wrap — the
|
|
175
|
-
*
|
|
203
|
+
* the wrap — the decorator sees role-grant-shape emissions, not just bare
|
|
204
|
+
* `emit` calls. Production never sets this.
|
|
176
205
|
*/
|
|
177
206
|
export type EmitDecorator = (inner: AuditEmitFn) => AuditEmitFn;
|
|
178
207
|
/** Options for `create_audit_emitter`. */
|
|
@@ -198,8 +227,7 @@ export interface CreateAuditEmitterOptions {
|
|
|
198
227
|
* the function exposed on the returned `AuditEmitter`, so both call
|
|
199
228
|
* shapes route through it — see `EmitDecorator` for the rationale.
|
|
200
229
|
*
|
|
201
|
-
* Leave unset in production
|
|
202
|
-
* `create_emit_ordering_audit_factory` in `testing/audit_drift_guard.ts`.
|
|
230
|
+
* Leave unset in production — it is a test instrumentation seam.
|
|
203
231
|
*/
|
|
204
232
|
emit_decorator?: EmitDecorator;
|
|
205
233
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit_emitter.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/audit_emitter.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"audit_emitter.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/audit_emitter.ts"],"names":[],"mappings":"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"}
|