@voltro/plugin-audit 0.85.0 → 0.87.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 +5987 -0
- package/THIRD-PARTY-NOTICES.md +1122 -31
- package/dist/chain.js +205 -0
- package/dist/index.d.ts +74 -13
- package/dist/index.js +299 -404
- 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 +4 -4
package/dist/index.js
CHANGED
|
@@ -1,434 +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, k)) i[M(e, n)] = N(a, t + 1, n);
|
|
23
|
-
return r.length > k && (i["…"] = `${r.length - k} more key(s)`), i;
|
|
24
|
-
}
|
|
25
|
-
return r;
|
|
26
|
-
}, P = (e, t = 16) => ({ __redacted: N(e, 0, t) }), F = "_voltro_audit_log", I = [
|
|
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
|
-
], L = (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(L).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)}:${L(t)}`).join(",")}}` : JSON.stringify(String(e));
|
|
46
|
-
}, ne = (e) => e instanceof Date ? e.toISOString() : e, re = (e) => L(Object.fromEntries(I.map((t) => [t, ne(e[t] ?? null)]))), ie = (e) => {
|
|
47
|
-
let t = process.env.VOLTRO_AUDIT_CHAIN_SECRET;
|
|
48
|
-
return t ? E("sha256", t).update(e, "utf8").digest("hex") : T("sha256").update(e, "utf8").digest("hex");
|
|
49
|
-
}, R = (e, t) => ie(JSON.stringify([
|
|
50
|
-
t.chainId,
|
|
51
|
-
t.seq,
|
|
52
|
-
t.prevHash,
|
|
53
|
-
re(e)
|
|
54
|
-
])), z = (e = D(12).toString("base64url")) => {
|
|
55
|
-
let t = 0, n = null;
|
|
56
|
-
return {
|
|
57
|
-
chainId: e,
|
|
58
|
-
link: (r) => {
|
|
59
|
-
t += 1;
|
|
60
|
-
let i = R(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
|
-
};
|
|
75
|
-
async function* B(e, t) {
|
|
76
|
-
let n = t.chainId === void 0 ? void 0 : u("chainId", t.chainId), r = (e, t, n) => ({
|
|
77
|
-
table: F,
|
|
78
|
-
predicate: e,
|
|
79
|
-
order: n,
|
|
80
|
-
take: t,
|
|
81
|
-
skip: void 0,
|
|
82
|
-
projection: void 0
|
|
83
|
-
});
|
|
84
|
-
if (t.limit !== void 0) {
|
|
85
|
-
yield* await e.query(r(n, t.limit, [{
|
|
86
|
-
column: "chainId",
|
|
87
|
-
direction: "asc"
|
|
88
|
-
}, {
|
|
89
|
-
column: "seq",
|
|
90
|
-
direction: "asc"
|
|
91
|
-
}]));
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
let i = [...await e.query({
|
|
95
|
-
...r(n, void 0, [{
|
|
96
|
-
column: "chainId",
|
|
97
|
-
direction: "asc"
|
|
98
|
-
}]),
|
|
99
|
-
groupBy: ["chainId"],
|
|
100
|
-
aggregations: [
|
|
101
|
-
l("chainId"),
|
|
102
|
-
{
|
|
103
|
-
op: "max",
|
|
104
|
-
column: "seq",
|
|
105
|
-
alias: "lastSeq"
|
|
106
|
-
},
|
|
107
|
-
{
|
|
108
|
-
op: "max",
|
|
109
|
-
column: "id",
|
|
110
|
-
alias: "lastId"
|
|
111
|
-
}
|
|
112
|
-
]
|
|
113
|
-
})].sort((e, t) => String(e.chainId) < String(t.chainId) ? -1 : +(String(e.chainId) > String(t.chainId)));
|
|
114
|
-
for (let t of i) {
|
|
115
|
-
let n = t.chainId, i = n == null ? h("chainId") : u("chainId", n), a = n == null ? [!1] : [!1, !0];
|
|
116
|
-
for (let o of a) {
|
|
117
|
-
if (o && t.lastSeq == null) continue;
|
|
118
|
-
let a = [i, _("id", t.lastId)];
|
|
119
|
-
n != null && a.push(o ? c(m("seq"), _("seq", t.lastSeq)) : h("seq"));
|
|
120
|
-
let s;
|
|
121
|
-
for (;;) {
|
|
122
|
-
let t = s === void 0 ? void 0 : o ? v(d("seq", s.seq), c(u("seq", s.seq), d("id", s.id))) : d("id", s.id), n = await e.query(r(c(...a, ...t ? [t] : []), 1e3, [...o ? [{
|
|
123
|
-
column: "seq",
|
|
124
|
-
direction: "asc"
|
|
125
|
-
}] : [], {
|
|
126
|
-
column: "id",
|
|
127
|
-
direction: "asc"
|
|
128
|
-
}]));
|
|
129
|
-
if (yield* n, n.length < 1e3) break;
|
|
130
|
-
let i = n[n.length - 1];
|
|
131
|
-
if (i.id === void 0 || i.id === s?.id) throw Error("audit verification cursor did not advance");
|
|
132
|
-
s = i;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
var V = async (e, t = {}) => {
|
|
138
|
-
let n = [], r = [], i = 0, a = 0, o = null, s = () => {
|
|
139
|
-
o &&= (r.push({
|
|
140
|
-
chainId: o.chainId,
|
|
141
|
-
from: o.from,
|
|
142
|
-
to: o.last,
|
|
143
|
-
tip: o.tip,
|
|
144
|
-
prunedPrefix: o.from > 1
|
|
145
|
-
}), null);
|
|
146
|
-
};
|
|
147
|
-
for await (let r of B(e, t)) {
|
|
148
|
-
let e = r.chainId, t = r.hash, c = r.seq;
|
|
149
|
-
if (typeof e != "string" || typeof t != "string" || c == null) {
|
|
150
|
-
i += 1;
|
|
151
|
-
continue;
|
|
152
|
-
}
|
|
153
|
-
let l = Number(c), u = typeof r.prevHash == "string" ? r.prevHash : null, d = typeof r.id == "string" ? r.id : void 0;
|
|
154
|
-
a += 1, !o || o.chainId !== e ? (s(), o = {
|
|
155
|
-
chainId: e,
|
|
156
|
-
from: l,
|
|
157
|
-
last: l,
|
|
158
|
-
tip: t
|
|
159
|
-
}) : (l === o.last + 1 ? u !== o.tip && n.push({
|
|
160
|
-
kind: "broken-link",
|
|
161
|
-
chainId: e,
|
|
162
|
-
seq: l,
|
|
163
|
-
...d ? { rowId: d } : {},
|
|
164
|
-
detail: `prevHash does not match the hash of seq ${o.last}`
|
|
165
|
-
}) : n.push({
|
|
166
|
-
kind: "gap",
|
|
167
|
-
chainId: e,
|
|
168
|
-
seq: o.last + 1,
|
|
169
|
-
detail: `chain jumps from seq ${o.last} to ${l} — ${l - o.last - 1} row(s) missing`
|
|
170
|
-
}), o.last = l, o.tip = t), R(r, {
|
|
171
|
-
chainId: e,
|
|
172
|
-
seq: l,
|
|
173
|
-
prevHash: u
|
|
174
|
-
}) !== t && n.push({
|
|
175
|
-
kind: "tampered",
|
|
176
|
-
chainId: e,
|
|
177
|
-
seq: l,
|
|
178
|
-
...d ? { rowId: d } : {},
|
|
179
|
-
detail: "the row content does not hash to its stored hash — a column was altered"
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
return s(), {
|
|
183
|
-
ok: n.length === 0,
|
|
184
|
-
rowsChecked: a,
|
|
185
|
-
unchainedRows: i,
|
|
186
|
-
chains: r,
|
|
187
|
-
issues: n,
|
|
188
|
-
keyed: !!process.env.VOLTRO_AUDIT_CHAIN_SECRET
|
|
189
|
-
};
|
|
190
|
-
}, H = S(F, {
|
|
191
|
-
id: f({ prefix: "audit" }),
|
|
192
|
-
tag: C(),
|
|
193
|
-
at: w(),
|
|
194
|
-
subjectId: C().nullable(),
|
|
195
|
-
tenantId: C().nullable(),
|
|
196
|
-
traceId: C(),
|
|
197
|
-
status: C(),
|
|
198
|
-
durationMs: C(),
|
|
199
|
-
subject: g(),
|
|
200
|
-
actor: g().nullable(),
|
|
201
|
-
scope: g().nullable(),
|
|
202
|
-
scopeKey: C().nullable(),
|
|
203
|
-
metadata: g().nullable(),
|
|
204
|
-
impersonation: g().nullable(),
|
|
205
|
-
input: g(),
|
|
206
|
-
outcome: g(),
|
|
207
|
-
errorTag: C().nullable(),
|
|
208
|
-
chainId: C().nullable(),
|
|
209
|
-
seq: p().nullable(),
|
|
210
|
-
prevHash: C().nullable(),
|
|
211
|
-
hash: C().nullable()
|
|
212
|
-
}).index("byAuditTag", ["tag"]).index("byAuditTrace", ["traceId"]).index("byAuditSubjectStatus", [
|
|
213
|
-
"subjectId",
|
|
214
|
-
"status",
|
|
215
|
-
"at"
|
|
216
|
-
]).index("byAuditTenantStatus", [
|
|
217
|
-
"tenantId",
|
|
218
|
-
"status",
|
|
219
|
-
"at"
|
|
220
|
-
]).index("byAuditScope", ["scopeKey", "at"]).index("byAuditChain", ["chainId", "seq"]), U = [H], W = (e) => ({
|
|
221
|
-
tag: e.tag,
|
|
222
|
-
at: new Date(e.ts),
|
|
223
|
-
subjectId: e.subject.id ?? null,
|
|
224
|
-
tenantId: e.subject.tenantId ?? null,
|
|
225
|
-
traceId: e.traceId,
|
|
226
|
-
status: e.outcome.kind,
|
|
227
|
-
durationMs: String(e.outcome.durationMs),
|
|
228
|
-
subject: e.subject,
|
|
229
|
-
actor: e.actor ?? null,
|
|
230
|
-
scope: e.scope ?? null,
|
|
231
|
-
scopeKey: x(e.scope),
|
|
232
|
-
metadata: e.metadata ?? null,
|
|
233
|
-
impersonation: e.impersonation ?? null,
|
|
234
|
-
input: e.input,
|
|
235
|
-
outcome: e.outcome,
|
|
236
|
-
errorTag: e.outcome.kind === "error" ? G(e.outcome.error) : null
|
|
237
|
-
}), G = (e) => {
|
|
238
|
-
if (typeof e != "object" || !e) return null;
|
|
239
|
-
let t = e._tag;
|
|
240
|
-
return typeof t == "string" && t !== "" ? t : null;
|
|
241
|
-
}, K = async (e, t) => e.query({
|
|
242
|
-
table: F,
|
|
243
|
-
predicate: u("traceId", t),
|
|
244
|
-
order: [{
|
|
245
|
-
column: "at",
|
|
246
|
-
direction: "asc"
|
|
247
|
-
}]
|
|
248
|
-
}), q = async (e, t, n = {}) => {
|
|
249
|
-
let r = x(t);
|
|
250
|
-
if (r === null) return [];
|
|
251
|
-
let i = u("scopeKey", r);
|
|
252
|
-
return e.query({
|
|
253
|
-
table: F,
|
|
254
|
-
predicate: n.status === void 0 ? i : c(i, u("status", n.status)),
|
|
255
|
-
order: [{
|
|
256
|
-
column: "at",
|
|
257
|
-
direction: "desc"
|
|
258
|
-
}],
|
|
259
|
-
take: n.limit ?? 100
|
|
260
|
-
});
|
|
261
|
-
}, J = async (e, t, n = {}) => {
|
|
262
|
-
let r = u("subjectId", t);
|
|
263
|
-
return e.query({
|
|
264
|
-
table: F,
|
|
265
|
-
predicate: n.status === void 0 ? r : c(r, u("status", n.status)),
|
|
266
|
-
order: [{
|
|
267
|
-
column: "at",
|
|
268
|
-
direction: "desc"
|
|
269
|
-
}],
|
|
270
|
-
take: n.limit ?? 100
|
|
271
|
-
});
|
|
272
|
-
}, Y = (e) => {
|
|
273
|
-
let t = z();
|
|
274
|
-
return async (n) => {
|
|
275
|
-
let r = n.actor !== void 0 || typeof e.query != "function" ? n : {
|
|
276
|
-
...n,
|
|
277
|
-
actor: await y(e, n.subject.id ?? null, n.subject.type)
|
|
278
|
-
};
|
|
279
|
-
await e.insert(F, t.link(W(r)));
|
|
280
|
-
};
|
|
281
|
-
}, X = s({ scope: "@voltro/plugin-audit" }), Z = 1e3, Q = [], ae = () => [...Q], oe = () => {
|
|
282
|
-
Q.length = 0;
|
|
283
|
-
}, se = (e) => {
|
|
284
|
-
Q.push(e), Q.length > Z && Q.splice(0, Q.length - Z);
|
|
285
|
-
}, ce = (e) => {
|
|
286
|
-
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 = {
|
|
287
19
|
subject: t,
|
|
288
20
|
tenant: e.subject.tenantId ?? null,
|
|
289
21
|
status: n,
|
|
290
22
|
durationMs: e.outcome.durationMs,
|
|
291
23
|
traceId: e.traceId
|
|
292
24
|
};
|
|
293
|
-
n === "error" ?
|
|
294
|
-
},
|
|
295
|
-
let
|
|
296
|
-
return
|
|
297
|
-
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),
|
|
298
30
|
catch: (e) => e
|
|
299
31
|
});
|
|
300
|
-
}) : e === "datastore" ? (e) =>
|
|
301
|
-
let
|
|
302
|
-
return
|
|
303
|
-
try: () =>
|
|
32
|
+
}) : e === "datastore" ? (e) => S.suspend(() => {
|
|
33
|
+
let n = t();
|
|
34
|
+
return n ? S.tryPromise({
|
|
35
|
+
try: () => n(e),
|
|
304
36
|
catch: (e) => e
|
|
305
|
-
}) :
|
|
306
|
-
}) : e === "memory" ? (e) =>
|
|
307
|
-
let
|
|
308
|
-
return
|
|
309
|
-
},
|
|
310
|
-
let
|
|
311
|
-
|
|
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({
|
|
312
52
|
source: "plugin",
|
|
313
|
-
table:
|
|
53
|
+
table: t,
|
|
314
54
|
timeColumn: "at",
|
|
315
|
-
ttlMs:
|
|
55
|
+
ttlMs: O(process.env.VOLTRO_AUDIT_LOG_TTL_HOURS, 8760)
|
|
316
56
|
});
|
|
317
|
-
let
|
|
318
|
-
let
|
|
319
|
-
return
|
|
320
|
-
},
|
|
321
|
-
let
|
|
322
|
-
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" ? {
|
|
323
63
|
...t,
|
|
324
|
-
input:
|
|
325
|
-
} :
|
|
64
|
+
input: B
|
|
65
|
+
} : r === "shape" ? {
|
|
326
66
|
...t,
|
|
327
|
-
input:
|
|
67
|
+
input: e(t.input, V)
|
|
328
68
|
} : {
|
|
329
69
|
...t,
|
|
330
|
-
input:
|
|
70
|
+
input: r(t)
|
|
331
71
|
};
|
|
332
|
-
},
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
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 {
|
|
337
78
|
...t,
|
|
338
79
|
outcome: {
|
|
339
|
-
...
|
|
340
|
-
value:
|
|
80
|
+
...i,
|
|
81
|
+
value: a
|
|
341
82
|
}
|
|
342
83
|
};
|
|
343
|
-
let
|
|
84
|
+
let o = i.error, s = typeof o == "object" && o ? o._tag : void 0;
|
|
344
85
|
return {
|
|
345
86
|
...t,
|
|
346
87
|
outcome: {
|
|
347
|
-
...
|
|
348
|
-
error:
|
|
349
|
-
_tag:
|
|
350
|
-
...
|
|
88
|
+
...i,
|
|
89
|
+
error: s === void 0 ? a : {
|
|
90
|
+
_tag: s,
|
|
91
|
+
...a
|
|
351
92
|
}
|
|
352
93
|
}
|
|
353
94
|
};
|
|
354
|
-
},
|
|
355
|
-
let
|
|
356
|
-
if (
|
|
357
|
-
if (typeof
|
|
95
|
+
}, W = (t) => {
|
|
96
|
+
let r = n.redactSubject ?? "metadata";
|
|
97
|
+
if (r === "none") return t;
|
|
98
|
+
if (typeof r == "function") return {
|
|
358
99
|
...t,
|
|
359
|
-
subject:
|
|
100
|
+
subject: r(t.subject)
|
|
360
101
|
};
|
|
361
|
-
let
|
|
362
|
-
if (
|
|
363
|
-
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;
|
|
364
105
|
return {
|
|
365
106
|
...t,
|
|
366
107
|
subject: {
|
|
367
|
-
...
|
|
368
|
-
metadata:
|
|
108
|
+
...o,
|
|
109
|
+
metadata: s
|
|
369
110
|
}
|
|
370
111
|
};
|
|
371
|
-
},
|
|
372
|
-
let t =
|
|
112
|
+
}, G = (e) => {
|
|
113
|
+
let t = ie(e.subject);
|
|
373
114
|
return t === null ? e : {
|
|
374
115
|
...e,
|
|
375
116
|
impersonation: t
|
|
376
117
|
};
|
|
377
|
-
},
|
|
378
|
-
if (e
|
|
379
|
-
|
|
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);
|
|
380
143
|
} catch {
|
|
381
144
|
return;
|
|
382
145
|
}
|
|
383
|
-
},
|
|
384
|
-
tag:
|
|
385
|
-
subject:
|
|
386
|
-
input:
|
|
387
|
-
outcome:
|
|
388
|
-
})).pipe(
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
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({
|
|
412
189
|
ts: r,
|
|
413
|
-
tag:
|
|
414
|
-
subject:
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
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, {
|
|
420
234
|
kind: "error",
|
|
421
|
-
error:
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
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) => {
|
|
427
259
|
let t = `http.${e.method.toUpperCase()} ${e.path}`;
|
|
428
|
-
|
|
260
|
+
F(t) && S.runPromise(J({
|
|
429
261
|
ts: Date.now() - e.durationMs,
|
|
430
262
|
tag: t,
|
|
431
|
-
subject:
|
|
263
|
+
subject: C(null),
|
|
432
264
|
traceId: e.traceId,
|
|
433
265
|
input: {
|
|
434
266
|
method: e.method,
|
|
@@ -451,35 +283,98 @@ var V = async (e, t = {}) => {
|
|
|
451
283
|
value: { status: e.status },
|
|
452
284
|
durationMs: e.durationMs
|
|
453
285
|
}
|
|
454
|
-
}).pipe(
|
|
455
|
-
},
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
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,
|
|
462
348
|
description: "Records every mutation invocation; ships an audit() schema mixin for row-level metadata.",
|
|
463
349
|
permissions: [
|
|
464
350
|
"rpc:intercept:mutation",
|
|
465
351
|
"rpc:intercept:action",
|
|
466
352
|
"rpc:intercept:workflow",
|
|
467
353
|
"http:intercept",
|
|
468
|
-
...
|
|
469
|
-
...
|
|
354
|
+
...r ? ["store:write"] : [],
|
|
355
|
+
...l ? ["outbox:handle"] : [],
|
|
356
|
+
...n.recordQueries === !0 ? ["rpc:intercept:query"] : []
|
|
470
357
|
],
|
|
471
|
-
...
|
|
472
|
-
...
|
|
358
|
+
...r ? {
|
|
359
|
+
...n.tables === !1 ? {} : { extendSchema: { tables: d } },
|
|
473
360
|
bindDataStore: (e) => {
|
|
474
|
-
|
|
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);
|
|
475
364
|
}
|
|
476
365
|
} : {},
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
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 } : {}
|
|
482
377
|
});
|
|
483
378
|
};
|
|
484
379
|
//#endregion
|
|
485
|
-
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 };
|