@usebetterdev/audit-core 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 CHANGED
@@ -22,20 +22,33 @@ var index_exports = {};
22
22
  __export(index_exports, {
23
23
  AUDIT_LOG_SCHEMA: () => AUDIT_LOG_SCHEMA,
24
24
  AuditQueryBuilder: () => AuditQueryBuilder,
25
+ VALID_OPERATIONS: () => VALID_OPERATIONS2,
26
+ VALID_SEVERITIES: () => VALID_SEVERITIES2,
27
+ assembleStats: () => assembleStats,
25
28
  betterAudit: () => betterAudit,
26
29
  createAuditApi: () => createAuditApi,
27
30
  createAuditConsoleEndpoints: () => createAuditConsoleEndpoints,
28
31
  createExportResponse: () => createExportResponse,
32
+ decodeCursor: () => decodeCursor,
33
+ defaultExtractor: () => defaultExtractor,
34
+ encodeCursor: () => encodeCursor,
35
+ escapeLikePattern: () => escapeLikePattern,
29
36
  fromBearerToken: () => fromBearerToken,
30
37
  fromCookie: () => fromCookie,
31
38
  fromHeader: () => fromHeader,
32
39
  getAuditContext: () => getAuditContext,
33
40
  handleMiddleware: () => handleMiddleware,
41
+ interpretFilters: () => interpretFilters,
42
+ isAuditOperation: () => isAuditOperation,
43
+ isAuditSeverity: () => isAuditSeverity,
34
44
  mergeAuditContext: () => mergeAuditContext,
35
45
  normalizeInput: () => normalizeInput,
36
46
  parseDuration: () => parseDuration,
47
+ resolveTimeFilter: () => resolveTimeFilter,
37
48
  runExport: () => runExport,
38
- runWithAuditContext: () => runWithAuditContext
49
+ runWithAuditContext: () => runWithAuditContext,
50
+ safeExtract: () => safeExtract,
51
+ toCount: () => toCount
39
52
  });
40
53
  module.exports = __toCommonJS(index_exports);
41
54
 
@@ -1509,6 +1522,171 @@ var AUDIT_LOG_SCHEMA = {
1509
1522
  }
1510
1523
  };
1511
1524
 
