@usebetterdev/audit-core 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 +348 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +141 -9
- package/dist/index.d.ts +141 -9
- package/dist/index.js +334 -25
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -725,8 +725,41 @@ async function runExport(executor, options) {
|
|
|
725
725
|
return { rowCount };
|
|
726
726
|
}
|
|
727
727
|
|
|
728
|
+
// src/cursor.ts
|
|
729
|
+
var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
730
|
+
function encodeCursor(timestamp, id) {
|
|
731
|
+
const payload = JSON.stringify({ t: timestamp.toISOString(), i: id });
|
|
732
|
+
return btoa(payload);
|
|
733
|
+
}
|
|
734
|
+
function decodeCursor(cursor) {
|
|
735
|
+
let parsed;
|
|
736
|
+
try {
|
|
737
|
+
parsed = JSON.parse(atob(cursor));
|
|
738
|
+
} catch {
|
|
739
|
+
throw new Error("Invalid cursor: failed to decode");
|
|
740
|
+
}
|
|
741
|
+
if (typeof parsed !== "object" || parsed === null || !("t" in parsed) || !("i" in parsed)) {
|
|
742
|
+
throw new Error("Invalid cursor: missing required fields");
|
|
743
|
+
}
|
|
744
|
+
const record = parsed;
|
|
745
|
+
const t = record["t"];
|
|
746
|
+
const i = record["i"];
|
|
747
|
+
if (typeof t !== "string" || typeof i !== "string") {
|
|
748
|
+
throw new Error("Invalid cursor: fields must be strings");
|
|
749
|
+
}
|
|
750
|
+
const timestamp = new Date(t);
|
|
751
|
+
if (isNaN(timestamp.getTime())) {
|
|
752
|
+
throw new Error("Invalid cursor: invalid timestamp");
|
|
753
|
+
}
|
|
754
|
+
if (!UUID_PATTERN.test(i)) {
|
|
755
|
+
throw new Error("Invalid cursor: id must be a valid UUID");
|
|
756
|
+
}
|
|
757
|
+
return { timestamp, id: i };
|
|
758
|
+
}
|
|
759
|
+
|
|
728
760
|
// src/audit-api.ts
|
|
729
|
-
var
|
|
761
|
+
var SEVERITY_VALUES = ["low", "medium", "high", "critical"];
|
|
762
|
+
var VALID_SEVERITIES = new Set(SEVERITY_VALUES);
|
|
730
763
|
var VALID_OPERATIONS = /* @__PURE__ */ new Set(["INSERT", "UPDATE", "DELETE"]);
|
|
731
764
|
function toTimeFilter(date) {
|
|
732
765
|
return { date };
|
|
@@ -738,18 +771,23 @@ function buildQuerySpec(filters, effectiveLimit) {
|
|
|
738
771
|
limit
|
|
739
772
|
};
|
|
740
773
|
if (filters.tableName !== void 0) {
|
|
741
|
-
spec.filters.resource = { tableName: filters.tableName };
|
|
774
|
+
spec.filters.resource = filters.recordId !== void 0 ? { tableName: filters.tableName, recordId: filters.recordId } : { tableName: filters.tableName };
|
|
742
775
|
}
|
|
743
776
|
if (filters.actorId !== void 0) {
|
|
744
|
-
|
|
777
|
+
const raw = filters.actorId.split(",").map((v) => v.trim()).filter((v) => v.length > 0);
|
|
778
|
+
spec.filters.actorIds = [...new Set(raw)];
|
|
745
779
|
}
|
|
746
780
|
if (filters.severity !== void 0) {
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
)
|
|
781
|
+
const raw = filters.severity.split(",").map((v) => v.trim()).filter((v) => v.length > 0);
|
|
782
|
+
const unique = [...new Set(raw)];
|
|
783
|
+
for (const value of unique) {
|
|
784
|
+
if (!VALID_SEVERITIES.has(value)) {
|
|
785
|
+
throw new Error(
|
|
786
|
+
`Invalid severity "${value}". Must be one of: low, medium, high, critical`
|
|
787
|
+
);
|
|
788
|
+
}
|
|
751
789
|
}
|
|
752
|
-
spec.filters.severities =
|
|
790
|
+
spec.filters.severities = unique.filter((v) => VALID_SEVERITIES.has(v));
|
|
753
791
|
}
|
|
754
792
|
if (filters.compliance !== void 0) {
|
|
755
793
|
spec.filters.compliance = [filters.compliance];
|
|
@@ -775,6 +813,12 @@ function buildQuerySpec(filters, effectiveLimit) {
|
|
|
775
813
|
if (filters.cursor !== void 0) {
|
|
776
814
|
spec.cursor = filters.cursor;
|
|
777
815
|
}
|
|
816
|
+
if (filters.direction === "before") {
|
|
817
|
+
spec.sortOrder = "asc";
|
|
818
|
+
}
|
|
819
|
+
if (filters.order !== void 0) {
|
|
820
|
+
spec.sortOrder = filters.order;
|
|
821
|
+
}
|
|
778
822
|
return spec;
|
|
779
823
|
}
|
|
780
824
|
function createAuditApi(adapter, registry, maxQueryLimit) {
|
|
@@ -813,12 +857,66 @@ function createAuditApi(adapter, registry, maxQueryLimit) {
|
|
|
813
857
|
}
|
|
814
858
|
async function queryLogs(filters) {
|
|
815
859
|
const queryFn = requireQueryLogs();
|
|
816
|
-
const
|
|
860
|
+
const resolved = filters ?? {};
|
|
861
|
+
const spec = buildQuerySpec(resolved, effectiveLimit);
|
|
817
862
|
const result = await queryFn(spec);
|
|
863
|
+
if (resolved.direction === "before") {
|
|
864
|
+
const entries = [...result.entries].reverse();
|
|
865
|
+
const lastEntry = entries[entries.length - 1];
|
|
866
|
+
return {
|
|
867
|
+
entries,
|
|
868
|
+
// Adapter's "next" in ASC = newer entries = our prev
|
|
869
|
+
...result.nextCursor !== void 0 && { prevCursor: result.nextCursor },
|
|
870
|
+
hasPrevPage: result.nextCursor !== void 0,
|
|
871
|
+
// Since we started from a cursor, there are older entries behind it
|
|
872
|
+
...resolved.cursor !== void 0 && lastEntry !== void 0 && { nextCursor: encodeCursor(lastEntry.timestamp, lastEntry.id) },
|
|
873
|
+
hasNextPage: resolved.cursor !== void 0
|
|
874
|
+
};
|
|
875
|
+
}
|
|
876
|
+
const firstEntry = result.entries[0];
|
|
877
|
+
const prevCursor = resolved.cursor !== void 0 && firstEntry !== void 0 ? encodeCursor(firstEntry.timestamp, firstEntry.id) : void 0;
|
|
818
878
|
return {
|
|
819
879
|
entries: result.entries,
|
|
820
880
|
...result.nextCursor !== void 0 && { nextCursor: result.nextCursor },
|
|
821
|
-
hasNextPage: result.nextCursor !== void 0
|
|
881
|
+
hasNextPage: result.nextCursor !== void 0,
|
|
882
|
+
hasPrevPage: resolved.cursor !== void 0,
|
|
883
|
+
...prevCursor !== void 0 && { prevCursor }
|
|
884
|
+
};
|
|
885
|
+
}
|
|
886
|
+
async function queryLogsAround(anchorId, filters) {
|
|
887
|
+
const queryFn = requireQueryLogs();
|
|
888
|
+
const getLogFn = requireGetLogById();
|
|
889
|
+
const anchor = await getLogFn(anchorId);
|
|
890
|
+
if (anchor === null) {
|
|
891
|
+
return { entries: [], hasNextPage: false, hasPrevPage: false };
|
|
892
|
+
}
|
|
893
|
+
const resolved = filters ?? {};
|
|
894
|
+
const limit = Math.min(resolved.limit ?? effectiveLimit, effectiveLimit);
|
|
895
|
+
const remaining = Math.max(limit - 1, 0);
|
|
896
|
+
const olderCount = Math.ceil(remaining / 2);
|
|
897
|
+
const newerCount = Math.floor(remaining / 2);
|
|
898
|
+
const anchorCursor = encodeCursor(anchor.timestamp, anchor.id);
|
|
899
|
+
const { direction: _dir, ...baseFilters } = resolved;
|
|
900
|
+
const olderSpec = buildQuerySpec({ ...baseFilters, cursor: anchorCursor, limit: olderCount }, effectiveLimit);
|
|
901
|
+
olderSpec.sortOrder = "desc";
|
|
902
|
+
const newerSpec = buildQuerySpec({ ...baseFilters, cursor: anchorCursor, limit: newerCount }, effectiveLimit);
|
|
903
|
+
newerSpec.sortOrder = "asc";
|
|
904
|
+
const [olderResult, newerResult] = await Promise.all([
|
|
905
|
+
queryFn(olderSpec),
|
|
906
|
+
queryFn(newerSpec)
|
|
907
|
+
]);
|
|
908
|
+
const newerEntries = [...newerResult.entries].reverse();
|
|
909
|
+
const entries = [...newerEntries, anchor, ...olderResult.entries];
|
|
910
|
+
const hasNextPage = olderResult.nextCursor !== void 0;
|
|
911
|
+
const hasPrevPage = newerResult.nextCursor !== void 0;
|
|
912
|
+
const oldest = entries[entries.length - 1];
|
|
913
|
+
const newest = entries[0];
|
|
914
|
+
return {
|
|
915
|
+
entries,
|
|
916
|
+
hasNextPage,
|
|
917
|
+
hasPrevPage,
|
|
918
|
+
...hasNextPage && oldest !== void 0 && { nextCursor: encodeCursor(oldest.timestamp, oldest.id) },
|
|
919
|
+
...hasPrevPage && newest !== void 0 && { prevCursor: encodeCursor(newest.timestamp, newest.id) }
|
|
822
920
|
};
|
|
823
921
|
}
|
|
824
922
|
async function getLog(id) {
|
|
@@ -863,7 +961,7 @@ function createAuditApi(adapter, registry, maxQueryLimit) {
|
|
|
863
961
|
}
|
|
864
962
|
async function exportLogs(filters, format) {
|
|
865
963
|
const queryFn = requireQueryLogs();
|
|
866
|
-
const exportFormat = format ?? "
|
|
964
|
+
const exportFormat = format ?? "csv";
|
|
867
965
|
const spec = buildQuerySpec(filters ?? {}, effectiveLimit);
|
|
868
966
|
const queryBuilder = new AuditQueryBuilder(
|
|
869
967
|
(s) => queryFn(s),
|
|
@@ -889,7 +987,7 @@ function createAuditApi(adapter, registry, maxQueryLimit) {
|
|
|
889
987
|
const purgeFn = requirePurgeLogs();
|
|
890
988
|
return purgeFn(options);
|
|
891
989
|
}
|
|
892
|
-
return { queryLogs, getLog, getStats, getEnrichments, exportLogs, purgeLogs };
|
|
990
|
+
return { queryLogs, queryLogsAround, getLog, getStats, getEnrichments, exportLogs, purgeLogs };
|
|
893
991
|
}
|
|
894
992
|
|
|
895
993
|
// ../../shared/console-utils/src/index.ts
|
|
@@ -923,7 +1021,7 @@ function exceedsMaxLength(value) {
|
|
|
923
1021
|
return value !== void 0 && value.length > MAX_PARAM_LENGTH;
|
|
924
1022
|
}
|
|
925
1023
|
function hasLongQueryParam(query) {
|
|
926
|
-
return exceedsMaxLength(query.tableName) || exceedsMaxLength(query.actorId) || exceedsMaxLength(query.cursor) || exceedsMaxLength(query.operation) || exceedsMaxLength(query.severity) || exceedsMaxLength(query.compliance) || exceedsMaxLength(query.search);
|
|
1024
|
+
return exceedsMaxLength(query.tableName) || exceedsMaxLength(query.recordId) || exceedsMaxLength(query.actorId) || exceedsMaxLength(query.cursor) || exceedsMaxLength(query.operation) || exceedsMaxLength(query.severity) || exceedsMaxLength(query.compliance) || exceedsMaxLength(query.search) || exceedsMaxLength(query.around) || exceedsMaxLength(query.direction) || exceedsMaxLength(query.order);
|
|
927
1025
|
}
|
|
928
1026
|
function parseConsoleQueryFilters(query) {
|
|
929
1027
|
const filters = {};
|
|
@@ -937,6 +1035,12 @@ function parseConsoleQueryFilters(query) {
|
|
|
937
1035
|
if (query.tableName !== void 0) {
|
|
938
1036
|
filters.tableName = query.tableName;
|
|
939
1037
|
}
|
|
1038
|
+
if (query.recordId !== void 0) {
|
|
1039
|
+
if (query.tableName === void 0) {
|
|
1040
|
+
return { error: "'recordId' requires 'tableName'" };
|
|
1041
|
+
}
|
|
1042
|
+
filters.recordId = query.recordId;
|
|
1043
|
+
}
|
|
940
1044
|
if (query.operation !== void 0) {
|
|
941
1045
|
filters.operation = query.operation;
|
|
942
1046
|
}
|
|
@@ -955,6 +1059,18 @@ function parseConsoleQueryFilters(query) {
|
|
|
955
1059
|
if (query.cursor !== void 0) {
|
|
956
1060
|
filters.cursor = query.cursor;
|
|
957
1061
|
}
|
|
1062
|
+
if (query.direction !== void 0) {
|
|
1063
|
+
if (query.direction !== "after" && query.direction !== "before") {
|
|
1064
|
+
return { error: "Invalid 'direction': must be 'after' or 'before'" };
|
|
1065
|
+
}
|
|
1066
|
+
filters.direction = query.direction;
|
|
1067
|
+
}
|
|
1068
|
+
if (query.order !== void 0) {
|
|
1069
|
+
if (query.order !== "asc" && query.order !== "desc") {
|
|
1070
|
+
return { error: "Invalid 'order': must be 'asc' or 'desc'" };
|
|
1071
|
+
}
|
|
1072
|
+
filters.order = query.order;
|
|
1073
|
+
}
|
|
958
1074
|
if (query.since !== void 0) {
|
|
959
1075
|
const since = parseIsoDate(query.since);
|
|
960
1076
|
if (since === void 0) {
|
|
@@ -969,6 +1085,9 @@ function parseConsoleQueryFilters(query) {
|
|
|
969
1085
|
}
|
|
970
1086
|
filters.until = until;
|
|
971
1087
|
}
|
|
1088
|
+
if (filters.since !== void 0 && filters.until !== void 0 && filters.since >= filters.until) {
|
|
1089
|
+
return { error: "'since' must be before 'until'" };
|
|
1090
|
+
}
|
|
972
1091
|
return { filters };
|
|
973
1092
|
}
|
|
974
1093
|
function serializeLog(log) {
|
|
@@ -985,14 +1104,22 @@ function createAuditConsoleEndpoints(api) {
|
|
|
985
1104
|
requiredPermission: "read",
|
|
986
1105
|
async handler(request) {
|
|
987
1106
|
try {
|
|
988
|
-
|
|
1107
|
+
const query = request.query;
|
|
1108
|
+
if (hasLongQueryParam(query)) {
|
|
989
1109
|
return { status: 400, body: { error: "Query parameter exceeds maximum length" } };
|
|
990
1110
|
}
|
|
991
|
-
const parsed = parseConsoleQueryFilters(
|
|
1111
|
+
const parsed = parseConsoleQueryFilters(query);
|
|
992
1112
|
if ("error" in parsed) {
|
|
993
1113
|
return { status: 400, body: { error: parsed.error } };
|
|
994
1114
|
}
|
|
995
|
-
|
|
1115
|
+
if (parsed.filters.order !== void 0 && parsed.filters.direction !== void 0) {
|
|
1116
|
+
return { status: 400, body: { error: "'order' cannot be combined with 'direction'" } };
|
|
1117
|
+
}
|
|
1118
|
+
const around = query.around;
|
|
1119
|
+
if (around !== void 0 && (parsed.filters.cursor !== void 0 || parsed.filters.direction !== void 0 || parsed.filters.order !== void 0)) {
|
|
1120
|
+
return { status: 400, body: { error: "'around' cannot be combined with 'cursor', 'direction', or 'order'" } };
|
|
1121
|
+
}
|
|
1122
|
+
const result = around !== void 0 ? await api.queryLogsAround(around, parsed.filters) : await api.queryLogs(parsed.filters);
|
|
996
1123
|
const body = {
|
|
997
1124
|
entries: result.entries.map(serializeLog),
|
|
998
1125
|
hasNextPage: result.hasNextPage
|
|
@@ -1000,6 +1127,12 @@ function createAuditConsoleEndpoints(api) {
|
|
|
1000
1127
|
if (result.nextCursor !== void 0) {
|
|
1001
1128
|
body.nextCursor = result.nextCursor;
|
|
1002
1129
|
}
|
|
1130
|
+
if (result.prevCursor !== void 0) {
|
|
1131
|
+
body.prevCursor = result.prevCursor;
|
|
1132
|
+
}
|
|
1133
|
+
if (result.hasPrevPage) {
|
|
1134
|
+
body.hasPrevPage = result.hasPrevPage;
|
|
1135
|
+
}
|
|
1003
1136
|
return { status: 200, body };
|
|
1004
1137
|
} catch {
|
|
1005
1138
|
return { status: 500, body: { error: "Internal server error" } };
|
|
@@ -1032,14 +1165,28 @@ function createAuditConsoleEndpoints(api) {
|
|
|
1032
1165
|
requiredPermission: "read",
|
|
1033
1166
|
async handler(request) {
|
|
1034
1167
|
try {
|
|
1168
|
+
const query = request.query;
|
|
1169
|
+
if (exceedsMaxLength(query.since) || exceedsMaxLength(query.until)) {
|
|
1170
|
+
return { status: 400, body: { error: "Query parameter exceeds maximum length" } };
|
|
1171
|
+
}
|
|
1035
1172
|
const options = {};
|
|
1036
|
-
if (
|
|
1037
|
-
const since = parseIsoDate(
|
|
1173
|
+
if (query.since !== void 0) {
|
|
1174
|
+
const since = parseIsoDate(query.since);
|
|
1038
1175
|
if (since === void 0) {
|
|
1039
1176
|
return { status: 400, body: { error: "Invalid 'since': must be an ISO-8601 date" } };
|
|
1040
1177
|
}
|
|
1041
1178
|
options.since = since;
|
|
1042
1179
|
}
|
|
1180
|
+
if (query.until !== void 0) {
|
|
1181
|
+
const until = parseIsoDate(query.until);
|
|
1182
|
+
if (until === void 0) {
|
|
1183
|
+
return { status: 400, body: { error: "Invalid 'until': must be an ISO-8601 date" } };
|
|
1184
|
+
}
|
|
1185
|
+
options.until = until;
|
|
1186
|
+
}
|
|
1187
|
+
if (options.since !== void 0 && options.until !== void 0 && options.since >= options.until) {
|
|
1188
|
+
return { status: 400, body: { error: "'since' must be before 'until'" } };
|
|
1189
|
+
}
|
|
1043
1190
|
const stats = await api.getStats(options);
|
|
1044
1191
|
return { status: 200, body: stats };
|
|
1045
1192
|
} catch {
|
|
@@ -1066,20 +1213,33 @@ function createAuditConsoleEndpoints(api) {
|
|
|
1066
1213
|
requiredPermission: "read",
|
|
1067
1214
|
async handler(request) {
|
|
1068
1215
|
try {
|
|
1069
|
-
const
|
|
1216
|
+
const query = request.query;
|
|
1217
|
+
const format = query.format;
|
|
1070
1218
|
if (format !== void 0 && format !== "csv" && format !== "json") {
|
|
1071
1219
|
return { status: 400, body: { error: "Invalid format. Must be 'csv' or 'json'" } };
|
|
1072
1220
|
}
|
|
1073
|
-
if (hasLongQueryParam(
|
|
1221
|
+
if (hasLongQueryParam(query)) {
|
|
1074
1222
|
return { status: 400, body: { error: "Query parameter exceeds maximum length" } };
|
|
1075
1223
|
}
|
|
1076
|
-
const parsed = parseConsoleQueryFilters(
|
|
1224
|
+
const parsed = parseConsoleQueryFilters(query);
|
|
1077
1225
|
if ("error" in parsed) {
|
|
1078
1226
|
return { status: 400, body: { error: parsed.error } };
|
|
1079
1227
|
}
|
|
1080
|
-
const
|
|
1081
|
-
const data = await api.exportLogs(parsed.filters,
|
|
1082
|
-
|
|
1228
|
+
const effectiveFormat = format ?? "csv";
|
|
1229
|
+
const data = await api.exportLogs(parsed.filters, effectiveFormat);
|
|
1230
|
+
const contentType = effectiveFormat === "csv" ? "text/csv; charset=utf-8" : "application/json; charset=utf-8";
|
|
1231
|
+
const ext = effectiveFormat === "csv" ? "csv" : "json";
|
|
1232
|
+
const dateStamp = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
1233
|
+
const filename = `audit-export-${dateStamp}.${ext}`;
|
|
1234
|
+
return {
|
|
1235
|
+
status: 200,
|
|
1236
|
+
body: data,
|
|
1237
|
+
headers: {
|
|
1238
|
+
"content-type": contentType,
|
|
1239
|
+
"content-disposition": `attachment; filename="${filename}"`,
|
|
1240
|
+
"cache-control": "no-cache"
|
|
1241
|
+
}
|
|
1242
|
+
};
|
|
1083
1243
|
} catch {
|
|
1084
1244
|
return { status: 500, body: { error: "Internal server error" } };
|
|
1085
1245
|
}
|
|
@@ -1468,6 +1628,139 @@ var AUDIT_LOG_SCHEMA = {
|
|
|
1468
1628
|
}
|
|
1469
1629
|
};
|
|
1470
1630
|
|
|
1631
|
+
// src/escape.ts
|
|
1632
|
+
function escapeLikePattern(input) {
|
|
1633
|
+
return input.replace(/[%_\\]/g, "\\$&");
|
|
1634
|
+
}
|
|
1635
|
+
|
|
1636
|
+
// src/time-filter.ts
|
|
1637
|
+
function resolveTimeFilter(filter) {
|
|
1638
|
+
if ("date" in filter && filter.date !== void 0) {
|
|
1639
|
+
return filter.date;
|
|
1640
|
+
}
|
|
1641
|
+
if ("duration" in filter && filter.duration !== void 0) {
|
|
1642
|
+
return parseDuration(filter.duration);
|
|
1643
|
+
}
|
|
1644
|
+
throw new Error("TimeFilter must have either date or duration");
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1647
|
+
// src/filter-builder.ts
|
|
1648
|
+
function interpretFilters(filters, options) {
|
|
1649
|
+
const conditions = [];
|
|
1650
|
+
if (filters.resource !== void 0) {
|
|
1651
|
+
conditions.push({ kind: "eq", field: "tableName", value: filters.resource.tableName });
|
|
1652
|
+
if (filters.resource.recordId !== void 0) {
|
|
1653
|
+
conditions.push({ kind: "eq", field: "recordId", value: filters.resource.recordId });
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
1656
|
+
pushArrayFilter(conditions, "actorId", filters.actorIds);
|
|
1657
|
+
pushArrayFilter(conditions, "severity", filters.severities);
|
|
1658
|
+
pushArrayFilter(conditions, "operation", filters.operations);
|
|
1659
|
+
if (filters.since !== void 0) {
|
|
1660
|
+
conditions.push({ kind: "timestampGte", value: resolveTimeFilter(filters.since) });
|
|
1661
|
+
}
|
|
1662
|
+
if (filters.until !== void 0) {
|
|
1663
|
+
conditions.push({ kind: "timestampLte", value: resolveTimeFilter(filters.until) });
|
|
1664
|
+
}
|
|
1665
|
+
if (filters.searchText !== void 0 && filters.searchText.length > 0) {
|
|
1666
|
+
const escaped = escapeLikePattern(filters.searchText);
|
|
1667
|
+
conditions.push({ kind: "search", pattern: `%${escaped}%` });
|
|
1668
|
+
}
|
|
1669
|
+
if (filters.compliance !== void 0 && filters.compliance.length > 0) {
|
|
1670
|
+
conditions.push({ kind: "compliance", tags: [...filters.compliance] });
|
|
1671
|
+
}
|
|
1672
|
+
if (options?.cursor !== void 0) {
|
|
1673
|
+
conditions.push({
|
|
1674
|
+
kind: "cursor",
|
|
1675
|
+
timestamp: options.cursor.timestamp,
|
|
1676
|
+
id: options.cursor.id,
|
|
1677
|
+
sortOrder: options.sortOrder ?? "desc"
|
|
1678
|
+
});
|
|
1679
|
+
}
|
|
1680
|
+
return conditions;
|
|
1681
|
+
}
|
|
1682
|
+
function pushArrayFilter(conditions, field, values) {
|
|
1683
|
+
if (values === void 0 || values.length === 0) {
|
|
1684
|
+
return;
|
|
1685
|
+
}
|
|
1686
|
+
if (values.length === 1) {
|
|
1687
|
+
const first = values[0];
|
|
1688
|
+
if (first !== void 0) {
|
|
1689
|
+
conditions.push({ kind: "eq", field, value: first });
|
|
1690
|
+
}
|
|
1691
|
+
} else {
|
|
1692
|
+
conditions.push({ kind: "in", field, values: [...values] });
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1696
|
+
// src/stats.ts
|
|
1697
|
+
function toCount(value) {
|
|
1698
|
+
if (typeof value === "number") {
|
|
1699
|
+
return value;
|
|
1700
|
+
}
|
|
1701
|
+
if (typeof value === "string") {
|
|
1702
|
+
const n = Number(value);
|
|
1703
|
+
return Number.isNaN(n) ? 0 : n;
|
|
1704
|
+
}
|
|
1705
|
+
if (typeof value === "bigint") {
|
|
1706
|
+
return Number(value);
|
|
1707
|
+
}
|
|
1708
|
+
return 0;
|
|
1709
|
+
}
|
|
1710
|
+
function assembleStats(summaryRows, eventsPerDayRows, topActorsRows, topTablesRows, operationRows, severityRows) {
|
|
1711
|
+
const summary = summaryRows[0];
|
|
1712
|
+
const totalLogs = summary !== void 0 ? toCount(summary.totalLogs) : 0;
|
|
1713
|
+
const tablesAudited = summary !== void 0 ? toCount(summary.tablesAudited) : 0;
|
|
1714
|
+
const eventsPerDay = eventsPerDayRows.map((row) => ({
|
|
1715
|
+
date: row.date instanceof Date ? row.date.toISOString().split("T")[0] ?? "" : String(row.date),
|
|
1716
|
+
count: toCount(row.count)
|
|
1717
|
+
}));
|
|
1718
|
+
const topActors = topActorsRows.map((row) => ({
|
|
1719
|
+
actorId: String(row.actorId),
|
|
1720
|
+
count: toCount(row.count)
|
|
1721
|
+
}));
|
|
1722
|
+
const topTables = topTablesRows.map((row) => ({
|
|
1723
|
+
tableName: String(row.tableName),
|
|
1724
|
+
count: toCount(row.count)
|
|
1725
|
+
}));
|
|
1726
|
+
const operationBreakdown = {};
|
|
1727
|
+
for (const row of operationRows) {
|
|
1728
|
+
operationBreakdown[String(row.operation)] = toCount(row.count);
|
|
1729
|
+
}
|
|
1730
|
+
const severityBreakdown = {};
|
|
1731
|
+
for (const row of severityRows) {
|
|
1732
|
+
severityBreakdown[String(row.severity)] = toCount(row.count);
|
|
1733
|
+
}
|
|
1734
|
+
return {
|
|
1735
|
+
totalLogs,
|
|
1736
|
+
tablesAudited,
|
|
1737
|
+
eventsPerDay,
|
|
1738
|
+
topActors,
|
|
1739
|
+
topTables,
|
|
1740
|
+
operationBreakdown,
|
|
1741
|
+
severityBreakdown
|
|
1742
|
+
};
|
|
1743
|
+
}
|
|
1744
|
+
|
|
1745
|
+
// src/validation.ts
|
|
1746
|
+
var VALID_OPERATIONS2 = /* @__PURE__ */ new Set([
|
|
1747
|
+
"INSERT",
|
|
1748
|
+
"UPDATE",
|
|
1749
|
+
"DELETE"
|
|
1750
|
+
]);
|
|
1751
|
+
var VALID_SEVERITIES2 = /* @__PURE__ */ new Set([
|
|
1752
|
+
"low",
|
|
1753
|
+
"medium",
|
|
1754
|
+
"high",
|
|
1755
|
+
"critical"
|
|
1756
|
+
]);
|
|
1757
|
+
function isAuditOperation(value) {
|
|
1758
|
+
return VALID_OPERATIONS2.has(value);
|
|
1759
|
+
}
|
|
1760
|
+
function isAuditSeverity(value) {
|
|
1761
|
+
return VALID_SEVERITIES2.has(value);
|
|
1762
|
+
}
|
|
1763
|
+
|
|
1471
1764
|
// src/context-extractor.ts
|
|
1472
1765
|
function decodeJwtPayload(token) {
|
|
1473
1766
|
try {
|
|
@@ -1545,6 +1838,9 @@ function fromHeader(headerName) {
|
|
|
1545
1838
|
return value.trim();
|
|
1546
1839
|
};
|
|
1547
1840
|
}
|
|
1841
|
+
var defaultExtractor = {
|
|
1842
|
+
actor: fromBearerToken("sub")
|
|
1843
|
+
};
|
|
1548
1844
|
async function safeExtract(extractor, request, onError) {
|
|
1549
1845
|
if (!extractor) {
|
|
1550
1846
|
return void 0;
|
|
@@ -1570,19 +1866,32 @@ async function handleMiddleware(extractor, request, next, options = {}) {
|
|
|
1570
1866
|
export {
|
|
1571
1867
|
AUDIT_LOG_SCHEMA,
|
|
1572
1868
|
AuditQueryBuilder,
|
|
1869
|
+
VALID_OPERATIONS2 as VALID_OPERATIONS,
|
|
1870
|
+
VALID_SEVERITIES2 as VALID_SEVERITIES,
|
|
1871
|
+
assembleStats,
|
|
1573
1872
|
betterAudit,
|
|
1574
1873
|
createAuditApi,
|
|
1575
1874
|
createAuditConsoleEndpoints,
|
|
1576
1875
|
createExportResponse,
|
|
1876
|
+
decodeCursor,
|
|
1877
|
+
defaultExtractor,
|
|
1878
|
+
encodeCursor,
|
|
1879
|
+
escapeLikePattern,
|
|
1577
1880
|
fromBearerToken,
|
|
1578
1881
|
fromCookie,
|
|
1579
1882
|
fromHeader,
|
|
1580
1883
|
getAuditContext,
|
|
1581
1884
|
handleMiddleware,
|
|
1885
|
+
interpretFilters,
|
|
1886
|
+
isAuditOperation,
|
|
1887
|
+
isAuditSeverity,
|
|
1582
1888
|
mergeAuditContext,
|
|
1583
1889
|
normalizeInput,
|
|
1584
1890
|
parseDuration,
|
|
1891
|
+
resolveTimeFilter,
|
|
1585
1892
|
runExport,
|
|
1586
|
-
runWithAuditContext
|
|
1893
|
+
runWithAuditContext,
|
|
1894
|
+
safeExtract,
|
|
1895
|
+
toCount
|
|
1587
1896
|
};
|
|
1588
1897
|
//# sourceMappingURL=index.js.map
|