@usebetterdev/audit-drizzle 0.6.1 → 0.8.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/index.cjs +145 -350
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +40 -42
- package/dist/index.d.ts +40 -42
- package/dist/index.js +144 -342
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -21,19 +21,19 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
auditLogs: () => auditLogs,
|
|
24
|
-
buildCursorCondition: () => buildCursorCondition,
|
|
25
24
|
buildOrderBy: () => buildOrderBy,
|
|
26
25
|
buildWhereConditions: () => buildWhereConditions,
|
|
27
|
-
decodeCursor: () => decodeCursor,
|
|
26
|
+
decodeCursor: () => import_audit_core7.decodeCursor,
|
|
28
27
|
drizzleAuditAdapter: () => drizzleAuditAdapter,
|
|
29
28
|
drizzleSqliteAuditAdapter: () => drizzleSqliteAuditAdapter,
|
|
30
|
-
encodeCursor: () => encodeCursor,
|
|
29
|
+
encodeCursor: () => import_audit_core7.encodeCursor,
|
|
31
30
|
sqliteAuditLogs: () => sqliteAuditLogs,
|
|
32
31
|
withAuditProxy: () => withAuditProxy
|
|
33
32
|
});
|
|
34
33
|
module.exports = __toCommonJS(index_exports);
|
|
35
34
|
|
|
36
35
|
// src/adapter.ts
|
|
36
|
+
var import_audit_core3 = require("@usebetterdev/audit-core");
|
|
37
37
|
var import_drizzle_orm2 = require("drizzle-orm");
|
|
38
38
|
|
|
39
39
|
// src/schema.ts
|
|
@@ -77,23 +77,7 @@ var auditLogs = (0, import_pg_core.pgTable)(
|
|
|
77
77
|
);
|
|
78
78
|
|
|
79
79
|
// src/column-map.ts
|
|
80
|
-
var
|
|
81
|
-
"INSERT",
|
|
82
|
-
"UPDATE",
|
|
83
|
-
"DELETE"
|
|
84
|
-
]);
|
|
85
|
-
var VALID_SEVERITIES = /* @__PURE__ */ new Set([
|
|
86
|
-
"low",
|
|
87
|
-
"medium",
|
|
88
|
-
"high",
|
|
89
|
-
"critical"
|
|
90
|
-
]);
|
|
91
|
-
function isAuditOperation(value) {
|
|
92
|
-
return VALID_OPERATIONS.has(value);
|
|
93
|
-
}
|
|
94
|
-
function isAuditSeverity(value) {
|
|
95
|
-
return VALID_SEVERITIES.has(value);
|
|
96
|
-
}
|
|
80
|
+
var import_audit_core = require("@usebetterdev/audit-core");
|
|
97
81
|
function auditLogToRow(log) {
|
|
98
82
|
const row = {
|
|
99
83
|
id: log.id,
|
|
@@ -141,7 +125,7 @@ function auditLogToRow(log) {
|
|
|
141
125
|
return row;
|
|
142
126
|
}
|
|
143
127
|
function rowToAuditLog(row) {
|
|
144
|
-
if (!isAuditOperation(row.operation)) {
|
|
128
|
+
if (!(0, import_audit_core.isAuditOperation)(row.operation)) {
|
|
145
129
|
throw new Error(
|
|
146
130
|
`Invalid audit operation: "${row.operation}". Expected one of: INSERT, UPDATE, DELETE`
|
|
147
131
|
);
|
|
@@ -172,7 +156,7 @@ function rowToAuditLog(row) {
|
|
|
172
156
|
log.description = row.description;
|
|
173
157
|
}
|
|
174
158
|
if (row.severity !== null && row.severity !== void 0) {
|
|
175
|
-
if (!isAuditSeverity(row.severity)) {
|
|
159
|
+
if (!(0, import_audit_core.isAuditSeverity)(row.severity)) {
|
|
176
160
|
throw new Error(
|
|
177
161
|
`Invalid audit severity: "${row.severity}". Expected one of: low, medium, high, critical`
|
|
178
162
|
);
|
|
@@ -198,87 +182,68 @@ function rowToAuditLog(row) {
|
|
|
198
182
|
}
|
|
199
183
|
|
|
200
184
|
// src/query.ts
|
|
201
|
-
var
|
|
185
|
+
var import_audit_core2 = require("@usebetterdev/audit-core");
|
|
202
186
|
var import_drizzle_orm = require("drizzle-orm");
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
}
|
|
215
|
-
function buildWhereConditions(filters) {
|
|
216
|
-
const conditions = [];
|
|
217
|
-
if (filters.resource !== void 0) {
|
|
218
|
-
conditions.push((0, import_drizzle_orm.eq)(auditLogs.tableName, filters.resource.tableName));
|
|
219
|
-
if (filters.resource.recordId !== void 0) {
|
|
220
|
-
conditions.push((0, import_drizzle_orm.eq)(auditLogs.recordId, filters.resource.recordId));
|
|
187
|
+
var FIELD_COLUMNS = {
|
|
188
|
+
tableName: auditLogs.tableName,
|
|
189
|
+
recordId: auditLogs.recordId,
|
|
190
|
+
actorId: auditLogs.actorId,
|
|
191
|
+
severity: auditLogs.severity,
|
|
192
|
+
operation: auditLogs.operation
|
|
193
|
+
};
|
|
194
|
+
function mapCondition(condition) {
|
|
195
|
+
switch (condition.kind) {
|
|
196
|
+
case "eq": {
|
|
197
|
+
return (0, import_drizzle_orm.eq)(FIELD_COLUMNS[condition.field], condition.value);
|
|
221
198
|
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
if (filters.actorIds.length === 1) {
|
|
225
|
-
conditions.push((0, import_drizzle_orm.eq)(auditLogs.actorId, filters.actorIds[0]));
|
|
226
|
-
} else {
|
|
227
|
-
conditions.push((0, import_drizzle_orm.inArray)(auditLogs.actorId, filters.actorIds));
|
|
199
|
+
case "in": {
|
|
200
|
+
return (0, import_drizzle_orm.inArray)(FIELD_COLUMNS[condition.field], condition.values);
|
|
228
201
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
if (filters.severities.length === 1) {
|
|
232
|
-
conditions.push((0, import_drizzle_orm.eq)(auditLogs.severity, filters.severities[0]));
|
|
233
|
-
} else {
|
|
234
|
-
conditions.push((0, import_drizzle_orm.inArray)(auditLogs.severity, filters.severities));
|
|
202
|
+
case "timestampGte": {
|
|
203
|
+
return (0, import_drizzle_orm.gte)(auditLogs.timestamp, condition.value);
|
|
235
204
|
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
if (filters.operations.length === 1) {
|
|
239
|
-
conditions.push((0, import_drizzle_orm.eq)(auditLogs.operation, filters.operations[0]));
|
|
240
|
-
} else {
|
|
241
|
-
conditions.push((0, import_drizzle_orm.inArray)(auditLogs.operation, filters.operations));
|
|
205
|
+
case "timestampLte": {
|
|
206
|
+
return (0, import_drizzle_orm.lte)(auditLogs.timestamp, condition.value);
|
|
242
207
|
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
(0, import_drizzle_orm.
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
208
|
+
case "search": {
|
|
209
|
+
return (0, import_drizzle_orm.or)(
|
|
210
|
+
(0, import_drizzle_orm.ilike)(auditLogs.label, condition.pattern),
|
|
211
|
+
(0, import_drizzle_orm.ilike)(auditLogs.description, condition.pattern)
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
case "compliance": {
|
|
215
|
+
return import_drizzle_orm.sql`${auditLogs.compliance} @> ${JSON.stringify(condition.tags)}::jsonb`;
|
|
216
|
+
}
|
|
217
|
+
case "cursor": {
|
|
218
|
+
const tsCompare = condition.sortOrder === "asc" ? import_drizzle_orm.gt : import_drizzle_orm.lt;
|
|
219
|
+
const idCompare = condition.sortOrder === "asc" ? import_drizzle_orm.gt : import_drizzle_orm.lt;
|
|
220
|
+
return (0, import_drizzle_orm.or)(
|
|
221
|
+
tsCompare(auditLogs.timestamp, condition.timestamp),
|
|
222
|
+
(0, import_drizzle_orm.and)(
|
|
223
|
+
(0, import_drizzle_orm.eq)(auditLogs.timestamp, condition.timestamp),
|
|
224
|
+
idCompare(auditLogs.id, condition.id)
|
|
225
|
+
)
|
|
226
|
+
);
|
|
259
227
|
}
|
|
260
228
|
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
229
|
+
}
|
|
230
|
+
function buildWhereConditions(filters, cursor, sortOrder) {
|
|
231
|
+
const decoded = cursor !== void 0 ? (0, import_audit_core2.decodeCursor)(cursor) : void 0;
|
|
232
|
+
const irConditions = (0, import_audit_core2.interpretFilters)(filters, {
|
|
233
|
+
cursor: decoded,
|
|
234
|
+
sortOrder
|
|
235
|
+
});
|
|
236
|
+
const sqlConditions = [];
|
|
237
|
+
for (const c of irConditions) {
|
|
238
|
+
const mapped = mapCondition(c);
|
|
239
|
+
if (mapped !== void 0) {
|
|
240
|
+
sqlConditions.push(mapped);
|
|
241
|
+
}
|
|
265
242
|
}
|
|
266
|
-
if (
|
|
243
|
+
if (sqlConditions.length === 0) {
|
|
267
244
|
return void 0;
|
|
268
245
|
}
|
|
269
|
-
return (0, import_drizzle_orm.and)(...
|
|
270
|
-
}
|
|
271
|
-
function buildCursorCondition(cursor, sortOrder) {
|
|
272
|
-
const decoded = decodeCursor(cursor);
|
|
273
|
-
const tsCompare = sortOrder === "asc" ? import_drizzle_orm.gt : import_drizzle_orm.lt;
|
|
274
|
-
const idCompare = sortOrder === "asc" ? import_drizzle_orm.gt : import_drizzle_orm.lt;
|
|
275
|
-
return (0, import_drizzle_orm.or)(
|
|
276
|
-
tsCompare(auditLogs.timestamp, decoded.timestamp),
|
|
277
|
-
(0, import_drizzle_orm.and)(
|
|
278
|
-
(0, import_drizzle_orm.eq)(auditLogs.timestamp, decoded.timestamp),
|
|
279
|
-
idCompare(auditLogs.id, decoded.id)
|
|
280
|
-
)
|
|
281
|
-
);
|
|
246
|
+
return (0, import_drizzle_orm.and)(...sqlConditions);
|
|
282
247
|
}
|
|
283
248
|
function buildOrderBy(sortOrder) {
|
|
284
249
|
if (sortOrder === "asc") {
|
|
@@ -286,47 +251,10 @@ function buildOrderBy(sortOrder) {
|
|
|
286
251
|
}
|
|
287
252
|
return [(0, import_drizzle_orm.desc)(auditLogs.timestamp), (0, import_drizzle_orm.desc)(auditLogs.id)];
|
|
288
253
|
}
|
|
289
|
-
function encodeCursor(timestamp2, id) {
|
|
290
|
-
const payload = JSON.stringify({ t: timestamp2.toISOString(), i: id });
|
|
291
|
-
return btoa(payload);
|
|
292
|
-
}
|
|
293
|
-
var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
294
|
-
function decodeCursor(cursor) {
|
|
295
|
-
let parsed;
|
|
296
|
-
try {
|
|
297
|
-
parsed = JSON.parse(atob(cursor));
|
|
298
|
-
} catch {
|
|
299
|
-
throw new Error("Invalid cursor: failed to decode");
|
|
300
|
-
}
|
|
301
|
-
if (typeof parsed !== "object" || parsed === null || !("t" in parsed) || !("i" in parsed)) {
|
|
302
|
-
throw new Error("Invalid cursor: missing required fields");
|
|
303
|
-
}
|
|
304
|
-
const { t, i } = parsed;
|
|
305
|
-
if (typeof t !== "string" || typeof i !== "string") {
|
|
306
|
-
throw new Error("Invalid cursor: fields must be strings");
|
|
307
|
-
}
|
|
308
|
-
const timestamp2 = new Date(t);
|
|
309
|
-
if (isNaN(timestamp2.getTime())) {
|
|
310
|
-
throw new Error("Invalid cursor: invalid timestamp");
|
|
311
|
-
}
|
|
312
|
-
if (!UUID_PATTERN.test(i)) {
|
|
313
|
-
throw new Error("Invalid cursor: id must be a valid UUID");
|
|
314
|
-
}
|
|
315
|
-
return { timestamp: timestamp2, id: i };
|
|
316
|
-
}
|
|
317
254
|
|
|
318
255
|
// src/adapter.ts
|
|
319
256
|
var DEFAULT_LIMIT = 50;
|
|
320
257
|
var MAX_LIMIT = 250;
|
|
321
|
-
function toCount(value) {
|
|
322
|
-
if (typeof value === "number") {
|
|
323
|
-
return value;
|
|
324
|
-
}
|
|
325
|
-
if (typeof value === "string") {
|
|
326
|
-
return Number(value);
|
|
327
|
-
}
|
|
328
|
-
return 0;
|
|
329
|
-
}
|
|
330
258
|
function drizzleAuditAdapter(db) {
|
|
331
259
|
return {
|
|
332
260
|
async writeLog(log) {
|
|
@@ -336,9 +264,7 @@ function drizzleAuditAdapter(db) {
|
|
|
336
264
|
async queryLogs(spec) {
|
|
337
265
|
const sortOrder = spec.sortOrder ?? "desc";
|
|
338
266
|
const limit = Math.min(spec.limit ?? DEFAULT_LIMIT, MAX_LIMIT);
|
|
339
|
-
const
|
|
340
|
-
const cursorCondition = spec.cursor !== void 0 ? buildCursorCondition(spec.cursor, sortOrder) : void 0;
|
|
341
|
-
const combined = (0, import_drizzle_orm2.and)(whereCondition, cursorCondition);
|
|
267
|
+
const combined = buildWhereConditions(spec.filters, spec.cursor, sortOrder);
|
|
342
268
|
const fetchLimit = limit + 1;
|
|
343
269
|
const orderColumns = buildOrderBy(sortOrder);
|
|
344
270
|
const query = db.select().from(auditLogs).where(combined).orderBy(...orderColumns).limit(fetchLimit);
|
|
@@ -348,7 +274,7 @@ function drizzleAuditAdapter(db) {
|
|
|
348
274
|
const entries = resultRows.map(rowToAuditLog);
|
|
349
275
|
const lastRow = resultRows[resultRows.length - 1];
|
|
350
276
|
if (hasNextPage && lastRow !== void 0) {
|
|
351
|
-
return { entries, nextCursor: encodeCursor(lastRow.timestamp, lastRow.id) };
|
|
277
|
+
return { entries, nextCursor: (0, import_audit_core3.encodeCursor)(lastRow.timestamp, lastRow.id) };
|
|
352
278
|
}
|
|
353
279
|
return { entries };
|
|
354
280
|
},
|
|
@@ -382,30 +308,32 @@ function drizzleAuditAdapter(db) {
|
|
|
382
308
|
},
|
|
383
309
|
async getStats(options) {
|
|
384
310
|
const sinceCondition = options?.since !== void 0 ? (0, import_drizzle_orm2.gte)(auditLogs.timestamp, options.since) : void 0;
|
|
311
|
+
const untilCondition = options?.until !== void 0 ? (0, import_drizzle_orm2.lt)(auditLogs.timestamp, options.until) : void 0;
|
|
312
|
+
const timeCondition = (0, import_drizzle_orm2.and)(sinceCondition, untilCondition);
|
|
385
313
|
const summaryQuery = db.select({
|
|
386
314
|
totalLogs: import_drizzle_orm2.sql`count(*)`,
|
|
387
315
|
tablesAudited: import_drizzle_orm2.sql`count(DISTINCT ${auditLogs.tableName})`
|
|
388
|
-
}).from(auditLogs).where(
|
|
316
|
+
}).from(auditLogs).where(timeCondition);
|
|
389
317
|
const eventsPerDayQuery = db.select({
|
|
390
318
|
date: import_drizzle_orm2.sql`date_trunc('day', ${auditLogs.timestamp})::date`,
|
|
391
319
|
count: import_drizzle_orm2.sql`count(*)`
|
|
392
|
-
}).from(auditLogs).where(
|
|
320
|
+
}).from(auditLogs).where(timeCondition).groupBy(import_drizzle_orm2.sql`date_trunc('day', ${auditLogs.timestamp})`).orderBy(import_drizzle_orm2.sql`date_trunc('day', ${auditLogs.timestamp})`).limit(365);
|
|
393
321
|
const topActorsQuery = db.select({
|
|
394
322
|
actorId: auditLogs.actorId,
|
|
395
323
|
count: import_drizzle_orm2.sql`count(*)`
|
|
396
|
-
}).from(auditLogs).where((0, import_drizzle_orm2.and)(
|
|
324
|
+
}).from(auditLogs).where((0, import_drizzle_orm2.and)(timeCondition, (0, import_drizzle_orm2.isNotNull)(auditLogs.actorId))).groupBy(auditLogs.actorId).orderBy((0, import_drizzle_orm2.desc)(import_drizzle_orm2.sql`count(*)`)).limit(10);
|
|
397
325
|
const topTablesQuery = db.select({
|
|
398
326
|
tableName: auditLogs.tableName,
|
|
399
327
|
count: import_drizzle_orm2.sql`count(*)`
|
|
400
|
-
}).from(auditLogs).where(
|
|
328
|
+
}).from(auditLogs).where(timeCondition).groupBy(auditLogs.tableName).orderBy((0, import_drizzle_orm2.desc)(import_drizzle_orm2.sql`count(*)`)).limit(10);
|
|
401
329
|
const operationQuery = db.select({
|
|
402
330
|
operation: auditLogs.operation,
|
|
403
331
|
count: import_drizzle_orm2.sql`count(*)`
|
|
404
|
-
}).from(auditLogs).where(
|
|
332
|
+
}).from(auditLogs).where(timeCondition).groupBy(auditLogs.operation);
|
|
405
333
|
const severityQuery = db.select({
|
|
406
334
|
severity: auditLogs.severity,
|
|
407
335
|
count: import_drizzle_orm2.sql`count(*)`
|
|
408
|
-
}).from(auditLogs).where((0, import_drizzle_orm2.and)(
|
|
336
|
+
}).from(auditLogs).where((0, import_drizzle_orm2.and)(timeCondition, (0, import_drizzle_orm2.isNotNull)(auditLogs.severity))).groupBy(auditLogs.severity);
|
|
409
337
|
const results = await Promise.all([
|
|
410
338
|
summaryQuery,
|
|
411
339
|
eventsPerDayQuery,
|
|
@@ -422,7 +350,7 @@ function drizzleAuditAdapter(db) {
|
|
|
422
350
|
operationRows,
|
|
423
351
|
severityRows
|
|
424
352
|
] = results;
|
|
425
|
-
return assembleStats(
|
|
353
|
+
return (0, import_audit_core3.assembleStats)(
|
|
426
354
|
summaryRows,
|
|
427
355
|
eventsPerDayRows,
|
|
428
356
|
topActorsRows,
|
|
@@ -433,42 +361,9 @@ function drizzleAuditAdapter(db) {
|
|
|
433
361
|
}
|
|
434
362
|
};
|
|
435
363
|
}
|
|
436
|
-
function assembleStats(summaryRows, eventsPerDayRows, topActorsRows, topTablesRows, operationRows, severityRows) {
|
|
437
|
-
const summary = summaryRows[0];
|
|
438
|
-
const totalLogs = summary !== void 0 ? toCount(summary.totalLogs) : 0;
|
|
439
|
-
const tablesAudited = summary !== void 0 ? toCount(summary.tablesAudited) : 0;
|
|
440
|
-
const eventsPerDay = eventsPerDayRows.map((row) => ({
|
|
441
|
-
date: row.date instanceof Date ? row.date.toISOString().split("T")[0] : String(row.date),
|
|
442
|
-
count: toCount(row.count)
|
|
443
|
-
}));
|
|
444
|
-
const topActors = topActorsRows.map((row) => ({
|
|
445
|
-
actorId: String(row.actorId),
|
|
446
|
-
count: toCount(row.count)
|
|
447
|
-
}));
|
|
448
|
-
const topTables = topTablesRows.map((row) => ({
|
|
449
|
-
tableName: String(row.tableName),
|
|
450
|
-
count: toCount(row.count)
|
|
451
|
-
}));
|
|
452
|
-
const operationBreakdown = {};
|
|
453
|
-
for (const row of operationRows) {
|
|
454
|
-
operationBreakdown[String(row.operation)] = toCount(row.count);
|
|
455
|
-
}
|
|
456
|
-
const severityBreakdown = {};
|
|
457
|
-
for (const row of severityRows) {
|
|
458
|
-
severityBreakdown[String(row.severity)] = toCount(row.count);
|
|
459
|
-
}
|
|
460
|
-
return {
|
|
461
|
-
totalLogs,
|
|
462
|
-
tablesAudited,
|
|
463
|
-
eventsPerDay,
|
|
464
|
-
topActors,
|
|
465
|
-
topTables,
|
|
466
|
-
operationBreakdown,
|
|
467
|
-
severityBreakdown
|
|
468
|
-
};
|
|
469
|
-
}
|
|
470
364
|
|
|
471
365
|
// src/sqlite-adapter.ts
|
|
366
|
+
var import_audit_core6 = require("@usebetterdev/audit-core");
|
|
472
367
|
var import_drizzle_orm4 = require("drizzle-orm");
|
|
473
368
|
|
|
474
369
|
// src/sqlite-schema.ts
|
|
@@ -512,23 +407,7 @@ var sqliteAuditLogs = (0, import_sqlite_core.sqliteTable)(
|
|
|
512
407
|
);
|
|
513
408
|
|
|
514
409
|
// src/sqlite-column-map.ts
|
|
515
|
-
var
|
|
516
|
-
"INSERT",
|
|
517
|
-
"UPDATE",
|
|
518
|
-
"DELETE"
|
|
519
|
-
]);
|
|
520
|
-
var VALID_SEVERITIES2 = /* @__PURE__ */ new Set([
|
|
521
|
-
"low",
|
|
522
|
-
"medium",
|
|
523
|
-
"high",
|
|
524
|
-
"critical"
|
|
525
|
-
]);
|
|
526
|
-
function isAuditOperation2(value) {
|
|
527
|
-
return VALID_OPERATIONS2.has(value);
|
|
528
|
-
}
|
|
529
|
-
function isAuditSeverity2(value) {
|
|
530
|
-
return VALID_SEVERITIES2.has(value);
|
|
531
|
-
}
|
|
410
|
+
var import_audit_core4 = require("@usebetterdev/audit-core");
|
|
532
411
|
function sqliteAuditLogToRow(log) {
|
|
533
412
|
const row = {
|
|
534
413
|
id: log.id,
|
|
@@ -576,7 +455,7 @@ function sqliteAuditLogToRow(log) {
|
|
|
576
455
|
return row;
|
|
577
456
|
}
|
|
578
457
|
function sqliteRowToAuditLog(row) {
|
|
579
|
-
if (!
|
|
458
|
+
if (!(0, import_audit_core4.isAuditOperation)(row.operation)) {
|
|
580
459
|
throw new Error(
|
|
581
460
|
`Invalid audit operation: "${row.operation}". Expected one of: INSERT, UPDATE, DELETE`
|
|
582
461
|
);
|
|
@@ -607,7 +486,7 @@ function sqliteRowToAuditLog(row) {
|
|
|
607
486
|
log.description = row.description;
|
|
608
487
|
}
|
|
609
488
|
if (row.severity !== null && row.severity !== void 0) {
|
|
610
|
-
if (!
|
|
489
|
+
if (!(0, import_audit_core4.isAuditSeverity)(row.severity)) {
|
|
611
490
|
throw new Error(
|
|
612
491
|
`Invalid audit severity: "${row.severity}". Expected one of: low, medium, high, critical`
|
|
613
492
|
);
|
|
@@ -633,89 +512,74 @@ function sqliteRowToAuditLog(row) {
|
|
|
633
512
|
}
|
|
634
513
|
|
|
635
514
|
// src/sqlite-query.ts
|
|
636
|
-
var
|
|
515
|
+
var import_audit_core5 = require("@usebetterdev/audit-core");
|
|
637
516
|
var import_drizzle_orm3 = require("drizzle-orm");
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
}
|
|
650
|
-
function buildSqliteWhereConditions(filters) {
|
|
651
|
-
const conditions = [];
|
|
652
|
-
if (filters.resource !== void 0) {
|
|
653
|
-
conditions.push((0, import_drizzle_orm3.eq)(sqliteAuditLogs.tableName, filters.resource.tableName));
|
|
654
|
-
if (filters.resource.recordId !== void 0) {
|
|
655
|
-
conditions.push((0, import_drizzle_orm3.eq)(sqliteAuditLogs.recordId, filters.resource.recordId));
|
|
517
|
+
var FIELD_COLUMNS2 = {
|
|
518
|
+
tableName: sqliteAuditLogs.tableName,
|
|
519
|
+
recordId: sqliteAuditLogs.recordId,
|
|
520
|
+
actorId: sqliteAuditLogs.actorId,
|
|
521
|
+
severity: sqliteAuditLogs.severity,
|
|
522
|
+
operation: sqliteAuditLogs.operation
|
|
523
|
+
};
|
|
524
|
+
function mapCondition2(condition) {
|
|
525
|
+
switch (condition.kind) {
|
|
526
|
+
case "eq": {
|
|
527
|
+
return (0, import_drizzle_orm3.eq)(FIELD_COLUMNS2[condition.field], condition.value);
|
|
656
528
|
}
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
if (filters.actorIds.length === 1) {
|
|
660
|
-
conditions.push((0, import_drizzle_orm3.eq)(sqliteAuditLogs.actorId, filters.actorIds[0]));
|
|
661
|
-
} else {
|
|
662
|
-
conditions.push((0, import_drizzle_orm3.inArray)(sqliteAuditLogs.actorId, filters.actorIds));
|
|
529
|
+
case "in": {
|
|
530
|
+
return (0, import_drizzle_orm3.inArray)(FIELD_COLUMNS2[condition.field], condition.values);
|
|
663
531
|
}
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
if (filters.severities.length === 1) {
|
|
667
|
-
conditions.push((0, import_drizzle_orm3.eq)(sqliteAuditLogs.severity, filters.severities[0]));
|
|
668
|
-
} else {
|
|
669
|
-
conditions.push((0, import_drizzle_orm3.inArray)(sqliteAuditLogs.severity, filters.severities));
|
|
532
|
+
case "timestampGte": {
|
|
533
|
+
return (0, import_drizzle_orm3.gte)(sqliteAuditLogs.timestamp, condition.value);
|
|
670
534
|
}
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
if (filters.operations.length === 1) {
|
|
674
|
-
conditions.push((0, import_drizzle_orm3.eq)(sqliteAuditLogs.operation, filters.operations[0]));
|
|
675
|
-
} else {
|
|
676
|
-
conditions.push((0, import_drizzle_orm3.inArray)(sqliteAuditLogs.operation, filters.operations));
|
|
535
|
+
case "timestampLte": {
|
|
536
|
+
return (0, import_drizzle_orm3.lte)(sqliteAuditLogs.timestamp, condition.value);
|
|
677
537
|
}
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
conditions.push((0, import_drizzle_orm3.lte)(sqliteAuditLogs.timestamp, resolveTimeFilter2(filters.until)));
|
|
684
|
-
}
|
|
685
|
-
if (filters.searchText !== void 0 && filters.searchText.length > 0) {
|
|
686
|
-
const escaped = escapeLikePattern2(filters.searchText);
|
|
687
|
-
const pattern = `%${escaped}%`;
|
|
688
|
-
const searchCondition = (0, import_drizzle_orm3.or)(
|
|
689
|
-
(0, import_drizzle_orm3.like)(sqliteAuditLogs.label, pattern),
|
|
690
|
-
(0, import_drizzle_orm3.like)(sqliteAuditLogs.description, pattern)
|
|
691
|
-
);
|
|
692
|
-
if (searchCondition !== void 0) {
|
|
693
|
-
conditions.push(searchCondition);
|
|
538
|
+
case "search": {
|
|
539
|
+
return (0, import_drizzle_orm3.or)(
|
|
540
|
+
(0, import_drizzle_orm3.like)(sqliteAuditLogs.label, condition.pattern),
|
|
541
|
+
(0, import_drizzle_orm3.like)(sqliteAuditLogs.description, condition.pattern)
|
|
542
|
+
);
|
|
694
543
|
}
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
544
|
+
case "compliance": {
|
|
545
|
+
const tagConditions = [];
|
|
546
|
+
for (const tag of condition.tags) {
|
|
547
|
+
tagConditions.push(
|
|
548
|
+
import_drizzle_orm3.sql`EXISTS (SELECT 1 FROM json_each(${sqliteAuditLogs.compliance}) WHERE value = ${tag})`
|
|
549
|
+
);
|
|
550
|
+
}
|
|
551
|
+
return (0, import_drizzle_orm3.and)(...tagConditions);
|
|
552
|
+
}
|
|
553
|
+
case "cursor": {
|
|
554
|
+
const tsCompare = condition.sortOrder === "asc" ? import_drizzle_orm3.gt : import_drizzle_orm3.lt;
|
|
555
|
+
const idCompare = condition.sortOrder === "asc" ? import_drizzle_orm3.gt : import_drizzle_orm3.lt;
|
|
556
|
+
return (0, import_drizzle_orm3.or)(
|
|
557
|
+
tsCompare(sqliteAuditLogs.timestamp, condition.timestamp),
|
|
558
|
+
(0, import_drizzle_orm3.and)(
|
|
559
|
+
(0, import_drizzle_orm3.eq)(sqliteAuditLogs.timestamp, condition.timestamp),
|
|
560
|
+
idCompare(sqliteAuditLogs.id, condition.id)
|
|
561
|
+
)
|
|
700
562
|
);
|
|
701
563
|
}
|
|
702
564
|
}
|
|
703
|
-
|
|
565
|
+
}
|
|
566
|
+
function buildSqliteWhereConditions(filters, cursor, sortOrder) {
|
|
567
|
+
const decoded = cursor !== void 0 ? (0, import_audit_core5.decodeCursor)(cursor) : void 0;
|
|
568
|
+
const irConditions = (0, import_audit_core5.interpretFilters)(filters, {
|
|
569
|
+
cursor: decoded,
|
|
570
|
+
sortOrder
|
|
571
|
+
});
|
|
572
|
+
const sqlConditions = [];
|
|
573
|
+
for (const c of irConditions) {
|
|
574
|
+
const mapped = mapCondition2(c);
|
|
575
|
+
if (mapped !== void 0) {
|
|
576
|
+
sqlConditions.push(mapped);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
if (sqlConditions.length === 0) {
|
|
704
580
|
return void 0;
|
|
705
581
|
}
|
|
706
|
-
return (0, import_drizzle_orm3.and)(...
|
|
707
|
-
}
|
|
708
|
-
function buildSqliteCursorCondition(cursor, sortOrder) {
|
|
709
|
-
const decoded = decodeSqliteCursor(cursor);
|
|
710
|
-
const tsCompare = sortOrder === "asc" ? import_drizzle_orm3.gt : import_drizzle_orm3.lt;
|
|
711
|
-
const idCompare = sortOrder === "asc" ? import_drizzle_orm3.gt : import_drizzle_orm3.lt;
|
|
712
|
-
return (0, import_drizzle_orm3.or)(
|
|
713
|
-
tsCompare(sqliteAuditLogs.timestamp, decoded.timestamp),
|
|
714
|
-
(0, import_drizzle_orm3.and)(
|
|
715
|
-
(0, import_drizzle_orm3.eq)(sqliteAuditLogs.timestamp, decoded.timestamp),
|
|
716
|
-
idCompare(sqliteAuditLogs.id, decoded.id)
|
|
717
|
-
)
|
|
718
|
-
);
|
|
582
|
+
return (0, import_drizzle_orm3.and)(...sqlConditions);
|
|
719
583
|
}
|
|
720
584
|
function buildSqliteOrderBy(sortOrder) {
|
|
721
585
|
if (sortOrder === "asc") {
|
|
@@ -723,47 +587,10 @@ function buildSqliteOrderBy(sortOrder) {
|
|
|
723
587
|
}
|
|
724
588
|
return [(0, import_drizzle_orm3.desc)(sqliteAuditLogs.timestamp), (0, import_drizzle_orm3.desc)(sqliteAuditLogs.id)];
|
|
725
589
|
}
|
|
726
|
-
function encodeSqliteCursor(timestamp2, id) {
|
|
727
|
-
const payload = JSON.stringify({ t: timestamp2.toISOString(), i: id });
|
|
728
|
-
return btoa(payload);
|
|
729
|
-
}
|
|
730
|
-
var UUID_PATTERN2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
731
|
-
function decodeSqliteCursor(cursor) {
|
|
732
|
-
let parsed;
|
|
733
|
-
try {
|
|
734
|
-
parsed = JSON.parse(atob(cursor));
|
|
735
|
-
} catch {
|
|
736
|
-
throw new Error("Invalid cursor: failed to decode");
|
|
737
|
-
}
|
|
738
|
-
if (typeof parsed !== "object" || parsed === null || !("t" in parsed) || !("i" in parsed)) {
|
|
739
|
-
throw new Error("Invalid cursor: missing required fields");
|
|
740
|
-
}
|
|
741
|
-
const { t, i } = parsed;
|
|
742
|
-
if (typeof t !== "string" || typeof i !== "string") {
|
|
743
|
-
throw new Error("Invalid cursor: fields must be strings");
|
|
744
|
-
}
|
|
745
|
-
const timestamp2 = new Date(t);
|
|
746
|
-
if (isNaN(timestamp2.getTime())) {
|
|
747
|
-
throw new Error("Invalid cursor: invalid timestamp");
|
|
748
|
-
}
|
|
749
|
-
if (!UUID_PATTERN2.test(i)) {
|
|
750
|
-
throw new Error("Invalid cursor: id must be a valid UUID");
|
|
751
|
-
}
|
|
752
|
-
return { timestamp: timestamp2, id: i };
|
|
753
|
-
}
|
|
754
590
|
|
|
755
591
|
// src/sqlite-adapter.ts
|
|
756
592
|
var DEFAULT_LIMIT2 = 50;
|
|
757
593
|
var MAX_LIMIT2 = 250;
|
|
758
|
-
function toCount2(value) {
|
|
759
|
-
if (typeof value === "number") {
|
|
760
|
-
return value;
|
|
761
|
-
}
|
|
762
|
-
if (typeof value === "string") {
|
|
763
|
-
return Number(value);
|
|
764
|
-
}
|
|
765
|
-
return 0;
|
|
766
|
-
}
|
|
767
594
|
function drizzleSqliteAuditAdapter(db) {
|
|
768
595
|
return {
|
|
769
596
|
async writeLog(log) {
|
|
@@ -773,9 +600,7 @@ function drizzleSqliteAuditAdapter(db) {
|
|
|
773
600
|
async queryLogs(spec) {
|
|
774
601
|
const sortOrder = spec.sortOrder ?? "desc";
|
|
775
602
|
const limit = Math.min(spec.limit ?? DEFAULT_LIMIT2, MAX_LIMIT2);
|
|
776
|
-
const
|
|
777
|
-
const cursorCondition = spec.cursor !== void 0 ? buildSqliteCursorCondition(spec.cursor, sortOrder) : void 0;
|
|
778
|
-
const combined = (0, import_drizzle_orm4.and)(whereCondition, cursorCondition);
|
|
603
|
+
const combined = buildSqliteWhereConditions(spec.filters, spec.cursor, sortOrder);
|
|
779
604
|
const fetchLimit = limit + 1;
|
|
780
605
|
const orderColumns = buildSqliteOrderBy(sortOrder);
|
|
781
606
|
const query = db.select().from(sqliteAuditLogs).where(combined).orderBy(...orderColumns).limit(fetchLimit);
|
|
@@ -785,7 +610,7 @@ function drizzleSqliteAuditAdapter(db) {
|
|
|
785
610
|
const entries = resultRows.map(sqliteRowToAuditLog);
|
|
786
611
|
const lastRow = resultRows[resultRows.length - 1];
|
|
787
612
|
if (hasNextPage && lastRow !== void 0) {
|
|
788
|
-
return { entries, nextCursor:
|
|
613
|
+
return { entries, nextCursor: (0, import_audit_core6.encodeCursor)(lastRow.timestamp, lastRow.id) };
|
|
789
614
|
}
|
|
790
615
|
return { entries };
|
|
791
616
|
},
|
|
@@ -808,35 +633,37 @@ function drizzleSqliteAuditAdapter(db) {
|
|
|
808
633
|
}
|
|
809
634
|
await db.delete(sqliteAuditLogs).where((0, import_drizzle_orm4.and)(...conditions));
|
|
810
635
|
const changesResult = await db.select({ count: import_drizzle_orm4.sql`changes()` }).from(sqliteAuditLogs);
|
|
811
|
-
const deletedCount = changesResult[0] !== void 0 ?
|
|
636
|
+
const deletedCount = changesResult[0] !== void 0 ? (0, import_audit_core6.toCount)(changesResult[0].count) : 0;
|
|
812
637
|
return { deletedCount };
|
|
813
638
|
},
|
|
814
639
|
async getStats(options) {
|
|
815
640
|
const sinceCondition = options?.since !== void 0 ? (0, import_drizzle_orm4.gte)(sqliteAuditLogs.timestamp, options.since) : void 0;
|
|
641
|
+
const untilCondition = options?.until !== void 0 ? (0, import_drizzle_orm4.lt)(sqliteAuditLogs.timestamp, options.until) : void 0;
|
|
642
|
+
const timeCondition = (0, import_drizzle_orm4.and)(sinceCondition, untilCondition);
|
|
816
643
|
const summaryQuery = db.select({
|
|
817
644
|
totalLogs: import_drizzle_orm4.sql`count(*)`,
|
|
818
645
|
tablesAudited: import_drizzle_orm4.sql`count(DISTINCT ${sqliteAuditLogs.tableName})`
|
|
819
|
-
}).from(sqliteAuditLogs).where(
|
|
646
|
+
}).from(sqliteAuditLogs).where(timeCondition);
|
|
820
647
|
const eventsPerDayQuery = db.select({
|
|
821
648
|
date: import_drizzle_orm4.sql`strftime('%Y-%m-%d', ${sqliteAuditLogs.timestamp}, 'unixepoch')`,
|
|
822
649
|
count: import_drizzle_orm4.sql`count(*)`
|
|
823
|
-
}).from(sqliteAuditLogs).where(
|
|
650
|
+
}).from(sqliteAuditLogs).where(timeCondition).groupBy(import_drizzle_orm4.sql`strftime('%Y-%m-%d', ${sqliteAuditLogs.timestamp}, 'unixepoch')`).orderBy(import_drizzle_orm4.sql`strftime('%Y-%m-%d', ${sqliteAuditLogs.timestamp}, 'unixepoch')`).limit(365);
|
|
824
651
|
const topActorsQuery = db.select({
|
|
825
652
|
actorId: sqliteAuditLogs.actorId,
|
|
826
653
|
count: import_drizzle_orm4.sql`count(*)`
|
|
827
|
-
}).from(sqliteAuditLogs).where((0, import_drizzle_orm4.and)(
|
|
654
|
+
}).from(sqliteAuditLogs).where((0, import_drizzle_orm4.and)(timeCondition, (0, import_drizzle_orm4.isNotNull)(sqliteAuditLogs.actorId))).groupBy(sqliteAuditLogs.actorId).orderBy((0, import_drizzle_orm4.desc)(import_drizzle_orm4.sql`count(*)`)).limit(10);
|
|
828
655
|
const topTablesQuery = db.select({
|
|
829
656
|
tableName: sqliteAuditLogs.tableName,
|
|
830
657
|
count: import_drizzle_orm4.sql`count(*)`
|
|
831
|
-
}).from(sqliteAuditLogs).where(
|
|
658
|
+
}).from(sqliteAuditLogs).where(timeCondition).groupBy(sqliteAuditLogs.tableName).orderBy((0, import_drizzle_orm4.desc)(import_drizzle_orm4.sql`count(*)`)).limit(10);
|
|
832
659
|
const operationQuery = db.select({
|
|
833
660
|
operation: sqliteAuditLogs.operation,
|
|
834
661
|
count: import_drizzle_orm4.sql`count(*)`
|
|
835
|
-
}).from(sqliteAuditLogs).where(
|
|
662
|
+
}).from(sqliteAuditLogs).where(timeCondition).groupBy(sqliteAuditLogs.operation);
|
|
836
663
|
const severityQuery = db.select({
|
|
837
664
|
severity: sqliteAuditLogs.severity,
|
|
838
665
|
count: import_drizzle_orm4.sql`count(*)`
|
|
839
|
-
}).from(sqliteAuditLogs).where((0, import_drizzle_orm4.and)(
|
|
666
|
+
}).from(sqliteAuditLogs).where((0, import_drizzle_orm4.and)(timeCondition, (0, import_drizzle_orm4.isNotNull)(sqliteAuditLogs.severity))).groupBy(sqliteAuditLogs.severity);
|
|
840
667
|
const results = await Promise.all([
|
|
841
668
|
summaryQuery,
|
|
842
669
|
eventsPerDayQuery,
|
|
@@ -853,7 +680,7 @@ function drizzleSqliteAuditAdapter(db) {
|
|
|
853
680
|
operationRows,
|
|
854
681
|
severityRows
|
|
855
682
|
] = results;
|
|
856
|
-
return
|
|
683
|
+
return (0, import_audit_core6.assembleStats)(
|
|
857
684
|
summaryRows,
|
|
858
685
|
eventsPerDayRows,
|
|
859
686
|
topActorsRows,
|
|
@@ -864,40 +691,6 @@ function drizzleSqliteAuditAdapter(db) {
|
|
|
864
691
|
}
|
|
865
692
|
};
|
|
866
693
|
}
|
|
867
|
-
function assembleStats2(summaryRows, eventsPerDayRows, topActorsRows, topTablesRows, operationRows, severityRows) {
|
|
868
|
-
const summary = summaryRows[0];
|
|
869
|
-
const totalLogs = summary !== void 0 ? toCount2(summary.totalLogs) : 0;
|
|
870
|
-
const tablesAudited = summary !== void 0 ? toCount2(summary.tablesAudited) : 0;
|
|
871
|
-
const eventsPerDay = eventsPerDayRows.map((row) => ({
|
|
872
|
-
date: String(row.date),
|
|
873
|
-
count: toCount2(row.count)
|
|
874
|
-
}));
|
|
875
|
-
const topActors = topActorsRows.map((row) => ({
|
|
876
|
-
actorId: String(row.actorId),
|
|
877
|
-
count: toCount2(row.count)
|
|
878
|
-
}));
|
|
879
|
-
const topTables = topTablesRows.map((row) => ({
|
|
880
|
-
tableName: String(row.tableName),
|
|
881
|
-
count: toCount2(row.count)
|
|
882
|
-
}));
|
|
883
|
-
const operationBreakdown = {};
|
|
884
|
-
for (const row of operationRows) {
|
|
885
|
-
operationBreakdown[String(row.operation)] = toCount2(row.count);
|
|
886
|
-
}
|
|
887
|
-
const severityBreakdown = {};
|
|
888
|
-
for (const row of severityRows) {
|
|
889
|
-
severityBreakdown[String(row.severity)] = toCount2(row.count);
|
|
890
|
-
}
|
|
891
|
-
return {
|
|
892
|
-
totalLogs,
|
|
893
|
-
tablesAudited,
|
|
894
|
-
eventsPerDay,
|
|
895
|
-
topActors,
|
|
896
|
-
topTables,
|
|
897
|
-
operationBreakdown,
|
|
898
|
-
severityBreakdown
|
|
899
|
-
};
|
|
900
|
-
}
|
|
901
694
|
|
|
902
695
|
// src/proxy.ts
|
|
903
696
|
var import_drizzle_orm5 = require("drizzle-orm");
|
|
@@ -1390,10 +1183,12 @@ async function fireCaptureLog(result, ctx, state) {
|
|
|
1390
1183
|
}
|
|
1391
1184
|
}
|
|
1392
1185
|
}
|
|
1186
|
+
|
|
1187
|
+
// src/index.ts
|
|
1188
|
+
var import_audit_core7 = require("@usebetterdev/audit-core");
|
|
1393
1189
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1394
1190
|
0 && (module.exports = {
|
|
1395
1191
|
auditLogs,
|
|
1396
|
-
buildCursorCondition,
|
|
1397
1192
|
buildOrderBy,
|
|
1398
1193
|
buildWhereConditions,
|
|
1399
1194
|
decodeCursor,
|