@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 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 VALID_OPERATIONS = /* @__PURE__ */ new Set([
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 import_audit_core = require("@usebetterdev/audit-core");
185
+ var import_audit_core2 = require("@usebetterdev/audit-core");
202
186
  var import_drizzle_orm = require("drizzle-orm");
203
- function escapeLikePattern(input) {
204
- return input.replace(/[%_\\]/g, "\\$&");
205
- }
206
- function resolveTimeFilter(filter) {
207
- if ("date" in filter && filter.date !== void 0) {
208
- return filter.date;
209
- }
210
- if ("duration" in filter && filter.duration !== void 0) {
211
- return (0, import_audit_core.parseDuration)(filter.duration);
212
- }
213
- throw new Error("TimeFilter must have either date or duration");
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
- if (filters.actorIds !== void 0 && filters.actorIds.length > 0) {
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
- if (filters.severities !== void 0 && filters.severities.length > 0) {
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
- if (filters.operations !== void 0 && filters.operations.length > 0) {
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
- if (filters.since !== void 0) {
245
- conditions.push((0, import_drizzle_orm.gte)(auditLogs.timestamp, resolveTimeFilter(filters.since)));
246
- }
247
- if (filters.until !== void 0) {
248
- conditions.push((0, import_drizzle_orm.lte)(auditLogs.timestamp, resolveTimeFilter(filters.until)));
249
- }
250
- if (filters.searchText !== void 0 && filters.searchText.length > 0) {
251
- const escaped = escapeLikePattern(filters.searchText);
252
- const pattern = `%${escaped}%`;
253
- const searchCondition = (0, import_drizzle_orm.or)(
254
- (0, import_drizzle_orm.ilike)(auditLogs.label, pattern),
255
- (0, import_drizzle_orm.ilike)(auditLogs.description, pattern)
256
- );
257
- if (searchCondition !== void 0) {
258
- conditions.push(searchCondition);
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
- if (filters.compliance !== void 0 && filters.compliance.length > 0) {
262
- conditions.push(
263
- import_drizzle_orm.sql`${auditLogs.compliance} @> ${JSON.stringify(filters.compliance)}::jsonb`
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 (conditions.length === 0) {
243
+ if (sqlConditions.length === 0) {
267
244
  return void 0;
268
245
  }
269
- return (0, import_drizzle_orm.and)(...conditions);
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 whereCondition = buildWhereConditions(spec.filters);
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(sinceCondition);
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(sinceCondition).groupBy(import_drizzle_orm2.sql`date_trunc('day', ${auditLogs.timestamp})`).orderBy(import_drizzle_orm2.sql`date_trunc('day', ${auditLogs.timestamp})`).limit(365);
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)(sinceCondition, (0, import_drizzle_orm2.isNotNull)(auditLogs.actorId))).groupBy(auditLogs.actorId).orderBy((0, import_drizzle_orm2.desc)(import_drizzle_orm2.sql`count(*)`)).limit(10);
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(sinceCondition).groupBy(auditLogs.tableName).orderBy((0, import_drizzle_orm2.desc)(import_drizzle_orm2.sql`count(*)`)).limit(10);
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(sinceCondition).groupBy(auditLogs.operation);
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)(sinceCondition, (0, import_drizzle_orm2.isNotNull)(auditLogs.severity))).groupBy(auditLogs.severity);
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 VALID_OPERATIONS2 = /* @__PURE__ */ new Set([
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 (!isAuditOperation2(row.operation)) {
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 (!isAuditSeverity2(row.severity)) {
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 import_audit_core2 = require("@usebetterdev/audit-core");
515
+ var import_audit_core5 = require("@usebetterdev/audit-core");
637
516
  var import_drizzle_orm3 = require("drizzle-orm");
638
- function escapeLikePattern2(input) {
639
- return input.replace(/[%_\\]/g, "\\$&");
640
- }
641
- function resolveTimeFilter2(filter) {
642
- if ("date" in filter && filter.date !== void 0) {
643
- return filter.date;
644
- }
645
- if ("duration" in filter && filter.duration !== void 0) {
646
- return (0, import_audit_core2.parseDuration)(filter.duration);
647
- }
648
- throw new Error("TimeFilter must have either date or duration");
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
- if (filters.actorIds !== void 0 && filters.actorIds.length > 0) {
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
- if (filters.severities !== void 0 && filters.severities.length > 0) {
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
- if (filters.operations !== void 0 && filters.operations.length > 0) {
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
- if (filters.since !== void 0) {
680
- conditions.push((0, import_drizzle_orm3.gte)(sqliteAuditLogs.timestamp, resolveTimeFilter2(filters.since)));
681
- }
682
- if (filters.until !== void 0) {
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
- if (filters.compliance !== void 0 && filters.compliance.length > 0) {
697
- for (const tag of filters.compliance) {
698
- conditions.push(
699
- import_drizzle_orm3.sql`EXISTS (SELECT 1 FROM json_each(${sqliteAuditLogs.compliance}) WHERE value = ${tag})`
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
- if (conditions.length === 0) {
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)(...conditions);
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 whereCondition = buildSqliteWhereConditions(spec.filters);
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: encodeSqliteCursor(lastRow.timestamp, lastRow.id) };
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 ? toCount2(changesResult[0].count) : 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(sinceCondition);
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(sinceCondition).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);
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)(sinceCondition, (0, import_drizzle_orm4.isNotNull)(sqliteAuditLogs.actorId))).groupBy(sqliteAuditLogs.actorId).orderBy((0, import_drizzle_orm4.desc)(import_drizzle_orm4.sql`count(*)`)).limit(10);
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(sinceCondition).groupBy(sqliteAuditLogs.tableName).orderBy((0, import_drizzle_orm4.desc)(import_drizzle_orm4.sql`count(*)`)).limit(10);
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(sinceCondition).groupBy(sqliteAuditLogs.operation);
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)(sinceCondition, (0, import_drizzle_orm4.isNotNull)(sqliteAuditLogs.severity))).groupBy(sqliteAuditLogs.severity);
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 assembleStats2(
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,