1525
+ // src/cursor.ts
1526
+ var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
1527
+ function encodeCursor(timestamp, id) {
1528
+ const payload = JSON.stringify({ t: timestamp.toISOString(), i: id });
1529
+ return btoa(payload);
1530
+ }
1531
+ function decodeCursor(cursor) {
1532
+ let parsed;
1533
+ try {
1534
+ parsed = JSON.parse(atob(cursor));
1535
+ } catch {
1536
+ throw new Error("Invalid cursor: failed to decode");
1537
+ }
1538
+ if (typeof parsed !== "object" || parsed === null || !("t" in parsed) || !("i" in parsed)) {
1539
+ throw new Error("Invalid cursor: missing required fields");
1540
+ }
1541
+ const record = parsed;
1542
+ const t = record["t"];
1543
+ const i = record["i"];
1544
+ if (typeof t !== "string" || typeof i !== "string") {
1545
+ throw new Error("Invalid cursor: fields must be strings");
1546
+ }
1547
+ const timestamp = new Date(t);
1548
+ if (isNaN(timestamp.getTime())) {
1549
+ throw new Error("Invalid cursor: invalid timestamp");
1550
+ }
1551
+ if (!UUID_PATTERN.test(i)) {
1552
+ throw new Error("Invalid cursor: id must be a valid UUID");
1553
+ }
1554
+ return { timestamp, id: i };
1555
+ }
1556
+
1557
+ // src/escape.ts
1558
+ function escapeLikePattern(input) {
1559
+ return input.replace(/[%_\\]/g, "\\$&");
1560
+ }
1561
+
1562
+ // src/time-filter.ts
1563
+ function resolveTimeFilter(filter) {
1564
+ if ("date" in filter && filter.date !== void 0) {
1565
+ return filter.date;
1566
+ }
1567
+ if ("duration" in filter && filter.duration !== void 0) {
1568
+ return parseDuration(filter.duration);
1569
+ }
1570
+ throw new Error("TimeFilter must have either date or duration");
1571
+ }
1572
+
1573
+ // src/filter-builder.ts
1574
+ function interpretFilters(filters, options) {
1575
+ const conditions = [];
1576
+ if (filters.resource !== void 0) {
1577
+ conditions.push({ kind: "eq", field: "tableName", value: filters.resource.tableName });
1578
+ if (filters.resource.recordId !== void 0) {
1579
+ conditions.push({ kind: "eq", field: "recordId", value: filters.resource.recordId });
1580
+ }
1581
+ }
1582
+ pushArrayFilter(conditions, "actorId", filters.actorIds);
1583
+ pushArrayFilter(conditions, "severity", filters.severities);
1584
+ pushArrayFilter(conditions, "operation", filters.operations);
1585
+ if (filters.since !== void 0) {
1586
+ conditions.push({ kind: "timestampGte", value: resolveTimeFilter(filters.since) });
1587
+ }
1588
+ if (filters.until !== void 0) {
1589
+ conditions.push({ kind: "timestampLte", value: resolveTimeFilter(filters.until) });
1590
+ }
1591
+ if (filters.searchText !== void 0 && filters.searchText.length > 0) {
1592
+ const escaped = escapeLikePattern(filters.searchText);
1593
+ conditions.push({ kind: "search", pattern: `%${escaped}%` });
1594
+ }
1595
+ if (filters.compliance !== void 0 && filters.compliance.length > 0) {
1596
+ conditions.push({ kind: "compliance", tags: [...filters.compliance] });
1597
+ }
1598
+ if (options?.cursor !== void 0) {
1599
+ conditions.push({
1600
+ kind: "cursor",
1601
+ timestamp: options.cursor.timestamp,
1602
+ id: options.cursor.id,
1603
+ sortOrder: options.sortOrder ?? "desc"
1604
+ });
1605
+ }
1606
+ return conditions;
1607
+ }
1608
+ function pushArrayFilter(conditions, field, values) {
1609
+ if (values === void 0 || values.length === 0) {
1610
+ return;
1611
+ }
1612
+ if (values.length === 1) {
1613
+ const first = values[0];
1614
+ if (first !== void 0) {
1615
+ conditions.push({ kind: "eq", field, value: first });
1616
+ }
1617
+ } else {
1618
+ conditions.push({ kind: "in", field, values: [...values] });
1619
+ }
1620
+ }
1621
+
1622
+ // src/stats.ts
1623
+ function toCount(value) {
1624
+ if (typeof value === "number") {
1625
+ return value;
1626
+ }
1627
+ if (typeof value === "string") {
1628
+ const n = Number(value);
1629
+ return Number.isNaN(n) ? 0 : n;
1630
+ }
1631
+ if (typeof value === "bigint") {
1632
+ return Number(value);
1633
+ }
1634
+ return 0;
1635
+ }
1636
+ function assembleStats(summaryRows, eventsPerDayRows, topActorsRows, topTablesRows, operationRows, severityRows) {
1637
+ const summary = summaryRows[0];
1638
+ const totalLogs = summary !== void 0 ? toCount(summary.totalLogs) : 0;
1639
+ const tablesAudited = summary !== void 0 ? toCount(summary.tablesAudited) : 0;
1640
+ const eventsPerDay = eventsPerDayRows.map((row) => ({
1641
+ date: row.date instanceof Date ? row.date.toISOString().split("T")[0] ?? "" : String(row.date),
1642
+ count: toCount(row.count)
1643
+ }));
1644
+ const topActors = topActorsRows.map((row) => ({
1645
+ actorId: String(row.actorId),
1646
+ count: toCount(row.count)
1647
+ }));
1648
+ const topTables = topTablesRows.map((row) => ({
1649
+ tableName: String(row.tableName),
1650
+ count: toCount(row.count)
1651
+ }));
1652
+ const operationBreakdown = {};
1653
+ for (const row of operationRows) {
1654
+ operationBreakdown[String(row.operation)] = toCount(row.count);
1655
+ }
1656
+ const severityBreakdown = {};
1657
+ for (const row of severityRows) {
1658
+ severityBreakdown[String(row.severity)] = toCount(row.count);
1659
+ }
1660
+ return {
1661
+ totalLogs,
1662
+ tablesAudited,
1663
+ eventsPerDay,
1664
+ topActors,
1665
+ topTables,
1666
+ operationBreakdown,
1667
+ severityBreakdown
1668
+ };
1669
+ }
1670
+
1671
+ // src/validation.ts
1672
+ var VALID_OPERATIONS2 = /* @__PURE__ */ new Set([
1673
+ "INSERT",
1674
+ "UPDATE",
1675
+ "DELETE"
1676
+ ]);
1677
+ var VALID_SEVERITIES2 = /* @__PURE__ */ new Set([
1678
+ "low",
1679
+ "medium",
1680
+ "high",
1681
+ "critical"
1682
+ ]);
1683
+ function isAuditOperation(value) {
1684
+ return VALID_OPERATIONS2.has(value);
1685
+ }
1686
+ function isAuditSeverity(value) {
1687
+ return VALID_SEVERITIES2.has(value);
1688
+ }
1689
+
1512
1690
  // src/context-extractor.ts
1513
1691
  function decodeJwtPayload(token) {
1514
1692
  try {
@@ -1586,6 +1764,9 @@ function fromHeader(headerName) {
1586
1764
  return value.trim();
1587
1765
  };
1588
1766
  }
1767
+ var defaultExtractor = {
1768
+ actor: fromBearerToken("sub")
1769
+ };
1589
1770
  async function safeExtract(extractor, request, onError) {
1590
1771
  if (!extractor) {
1591
1772
  return void 0;
@@ -1612,19 +1793,32 @@ async function handleMiddleware(extractor, request, next, options = {}) {
1612
1793
  0 && (module.exports = {
1613
1794
  AUDIT_LOG_SCHEMA,
1614
1795
  AuditQueryBuilder,
1796
+ VALID_OPERATIONS,
1797
+ VALID_SEVERITIES,
1798
+ assembleStats,
1615
1799
  betterAudit,
1616
1800
  createAuditApi,
1617
1801
  createAuditConsoleEndpoints,
1618
1802
  createExportResponse,
1803
+ decodeCursor,
1804
+ defaultExtractor,
1805
+ encodeCursor,
1806
+ escapeLikePattern,
1619
1807
  fromBearerToken,
1620
1808
  fromCookie,
1621
1809
  fromHeader,
1622
1810
  getAuditContext,
1623
1811
  handleMiddleware,
1812
+ interpretFilters,
1813
+ isAuditOperation,
1814
+ isAuditSeverity,
1624
1815
  mergeAuditContext,
1625
1816
  normalizeInput,
1626
1817
  parseDuration,
1818
+ resolveTimeFilter,
1627
1819
  runExport,
1628
- runWithAuditContext
1820
+ runWithAuditContext,
1821
+ safeExtract,
1822
+ toCount
1629
1823
  });
1630
1824
  //# sourceMappingURL=index.cjs.map