@fuzdev/fuz_app 0.38.1 → 0.40.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/auth/CLAUDE.md +124 -36
- package/dist/auth/account_actions.d.ts +5 -3
- package/dist/auth/account_actions.d.ts.map +1 -1
- package/dist/auth/account_actions.js +5 -6
- package/dist/auth/account_routes.d.ts.map +1 -1
- package/dist/auth/account_routes.js +7 -7
- package/dist/auth/admin_action_specs.d.ts +6 -138
- package/dist/auth/admin_action_specs.d.ts.map +1 -1
- package/dist/auth/admin_action_specs.js +4 -2
- package/dist/auth/admin_actions.d.ts +4 -3
- package/dist/auth/admin_actions.d.ts.map +1 -1
- package/dist/auth/admin_actions.js +8 -9
- package/dist/auth/audit_log_queries.d.ts +32 -20
- package/dist/auth/audit_log_queries.d.ts.map +1 -1
- package/dist/auth/audit_log_queries.js +52 -40
- package/dist/auth/audit_log_schema.d.ts +105 -84
- package/dist/auth/audit_log_schema.d.ts.map +1 -1
- package/dist/auth/audit_log_schema.js +84 -12
- package/dist/auth/bootstrap_routes.d.ts.map +1 -1
- package/dist/auth/bootstrap_routes.js +3 -3
- package/dist/auth/cleanup.d.ts +9 -1
- package/dist/auth/cleanup.d.ts.map +1 -1
- package/dist/auth/cleanup.js +2 -2
- package/dist/auth/deps.d.ts +13 -1
- package/dist/auth/deps.d.ts.map +1 -1
- package/dist/auth/permit_offer_actions.d.ts +16 -2
- package/dist/auth/permit_offer_actions.d.ts.map +1 -1
- package/dist/auth/permit_offer_actions.js +26 -8
- package/dist/auth/role_schema.d.ts +10 -1
- package/dist/auth/role_schema.d.ts.map +1 -1
- package/dist/auth/role_schema.js +10 -1
- package/dist/auth/self_service_role_actions.d.ts +136 -0
- package/dist/auth/self_service_role_actions.d.ts.map +1 -0
- package/dist/auth/self_service_role_actions.js +198 -0
- package/dist/auth/signup_routes.d.ts.map +1 -1
- package/dist/auth/signup_routes.js +2 -2
- package/dist/auth/standard_rpc_actions.d.ts +1 -1
- package/dist/auth/standard_rpc_actions.js +1 -1
- package/dist/http/jsonrpc_errors.d.ts +27 -75
- package/dist/http/jsonrpc_errors.d.ts.map +1 -1
- package/dist/http/jsonrpc_errors.js +16 -9
- package/dist/server/app_backend.d.ts +26 -7
- package/dist/server/app_backend.d.ts.map +1 -1
- package/dist/server/app_backend.js +29 -7
- package/dist/server/app_server.d.ts +6 -7
- package/dist/server/app_server.d.ts.map +1 -1
- package/dist/server/app_server.js +16 -29
- package/dist/ui/AdminAccounts.svelte +19 -0
- package/dist/ui/AdminAccounts.svelte.d.ts +2 -17
- package/dist/ui/AdminAccounts.svelte.d.ts.map +1 -1
- package/dist/ui/AdminPermitHistory.svelte +23 -2
- package/dist/ui/AdminPermitHistory.svelte.d.ts +2 -17
- package/dist/ui/AdminPermitHistory.svelte.d.ts.map +1 -1
- package/dist/ui/CLAUDE.md +11 -0
- package/dist/ui/PermitOfferHistory.svelte +11 -5
- package/dist/ui/PermitOfferHistory.svelte.d.ts +7 -1
- package/dist/ui/PermitOfferHistory.svelte.d.ts.map +1 -1
- package/dist/ui/PermitOfferInbox.svelte +12 -7
- package/dist/ui/PermitOfferInbox.svelte.d.ts +8 -3
- package/dist/ui/PermitOfferInbox.svelte.d.ts.map +1 -1
- package/dist/ui/admin_rpc_adapters.d.ts +16 -1
- package/dist/ui/admin_rpc_adapters.d.ts.map +1 -1
- package/dist/ui/admin_rpc_adapters.js +12 -1
- package/dist/ui/format_scope.d.ts +45 -0
- package/dist/ui/format_scope.d.ts.map +1 -0
- package/dist/ui/format_scope.js +34 -0
- package/dist/ui/ui_format.d.ts +2 -3
- package/dist/ui/ui_format.d.ts.map +1 -1
- package/dist/ui/ui_format.js +1 -1
- package/package.json +1 -1
|
@@ -43,12 +43,11 @@ import { admin_account_list_action_spec, admin_session_list_action_spec, admin_s
|
|
|
43
43
|
/**
|
|
44
44
|
* Create the admin-only RPC actions.
|
|
45
45
|
*
|
|
46
|
-
* @param deps -
|
|
46
|
+
* @param deps - `AdminActionDeps` slice of `AppDeps` (`log`, `on_audit_event`, optional `audit_log_config`)
|
|
47
47
|
* @param options - role schema for `grantable_roles` derivation
|
|
48
48
|
* @returns the `RpcAction` array to spread into a `create_rpc_endpoint` call
|
|
49
49
|
*/
|
|
50
50
|
export const create_admin_actions = (deps, options = {}) => {
|
|
51
|
-
const { log, on_audit_event } = deps;
|
|
52
51
|
const role_options = options.roles?.role_options ?? BUILTIN_ROLE_OPTIONS;
|
|
53
52
|
const grantable_roles = [];
|
|
54
53
|
for (const [name, rc] of role_options) {
|
|
@@ -81,7 +80,7 @@ export const create_admin_actions = (deps, options = {}) => {
|
|
|
81
80
|
reason: ERROR_ACCOUNT_NOT_FOUND,
|
|
82
81
|
attempted_account_id: input.account_id,
|
|
83
82
|
},
|
|
84
|
-
},
|
|
83
|
+
}, deps);
|
|
85
84
|
throw jsonrpc_errors.not_found('account', { reason: ERROR_ACCOUNT_NOT_FOUND });
|
|
86
85
|
}
|
|
87
86
|
const count = await query_session_revoke_all_for_account(ctx, input.account_id);
|
|
@@ -92,7 +91,7 @@ export const create_admin_actions = (deps, options = {}) => {
|
|
|
92
91
|
target_account_id: input.account_id,
|
|
93
92
|
ip: ctx.client_ip,
|
|
94
93
|
metadata: { count },
|
|
95
|
-
},
|
|
94
|
+
}, deps);
|
|
96
95
|
return { ok: true, count };
|
|
97
96
|
};
|
|
98
97
|
const token_revoke_all_handler = async (input, ctx) => {
|
|
@@ -112,7 +111,7 @@ export const create_admin_actions = (deps, options = {}) => {
|
|
|
112
111
|
reason: ERROR_ACCOUNT_NOT_FOUND,
|
|
113
112
|
attempted_account_id: input.account_id,
|
|
114
113
|
},
|
|
115
|
-
},
|
|
114
|
+
}, deps);
|
|
116
115
|
throw jsonrpc_errors.not_found('account', { reason: ERROR_ACCOUNT_NOT_FOUND });
|
|
117
116
|
}
|
|
118
117
|
const count = await query_revoke_all_api_tokens_for_account(ctx, input.account_id);
|
|
@@ -123,7 +122,7 @@ export const create_admin_actions = (deps, options = {}) => {
|
|
|
123
122
|
target_account_id: input.account_id,
|
|
124
123
|
ip: ctx.client_ip,
|
|
125
124
|
metadata: { count },
|
|
126
|
-
},
|
|
125
|
+
}, deps);
|
|
127
126
|
return { ok: true, count };
|
|
128
127
|
};
|
|
129
128
|
const audit_log_list_handler = async (input, ctx) => {
|
|
@@ -188,7 +187,7 @@ export const create_admin_actions = (deps, options = {}) => {
|
|
|
188
187
|
account_id: auth.account.id,
|
|
189
188
|
ip: ctx.client_ip,
|
|
190
189
|
metadata: { invite_id: invite.id, email, username },
|
|
191
|
-
},
|
|
190
|
+
}, deps);
|
|
192
191
|
return { ok: true, invite };
|
|
193
192
|
};
|
|
194
193
|
const invite_list_handler = async (_input, ctx) => {
|
|
@@ -207,7 +206,7 @@ export const create_admin_actions = (deps, options = {}) => {
|
|
|
207
206
|
account_id: auth.account.id,
|
|
208
207
|
ip: ctx.client_ip,
|
|
209
208
|
metadata: { invite_id: input.invite_id },
|
|
210
|
-
},
|
|
209
|
+
}, deps);
|
|
211
210
|
return { ok: true };
|
|
212
211
|
};
|
|
213
212
|
const actions = [
|
|
@@ -246,7 +245,7 @@ export const create_admin_actions = (deps, options = {}) => {
|
|
|
246
245
|
old_value,
|
|
247
246
|
new_value: input.open_signup,
|
|
248
247
|
},
|
|
249
|
-
},
|
|
248
|
+
}, deps);
|
|
250
249
|
const settings = await query_app_settings_load_with_username(ctx);
|
|
251
250
|
return { ok: true, settings };
|
|
252
251
|
};
|
|
@@ -11,33 +11,35 @@
|
|
|
11
11
|
*
|
|
12
12
|
* @module
|
|
13
13
|
*/
|
|
14
|
-
import type { Logger } from '@fuzdev/fuz_util/log.js';
|
|
15
14
|
import type { QueryDeps } from '../db/query_deps.js';
|
|
16
15
|
import type { RouteContext } from '../http/route_spec.js';
|
|
17
|
-
import
|
|
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';
|
|
18
18
|
/** Default limit for audit log listings. */
|
|
19
19
|
export declare const AUDIT_LOG_DEFAULT_LIMIT = 50;
|
|
20
20
|
/** Number of audit metadata validation failures observed since process start. */
|
|
21
21
|
export declare const get_audit_metadata_validation_failures: () => number;
|
|
22
|
-
/** Reset the counter — for tests only
|
|
22
|
+
/** Reset the counter — for tests only. */
|
|
23
23
|
export declare const reset_audit_metadata_validation_failures: () => void;
|
|
24
|
+
/** Number of audit unknown-event-type failures observed since process start. */
|
|
25
|
+
export declare const get_audit_unknown_event_type_failures: () => number;
|
|
26
|
+
/** Reset the counter — for tests only. */
|
|
27
|
+
export declare const reset_audit_unknown_event_type_failures: () => void;
|
|
24
28
|
/**
|
|
25
29
|
* Insert an audit log entry.
|
|
26
30
|
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* `audit_metadata_validation_failures` (sampled via the exported getter)
|
|
33
|
-
* but never throw — the audit row is still written. Schema-vs-runtime
|
|
34
|
-
* drift is an operator signal, not a request-failing condition.
|
|
31
|
+
* `RETURNING *` so callers receive DB-assigned fields (`id`, `seq`,
|
|
32
|
+
* `created_at`). Validates `metadata` against `config.metadata_schemas`;
|
|
33
|
+
* unknown `event_type` and metadata mismatches log + bump their counters
|
|
34
|
+
* but write the row anyway. Consumers extend the recognized set via
|
|
35
|
+
* `create_audit_log_config({extra_events})`.
|
|
35
36
|
*
|
|
36
37
|
* @param deps - query dependencies
|
|
37
38
|
* @param input - the audit event to record
|
|
39
|
+
* @param config - audit-log config. Defaults to `BUILTIN_AUDIT_LOG_CONFIG`.
|
|
38
40
|
* @returns the inserted audit log row
|
|
39
41
|
*/
|
|
40
|
-
export declare const query_audit_log: <T extends
|
|
42
|
+
export declare const query_audit_log: <T extends string>(deps: QueryDeps, input: AuditLogInput<T>, config?: AuditLogConfig) => Promise<AuditLogEvent>;
|
|
41
43
|
/**
|
|
42
44
|
* List audit log entries, newest first.
|
|
43
45
|
*
|
|
@@ -79,19 +81,29 @@ export declare const query_audit_log_list_permit_history: (deps: QueryDeps, limi
|
|
|
79
81
|
* @returns the number of entries deleted
|
|
80
82
|
*/
|
|
81
83
|
export declare const query_audit_log_cleanup_before: (deps: QueryDeps, before: Date) => Promise<number>;
|
|
84
|
+
/**
|
|
85
|
+
* Capabilities required by `audit_log_fire_and_forget`.
|
|
86
|
+
*
|
|
87
|
+
* Defined as a slice of `AppDeps` so call sites can pass the surrounding deps
|
|
88
|
+
* bundle directly without a structural-compatibility coincidence. The bundled
|
|
89
|
+
* shape replaces the prior `(log, on_audit_event, config?)` positional args
|
|
90
|
+
* — consumers that forgot the trailing `config` would silently fall back to
|
|
91
|
+
* `BUILTIN_AUDIT_LOG_CONFIG` and skip metadata validation for their own
|
|
92
|
+
* event types. `audit_log_config` is optional on `AppDeps` and defaults to
|
|
93
|
+
* `BUILTIN_AUDIT_LOG_CONFIG` inside `audit_log_fire_and_forget` when absent.
|
|
94
|
+
*/
|
|
95
|
+
export type AuditLogFireAndForgetDeps = Pick<AppDeps, 'log' | 'on_audit_event' | 'audit_log_config'>;
|
|
82
96
|
/**
|
|
83
97
|
* Log an audit event without blocking the caller.
|
|
84
98
|
*
|
|
85
|
-
* Errors are logged
|
|
86
|
-
*
|
|
87
|
-
* Write
|
|
88
|
-
* so the error message indicates which phase failed.
|
|
99
|
+
* Errors are logged — audit logging never breaks auth flows. Uses
|
|
100
|
+
* `background_db` so entries persist even when the request transaction
|
|
101
|
+
* rolls back. Write and `on_audit_event` callback failures are logged separately.
|
|
89
102
|
*
|
|
90
103
|
* @param route - `background_db` and `pending_effects` from the route context
|
|
91
104
|
* @param input - the audit event to record
|
|
92
|
-
* @param
|
|
93
|
-
* @
|
|
94
|
-
* @returns the settled promise (callers may ignore it — fire-and-forget semantics preserved)
|
|
105
|
+
* @param deps - logger, `on_audit_event` callback, and optional `audit_log_config`
|
|
106
|
+
* @returns the settled promise (callers may ignore it)
|
|
95
107
|
*/
|
|
96
|
-
export declare const audit_log_fire_and_forget: <T extends
|
|
108
|
+
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>;
|
|
97
109
|
//# 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,
|
|
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,KAAK,EAAC,YAAY,EAAC,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,WAAW,CAAC;AACvC,OAAO,EAEN,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,8BAA8B,EACnC,KAAK,sBAAsB,EAC3B,MAAM,uBAAuB,CAAC;AAE/B,4CAA4C;AAC5C,eAAO,MAAM,uBAAuB,KAAK,CAAC;AAa1C,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;;;;;;;;;;;;;GAaG;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,CAmCvB,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;;;;;;GAMG;AACH,eAAO,MAAM,gCAAgC,GAC5C,MAAM,SAAS,EACf,YAAY,MAAM,EAClB,cAA+B,KAC7B,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,CAO9B,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,mCAAmC,GAC/C,MAAM,SAAS,EACf,cAA+B,EAC/B,eAAU,KACR,OAAO,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAYvC,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,8BAA8B,GAC1C,MAAM,SAAS,EACf,QAAQ,IAAI,KACV,OAAO,CAAC,MAAM,CAMhB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,MAAM,MAAM,yBAAyB,GAAG,IAAI,CAC3C,OAAO,EACP,KAAK,GAAG,gBAAgB,GAAG,kBAAkB,CAC7C,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,yBAAyB,GAAI,CAAC,SAAS,MAAM,EACzD,OAAO,IAAI,CAAC,YAAY,EAAE,eAAe,GAAG,iBAAiB,CAAC,EAC9D,OAAO,aAAa,CAAC,CAAC,CAAC,EACvB,MAAM,yBAAyB,KAC7B,OAAO,CAAC,IAAI,CAed,CAAC"}
|
|
@@ -12,54 +12,67 @@
|
|
|
12
12
|
* @module
|
|
13
13
|
*/
|
|
14
14
|
import { assert_row } from '../db/assert_row.js';
|
|
15
|
-
import {
|
|
15
|
+
import { BUILTIN_AUDIT_LOG_CONFIG, } from './audit_log_schema.js';
|
|
16
16
|
/** Default limit for audit log listings. */
|
|
17
17
|
export const AUDIT_LOG_DEFAULT_LIMIT = 50;
|
|
18
18
|
/**
|
|
19
|
-
* Process-wide counter for audit metadata validation failures.
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* the counter via `get_audit_metadata_validation_failures()` (e.g. from
|
|
27
|
-
* a future `/metrics` surface or a debug RPC handler).
|
|
28
|
-
*
|
|
29
|
-
* Single-process scope: fuz_app's runtime state lives in-process (rate
|
|
30
|
-
* limiter, daemon token state); this counter follows the same pattern
|
|
31
|
-
* and resets on server restart.
|
|
19
|
+
* Process-wide counter for audit metadata validation failures. `query_audit_log`
|
|
20
|
+
* increments on `safeParse` mismatch and writes the row anyway (fail-open —
|
|
21
|
+
* schema drift should not break auth flows). Independent of the
|
|
22
|
+
* unknown-event-type counter — `create_audit_log_config` keeps the two in
|
|
23
|
+
* sync, but a hand-rolled `AuditLogConfig` (or a cast escape) can have a
|
|
24
|
+
* schema entry without a matching `event_types` entry, in which case both
|
|
25
|
+
* counters bump on a single emission. In-process; resets on restart.
|
|
32
26
|
*/
|
|
33
27
|
let audit_metadata_validation_failures = 0;
|
|
34
28
|
/** Number of audit metadata validation failures observed since process start. */
|
|
35
29
|
export const get_audit_metadata_validation_failures = () => audit_metadata_validation_failures;
|
|
36
|
-
/** Reset the counter — for tests only
|
|
30
|
+
/** Reset the counter — for tests only. */
|
|
37
31
|
export const reset_audit_metadata_validation_failures = () => {
|
|
38
32
|
audit_metadata_validation_failures = 0;
|
|
39
33
|
};
|
|
34
|
+
/**
|
|
35
|
+
* Process-wide counter for audit-log emissions whose `event_type` is missing
|
|
36
|
+
* from the active config. Same fail-open posture as the metadata counter;
|
|
37
|
+
* orthogonal in implementation — metadata validation runs regardless of
|
|
38
|
+
* registration — though under the factory both counters track the same
|
|
39
|
+
* config (see `audit_metadata_validation_failures`). Catches typos and
|
|
40
|
+
* missing `extra_events` registrations.
|
|
41
|
+
*/
|
|
42
|
+
let audit_unknown_event_type_failures = 0;
|
|
43
|
+
/** Number of audit unknown-event-type failures observed since process start. */
|
|
44
|
+
export const get_audit_unknown_event_type_failures = () => audit_unknown_event_type_failures;
|
|
45
|
+
/** Reset the counter — for tests only. */
|
|
46
|
+
export const reset_audit_unknown_event_type_failures = () => {
|
|
47
|
+
audit_unknown_event_type_failures = 0;
|
|
48
|
+
};
|
|
40
49
|
/**
|
|
41
50
|
* Insert an audit log entry.
|
|
42
51
|
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
* `audit_metadata_validation_failures` (sampled via the exported getter)
|
|
49
|
-
* but never throw — the audit row is still written. Schema-vs-runtime
|
|
50
|
-
* drift is an operator signal, not a request-failing condition.
|
|
52
|
+
* `RETURNING *` so callers receive DB-assigned fields (`id`, `seq`,
|
|
53
|
+
* `created_at`). Validates `metadata` against `config.metadata_schemas`;
|
|
54
|
+
* unknown `event_type` and metadata mismatches log + bump their counters
|
|
55
|
+
* but write the row anyway. Consumers extend the recognized set via
|
|
56
|
+
* `create_audit_log_config({extra_events})`.
|
|
51
57
|
*
|
|
52
58
|
* @param deps - query dependencies
|
|
53
59
|
* @param input - the audit event to record
|
|
60
|
+
* @param config - audit-log config. Defaults to `BUILTIN_AUDIT_LOG_CONFIG`.
|
|
54
61
|
* @returns the inserted audit log row
|
|
55
62
|
*/
|
|
56
|
-
export const query_audit_log = async (deps, input) => {
|
|
63
|
+
export const query_audit_log = async (deps, input, config = BUILTIN_AUDIT_LOG_CONFIG) => {
|
|
64
|
+
if (!config.event_types.includes(input.event_type)) {
|
|
65
|
+
audit_unknown_event_type_failures++;
|
|
66
|
+
console.error(`[audit_log] unknown event_type '${input.event_type}' — register via create_audit_log_config({extra_events})`);
|
|
67
|
+
}
|
|
57
68
|
if (input.metadata != null) {
|
|
58
|
-
const schema =
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
69
|
+
const schema = config.metadata_schemas[input.event_type];
|
|
70
|
+
if (schema) {
|
|
71
|
+
const result = schema.safeParse(input.metadata);
|
|
72
|
+
if (!result.success) {
|
|
73
|
+
audit_metadata_validation_failures++;
|
|
74
|
+
console.error(`[audit_log] metadata mismatch for '${input.event_type}':`, result.error.issues);
|
|
75
|
+
}
|
|
63
76
|
}
|
|
64
77
|
}
|
|
65
78
|
const rows = await deps.db.query(`INSERT INTO audit_log (event_type, outcome, actor_id, account_id, target_account_id, ip, metadata)
|
|
@@ -201,25 +214,24 @@ export const query_audit_log_cleanup_before = async (deps, before) => {
|
|
|
201
214
|
/**
|
|
202
215
|
* Log an audit event without blocking the caller.
|
|
203
216
|
*
|
|
204
|
-
* Errors are logged
|
|
205
|
-
*
|
|
206
|
-
* Write
|
|
207
|
-
* so the error message indicates which phase failed.
|
|
217
|
+
* Errors are logged — audit logging never breaks auth flows. Uses
|
|
218
|
+
* `background_db` so entries persist even when the request transaction
|
|
219
|
+
* rolls back. Write and `on_audit_event` callback failures are logged separately.
|
|
208
220
|
*
|
|
209
221
|
* @param route - `background_db` and `pending_effects` from the route context
|
|
210
222
|
* @param input - the audit event to record
|
|
211
|
-
* @param
|
|
212
|
-
* @
|
|
213
|
-
* @returns the settled promise (callers may ignore it — fire-and-forget semantics preserved)
|
|
223
|
+
* @param deps - logger, `on_audit_event` callback, and optional `audit_log_config`
|
|
224
|
+
* @returns the settled promise (callers may ignore it)
|
|
214
225
|
*/
|
|
215
|
-
export const audit_log_fire_and_forget = (route, input,
|
|
216
|
-
const
|
|
226
|
+
export const audit_log_fire_and_forget = (route, input, deps) => {
|
|
227
|
+
const { log, on_audit_event, audit_log_config = BUILTIN_AUDIT_LOG_CONFIG } = deps;
|
|
228
|
+
const p = query_audit_log({ db: route.background_db }, input, audit_log_config)
|
|
217
229
|
.then((event) => {
|
|
218
230
|
try {
|
|
219
|
-
|
|
231
|
+
on_audit_event(event);
|
|
220
232
|
}
|
|
221
233
|
catch (callback_err) {
|
|
222
|
-
log.error('Audit log
|
|
234
|
+
log.error('Audit log on_audit_event callback failed:', callback_err);
|
|
223
235
|
}
|
|
224
236
|
})
|
|
225
237
|
.catch((err) => {
|
|
@@ -8,7 +8,12 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { z } from 'zod';
|
|
10
10
|
import { Uuid } from '../uuid.js';
|
|
11
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* All tracked auth event types. Frozen to convert accidental in-process
|
|
13
|
+
* mutation (test cross-contamination, cast escapes) into loud TypeErrors.
|
|
14
|
+
* Not a security boundary — in-process code has many other paths to subvert
|
|
15
|
+
* audit logging.
|
|
16
|
+
*/
|
|
12
17
|
export declare const AUDIT_EVENT_TYPES: readonly ["login", "logout", "bootstrap", "signup", "password_change", "session_revoke", "session_revoke_all", "token_create", "token_revoke", "token_revoke_all", "permit_grant", "permit_revoke", "permit_offer_create", "permit_offer_accept", "permit_offer_decline", "permit_offer_retract", "permit_offer_expire", "permit_offer_supersede", "invite_create", "invite_delete", "app_settings_update"];
|
|
13
18
|
/** Zod schema for audit event types. */
|
|
14
19
|
export declare const AuditEventType: z.ZodEnum<{
|
|
@@ -35,6 +40,15 @@ export declare const AuditEventType: z.ZodEnum<{
|
|
|
35
40
|
app_settings_update: "app_settings_update";
|
|
36
41
|
}>;
|
|
37
42
|
export type AuditEventType = z.infer<typeof AuditEventType>;
|
|
43
|
+
/**
|
|
44
|
+
* Letter start, then letters, digits, `_`, `.`, `/`, `-`. Accepts snake_case,
|
|
45
|
+
* dotted, and namespaced consumer conventions; rejects empty strings, leading
|
|
46
|
+
* separators, whitespace, and control characters.
|
|
47
|
+
*/
|
|
48
|
+
export declare const AUDIT_EVENT_TYPE_NAME_REGEX: RegExp;
|
|
49
|
+
/** Zod schema for valid audit event-type name strings. */
|
|
50
|
+
export declare const AuditEventTypeName: z.ZodString;
|
|
51
|
+
export type AuditEventTypeName = z.infer<typeof AuditEventTypeName>;
|
|
38
52
|
/** Zod schema for audit event outcomes. */
|
|
39
53
|
export declare const AuditOutcome: z.ZodEnum<{
|
|
40
54
|
success: "success";
|
|
@@ -42,13 +56,13 @@ export declare const AuditOutcome: z.ZodEnum<{
|
|
|
42
56
|
}>;
|
|
43
57
|
export type AuditOutcome = z.infer<typeof AuditOutcome>;
|
|
44
58
|
/**
|
|
45
|
-
* Per-event-type metadata Zod schemas.
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
59
|
+
* Per-event-type metadata Zod schemas. `z.looseObject` so consumers can
|
|
60
|
+
* add fields while known ones are validated. The record is frozen to
|
|
61
|
+
* catch mutation bugs at the key level (e.g. tests that try to swap in a
|
|
62
|
+
* stub schema); the Zod schemas themselves are reachable and mutable —
|
|
63
|
+
* freeze isn't a security boundary.
|
|
50
64
|
*/
|
|
51
|
-
export declare const AUDIT_METADATA_SCHEMAS: {
|
|
65
|
+
export declare const AUDIT_METADATA_SCHEMAS: Readonly<{
|
|
52
66
|
login: z.ZodNullable<z.ZodObject<{
|
|
53
67
|
username: z.ZodString;
|
|
54
68
|
}, z.core.$loose>>;
|
|
@@ -89,12 +103,14 @@ export declare const AUDIT_METADATA_SCHEMAS: {
|
|
|
89
103
|
permit_id: z.ZodOptional<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
|
|
90
104
|
scope_id: z.ZodOptional<z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>>;
|
|
91
105
|
source_offer_id: z.ZodOptional<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
|
|
106
|
+
self_service: z.ZodOptional<z.ZodBoolean>;
|
|
92
107
|
}, z.core.$loose>;
|
|
93
108
|
permit_revoke: z.ZodObject<{
|
|
94
109
|
role: z.ZodString;
|
|
95
110
|
permit_id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
|
|
96
111
|
scope_id: z.ZodOptional<z.ZodNullable<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>>;
|
|
97
112
|
reason: z.ZodOptional<z.ZodString>;
|
|
113
|
+
self_service: z.ZodOptional<z.ZodBoolean>;
|
|
98
114
|
}, z.core.$loose>;
|
|
99
115
|
permit_offer_create: z.ZodObject<{
|
|
100
116
|
offer_id: z.ZodOptional<z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">>;
|
|
@@ -147,16 +163,16 @@ export declare const AUDIT_METADATA_SCHEMAS: {
|
|
|
147
163
|
old_value: z.ZodUnknown;
|
|
148
164
|
new_value: z.ZodUnknown;
|
|
149
165
|
}, z.core.$loose>;
|
|
150
|
-
}
|
|
166
|
+
}>;
|
|
151
167
|
/** Mapped type of metadata shapes per event type, derived from Zod schemas. */
|
|
152
168
|
export type AuditMetadataMap = {
|
|
153
169
|
[K in AuditEventType]: z.infer<(typeof AUDIT_METADATA_SCHEMAS)[K]>;
|
|
154
170
|
};
|
|
155
|
-
/** Audit log row from the database. */
|
|
171
|
+
/** Audit log row from the database. See `AuditLogEventJson` for `event_type` widening rationale. */
|
|
156
172
|
export interface AuditLogEvent {
|
|
157
173
|
id: Uuid;
|
|
158
174
|
seq: number;
|
|
159
|
-
event_type:
|
|
175
|
+
event_type: AuditEventTypeName;
|
|
160
176
|
outcome: AuditOutcome;
|
|
161
177
|
actor_id: Uuid | null;
|
|
162
178
|
account_id: Uuid | null;
|
|
@@ -174,53 +190,102 @@ export declare const get_audit_metadata: <T extends AuditEventType>(event: Audit
|
|
|
174
190
|
event_type: T;
|
|
175
191
|
}) => AuditMetadataMap[T] | null;
|
|
176
192
|
/** Input for creating an audit log entry. */
|
|
177
|
-
export interface AuditLogInput<T extends
|
|
193
|
+
export interface AuditLogInput<T extends string = AuditEventType> {
|
|
178
194
|
event_type: T;
|
|
179
195
|
outcome?: AuditOutcome;
|
|
180
196
|
actor_id?: Uuid | null;
|
|
181
197
|
account_id?: Uuid | null;
|
|
182
198
|
target_account_id?: Uuid | null;
|
|
183
199
|
ip?: string | null;
|
|
184
|
-
|
|
200
|
+
/**
|
|
201
|
+
* Per-event-type metadata. Builtin `T` narrows to `AuditMetadataMap[T]`;
|
|
202
|
+
* consumer strings widen to a generic record (validation runs against
|
|
203
|
+
* `AuditLogConfig.metadata_schemas` at insert time).
|
|
204
|
+
*/
|
|
205
|
+
metadata?: T extends AuditEventType ? (AuditMetadataMap[T] & Record<string, unknown>) | null : Record<string, unknown> | null;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Configuration bundle for audit-log event types and metadata schemas.
|
|
209
|
+
*
|
|
210
|
+
* Lets consumers extend the closed `AUDIT_EVENT_TYPES` enum with their own
|
|
211
|
+
* event strings (and metadata Zod schemas) without forking. Pass to
|
|
212
|
+
* `audit_log_fire_and_forget` / `query_audit_log` as the optional `config`
|
|
213
|
+
* argument; both default to `BUILTIN_AUDIT_LOG_CONFIG`.
|
|
214
|
+
*
|
|
215
|
+
* The DB column is `TEXT NOT NULL` and never enforced an enum, so consumer
|
|
216
|
+
* event types round-trip through `query_audit_log_list` and SSE identically
|
|
217
|
+
* to builtins.
|
|
218
|
+
*
|
|
219
|
+
* Constructed configs are deep-frozen (wrapper, `event_types`,
|
|
220
|
+
* `metadata_schemas`) to catch accidental mutation bugs early. Not a
|
|
221
|
+
* security boundary against in-process code, which can subvert audit
|
|
222
|
+
* logging through other paths.
|
|
223
|
+
*/
|
|
224
|
+
export interface AuditLogConfig {
|
|
225
|
+
/** All recognized event-type strings — fuz_app builtins plus consumer extras. */
|
|
226
|
+
readonly event_types: ReadonlyArray<string>;
|
|
227
|
+
/**
|
|
228
|
+
* Per-event-type metadata schemas. Missing entries skip metadata
|
|
229
|
+
* validation for that type (row still written; metadata stored as raw JSONB).
|
|
230
|
+
*/
|
|
231
|
+
readonly metadata_schemas: Readonly<Record<string, z.ZodType>>;
|
|
232
|
+
}
|
|
233
|
+
/** Builtin fuz_app audit-log config — every existing event type and its metadata schema. */
|
|
234
|
+
export declare const BUILTIN_AUDIT_LOG_CONFIG: AuditLogConfig;
|
|
235
|
+
/** Options for `create_audit_log_config`. */
|
|
236
|
+
export interface CreateAuditLogConfigOptions {
|
|
237
|
+
/**
|
|
238
|
+
* Extra event types keyed by event-type string. Value is a Zod metadata
|
|
239
|
+
* schema, or `null` to register the type without validation (row still
|
|
240
|
+
* written, metadata stored as raw JSONB).
|
|
241
|
+
*
|
|
242
|
+
* Collisions with builtin event-type strings throw at construction.
|
|
243
|
+
* Schemas are run via `safeParse` at insert time; mismatches log + count
|
|
244
|
+
* but never throw (fail-open — see the drift counters in `audit_log_queries.ts`).
|
|
245
|
+
*/
|
|
246
|
+
extra_events?: Readonly<Record<string, z.ZodType | null>>;
|
|
185
247
|
}
|
|
248
|
+
/**
|
|
249
|
+
* Build an `AuditLogConfig` by merging fuz_app builtins with consumer extras.
|
|
250
|
+
*
|
|
251
|
+
* Throws when an `extra_events` key collides with a builtin event type, or
|
|
252
|
+
* fails `AuditEventTypeName` format validation.
|
|
253
|
+
*
|
|
254
|
+
* Call once at startup; pass the result to consumer-emitted
|
|
255
|
+
* `audit_log_fire_and_forget` calls. Builtin handlers omit the argument and
|
|
256
|
+
* pick up `BUILTIN_AUDIT_LOG_CONFIG`.
|
|
257
|
+
*/
|
|
258
|
+
export declare const create_audit_log_config: (options?: CreateAuditLogConfigOptions) => AuditLogConfig;
|
|
186
259
|
/** Options for listing audit log entries. */
|
|
187
260
|
export interface AuditLogListOptions {
|
|
188
261
|
limit?: number;
|
|
189
262
|
offset?: number;
|
|
190
|
-
|
|
191
|
-
|
|
263
|
+
/**
|
|
264
|
+
* Event-type filter. Accepts any string — builtins or consumer-registered
|
|
265
|
+
* via `create_audit_log_config({extra_events})`. The DB column is
|
|
266
|
+
* `TEXT NOT NULL` with no CHECK, so unknown strings simply match nothing.
|
|
267
|
+
*/
|
|
268
|
+
event_type?: string;
|
|
269
|
+
event_type_in?: Array<string>;
|
|
192
270
|
account_id?: Uuid;
|
|
193
271
|
outcome?: AuditOutcome;
|
|
194
272
|
/** When set, only return events with `seq` greater than this value. Enables SSE reconnection gap fill. */
|
|
195
273
|
since_seq?: number;
|
|
196
274
|
}
|
|
197
|
-
/**
|
|
275
|
+
/**
|
|
276
|
+
* Zod schema for client-safe audit log event.
|
|
277
|
+
*
|
|
278
|
+
* `event_type` is `AuditEventTypeName` (regex-validated string) — matches
|
|
279
|
+
* the `AuditLogEvent` row and the DB's `TEXT NOT NULL` column. Consumer
|
|
280
|
+
* types registered via `create_audit_log_config({extra_events})` round-trip
|
|
281
|
+
* through queries, `on_audit_event` callbacks, and JSON-RPC responses
|
|
282
|
+
* identically to builtins. `AuditLogInput<T>` stays parameterized on the
|
|
283
|
+
* write side so `AuditMetadataMap` narrowing via `get_audit_metadata` works.
|
|
284
|
+
*/
|
|
198
285
|
export declare const AuditLogEventJson: z.ZodObject<{
|
|
199
286
|
id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
|
|
200
287
|
seq: z.ZodNumber;
|
|
201
|
-
event_type: z.
|
|
202
|
-
login: "login";
|
|
203
|
-
logout: "logout";
|
|
204
|
-
bootstrap: "bootstrap";
|
|
205
|
-
signup: "signup";
|
|
206
|
-
password_change: "password_change";
|
|
207
|
-
session_revoke: "session_revoke";
|
|
208
|
-
session_revoke_all: "session_revoke_all";
|
|
209
|
-
token_create: "token_create";
|
|
210
|
-
token_revoke: "token_revoke";
|
|
211
|
-
token_revoke_all: "token_revoke_all";
|
|
212
|
-
permit_grant: "permit_grant";
|
|
213
|
-
permit_revoke: "permit_revoke";
|
|
214
|
-
permit_offer_create: "permit_offer_create";
|
|
215
|
-
permit_offer_accept: "permit_offer_accept";
|
|
216
|
-
permit_offer_decline: "permit_offer_decline";
|
|
217
|
-
permit_offer_retract: "permit_offer_retract";
|
|
218
|
-
permit_offer_expire: "permit_offer_expire";
|
|
219
|
-
permit_offer_supersede: "permit_offer_supersede";
|
|
220
|
-
invite_create: "invite_create";
|
|
221
|
-
invite_delete: "invite_delete";
|
|
222
|
-
app_settings_update: "app_settings_update";
|
|
223
|
-
}>;
|
|
288
|
+
event_type: z.ZodString;
|
|
224
289
|
outcome: z.ZodEnum<{
|
|
225
290
|
success: "success";
|
|
226
291
|
failure: "failure";
|
|
@@ -237,29 +302,7 @@ export type AuditLogEventJson = z.infer<typeof AuditLogEventJson>;
|
|
|
237
302
|
export declare const AuditLogEventWithUsernamesJson: z.ZodObject<{
|
|
238
303
|
id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
|
|
239
304
|
seq: z.ZodNumber;
|
|
240
|
-
event_type: z.
|
|
241
|
-
login: "login";
|
|
242
|
-
logout: "logout";
|
|
243
|
-
bootstrap: "bootstrap";
|
|
244
|
-
signup: "signup";
|
|
245
|
-
password_change: "password_change";
|
|
246
|
-
session_revoke: "session_revoke";
|
|
247
|
-
session_revoke_all: "session_revoke_all";
|
|
248
|
-
token_create: "token_create";
|
|
249
|
-
token_revoke: "token_revoke";
|
|
250
|
-
token_revoke_all: "token_revoke_all";
|
|
251
|
-
permit_grant: "permit_grant";
|
|
252
|
-
permit_revoke: "permit_revoke";
|
|
253
|
-
permit_offer_create: "permit_offer_create";
|
|
254
|
-
permit_offer_accept: "permit_offer_accept";
|
|
255
|
-
permit_offer_decline: "permit_offer_decline";
|
|
256
|
-
permit_offer_retract: "permit_offer_retract";
|
|
257
|
-
permit_offer_expire: "permit_offer_expire";
|
|
258
|
-
permit_offer_supersede: "permit_offer_supersede";
|
|
259
|
-
invite_create: "invite_create";
|
|
260
|
-
invite_delete: "invite_delete";
|
|
261
|
-
app_settings_update: "app_settings_update";
|
|
262
|
-
}>;
|
|
305
|
+
event_type: z.ZodString;
|
|
263
306
|
outcome: z.ZodEnum<{
|
|
264
307
|
success: "success";
|
|
265
308
|
failure: "failure";
|
|
@@ -278,29 +321,7 @@ export type AuditLogEventWithUsernamesJson = z.infer<typeof AuditLogEventWithUse
|
|
|
278
321
|
export declare const PermitHistoryEventJson: z.ZodObject<{
|
|
279
322
|
id: z.core.$ZodBranded<z.ZodUUID, "Uuid", "out">;
|
|
280
323
|
seq: z.ZodNumber;
|
|
281
|
-
event_type: z.
|
|
282
|
-
login: "login";
|
|
283
|
-
logout: "logout";
|
|
284
|
-
bootstrap: "bootstrap";
|
|
285
|
-
signup: "signup";
|
|
286
|
-
password_change: "password_change";
|
|
287
|
-
session_revoke: "session_revoke";
|
|
288
|
-
session_revoke_all: "session_revoke_all";
|
|
289
|
-
token_create: "token_create";
|
|
290
|
-
token_revoke: "token_revoke";
|
|
291
|
-
token_revoke_all: "token_revoke_all";
|
|
292
|
-
permit_grant: "permit_grant";
|
|
293
|
-
permit_revoke: "permit_revoke";
|
|
294
|
-
permit_offer_create: "permit_offer_create";
|
|
295
|
-
permit_offer_accept: "permit_offer_accept";
|
|
296
|
-
permit_offer_decline: "permit_offer_decline";
|
|
297
|
-
permit_offer_retract: "permit_offer_retract";
|
|
298
|
-
permit_offer_expire: "permit_offer_expire";
|
|
299
|
-
permit_offer_supersede: "permit_offer_supersede";
|
|
300
|
-
invite_create: "invite_create";
|
|
301
|
-
invite_delete: "invite_delete";
|
|
302
|
-
app_settings_update: "app_settings_update";
|
|
303
|
-
}>;
|
|
324
|
+
event_type: z.ZodString;
|
|
304
325
|
outcome: z.ZodEnum<{
|
|
305
326
|
success: "success";
|
|
306
327
|
failure: "failure";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit_log_schema.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/audit_log_schema.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,OAAO,EAAC,IAAI,EAAC,MAAM,YAAY,CAAC;AAGhC
|
|
1
|
+
{"version":3,"file":"audit_log_schema.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/audit_log_schema.ts"],"names":[],"mappings":"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"}
|