@usebetterdev/audit-drizzle 0.6.0 → 0.7.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 +129 -338
- 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 +128 -330
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// src/adapter.ts
|
|
2
|
+
import { encodeCursor, assembleStats } from "@usebetterdev/audit-core";
|
|
2
3
|
import { and as and2, eq as eq2, gte as gte2, lt as lt2, isNotNull, sql as sql2, desc as desc2 } from "drizzle-orm";
|
|
3
4
|
|
|
4
5
|
// src/schema.ts
|
|
@@ -50,23 +51,7 @@ var auditLogs = pgTable(
|
|
|
50
51
|
);
|
|
51
52
|
|
|
52
53
|
// src/column-map.ts
|
|
53
|
-
|
|
54
|
-
"INSERT",
|
|
55
|
-
"UPDATE",
|
|
56
|
-
"DELETE"
|
|
57
|
-
]);
|
|
58
|
-
var VALID_SEVERITIES = /* @__PURE__ */ new Set([
|
|
59
|
-
"low",
|
|
60
|
-
"medium",
|
|
61
|
-
"high",
|
|
62
|
-
"critical"
|
|
63
|
-
]);
|
|
64
|
-
function isAuditOperation(value) {
|
|
65
|
-
return VALID_OPERATIONS.has(value);
|
|
66
|
-
}
|
|
67
|
-
function isAuditSeverity(value) {
|
|
68
|
-
return VALID_SEVERITIES.has(value);
|
|
69
|
-
}
|
|
54
|
+
import { isAuditOperation, isAuditSeverity } from "@usebetterdev/audit-core";
|
|
70
55
|
function auditLogToRow(log) {
|
|
71
56
|
const row = {
|
|
72
57
|
id: log.id,
|
|
@@ -171,7 +156,10 @@ function rowToAuditLog(row) {
|
|
|
171
156
|
}
|
|
172
157
|
|
|
173
158
|
// src/query.ts
|
|
174
|
-
import {
|
|
159
|
+
import {
|
|
160
|
+
decodeCursor,
|
|
161
|
+
interpretFilters
|
|
162
|
+
} from "@usebetterdev/audit-core";
|
|
175
163
|
import {
|
|
176
164
|
and,
|
|
177
165
|
or,
|
|
@@ -186,85 +174,66 @@ import {
|
|
|
186
174
|
desc,
|
|
187
175
|
sql
|
|
188
176
|
} from "drizzle-orm";
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
}
|
|
201
|
-
function buildWhereConditions(filters) {
|
|
202
|
-
const conditions = [];
|
|
203
|
-
if (filters.resource !== void 0) {
|
|
204
|
-
conditions.push(eq(auditLogs.tableName, filters.resource.tableName));
|
|
205
|
-
if (filters.resource.recordId !== void 0) {
|
|
206
|
-
conditions.push(eq(auditLogs.recordId, filters.resource.recordId));
|
|
177
|
+
var FIELD_COLUMNS = {
|
|
178
|
+
tableName: auditLogs.tableName,
|
|
179
|
+
recordId: auditLogs.recordId,
|
|
180
|
+
actorId: auditLogs.actorId,
|
|
181
|
+
severity: auditLogs.severity,
|
|
182
|
+
operation: auditLogs.operation
|
|
183
|
+
};
|
|
184
|
+
function mapCondition(condition) {
|
|
185
|
+
switch (condition.kind) {
|
|
186
|
+
case "eq": {
|
|
187
|
+
return eq(FIELD_COLUMNS[condition.field], condition.value);
|
|
207
188
|
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
if (filters.actorIds.length === 1) {
|
|
211
|
-
conditions.push(eq(auditLogs.actorId, filters.actorIds[0]));
|
|
212
|
-
} else {
|
|
213
|
-
conditions.push(inArray(auditLogs.actorId, filters.actorIds));
|
|
189
|
+
case "in": {
|
|
190
|
+
return inArray(FIELD_COLUMNS[condition.field], condition.values);
|
|
214
191
|
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
if (filters.severities.length === 1) {
|
|
218
|
-
conditions.push(eq(auditLogs.severity, filters.severities[0]));
|
|
219
|
-
} else {
|
|
220
|
-
conditions.push(inArray(auditLogs.severity, filters.severities));
|
|
192
|
+
case "timestampGte": {
|
|
193
|
+
return gte(auditLogs.timestamp, condition.value);
|
|
221
194
|
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
if (filters.operations.length === 1) {
|
|
225
|
-
conditions.push(eq(auditLogs.operation, filters.operations[0]));
|
|
226
|
-
} else {
|
|
227
|
-
conditions.push(inArray(auditLogs.operation, filters.operations));
|
|
195
|
+
case "timestampLte": {
|
|
196
|
+
return lte(auditLogs.timestamp, condition.value);
|
|
228
197
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
198
|
+
case "search": {
|
|
199
|
+
return or(
|
|
200
|
+
ilike(auditLogs.label, condition.pattern),
|
|
201
|
+
ilike(auditLogs.description, condition.pattern)
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
case "compliance": {
|
|
205
|
+
return sql`${auditLogs.compliance} @> ${JSON.stringify(condition.tags)}::jsonb`;
|
|
206
|
+
}
|
|
207
|
+
case "cursor": {
|
|
208
|
+
const tsCompare = condition.sortOrder === "asc" ? gt : lt;
|
|
209
|
+
const idCompare = condition.sortOrder === "asc" ? gt : lt;
|
|
210
|
+
return or(
|
|
211
|
+
tsCompare(auditLogs.timestamp, condition.timestamp),
|
|
212
|
+
and(
|
|
213
|
+
eq(auditLogs.timestamp, condition.timestamp),
|
|
214
|
+
idCompare(auditLogs.id, condition.id)
|
|
215
|
+
)
|
|
216
|
+
);
|
|
245
217
|
}
|
|
246
218
|
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
219
|
+
}
|
|
220
|
+
function buildWhereConditions(filters, cursor, sortOrder) {
|
|
221
|
+
const decoded = cursor !== void 0 ? decodeCursor(cursor) : void 0;
|
|
222
|
+
const irConditions = interpretFilters(filters, {
|
|
223
|
+
cursor: decoded,
|
|
224
|
+
sortOrder
|
|
225
|
+
});
|
|
226
|
+
const sqlConditions = [];
|
|
227
|
+
for (const c of irConditions) {
|
|
228
|
+
const mapped = mapCondition(c);
|
|
229
|
+
if (mapped !== void 0) {
|
|
230
|
+
sqlConditions.push(mapped);
|
|
231
|
+
}
|
|
251
232
|
}
|
|
252
|
-
if (
|
|
233
|
+
if (sqlConditions.length === 0) {
|
|
253
234
|
return void 0;
|
|
254
235
|
}
|
|
255
|
-
return and(...
|
|
256
|
-
}
|
|
257
|
-
function buildCursorCondition(cursor, sortOrder) {
|
|
258
|
-
const decoded = decodeCursor(cursor);
|
|
259
|
-
const tsCompare = sortOrder === "asc" ? gt : lt;
|
|
260
|
-
const idCompare = sortOrder === "asc" ? gt : lt;
|
|
261
|
-
return or(
|
|
262
|
-
tsCompare(auditLogs.timestamp, decoded.timestamp),
|
|
263
|
-
and(
|
|
264
|
-
eq(auditLogs.timestamp, decoded.timestamp),
|
|
265
|
-
idCompare(auditLogs.id, decoded.id)
|
|
266
|
-
)
|
|
267
|
-
);
|
|
236
|
+
return and(...sqlConditions);
|
|
268
237
|
}
|
|
269
238
|
function buildOrderBy(sortOrder) {
|
|
270
239
|
if (sortOrder === "asc") {
|
|
@@ -272,47 +241,10 @@ function buildOrderBy(sortOrder) {
|
|
|
272
241
|
}
|
|
273
242
|
return [desc(auditLogs.timestamp), desc(auditLogs.id)];
|
|
274
243
|
}
|
|
275
|
-
function encodeCursor(timestamp2, id) {
|
|
276
|
-
const payload = JSON.stringify({ t: timestamp2.toISOString(), i: id });
|
|
277
|
-
return btoa(payload);
|
|
278
|
-
}
|
|
279
|
-
var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
280
|
-
function decodeCursor(cursor) {
|
|
281
|
-
let parsed;
|
|
282
|
-
try {
|
|
283
|
-
parsed = JSON.parse(atob(cursor));
|
|
284
|
-
} catch {
|
|
285
|
-
throw new Error("Invalid cursor: failed to decode");
|
|
286
|
-
}
|
|
287
|
-
if (typeof parsed !== "object" || parsed === null || !("t" in parsed) || !("i" in parsed)) {
|
|
288
|
-
throw new Error("Invalid cursor: missing required fields");
|
|
289
|
-
}
|
|
290
|
-
const { t, i } = parsed;
|
|
291
|
-
if (typeof t !== "string" || typeof i !== "string") {
|
|
292
|
-
throw new Error("Invalid cursor: fields must be strings");
|
|
293
|
-
}
|
|
294
|
-
const timestamp2 = new Date(t);
|
|
295
|
-
if (isNaN(timestamp2.getTime())) {
|
|
296
|
-
throw new Error("Invalid cursor: invalid timestamp");
|
|
297
|
-
}
|
|
298
|
-
if (!UUID_PATTERN.test(i)) {
|
|
299
|
-
throw new Error("Invalid cursor: id must be a valid UUID");
|
|
300
|
-
}
|
|
301
|
-
return { timestamp: timestamp2, id: i };
|
|
302
|
-
}
|
|
303
244
|
|
|
304
245
|
// src/adapter.ts
|
|
305
246
|
var DEFAULT_LIMIT = 50;
|
|
306
247
|
var MAX_LIMIT = 250;
|
|
307
|
-
function toCount(value) {
|
|
308
|
-
if (typeof value === "number") {
|
|
309
|
-
return value;
|
|
310
|
-
}
|
|
311
|
-
if (typeof value === "string") {
|
|
312
|
-
return Number(value);
|
|
313
|
-
}
|
|
314
|
-
return 0;
|
|
315
|
-
}
|
|
316
248
|
function drizzleAuditAdapter(db) {
|
|
317
249
|
return {
|
|
318
250
|
async writeLog(log) {
|
|
@@ -322,9 +254,7 @@ function drizzleAuditAdapter(db) {
|
|
|
322
254
|
async queryLogs(spec) {
|
|
323
255
|
const sortOrder = spec.sortOrder ?? "desc";
|
|
324
256
|
const limit = Math.min(spec.limit ?? DEFAULT_LIMIT, MAX_LIMIT);
|
|
325
|
-
const
|
|
326
|
-
const cursorCondition = spec.cursor !== void 0 ? buildCursorCondition(spec.cursor, sortOrder) : void 0;
|
|
327
|
-
const combined = and2(whereCondition, cursorCondition);
|
|
257
|
+
const combined = buildWhereConditions(spec.filters, spec.cursor, sortOrder);
|
|
328
258
|
const fetchLimit = limit + 1;
|
|
329
259
|
const orderColumns = buildOrderBy(sortOrder);
|
|
330
260
|
const query = db.select().from(auditLogs).where(combined).orderBy(...orderColumns).limit(fetchLimit);
|
|
@@ -419,42 +349,9 @@ function drizzleAuditAdapter(db) {
|
|
|
419
349
|
}
|
|
420
350
|
};
|
|
421
351
|
}
|
|
422
|
-
function assembleStats(summaryRows, eventsPerDayRows, topActorsRows, topTablesRows, operationRows, severityRows) {
|
|
423
|
-
const summary = summaryRows[0];
|
|
424
|
-
const totalLogs = summary !== void 0 ? toCount(summary.totalLogs) : 0;
|
|
425
|
-
const tablesAudited = summary !== void 0 ? toCount(summary.tablesAudited) : 0;
|
|
426
|
-
const eventsPerDay = eventsPerDayRows.map((row) => ({
|
|
427
|
-
date: row.date instanceof Date ? row.date.toISOString().split("T")[0] : String(row.date),
|
|
428
|
-
count: toCount(row.count)
|
|
429
|
-
}));
|
|
430
|
-
const topActors = topActorsRows.map((row) => ({
|
|
431
|
-
actorId: String(row.actorId),
|
|
432
|
-
count: toCount(row.count)
|
|
433
|
-
}));
|
|
434
|
-
const topTables = topTablesRows.map((row) => ({
|
|
435
|
-
tableName: String(row.tableName),
|
|
436
|
-
count: toCount(row.count)
|
|
437
|
-
}));
|
|
438
|
-
const operationBreakdown = {};
|
|
439
|
-
for (const row of operationRows) {
|
|
440
|
-
operationBreakdown[String(row.operation)] = toCount(row.count);
|
|
441
|
-
}
|
|
442
|
-
const severityBreakdown = {};
|
|
443
|
-
for (const row of severityRows) {
|
|
444
|
-
severityBreakdown[String(row.severity)] = toCount(row.count);
|
|
445
|
-
}
|
|
446
|
-
return {
|
|
447
|
-
totalLogs,
|
|
448
|
-
tablesAudited,
|
|
449
|
-
eventsPerDay,
|
|
450
|
-
topActors,
|
|
451
|
-
topTables,
|
|
452
|
-
operationBreakdown,
|
|
453
|
-
severityBreakdown
|
|
454
|
-
};
|
|
455
|
-
}
|
|
456
352
|
|
|
457
353
|
// src/sqlite-adapter.ts
|
|
354
|
+
import { encodeCursor as encodeCursor2, toCount, assembleStats as assembleStats2 } from "@usebetterdev/audit-core";
|
|
458
355
|
import { and as and4, eq as eq4, gte as gte4, lt as lt4, isNotNull as isNotNull2, sql as sql4, desc as desc4 } from "drizzle-orm";
|
|
459
356
|
|
|
460
357
|
// src/sqlite-schema.ts
|
|
@@ -503,23 +400,7 @@ var sqliteAuditLogs = sqliteTable(
|
|
|
503
400
|
);
|
|
504
401
|
|
|
505
402
|
// src/sqlite-column-map.ts
|
|
506
|
-
|
|
507
|
-
"INSERT",
|
|
508
|
-
"UPDATE",
|
|
509
|
-
"DELETE"
|
|
510
|
-
]);
|
|
511
|
-
var VALID_SEVERITIES2 = /* @__PURE__ */ new Set([
|
|
512
|
-
"low",
|
|
513
|
-
"medium",
|
|
514
|
-
"high",
|
|
515
|
-
"critical"
|
|
516
|
-
]);
|
|
517
|
-
function isAuditOperation2(value) {
|
|
518
|
-
return VALID_OPERATIONS2.has(value);
|
|
519
|
-
}
|
|
520
|
-
function isAuditSeverity2(value) {
|
|
521
|
-
return VALID_SEVERITIES2.has(value);
|
|
522
|
-
}
|
|
403
|
+
import { isAuditOperation as isAuditOperation2, isAuditSeverity as isAuditSeverity2 } from "@usebetterdev/audit-core";
|
|
523
404
|
function sqliteAuditLogToRow(log) {
|
|
524
405
|
const row = {
|
|
525
406
|
id: log.id,
|
|
@@ -624,7 +505,10 @@ function sqliteRowToAuditLog(row) {
|
|
|
624
505
|
}
|
|
625
506
|
|
|
626
507
|
// src/sqlite-query.ts
|
|
627
|
-
import {
|
|
508
|
+
import {
|
|
509
|
+
decodeCursor as decodeCursor2,
|
|
510
|
+
interpretFilters as interpretFilters2
|
|
511
|
+
} from "@usebetterdev/audit-core";
|
|
628
512
|
import {
|
|
629
513
|
and as and3,
|
|
630
514
|
or as or2,
|
|
@@ -639,87 +523,72 @@ import {
|
|
|
639
523
|
desc as desc3,
|
|
640
524
|
sql as sql3
|
|
641
525
|
} from "drizzle-orm";
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
}
|
|
654
|
-
function buildSqliteWhereConditions(filters) {
|
|
655
|
-
const conditions = [];
|
|
656
|
-
if (filters.resource !== void 0) {
|
|
657
|
-
conditions.push(eq3(sqliteAuditLogs.tableName, filters.resource.tableName));
|
|
658
|
-
if (filters.resource.recordId !== void 0) {
|
|
659
|
-
conditions.push(eq3(sqliteAuditLogs.recordId, filters.resource.recordId));
|
|
526
|
+
var FIELD_COLUMNS2 = {
|
|
527
|
+
tableName: sqliteAuditLogs.tableName,
|
|
528
|
+
recordId: sqliteAuditLogs.recordId,
|
|
529
|
+
actorId: sqliteAuditLogs.actorId,
|
|
530
|
+
severity: sqliteAuditLogs.severity,
|
|
531
|
+
operation: sqliteAuditLogs.operation
|
|
532
|
+
};
|
|
533
|
+
function mapCondition2(condition) {
|
|
534
|
+
switch (condition.kind) {
|
|
535
|
+
case "eq": {
|
|
536
|
+
return eq3(FIELD_COLUMNS2[condition.field], condition.value);
|
|
660
537
|
}
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
if (filters.actorIds.length === 1) {
|
|
664
|
-
conditions.push(eq3(sqliteAuditLogs.actorId, filters.actorIds[0]));
|
|
665
|
-
} else {
|
|
666
|
-
conditions.push(inArray2(sqliteAuditLogs.actorId, filters.actorIds));
|
|
538
|
+
case "in": {
|
|
539
|
+
return inArray2(FIELD_COLUMNS2[condition.field], condition.values);
|
|
667
540
|
}
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
if (filters.severities.length === 1) {
|
|
671
|
-
conditions.push(eq3(sqliteAuditLogs.severity, filters.severities[0]));
|
|
672
|
-
} else {
|
|
673
|
-
conditions.push(inArray2(sqliteAuditLogs.severity, filters.severities));
|
|
541
|
+
case "timestampGte": {
|
|
542
|
+
return gte3(sqliteAuditLogs.timestamp, condition.value);
|
|
674
543
|
}
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
if (filters.operations.length === 1) {
|
|
678
|
-
conditions.push(eq3(sqliteAuditLogs.operation, filters.operations[0]));
|
|
679
|
-
} else {
|
|
680
|
-
conditions.push(inArray2(sqliteAuditLogs.operation, filters.operations));
|
|
544
|
+
case "timestampLte": {
|
|
545
|
+
return lte2(sqliteAuditLogs.timestamp, condition.value);
|
|
681
546
|
}
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
conditions.push(lte2(sqliteAuditLogs.timestamp, resolveTimeFilter2(filters.until)));
|
|
688
|
-
}
|
|
689
|
-
if (filters.searchText !== void 0 && filters.searchText.length > 0) {
|
|
690
|
-
const escaped = escapeLikePattern2(filters.searchText);
|
|
691
|
-
const pattern = `%${escaped}%`;
|
|
692
|
-
const searchCondition = or2(
|
|
693
|
-
like(sqliteAuditLogs.label, pattern),
|
|
694
|
-
like(sqliteAuditLogs.description, pattern)
|
|
695
|
-
);
|
|
696
|
-
if (searchCondition !== void 0) {
|
|
697
|
-
conditions.push(searchCondition);
|
|
547
|
+
case "search": {
|
|
548
|
+
return or2(
|
|
549
|
+
like(sqliteAuditLogs.label, condition.pattern),
|
|
550
|
+
like(sqliteAuditLogs.description, condition.pattern)
|
|
551
|
+
);
|
|
698
552
|
}
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
553
|
+
case "compliance": {
|
|
554
|
+
const tagConditions = [];
|
|
555
|
+
for (const tag of condition.tags) {
|
|
556
|
+
tagConditions.push(
|
|
557
|
+
sql3`EXISTS (SELECT 1 FROM json_each(${sqliteAuditLogs.compliance}) WHERE value = ${tag})`
|
|
558
|
+
);
|
|
559
|
+
}
|
|
560
|
+
return and3(...tagConditions);
|
|
561
|
+
}
|
|
562
|
+
case "cursor": {
|
|
563
|
+
const tsCompare = condition.sortOrder === "asc" ? gt2 : lt3;
|
|
564
|
+
const idCompare = condition.sortOrder === "asc" ? gt2 : lt3;
|
|
565
|
+
return or2(
|
|
566
|
+
tsCompare(sqliteAuditLogs.timestamp, condition.timestamp),
|
|
567
|
+
and3(
|
|
568
|
+
eq3(sqliteAuditLogs.timestamp, condition.timestamp),
|
|
569
|
+
idCompare(sqliteAuditLogs.id, condition.id)
|
|
570
|
+
)
|
|
704
571
|
);
|
|
705
572
|
}
|
|
706
573
|
}
|
|
707
|
-
|
|
574
|
+
}
|
|
575
|
+
function buildSqliteWhereConditions(filters, cursor, sortOrder) {
|
|
576
|
+
const decoded = cursor !== void 0 ? decodeCursor2(cursor) : void 0;
|
|
577
|
+
const irConditions = interpretFilters2(filters, {
|
|
578
|
+
cursor: decoded,
|
|
579
|
+
sortOrder
|
|
580
|
+
});
|
|
581
|
+
const sqlConditions = [];
|
|
582
|
+
for (const c of irConditions) {
|
|
583
|
+
const mapped = mapCondition2(c);
|
|
584
|
+
if (mapped !== void 0) {
|
|
585
|
+
sqlConditions.push(mapped);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
if (sqlConditions.length === 0) {
|
|
708
589
|
return void 0;
|
|
709
590
|
}
|
|
710
|
-
return and3(...
|
|
711
|
-
}
|
|
712
|
-
function buildSqliteCursorCondition(cursor, sortOrder) {
|
|
713
|
-
const decoded = decodeSqliteCursor(cursor);
|
|
714
|
-
const tsCompare = sortOrder === "asc" ? gt2 : lt3;
|
|
715
|
-
const idCompare = sortOrder === "asc" ? gt2 : lt3;
|
|
716
|
-
return or2(
|
|
717
|
-
tsCompare(sqliteAuditLogs.timestamp, decoded.timestamp),
|
|
718
|
-
and3(
|
|
719
|
-
eq3(sqliteAuditLogs.timestamp, decoded.timestamp),
|
|
720
|
-
idCompare(sqliteAuditLogs.id, decoded.id)
|
|
721
|
-
)
|
|
722
|
-
);
|
|
591
|
+
return and3(...sqlConditions);
|
|
723
592
|
}
|
|
724
593
|
function buildSqliteOrderBy(sortOrder) {
|
|
725
594
|
if (sortOrder === "asc") {
|
|
@@ -727,47 +596,10 @@ function buildSqliteOrderBy(sortOrder) {
|
|
|
727
596
|
}
|
|
728
597
|
return [desc3(sqliteAuditLogs.timestamp), desc3(sqliteAuditLogs.id)];
|
|
729
598
|
}
|
|
730
|
-
function encodeSqliteCursor(timestamp2, id) {
|
|
731
|
-
const payload = JSON.stringify({ t: timestamp2.toISOString(), i: id });
|
|
732
|
-
return btoa(payload);
|
|
733
|
-
}
|
|
734
|
-
var UUID_PATTERN2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
735
|
-
function decodeSqliteCursor(cursor) {
|
|
736
|
-
let parsed;
|
|
737
|
-
try {
|
|
738
|
-
parsed = JSON.parse(atob(cursor));
|
|
739
|
-
} catch {
|
|
740
|
-
throw new Error("Invalid cursor: failed to decode");
|
|
741
|
-
}
|
|
742
|
-
if (typeof parsed !== "object" || parsed === null || !("t" in parsed) || !("i" in parsed)) {
|
|
743
|
-
throw new Error("Invalid cursor: missing required fields");
|
|
744
|
-
}
|
|
745
|
-
const { t, i } = parsed;
|
|
746
|
-
if (typeof t !== "string" || typeof i !== "string") {
|
|
747
|
-
throw new Error("Invalid cursor: fields must be strings");
|
|
748
|
-
}
|
|
749
|
-
const timestamp2 = new Date(t);
|
|
750
|
-
if (isNaN(timestamp2.getTime())) {
|
|
751
|
-
throw new Error("Invalid cursor: invalid timestamp");
|
|
752
|
-
}
|
|
753
|
-
if (!UUID_PATTERN2.test(i)) {
|
|
754
|
-
throw new Error("Invalid cursor: id must be a valid UUID");
|
|
755
|
-
}
|
|
756
|
-
return { timestamp: timestamp2, id: i };
|
|
757
|
-
}
|
|
758
599
|
|
|
759
600
|
// src/sqlite-adapter.ts
|
|
760
601
|
var DEFAULT_LIMIT2 = 50;
|
|
761
602
|
var MAX_LIMIT2 = 250;
|
|
762
|
-
function toCount2(value) {
|
|
763
|
-
if (typeof value === "number") {
|
|
764
|
-
return value;
|
|
765
|
-
}
|
|
766
|
-
if (typeof value === "string") {
|
|
767
|
-
return Number(value);
|
|
768
|
-
}
|
|
769
|
-
return 0;
|
|
770
|
-
}
|
|
771
603
|
function drizzleSqliteAuditAdapter(db) {
|
|
772
604
|
return {
|
|
773
605
|
async writeLog(log) {
|
|
@@ -777,9 +609,7 @@ function drizzleSqliteAuditAdapter(db) {
|
|
|
777
609
|
async queryLogs(spec) {
|
|
778
610
|
const sortOrder = spec.sortOrder ?? "desc";
|
|
779
611
|
const limit = Math.min(spec.limit ?? DEFAULT_LIMIT2, MAX_LIMIT2);
|
|
780
|
-
const
|
|
781
|
-
const cursorCondition = spec.cursor !== void 0 ? buildSqliteCursorCondition(spec.cursor, sortOrder) : void 0;
|
|
782
|
-
const combined = and4(whereCondition, cursorCondition);
|
|
612
|
+
const combined = buildSqliteWhereConditions(spec.filters, spec.cursor, sortOrder);
|
|
783
613
|
const fetchLimit = limit + 1;
|
|
784
614
|
const orderColumns = buildSqliteOrderBy(sortOrder);
|
|
785
615
|
const query = db.select().from(sqliteAuditLogs).where(combined).orderBy(...orderColumns).limit(fetchLimit);
|
|
@@ -789,7 +619,7 @@ function drizzleSqliteAuditAdapter(db) {
|
|
|
789
619
|
const entries = resultRows.map(sqliteRowToAuditLog);
|
|
790
620
|
const lastRow = resultRows[resultRows.length - 1];
|
|
791
621
|
if (hasNextPage && lastRow !== void 0) {
|
|
792
|
-
return { entries, nextCursor:
|
|
622
|
+
return { entries, nextCursor: encodeCursor2(lastRow.timestamp, lastRow.id) };
|
|
793
623
|
}
|
|
794
624
|
return { entries };
|
|
795
625
|
},
|
|
@@ -812,7 +642,7 @@ function drizzleSqliteAuditAdapter(db) {
|
|
|
812
642
|
}
|
|
813
643
|
await db.delete(sqliteAuditLogs).where(and4(...conditions));
|
|
814
644
|
const changesResult = await db.select({ count: sql4`changes()` }).from(sqliteAuditLogs);
|
|
815
|
-
const deletedCount = changesResult[0] !== void 0 ?
|
|
645
|
+
const deletedCount = changesResult[0] !== void 0 ? toCount(changesResult[0].count) : 0;
|
|
816
646
|
return { deletedCount };
|
|
817
647
|
},
|
|
818
648
|
async getStats(options) {
|
|
@@ -868,40 +698,6 @@ function drizzleSqliteAuditAdapter(db) {
|
|
|
868
698
|
}
|
|
869
699
|
};
|
|
870
700
|
}
|
|
871
|
-
function assembleStats2(summaryRows, eventsPerDayRows, topActorsRows, topTablesRows, operationRows, severityRows) {
|
|
872
|
-
const summary = summaryRows[0];
|
|
873
|
-
const totalLogs = summary !== void 0 ? toCount2(summary.totalLogs) : 0;
|
|
874
|
-
const tablesAudited = summary !== void 0 ? toCount2(summary.tablesAudited) : 0;
|
|
875
|
-
const eventsPerDay = eventsPerDayRows.map((row) => ({
|
|
876
|
-
date: String(row.date),
|
|
877
|
-
count: toCount2(row.count)
|
|
878
|
-
}));
|
|
879
|
-
const topActors = topActorsRows.map((row) => ({
|
|
880
|
-
actorId: String(row.actorId),
|
|
881
|
-
count: toCount2(row.count)
|
|
882
|
-
}));
|
|
883
|
-
const topTables = topTablesRows.map((row) => ({
|
|
884
|
-
tableName: String(row.tableName),
|
|
885
|
-
count: toCount2(row.count)
|
|
886
|
-
}));
|
|
887
|
-
const operationBreakdown = {};
|
|
888
|
-
for (const row of operationRows) {
|
|
889
|
-
operationBreakdown[String(row.operation)] = toCount2(row.count);
|
|
890
|
-
}
|
|
891
|
-
const severityBreakdown = {};
|
|
892
|
-
for (const row of severityRows) {
|
|
893
|
-
severityBreakdown[String(row.severity)] = toCount2(row.count);
|
|
894
|
-
}
|
|
895
|
-
return {
|
|
896
|
-
totalLogs,
|
|
897
|
-
tablesAudited,
|
|
898
|
-
eventsPerDay,
|
|
899
|
-
topActors,
|
|
900
|
-
topTables,
|
|
901
|
-
operationBreakdown,
|
|
902
|
-
severityBreakdown
|
|
903
|
-
};
|
|
904
|
-
}
|
|
905
701
|
|
|
906
702
|
// src/proxy.ts
|
|
907
703
|
import { getTableName } from "drizzle-orm";
|
|
@@ -1394,15 +1190,17 @@ async function fireCaptureLog(result, ctx, state) {
|
|
|
1394
1190
|
}
|
|
1395
1191
|
}
|
|
1396
1192
|
}
|
|
1193
|
+
|
|
1194
|
+
// src/index.ts
|
|
1195
|
+
import { encodeCursor as encodeCursor3, decodeCursor as decodeCursor3 } from "@usebetterdev/audit-core";
|
|
1397
1196
|
export {
|
|
1398
1197
|
auditLogs,
|
|
1399
|
-
buildCursorCondition,
|
|
1400
1198
|
buildOrderBy,
|
|
1401
1199
|
buildWhereConditions,
|
|
1402
|
-
decodeCursor,
|
|
1200
|
+
decodeCursor3 as decodeCursor,
|
|
1403
1201
|
drizzleAuditAdapter,
|
|
1404
1202
|
drizzleSqliteAuditAdapter,
|
|
1405
|
-
encodeCursor,
|
|
1203
|
+
encodeCursor3 as encodeCursor,
|
|
1406
1204
|
sqliteAuditLogs,
|
|
1407
1205
|
withAuditProxy
|
|
1408
1206
|
};
|