@voltro/plugin-audit 0.84.0 → 0.86.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/CHANGELOG.md +1215 -0
- package/THIRD-PARTY-NOTICES.md +5 -89
- package/dist/chain.js +205 -0
- package/dist/index.d.ts +75 -14
- package/dist/index.js +301 -375
- package/dist/invocationIdentity.js +11 -0
- package/dist/invocationQuery.js +14 -0
- package/dist/redactionShape.js +22 -0
- package/dist/store.js +183 -0
- package/dist/tableName.js +4 -0
- package/dist/transactionalCapture.js +101 -0
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -1,403 +1,266 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
if (r === "object") {
|
|
21
|
-
let r = Object.entries(e), i = {};
|
|
22
|
-
for (let [e, a] of r.slice(0, S)) i[E(e, n)] = D(a, t + 1, n);
|
|
23
|
-
return r.length > S && (i["…"] = `${r.length - S} more key(s)`), i;
|
|
24
|
-
}
|
|
25
|
-
return r;
|
|
26
|
-
}, O = (e, t = 16) => ({ __redacted: D(e, 0, t) }), k = "_voltro_audit_log", A = [
|
|
27
|
-
"tag",
|
|
28
|
-
"at",
|
|
29
|
-
"subjectId",
|
|
30
|
-
"tenantId",
|
|
31
|
-
"traceId",
|
|
32
|
-
"status",
|
|
33
|
-
"durationMs",
|
|
34
|
-
"subject",
|
|
35
|
-
"actor",
|
|
36
|
-
"scope",
|
|
37
|
-
"metadata",
|
|
38
|
-
"input",
|
|
39
|
-
"outcome",
|
|
40
|
-
"errorTag"
|
|
41
|
-
], j = (e) => {
|
|
42
|
-
if (e == null) return "null";
|
|
43
|
-
if (e instanceof Date) return JSON.stringify(e.toISOString());
|
|
44
|
-
let t = typeof e;
|
|
45
|
-
return t === "number" || t === "boolean" || t === "string" ? JSON.stringify(e) : t === "bigint" ? JSON.stringify(String(e)) : Array.isArray(e) ? `[${e.map(j).join(",")}]` : t === "object" ? `{${Object.entries(e).filter(([, e]) => e !== void 0).sort(([e], [t]) => e < t ? -1 : +(e > t)).map(([e, t]) => `${JSON.stringify(e)}:${j(t)}`).join(",")}}` : JSON.stringify(String(e));
|
|
46
|
-
}, M = (e) => e instanceof Date ? e.toISOString() : e, N = (e) => j(Object.fromEntries(A.map((t) => [t, M(e[t] ?? null)]))), P = (e) => {
|
|
47
|
-
let t = process.env.VOLTRO_AUDIT_CHAIN_SECRET;
|
|
48
|
-
return t ? y("sha256", t).update(e, "utf8").digest("hex") : v("sha256").update(e, "utf8").digest("hex");
|
|
49
|
-
}, F = (e, t) => P(JSON.stringify([
|
|
50
|
-
t.chainId,
|
|
51
|
-
t.seq,
|
|
52
|
-
t.prevHash,
|
|
53
|
-
N(e)
|
|
54
|
-
])), I = (e = b(12).toString("base64url")) => {
|
|
55
|
-
let t = 0, n = null;
|
|
56
|
-
return {
|
|
57
|
-
chainId: e,
|
|
58
|
-
link: (r) => {
|
|
59
|
-
t += 1;
|
|
60
|
-
let i = F(r, {
|
|
61
|
-
chainId: e,
|
|
62
|
-
seq: t,
|
|
63
|
-
prevHash: n
|
|
64
|
-
}), a = {
|
|
65
|
-
...r,
|
|
66
|
-
chainId: e,
|
|
67
|
-
seq: t,
|
|
68
|
-
prevHash: n,
|
|
69
|
-
hash: i
|
|
70
|
-
};
|
|
71
|
-
return n = i, a;
|
|
72
|
-
}
|
|
73
|
-
};
|
|
74
|
-
}, L = async (e, t = {}) => {
|
|
75
|
-
let n = t.chainId === void 0 ? void 0 : c("chainId", t.chainId), r = await e.query({
|
|
76
|
-
table: k,
|
|
77
|
-
...n ? { predicate: n } : {},
|
|
78
|
-
order: [{
|
|
79
|
-
column: "chainId",
|
|
80
|
-
direction: "asc"
|
|
81
|
-
}, {
|
|
82
|
-
column: "seq",
|
|
83
|
-
direction: "asc"
|
|
84
|
-
}],
|
|
85
|
-
...t.limit === void 0 ? {} : { take: t.limit }
|
|
86
|
-
}), i = [], a = [], o = 0, s = 0, l = null, u = () => {
|
|
87
|
-
l &&= (a.push({
|
|
88
|
-
chainId: l.chainId,
|
|
89
|
-
from: l.from,
|
|
90
|
-
to: l.last,
|
|
91
|
-
tip: l.tip,
|
|
92
|
-
prunedPrefix: l.from > 1
|
|
93
|
-
}), null);
|
|
94
|
-
};
|
|
95
|
-
for (let e of r) {
|
|
96
|
-
let t = e.chainId, n = e.hash, r = e.seq;
|
|
97
|
-
if (typeof t != "string" || typeof n != "string" || r == null) {
|
|
98
|
-
o += 1;
|
|
99
|
-
continue;
|
|
100
|
-
}
|
|
101
|
-
let a = Number(r), c = typeof e.prevHash == "string" ? e.prevHash : null, d = typeof e.id == "string" ? e.id : void 0;
|
|
102
|
-
s += 1, !l || l.chainId !== t ? (u(), l = {
|
|
103
|
-
chainId: t,
|
|
104
|
-
from: a,
|
|
105
|
-
last: a,
|
|
106
|
-
tip: n
|
|
107
|
-
}) : (a === l.last + 1 ? c !== l.tip && i.push({
|
|
108
|
-
kind: "broken-link",
|
|
109
|
-
chainId: t,
|
|
110
|
-
seq: a,
|
|
111
|
-
...d ? { rowId: d } : {},
|
|
112
|
-
detail: `prevHash does not match the hash of seq ${l.last}`
|
|
113
|
-
}) : i.push({
|
|
114
|
-
kind: "gap",
|
|
115
|
-
chainId: t,
|
|
116
|
-
seq: l.last + 1,
|
|
117
|
-
detail: `chain jumps from seq ${l.last} to ${a} — ${a - l.last - 1} row(s) missing`
|
|
118
|
-
}), l.last = a, l.tip = n), F(e, {
|
|
119
|
-
chainId: t,
|
|
120
|
-
seq: a,
|
|
121
|
-
prevHash: c
|
|
122
|
-
}) !== n && i.push({
|
|
123
|
-
kind: "tampered",
|
|
124
|
-
chainId: t,
|
|
125
|
-
seq: a,
|
|
126
|
-
...d ? { rowId: d } : {},
|
|
127
|
-
detail: "the row content does not hash to its stored hash — a column was altered"
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
return u(), {
|
|
131
|
-
ok: i.length === 0,
|
|
132
|
-
rowsChecked: s,
|
|
133
|
-
unchainedRows: o,
|
|
134
|
-
chains: a,
|
|
135
|
-
issues: i,
|
|
136
|
-
keyed: !!process.env.VOLTRO_AUDIT_CHAIN_SECRET
|
|
137
|
-
};
|
|
138
|
-
}, R = h(k, {
|
|
139
|
-
id: l({ prefix: "audit" }),
|
|
140
|
-
tag: g(),
|
|
141
|
-
at: _(),
|
|
142
|
-
subjectId: g().nullable(),
|
|
143
|
-
tenantId: g().nullable(),
|
|
144
|
-
traceId: g(),
|
|
145
|
-
status: g(),
|
|
146
|
-
durationMs: g(),
|
|
147
|
-
subject: d(),
|
|
148
|
-
actor: d().nullable(),
|
|
149
|
-
scope: d().nullable(),
|
|
150
|
-
scopeKey: g().nullable(),
|
|
151
|
-
metadata: d().nullable(),
|
|
152
|
-
impersonation: d().nullable(),
|
|
153
|
-
input: d(),
|
|
154
|
-
outcome: d(),
|
|
155
|
-
errorTag: g().nullable(),
|
|
156
|
-
chainId: g().nullable(),
|
|
157
|
-
seq: u().nullable(),
|
|
158
|
-
prevHash: g().nullable(),
|
|
159
|
-
hash: g().nullable()
|
|
160
|
-
}).index("byAuditTag", ["tag"]).index("byAuditTrace", ["traceId"]).index("byAuditSubjectStatus", [
|
|
161
|
-
"subjectId",
|
|
162
|
-
"status",
|
|
163
|
-
"at"
|
|
164
|
-
]).index("byAuditTenantStatus", [
|
|
165
|
-
"tenantId",
|
|
166
|
-
"status",
|
|
167
|
-
"at"
|
|
168
|
-
]).index("byAuditScope", ["scopeKey", "at"]).index("byAuditChain", ["chainId", "seq"]), z = [R], B = (e) => ({
|
|
169
|
-
tag: e.tag,
|
|
170
|
-
at: new Date(e.ts),
|
|
171
|
-
subjectId: e.subject.id ?? null,
|
|
172
|
-
tenantId: e.subject.tenantId ?? null,
|
|
173
|
-
traceId: e.traceId,
|
|
174
|
-
status: e.outcome.kind,
|
|
175
|
-
durationMs: String(e.outcome.durationMs),
|
|
176
|
-
subject: e.subject,
|
|
177
|
-
actor: e.actor ?? null,
|
|
178
|
-
scope: e.scope ?? null,
|
|
179
|
-
scopeKey: m(e.scope),
|
|
180
|
-
metadata: e.metadata ?? null,
|
|
181
|
-
impersonation: e.impersonation ?? null,
|
|
182
|
-
input: e.input,
|
|
183
|
-
outcome: e.outcome,
|
|
184
|
-
errorTag: e.outcome.kind === "error" ? V(e.outcome.error) : null
|
|
185
|
-
}), V = (e) => {
|
|
186
|
-
if (typeof e != "object" || !e) return null;
|
|
187
|
-
let t = e._tag;
|
|
188
|
-
return typeof t == "string" && t !== "" ? t : null;
|
|
189
|
-
}, H = async (e, t) => e.query({
|
|
190
|
-
table: k,
|
|
191
|
-
predicate: c("traceId", t),
|
|
192
|
-
order: [{
|
|
193
|
-
column: "at",
|
|
194
|
-
direction: "asc"
|
|
195
|
-
}]
|
|
196
|
-
}), U = async (e, t, n = {}) => {
|
|
197
|
-
let r = m(t);
|
|
198
|
-
if (r === null) return [];
|
|
199
|
-
let i = c("scopeKey", r);
|
|
200
|
-
return e.query({
|
|
201
|
-
table: k,
|
|
202
|
-
predicate: n.status === void 0 ? i : s(i, c("status", n.status)),
|
|
203
|
-
order: [{
|
|
204
|
-
column: "at",
|
|
205
|
-
direction: "desc"
|
|
206
|
-
}],
|
|
207
|
-
take: n.limit ?? 100
|
|
208
|
-
});
|
|
209
|
-
}, W = async (e, t, n = {}) => {
|
|
210
|
-
let r = c("subjectId", t);
|
|
211
|
-
return e.query({
|
|
212
|
-
table: k,
|
|
213
|
-
predicate: n.status === void 0 ? r : s(r, c("status", n.status)),
|
|
214
|
-
order: [{
|
|
215
|
-
column: "at",
|
|
216
|
-
direction: "desc"
|
|
217
|
-
}],
|
|
218
|
-
take: n.limit ?? 100
|
|
219
|
-
});
|
|
220
|
-
}, G = (e) => {
|
|
221
|
-
let t = I();
|
|
222
|
-
return async (n) => {
|
|
223
|
-
let r = n.actor !== void 0 || typeof e.query != "function" ? n : {
|
|
224
|
-
...n,
|
|
225
|
-
actor: await f(e, n.subject.id ?? null, n.subject.type)
|
|
226
|
-
};
|
|
227
|
-
await e.insert(k, t.link(B(r)));
|
|
228
|
-
};
|
|
229
|
-
}, K = o({ scope: "@voltro/plugin-audit" }), q = 1e3, J = [], Y = () => [...J], X = () => {
|
|
230
|
-
J.length = 0;
|
|
231
|
-
}, Z = (e) => {
|
|
232
|
-
J.push(e), J.length > q && J.splice(0, J.length - q);
|
|
233
|
-
}, Q = (e) => {
|
|
234
|
-
let t = e.subject.id ? `${e.subject.type}:${e.subject.id}` : e.subject.type, n = e.outcome.kind === "ok" ? "ok" : "error", r = {
|
|
1
|
+
import { shapeRedaction as e } from "./redactionShape.js";
|
|
2
|
+
import { AUDIT_LOG_TABLE as t } from "./tableName.js";
|
|
3
|
+
import { auditRowHash as n, makeAuditChain as r, verifyAuditChain as i } from "./chain.js";
|
|
4
|
+
import { assertAuditReceipt as a, auditByScope as o, auditBySubject as s, auditByTrace as c, auditEventToRow as l, auditLogTable as u, auditLogTables as d, dataStoreAuditSink as f } from "./store.js";
|
|
5
|
+
import { decodeAuditAdmissionIntent as ee, decodeAuditFailureIntent as te, decodeAuditIntent as p, decodeAuditInvocationOutcomeIntent as m, freezeAuditAdmissionIntent as h, freezeAuditFailureIntent as ne, freezeAuditIntent as g, freezeAuditInvocationOutcomeIntent as _ } from "./transactionalCapture.js";
|
|
6
|
+
import { audit as v } from "./mixin.js";
|
|
7
|
+
import { auditInvocationIdentity as y, auditInvocationQuery as b } from "./invocationQuery.js";
|
|
8
|
+
import { Cause as x, Effect as S } from "effect";
|
|
9
|
+
import { anonymousSubject as C, definePlugin as w, pluginInstanceName as re, rawImpersonationMark as ie } from "@voltro/protocol";
|
|
10
|
+
import { createLogger as T } from "@voltro/logger";
|
|
11
|
+
import { eq as ae, generateId as E, registerRetention as D, resolveActorSnapshot as oe, retentionTtlMsFromEnv as O } from "@voltro/database";
|
|
12
|
+
//#region src/index.ts
|
|
13
|
+
var k = T({ scope: "@voltro/plugin-audit" }), A = 1e3, j = [], M = () => [...j], N = () => {
|
|
14
|
+
j.length = 0;
|
|
15
|
+
}, P = (e) => {
|
|
16
|
+
j.push(e), j.length > A && j.splice(0, j.length - A);
|
|
17
|
+
}, F = (e) => {
|
|
18
|
+
let t = e.subject.id ? `${e.subject.type}:${e.subject.id}` : e.subject.type, n = e.outcome.kind, r = {
|
|
235
19
|
subject: t,
|
|
236
20
|
tenant: e.subject.tenantId ?? null,
|
|
237
21
|
status: n,
|
|
238
22
|
durationMs: e.outcome.durationMs,
|
|
239
23
|
traceId: e.traceId
|
|
240
24
|
};
|
|
241
|
-
n === "error" ?
|
|
242
|
-
},
|
|
243
|
-
let
|
|
244
|
-
return
|
|
245
|
-
try: () => Promise.resolve(
|
|
25
|
+
n === "error" ? k.warn(e.tag, r) : k.info(e.tag, r);
|
|
26
|
+
}, I = (e, t) => typeof e == "function" ? (t) => S.suspend(() => {
|
|
27
|
+
let n = e(t);
|
|
28
|
+
return n === void 0 ? S.void : S.isEffect(n) ? n : S.tryPromise({
|
|
29
|
+
try: () => Promise.resolve(n),
|
|
246
30
|
catch: (e) => e
|
|
247
31
|
});
|
|
248
|
-
}) : e === "datastore" ? (e) =>
|
|
249
|
-
let
|
|
250
|
-
return
|
|
251
|
-
try: () =>
|
|
32
|
+
}) : e === "datastore" ? (e) => S.suspend(() => {
|
|
33
|
+
let n = t();
|
|
34
|
+
return n ? S.tryPromise({
|
|
35
|
+
try: () => n(e),
|
|
252
36
|
catch: (e) => e
|
|
253
|
-
}) :
|
|
254
|
-
}) : e === "memory" ? (e) =>
|
|
255
|
-
let t =
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
return;
|
|
269
|
-
}
|
|
270
|
-
if (e._tag === "Parallel") {
|
|
271
|
-
r(e.left), r(e.right);
|
|
272
|
-
return;
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
};
|
|
277
|
-
return r(e), t[0] ?? n[0] ?? e;
|
|
278
|
-
}, $ = "@voltro/plugin-audit", re = (e = {}) => {
|
|
279
|
-
let o = e.sink === "datastore";
|
|
280
|
-
o && ee({
|
|
37
|
+
}) : S.void;
|
|
38
|
+
}) : e === "memory" ? (e) => S.sync(() => P(e)) : (e) => S.sync(() => F(e)), L = (e) => {
|
|
39
|
+
let t = e.reasons.filter(x.isFailReason).map((e) => e.error), n = e.reasons.filter(x.isDieReason).map((e) => e.defect);
|
|
40
|
+
return t[0] ?? n[0] ?? e;
|
|
41
|
+
}, R = "@voltro/plugin-audit", z = (n = {}) => {
|
|
42
|
+
let r = n.sink === "datastore", i = n.mutationCapture === "transactional-outbox", o = n.failureCapture === "outbox", s = n.successCapture === "outbox", c = n.invocationCapture === "required", l = i || o || s;
|
|
43
|
+
if (o && !r) throw TypeError("Outbox failure capture requires datastore sink");
|
|
44
|
+
if (s && !r) throw TypeError("Outbox success capture requires datastore sink");
|
|
45
|
+
if (i && !r) throw TypeError("Transactional audit capture requires the datastore sink");
|
|
46
|
+
if (c && (!r || !s || !o || n.record !== void 0 && n.record !== "all")) throw TypeError("Required invocation capture needs datastore sink, success/failure outbox capture and record: all");
|
|
47
|
+
let u = re({
|
|
48
|
+
base: R,
|
|
49
|
+
alias: n.alias
|
|
50
|
+
}), v = u + "/append", y = u + "/append-failure", b = u + "/append-invocation-outcome";
|
|
51
|
+
r && D({
|
|
281
52
|
source: "plugin",
|
|
282
|
-
table:
|
|
53
|
+
table: t,
|
|
283
54
|
timeColumn: "at",
|
|
284
|
-
ttlMs:
|
|
55
|
+
ttlMs: O(process.env.VOLTRO_AUDIT_LOG_TTL_HOURS, 8760)
|
|
285
56
|
});
|
|
286
|
-
let
|
|
287
|
-
let
|
|
288
|
-
return
|
|
289
|
-
},
|
|
290
|
-
let
|
|
291
|
-
return
|
|
57
|
+
let T, A, j = I(n.sink, () => T), M = (e) => e === void 0 || !e.global && !e.sticky ? e : new RegExp(e.source, e.flags.replace(/[gy]/g, "")), N = M(n.exclude), P = M(n.include), F = (e) => !(N?.test(e) || P && !P.test(e)), z = (e) => {
|
|
58
|
+
let t = n.record ?? "all";
|
|
59
|
+
return t === "all" ? !0 : t === "errors" ? e.outcome.kind === "error" : t(e);
|
|
60
|
+
}, B = { __redacted: "all" }, V = n.redactionLengthFloor ?? 16, H = (t) => {
|
|
61
|
+
let r = n.redactInput ?? "all";
|
|
62
|
+
return r === "none" ? t : r === "all" ? {
|
|
292
63
|
...t,
|
|
293
|
-
input:
|
|
294
|
-
} :
|
|
64
|
+
input: B
|
|
65
|
+
} : r === "shape" ? {
|
|
295
66
|
...t,
|
|
296
|
-
input:
|
|
67
|
+
input: e(t.input, V)
|
|
297
68
|
} : {
|
|
298
69
|
...t,
|
|
299
|
-
input:
|
|
70
|
+
input: r(t)
|
|
300
71
|
};
|
|
301
|
-
},
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
72
|
+
}, U = (t) => {
|
|
73
|
+
if (t.outcome.kind === "unknown") return t;
|
|
74
|
+
let r = n.redactOutcome ?? "all";
|
|
75
|
+
if (r === "none") return t;
|
|
76
|
+
let i = { ...t.outcome }, a = r === "all" ? B : r === "shape" ? ((t) => e(t, V))(i.kind === "ok" ? i.value : i.error) : r(t);
|
|
77
|
+
if (i.kind === "ok") return {
|
|
306
78
|
...t,
|
|
307
79
|
outcome: {
|
|
308
|
-
...
|
|
309
|
-
value:
|
|
80
|
+
...i,
|
|
81
|
+
value: a
|
|
310
82
|
}
|
|
311
83
|
};
|
|
312
|
-
let
|
|
84
|
+
let o = i.error, s = typeof o == "object" && o ? o._tag : void 0;
|
|
313
85
|
return {
|
|
314
86
|
...t,
|
|
315
87
|
outcome: {
|
|
316
|
-
...
|
|
317
|
-
error:
|
|
318
|
-
_tag:
|
|
319
|
-
...
|
|
88
|
+
...i,
|
|
89
|
+
error: s === void 0 ? a : {
|
|
90
|
+
_tag: s,
|
|
91
|
+
...a
|
|
320
92
|
}
|
|
321
93
|
}
|
|
322
94
|
};
|
|
323
|
-
},
|
|
324
|
-
let
|
|
325
|
-
if (
|
|
326
|
-
if (typeof
|
|
95
|
+
}, W = (t) => {
|
|
96
|
+
let r = n.redactSubject ?? "metadata";
|
|
97
|
+
if (r === "none") return t;
|
|
98
|
+
if (typeof r == "function") return {
|
|
327
99
|
...t,
|
|
328
|
-
subject:
|
|
100
|
+
subject: r(t.subject)
|
|
329
101
|
};
|
|
330
|
-
let
|
|
331
|
-
if (
|
|
332
|
-
let { metadata:
|
|
102
|
+
let i = t.subject;
|
|
103
|
+
if (i.metadata === void 0) return t;
|
|
104
|
+
let { metadata: a, ...o } = i, s = r === "metadata-shape" ? e(a, V) : B;
|
|
333
105
|
return {
|
|
334
106
|
...t,
|
|
335
107
|
subject: {
|
|
336
|
-
...
|
|
337
|
-
metadata:
|
|
108
|
+
...o,
|
|
109
|
+
metadata: s
|
|
338
110
|
}
|
|
339
111
|
};
|
|
340
|
-
},
|
|
341
|
-
let t =
|
|
112
|
+
}, G = (e) => {
|
|
113
|
+
let t = ie(e.subject);
|
|
342
114
|
return t === null ? e : {
|
|
343
115
|
...e,
|
|
344
116
|
impersonation: t
|
|
345
117
|
};
|
|
346
|
-
},
|
|
347
|
-
if (e
|
|
348
|
-
|
|
118
|
+
}, K = (e) => U(W(H(G(e)))), se = (e) => {
|
|
119
|
+
if (e == null) return null;
|
|
120
|
+
if (n.redactActor === void 0) return e;
|
|
121
|
+
let { id: t, type: r } = e, i = n.redactActor(Object.freeze({ ...e }));
|
|
122
|
+
if (typeof i != "object" || !i) throw TypeError("Actor redaction must return displayName and email labels");
|
|
123
|
+
let { displayName: a, email: o } = i;
|
|
124
|
+
if (a !== null && typeof a != "string" || o !== null && typeof o != "string") throw TypeError("Actor redaction labels must be strings or null");
|
|
125
|
+
return {
|
|
126
|
+
id: t,
|
|
127
|
+
type: r,
|
|
128
|
+
displayName: a,
|
|
129
|
+
email: o
|
|
130
|
+
};
|
|
131
|
+
}, q = async (e, t) => {
|
|
132
|
+
let n = e.actor === void 0 ? t === void 0 ? null : await oe(t, e.subject.id, e.subject.type) : e.actor;
|
|
133
|
+
return {
|
|
134
|
+
...K(e),
|
|
135
|
+
actor: se(n)
|
|
136
|
+
};
|
|
137
|
+
}, J = (e) => z(e) ? n.redactActor === void 0 ? j(K(e)) : S.tryPromise({
|
|
138
|
+
try: () => q(e, A),
|
|
139
|
+
catch: (e) => e
|
|
140
|
+
}).pipe(S.flatMap(j)) : S.void, Y = (e) => {
|
|
141
|
+
if (n.resolveScope !== void 0) try {
|
|
142
|
+
return n.resolveScope(e);
|
|
349
143
|
} catch {
|
|
350
144
|
return;
|
|
351
145
|
}
|
|
352
|
-
},
|
|
353
|
-
tag:
|
|
354
|
-
subject:
|
|
355
|
-
input:
|
|
356
|
-
outcome:
|
|
357
|
-
})).pipe(
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
146
|
+
}, X = (e, t) => n.metadata === void 0 ? S.succeed(void 0) : S.tryPromise(async () => n.metadata({
|
|
147
|
+
tag: e.tag,
|
|
148
|
+
subject: e.subject,
|
|
149
|
+
input: e.input,
|
|
150
|
+
outcome: t
|
|
151
|
+
})).pipe(S.catchCause(() => S.succeed(void 0))), Z = (e, t, r, i) => S.tryPromise({
|
|
152
|
+
try: async () => {
|
|
153
|
+
let a = i === void 0 ? n.resolveScope?.(e) : i.scope, o = {
|
|
154
|
+
...r,
|
|
155
|
+
durationMs: Date.now() - t,
|
|
156
|
+
...i === void 0 ? {} : { invocationId: i.outcome.invocationId }
|
|
157
|
+
}, s = await n.metadata?.({
|
|
158
|
+
...e,
|
|
159
|
+
outcome: { ...o }
|
|
160
|
+
}), c = {
|
|
161
|
+
ts: t,
|
|
162
|
+
tag: e.tag,
|
|
163
|
+
subject: e.subject,
|
|
164
|
+
traceId: e.traceId,
|
|
165
|
+
input: e.input,
|
|
166
|
+
outcome: o,
|
|
167
|
+
...a === void 0 ? {} : { scope: a },
|
|
168
|
+
...s === void 0 ? {} : { metadata: s }
|
|
169
|
+
};
|
|
170
|
+
if (!z(c)) return;
|
|
171
|
+
if (e.enqueueOutcome === void 0 || A === void 0) throw TypeError("Required audit outcome capture is unavailable");
|
|
172
|
+
let l = i === void 0 ? await q(c, A) : U({
|
|
173
|
+
...i,
|
|
174
|
+
outcome: o,
|
|
175
|
+
...s === void 0 ? {} : { metadata: s }
|
|
176
|
+
}), u = i === void 0 ? r.kind === "error" ? ne(l) : g(l) : _(l);
|
|
177
|
+
await e.enqueueOutcome(i === void 0 ? r.kind === "error" ? y : v : b, u);
|
|
178
|
+
},
|
|
179
|
+
catch: (e) => e
|
|
180
|
+
}), ce = (e, r) => S.tryPromise({
|
|
181
|
+
try: async () => {
|
|
182
|
+
if (e.enqueueOutcome === void 0 || A === void 0 || T === void 0) throw TypeError("Required audit invocation capture is unavailable");
|
|
183
|
+
let i = E({
|
|
184
|
+
kind: "typeid",
|
|
185
|
+
prefix: "audit"
|
|
186
|
+
}, t);
|
|
187
|
+
if (i === null) throw TypeError("Audit invocation identity is unavailable");
|
|
188
|
+
let a = n.resolveScope?.(e), o = await q({
|
|
381
189
|
ts: r,
|
|
382
|
-
tag:
|
|
383
|
-
subject:
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
190
|
+
tag: e.tag,
|
|
191
|
+
subject: e.subject,
|
|
192
|
+
traceId: e.traceId,
|
|
193
|
+
input: e.input,
|
|
194
|
+
...a === void 0 ? {} : { scope: a },
|
|
195
|
+
outcome: Object.freeze({
|
|
196
|
+
kind: "unknown",
|
|
197
|
+
invocationId: i,
|
|
198
|
+
durationMs: 0
|
|
199
|
+
})
|
|
200
|
+
}, A), s = ee(h(o));
|
|
201
|
+
return await T(s, i), s;
|
|
202
|
+
},
|
|
203
|
+
catch: (e) => e
|
|
204
|
+
}), Q = (e, t) => {
|
|
205
|
+
if (!F(t.tag)) return e;
|
|
206
|
+
let n = i && t.kind === "mutation", r = o && t.kind !== "query", a = s && (t.kind === "action" || t.kind === "workflow"), l = c && (t.kind === "action" || t.kind === "workflow");
|
|
207
|
+
return S.suspend(() => {
|
|
208
|
+
let i = Date.now(), o = n || r || a ? void 0 : Y(t), s = (s) => e.pipe(S.tap((e) => n ? S.void : a ? Z(t, i, {
|
|
209
|
+
kind: "ok",
|
|
210
|
+
value: e
|
|
211
|
+
}, s).pipe(S.catchCause(() => (k.warn("Audit success capture could not be queued", { tag: t.tag }), S.void))) : S.suspend(() => {
|
|
212
|
+
let n = r ? Y(t) : o;
|
|
213
|
+
return X(t, {
|
|
214
|
+
kind: "ok",
|
|
215
|
+
value: e
|
|
216
|
+
}).pipe(S.flatMap((r) => J({
|
|
217
|
+
ts: i,
|
|
218
|
+
tag: t.tag,
|
|
219
|
+
subject: t.subject,
|
|
220
|
+
...n === void 0 ? {} : { scope: n },
|
|
221
|
+
...r === void 0 ? {} : { metadata: r },
|
|
222
|
+
traceId: t.traceId,
|
|
223
|
+
input: t.input,
|
|
224
|
+
outcome: {
|
|
225
|
+
kind: "ok",
|
|
226
|
+
value: e,
|
|
227
|
+
durationMs: Date.now() - i
|
|
228
|
+
}
|
|
229
|
+
}))).pipe(S.catchCause(() => S.void));
|
|
230
|
+
})), S.tapCause((e) => {
|
|
231
|
+
if (s !== void 0 && x.hasInterrupts(e)) return S.void;
|
|
232
|
+
let c = L(e);
|
|
233
|
+
if (r) return Z(t, i, {
|
|
389
234
|
kind: "error",
|
|
390
|
-
error:
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
235
|
+
error: c
|
|
236
|
+
}, s).pipe(S.catchCause(() => (k.warn("Audit failure capture could not be queued", { tag: t.tag }), S.void)));
|
|
237
|
+
let l = n || a ? Y(t) : o;
|
|
238
|
+
return X(t, {
|
|
239
|
+
kind: "error",
|
|
240
|
+
error: c
|
|
241
|
+
}).pipe(S.flatMap((e) => J({
|
|
242
|
+
ts: i,
|
|
243
|
+
tag: t.tag,
|
|
244
|
+
subject: t.subject,
|
|
245
|
+
...l === void 0 ? {} : { scope: l },
|
|
246
|
+
...e === void 0 ? {} : { metadata: e },
|
|
247
|
+
traceId: t.traceId,
|
|
248
|
+
input: t.input,
|
|
249
|
+
outcome: {
|
|
250
|
+
kind: "error",
|
|
251
|
+
error: c,
|
|
252
|
+
durationMs: Date.now() - i
|
|
253
|
+
}
|
|
254
|
+
}))).pipe(S.catchCause(() => S.void));
|
|
255
|
+
}));
|
|
256
|
+
return l ? ce(t, i).pipe(S.flatMap(s)) : s();
|
|
257
|
+
});
|
|
258
|
+
}, le = (e) => {
|
|
259
|
+
let t = `http.${e.method.toUpperCase()} ${e.path}`;
|
|
260
|
+
F(t) && S.runPromise(J({
|
|
398
261
|
ts: Date.now() - e.durationMs,
|
|
399
|
-
tag:
|
|
400
|
-
subject:
|
|
262
|
+
tag: t,
|
|
263
|
+
subject: C(null),
|
|
401
264
|
traceId: e.traceId,
|
|
402
265
|
input: {
|
|
403
266
|
method: e.method,
|
|
@@ -420,35 +283,98 @@ var x = 4, S = 32, C = 64, w = /^[A-Za-z_$][A-Za-z0-9_$]*$/, T = (e, t) => e ===
|
|
|
420
283
|
value: { status: e.status },
|
|
421
284
|
durationMs: e.durationMs
|
|
422
285
|
}
|
|
423
|
-
}).pipe(
|
|
424
|
-
},
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
286
|
+
}).pipe(S.catchCause(() => S.void)));
|
|
287
|
+
}, ue = Q, de = Q, fe = Q, pe = Q, me = (e) => S.tryPromise({
|
|
288
|
+
try: async () => {
|
|
289
|
+
if (!F(e.tag)) return;
|
|
290
|
+
if (e.outbox === void 0) throw TypeError("Required audit transaction outbox is unavailable");
|
|
291
|
+
if (e.startedAt === void 0 || e.durationMs === void 0) throw TypeError("Required audit execution timing is unavailable");
|
|
292
|
+
let t = n.resolveScope?.(e), r = {
|
|
293
|
+
kind: "ok",
|
|
294
|
+
value: e.output,
|
|
295
|
+
durationMs: e.durationMs
|
|
296
|
+
}, i = await n.metadata?.({
|
|
297
|
+
...e,
|
|
298
|
+
outcome: r
|
|
299
|
+
}), a = {
|
|
300
|
+
ts: e.startedAt,
|
|
301
|
+
tag: e.tag,
|
|
302
|
+
subject: e.subject,
|
|
303
|
+
traceId: e.traceId,
|
|
304
|
+
input: e.input,
|
|
305
|
+
outcome: r,
|
|
306
|
+
...t === void 0 ? {} : { scope: t },
|
|
307
|
+
...i === void 0 ? {} : { metadata: i }
|
|
308
|
+
};
|
|
309
|
+
if (!z(a)) return;
|
|
310
|
+
let o = await q(a, e.store), s = g(o);
|
|
311
|
+
await e.outbox.enqueue(v, s);
|
|
312
|
+
},
|
|
313
|
+
catch: (e) => e
|
|
314
|
+
}), $ = (e, n) => ({
|
|
315
|
+
effect: e,
|
|
316
|
+
handler: (r) => S.tryPromise({
|
|
317
|
+
try: async () => {
|
|
318
|
+
let i = n(r.payload);
|
|
319
|
+
if (r.subjectId !== i.subject.id || r.tenantId !== i.subject.tenantId || r.traceId !== i.traceId) throw TypeError("Audit intent does not match its captured delivery authority");
|
|
320
|
+
if (T === void 0) throw TypeError("Required audit datastore is not bound");
|
|
321
|
+
if (e === b) {
|
|
322
|
+
let e = i.outcome.invocationId;
|
|
323
|
+
if (e === void 0 || A === void 0) throw TypeError("Audit invocation admission is unavailable");
|
|
324
|
+
let n = (await A.query({
|
|
325
|
+
table: t,
|
|
326
|
+
predicate: ae("id", e),
|
|
327
|
+
order: [],
|
|
328
|
+
take: 1
|
|
329
|
+
})).find((t) => t.id === e);
|
|
330
|
+
if (n === void 0) throw TypeError("Audit invocation admission is missing");
|
|
331
|
+
a({
|
|
332
|
+
...i,
|
|
333
|
+
metadata: void 0,
|
|
334
|
+
outcome: {
|
|
335
|
+
kind: "unknown",
|
|
336
|
+
invocationId: e,
|
|
337
|
+
durationMs: 0
|
|
338
|
+
}
|
|
339
|
+
}, n), await T(i, e + ":outcome");
|
|
340
|
+
} else await T(i, r.outboxId);
|
|
341
|
+
},
|
|
342
|
+
catch: (e) => e
|
|
343
|
+
})
|
|
344
|
+
});
|
|
345
|
+
return w({
|
|
346
|
+
name: u,
|
|
347
|
+
baseName: R,
|
|
431
348
|
description: "Records every mutation invocation; ships an audit() schema mixin for row-level metadata.",
|
|
432
349
|
permissions: [
|
|
433
350
|
"rpc:intercept:mutation",
|
|
434
351
|
"rpc:intercept:action",
|
|
435
352
|
"rpc:intercept:workflow",
|
|
436
353
|
"http:intercept",
|
|
437
|
-
...
|
|
438
|
-
...
|
|
354
|
+
...r ? ["store:write"] : [],
|
|
355
|
+
...l ? ["outbox:handle"] : [],
|
|
356
|
+
...n.recordQueries === !0 ? ["rpc:intercept:query"] : []
|
|
439
357
|
],
|
|
440
|
-
...
|
|
441
|
-
...
|
|
358
|
+
...r ? {
|
|
359
|
+
...n.tables === !1 ? {} : { extendSchema: { tables: d } },
|
|
442
360
|
bindDataStore: (e) => {
|
|
443
|
-
|
|
361
|
+
if (o && (typeof e != "object" || !e || !("query" in e) || typeof e.query != "function")) throw TypeError("Audit failure capture requires readable persistence");
|
|
362
|
+
if (s && (typeof e != "object" || !e || !("query" in e) || typeof e.query != "function")) throw TypeError("Audit success capture requires readable persistence");
|
|
363
|
+
T = f(e), typeof e == "object" && e && "query" in e && typeof e.query == "function" && (A = e);
|
|
444
364
|
}
|
|
445
365
|
} : {},
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
366
|
+
...i ? { beforeMutationCommit: me } : {},
|
|
367
|
+
...l ? { outboxHandlers: [
|
|
368
|
+
...i || s ? [$(v, p)] : [],
|
|
369
|
+
...o ? [$(y, te)] : [],
|
|
370
|
+
...c ? [$(b, m)] : []
|
|
371
|
+
] } : {},
|
|
372
|
+
interceptMutation: ue,
|
|
373
|
+
interceptAction: de,
|
|
374
|
+
interceptWorkflow: fe,
|
|
375
|
+
onHttpRoute: le,
|
|
376
|
+
...n.recordQueries === !0 ? { interceptQuery: pe } : {}
|
|
451
377
|
});
|
|
452
378
|
};
|
|
453
379
|
//#endregion
|
|
454
|
-
export {
|
|
380
|
+
export { t as AUDIT_LOG_TABLE, v as audit, o as auditByScope, s as auditBySubject, c as auditByTrace, l as auditEventToRow, y as auditInvocationIdentity, b as auditInvocationQuery, u as auditLogTable, d as auditLogTables, z as auditPlugin, n as auditRowHash, N as clearAuditBuffer, f as dataStoreAuditSink, r as makeAuditChain, M as readAuditBuffer, i as verifyAuditChain };
|