@geekmidas/audit 10.0.0-alpha.3 → 10.0.0-alpha.30
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/{Auditor-CW2NrfHS.d.mts → Auditor-BBXXCD0v.d.cts} +2 -7
- package/dist/Auditor-BBXXCD0v.d.cts.map +1 -0
- package/dist/{Auditor-DpBHXIJM.d.cts → Auditor-BBXXCD0v.d.mts} +2 -7
- package/dist/Auditor-BBXXCD0v.d.mts.map +1 -0
- package/dist/Auditor.d.cts +1 -1
- package/dist/Auditor.d.mts +1 -1
- package/dist/Auditor.mjs +1 -0
- package/dist/DefaultAuditor.cjs +95 -2
- package/dist/DefaultAuditor.cjs.map +1 -0
- package/dist/DefaultAuditor.d.cts +55 -3
- package/dist/DefaultAuditor.d.cts.map +1 -0
- package/dist/DefaultAuditor.d.mts +55 -3
- package/dist/DefaultAuditor.d.mts.map +1 -0
- package/dist/DefaultAuditor.mjs +94 -2
- package/dist/DefaultAuditor.mjs.map +1 -0
- package/dist/cache.cjs +166 -2
- package/dist/cache.cjs.map +1 -0
- package/dist/cache.d.cts +92 -3
- package/dist/cache.d.cts.map +1 -0
- package/dist/cache.d.mts +92 -3
- package/dist/cache.d.mts.map +1 -0
- package/dist/cache.mjs +165 -2
- package/dist/cache.mjs.map +1 -0
- package/dist/index.cjs +3 -3
- package/dist/index.d.cts +3 -3
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +2 -3
- package/dist/knex.cjs +9 -9
- package/dist/knex.cjs.map +1 -1
- package/dist/knex.d.cts +9 -11
- package/dist/knex.d.cts.map +1 -1
- package/dist/knex.d.mts +9 -11
- package/dist/knex.d.mts.map +1 -1
- package/dist/knex.mjs +7 -7
- package/dist/knex.mjs.map +1 -1
- package/dist/kysely.cjs +9 -9
- package/dist/kysely.cjs.map +1 -1
- package/dist/kysely.d.cts +9 -11
- package/dist/kysely.d.cts.map +1 -1
- package/dist/kysely.d.mts +9 -11
- package/dist/kysely.d.mts.map +1 -1
- package/dist/kysely.mjs +7 -7
- package/dist/kysely.mjs.map +1 -1
- package/dist/memory.cjs +6 -7
- package/dist/memory.cjs.map +1 -1
- package/dist/memory.d.cts +3 -7
- package/dist/memory.d.cts.map +1 -1
- package/dist/memory.d.mts +3 -7
- package/dist/memory.d.mts.map +1 -1
- package/dist/memory.mjs +3 -4
- package/dist/memory.mjs.map +1 -1
- package/dist/storage.d.cts +1 -1
- package/dist/storage.d.mts +1 -1
- package/dist/storage.mjs +1 -0
- package/dist/types.d.cts +1 -1
- package/dist/types.d.mts +1 -1
- package/dist/types.mjs +1 -0
- package/package.json +13 -13
- package/dist/Auditor-CW2NrfHS.d.mts.map +0 -1
- package/dist/Auditor-DpBHXIJM.d.cts.map +0 -1
- package/dist/DefaultAuditor-BAVnNmRh.mjs +0 -96
- package/dist/DefaultAuditor-BAVnNmRh.mjs.map +0 -1
- package/dist/DefaultAuditor-DlJ1ENfx.d.mts +0 -59
- package/dist/DefaultAuditor-DlJ1ENfx.d.mts.map +0 -1
- package/dist/DefaultAuditor-GRFI86N_.d.cts +0 -59
- package/dist/DefaultAuditor-GRFI86N_.d.cts.map +0 -1
- package/dist/DefaultAuditor-JbZ_BQfh.cjs +0 -102
- package/dist/DefaultAuditor-JbZ_BQfh.cjs.map +0 -1
- package/dist/cache-BbIl31RL.mjs +0 -167
- package/dist/cache-BbIl31RL.mjs.map +0 -1
- package/dist/cache-Bih6HxY6.d.cts +0 -96
- package/dist/cache-Bih6HxY6.d.cts.map +0 -1
- package/dist/cache-l7jAptBl.cjs +0 -173
- package/dist/cache-l7jAptBl.cjs.map +0 -1
- package/dist/cache-wET57t6d.d.mts +0 -96
- package/dist/cache-wET57t6d.d.mts.map +0 -1
- package/dist/chunk-CUT6urMc.cjs +0 -30
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { InferStandardSchema } from "@geekmidas/schema";
|
|
2
2
|
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
3
|
-
|
|
4
3
|
//#region src/storage.d.ts
|
|
5
|
-
|
|
6
4
|
/**
|
|
7
5
|
* Minimal interface for transaction-aware audit flushing.
|
|
8
6
|
* Use this when you need to flush audits within a database transaction.
|
|
@@ -188,7 +186,6 @@ interface AuditStorage<TAuditAction extends AuditableAction<string, unknown> = A
|
|
|
188
186
|
flush(trx?: unknown): Promise<void>;
|
|
189
187
|
}, callback: () => Promise<T>, db?: unknown): Promise<T>;
|
|
190
188
|
}
|
|
191
|
-
//# sourceMappingURL=storage.d.ts.map
|
|
192
189
|
//#endregion
|
|
193
190
|
//#region src/types.d.ts
|
|
194
191
|
/**
|
|
@@ -447,8 +444,6 @@ interface Auditor<TAuditAction extends AuditableAction<string, unknown> = Audita
|
|
|
447
444
|
*/
|
|
448
445
|
getTransaction(): TTransaction | undefined;
|
|
449
446
|
}
|
|
450
|
-
//# sourceMappingURL=Auditor.d.ts.map
|
|
451
|
-
|
|
452
447
|
//#endregion
|
|
453
|
-
export {
|
|
454
|
-
//# sourceMappingURL=Auditor-
|
|
448
|
+
export { AuditOptions as a, ExtractAuditPayload as c, ExtractStorageAuditAction as d, MappedAudit as f, TransactionAwareAuditor as h, AuditOperation as i, ExtractAuditType as l, AuditStorage as m, AuditActor as n, AuditRecord as o, AuditQueryOptions as p, AuditMetadata as r, AuditableAction as s, Auditor as t, ExtractAuditorAction as u };
|
|
449
|
+
//# sourceMappingURL=Auditor-BBXXCD0v.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Auditor-BBXXCD0v.d.cts","names":[],"sources":["../src/storage.ts","../src/types.ts","../src/Auditor.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;UAuBiB,wBAAwB;;EAExC,eAAe,KAAK;;EAEpB,MAAM,MAAM,eAAe;;;;;UAMX;;EAEhB;;EAEA,oBAAoB;;EAEpB;;EAEA;;EAEA,OAAO;;EAEP,KAAK;;EAEL;;EAEA;;EAEA;;EAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAgCgB,aAChB,qBAAqB,mCAAmC;;WAM/C,oBAAoB;;;;;;;;EAQ7B,MAAM,SAAS,eAAe,gBAAgB;;;;;;;;EAS9C,OAAO,SAAS,oBAAoB,QAAQ;;;;;;;;EAS5C,OAAO,SAAS,KAAK,yCAAyC;;;;;;;;;;;;;;;;;;;EAoB9D;;;;;;;;;;;;;;;EAgBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwCA,iBAAiB,GAChB;IACC,eAAe;IACf,MAAM,gBAAgB;KAEvB,gBAAgB,QAAQ,IACxB,eACE,QAAQ;;;;;;;;;;;;;;;;;;;KCvLA,gBAAgB,sBAAsB;EACjD,MAAM;EACN,SAAS;;;;;KAME,iBAAiB,UAAU,oCACtC,UAAU,sBAAsB,kBAAkB;;;;KAKvC,oBACX,UAAU,kCACV,cAAc,iBAAiB,MAC5B,UAAU,gBAAgB,aAAa,YAAY;;;;KAK3C;;;;UAKK;;EAEhB;;EAEA;;GAEC;;;;;UAMe;;EAEhB;;EAEA;;EAEA;;EAEA;;EAEA;;GAEC;;;;;UAMe,YAAY;;EAE5B;;EAEA;;EAEA,WAAW;;EAEX;;EAEA,oBAAoB;;EAEpB,YAAY;;EAEZ,YAAY;;EAEZ,UAAU;;EAEV,WAAW;;EAEX,QAAQ;;EAER,WAAW;;;;;UAMK;;EAEhB,oBAAoB;;EAEpB;;EAEA,YAAY;;EAEZ,YAAY;;EAEZ,YAAY;;;;;;UAOI,YAChB,qBAAqB,kCACrB,gBAAgB;;EAGhB,MAAM,iBAAiB;;EAEvB,UACC,UAAU,oBAAoB,aAC1B,oBAAoB,cAAc,iBAAiB;;EAExD,QAAQ,UAAU,oBAAoB;;EAEtC,YACC,UAAU,oBAAoB,sBACjB;;EAEd;;;;;KAMW,qBAAqB,KAAK,UAAU,cAAc,KAAK;;;;KAKvD,0BAA0B,KACrC,UAAU,mBAAmB,KAAK,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;UCrHtB,QAChB,qBAAqB,mCAAmC,kCAIxD;;;;;WAMS,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;EA0BhB,MAAM,cAAc,iBAAiB,eACpC,MAAM,OACN,SAAS,oBAAoB,cAAc,QAC3C,UAAU;;;;;;;;EAUX,OAAO,QAAQ,KAAK;;;;;EAMpB,cAAc;;;;;;;EAQd,MAAM,MAAM,eAAe;;;;;EAM3B;;;;;;;;;;;;;;;;;;;EAoBA,YAAY,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;EA2BtB,eAAe,KAAK;;;;;EAMpB,kBAAkB"}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { InferStandardSchema } from "@geekmidas/schema";
|
|
2
2
|
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
3
|
-
|
|
4
3
|
//#region src/storage.d.ts
|
|
5
|
-
|
|
6
4
|
/**
|
|
7
5
|
* Minimal interface for transaction-aware audit flushing.
|
|
8
6
|
* Use this when you need to flush audits within a database transaction.
|
|
@@ -188,7 +186,6 @@ interface AuditStorage<TAuditAction extends AuditableAction<string, unknown> = A
|
|
|
188
186
|
flush(trx?: unknown): Promise<void>;
|
|
189
187
|
}, callback: () => Promise<T>, db?: unknown): Promise<T>;
|
|
190
188
|
}
|
|
191
|
-
//# sourceMappingURL=storage.d.ts.map
|
|
192
189
|
//#endregion
|
|
193
190
|
//#region src/types.d.ts
|
|
194
191
|
/**
|
|
@@ -447,8 +444,6 @@ interface Auditor<TAuditAction extends AuditableAction<string, unknown> = Audita
|
|
|
447
444
|
*/
|
|
448
445
|
getTransaction(): TTransaction | undefined;
|
|
449
446
|
}
|
|
450
|
-
//# sourceMappingURL=Auditor.d.ts.map
|
|
451
|
-
|
|
452
447
|
//#endregion
|
|
453
|
-
export {
|
|
454
|
-
//# sourceMappingURL=Auditor-
|
|
448
|
+
export { AuditOptions as a, ExtractAuditPayload as c, ExtractStorageAuditAction as d, MappedAudit as f, TransactionAwareAuditor as h, AuditOperation as i, ExtractAuditType as l, AuditStorage as m, AuditActor as n, AuditRecord as o, AuditQueryOptions as p, AuditMetadata as r, AuditableAction as s, Auditor as t, ExtractAuditorAction as u };
|
|
449
|
+
//# sourceMappingURL=Auditor-BBXXCD0v.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Auditor-BBXXCD0v.d.mts","names":[],"sources":["../src/storage.ts","../src/types.ts","../src/Auditor.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;UAuBiB,wBAAwB;;EAExC,eAAe,KAAK;;EAEpB,MAAM,MAAM,eAAe;;;;;UAMX;;EAEhB;;EAEA,oBAAoB;;EAEpB;;EAEA;;EAEA,OAAO;;EAEP,KAAK;;EAEL;;EAEA;;EAEA;;EAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAgCgB,aAChB,qBAAqB,mCAAmC;;WAM/C,oBAAoB;;;;;;;;EAQ7B,MAAM,SAAS,eAAe,gBAAgB;;;;;;;;EAS9C,OAAO,SAAS,oBAAoB,QAAQ;;;;;;;;EAS5C,OAAO,SAAS,KAAK,yCAAyC;;;;;;;;;;;;;;;;;;;EAoB9D;;;;;;;;;;;;;;;EAgBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwCA,iBAAiB,GAChB;IACC,eAAe;IACf,MAAM,gBAAgB;KAEvB,gBAAgB,QAAQ,IACxB,eACE,QAAQ;;;;;;;;;;;;;;;;;;;KCvLA,gBAAgB,sBAAsB;EACjD,MAAM;EACN,SAAS;;;;;KAME,iBAAiB,UAAU,oCACtC,UAAU,sBAAsB,kBAAkB;;;;KAKvC,oBACX,UAAU,kCACV,cAAc,iBAAiB,MAC5B,UAAU,gBAAgB,aAAa,YAAY;;;;KAK3C;;;;UAKK;;EAEhB;;EAEA;;GAEC;;;;;UAMe;;EAEhB;;EAEA;;EAEA;;EAEA;;EAEA;;GAEC;;;;;UAMe,YAAY;;EAE5B;;EAEA;;EAEA,WAAW;;EAEX;;EAEA,oBAAoB;;EAEpB,YAAY;;EAEZ,YAAY;;EAEZ,UAAU;;EAEV,WAAW;;EAEX,QAAQ;;EAER,WAAW;;;;;UAMK;;EAEhB,oBAAoB;;EAEpB;;EAEA,YAAY;;EAEZ,YAAY;;EAEZ,YAAY;;;;;;UAOI,YAChB,qBAAqB,kCACrB,gBAAgB;;EAGhB,MAAM,iBAAiB;;EAEvB,UACC,UAAU,oBAAoB,aAC1B,oBAAoB,cAAc,iBAAiB;;EAExD,QAAQ,UAAU,oBAAoB;;EAEtC,YACC,UAAU,oBAAoB,sBACjB;;EAEd;;;;;KAMW,qBAAqB,KAAK,UAAU,cAAc,KAAK;;;;KAKvD,0BAA0B,KACrC,UAAU,mBAAmB,KAAK,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;UCrHtB,QAChB,qBAAqB,mCAAmC,kCAIxD;;;;;WAMS,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;EA0BhB,MAAM,cAAc,iBAAiB,eACpC,MAAM,OACN,SAAS,oBAAoB,cAAc,QAC3C,UAAU;;;;;;;;EAUX,OAAO,QAAQ,KAAK;;;;;EAMpB,cAAc;;;;;;;EAQd,MAAM,MAAM,eAAe;;;;;EAM3B;;;;;;;;;;;;;;;;;;;EAoBA,YAAY,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;EA2BtB,eAAe,KAAK;;;;;EAMpB,kBAAkB"}
|
package/dist/Auditor.d.cts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Auditor } from "./Auditor-
|
|
1
|
+
import { t as Auditor } from "./Auditor-BBXXCD0v.cjs";
|
|
2
2
|
export { Auditor };
|
package/dist/Auditor.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Auditor } from "./Auditor-
|
|
1
|
+
import { t as Auditor } from "./Auditor-BBXXCD0v.mjs";
|
|
2
2
|
export { Auditor };
|
package/dist/Auditor.mjs
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/DefaultAuditor.cjs
CHANGED
|
@@ -1,3 +1,96 @@
|
|
|
1
|
-
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
let nanoid = require("nanoid");
|
|
3
|
+
//#region src/DefaultAuditor.ts
|
|
4
|
+
/**
|
|
5
|
+
* Default implementation of the Auditor interface.
|
|
6
|
+
* Collects audit records in memory and flushes to storage.
|
|
7
|
+
*
|
|
8
|
+
* @template TAuditAction - Union of all allowed audit action types
|
|
9
|
+
* @template TTransaction - Transaction type (e.g., Kysely Transaction)
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* const auditor = new DefaultAuditor<AppAuditAction>({
|
|
14
|
+
* actor: { id: 'user-123', type: 'user' },
|
|
15
|
+
* storage: auditStorage,
|
|
16
|
+
* metadata: { requestId: 'req-456', endpoint: '/users' },
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* auditor.audit('user.created', { userId: '789', email: 'test@example.com' });
|
|
20
|
+
*
|
|
21
|
+
* // Flush inside transaction
|
|
22
|
+
* await auditor.flush(trx);
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
var DefaultAuditor = class {
|
|
26
|
+
actor;
|
|
27
|
+
storage;
|
|
28
|
+
metadata;
|
|
29
|
+
generateId;
|
|
30
|
+
records = [];
|
|
31
|
+
transaction;
|
|
32
|
+
constructor(config) {
|
|
33
|
+
this.actor = config.actor;
|
|
34
|
+
this.storage = config.storage;
|
|
35
|
+
this.metadata = config.metadata;
|
|
36
|
+
this.generateId = config.generateId ?? (() => (0, nanoid.nanoid)());
|
|
37
|
+
}
|
|
38
|
+
audit(type, payload, options) {
|
|
39
|
+
const record = {
|
|
40
|
+
id: this.generateId(),
|
|
41
|
+
type,
|
|
42
|
+
operation: options?.operation ?? "CUSTOM",
|
|
43
|
+
table: options?.table,
|
|
44
|
+
entityId: options?.entityId,
|
|
45
|
+
oldValues: options?.oldValues,
|
|
46
|
+
newValues: options?.newValues,
|
|
47
|
+
payload,
|
|
48
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
49
|
+
actor: this.actor,
|
|
50
|
+
metadata: this.metadata
|
|
51
|
+
};
|
|
52
|
+
this.records.push(record);
|
|
53
|
+
}
|
|
54
|
+
record(record) {
|
|
55
|
+
const fullRecord = {
|
|
56
|
+
...record,
|
|
57
|
+
id: this.generateId(),
|
|
58
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
59
|
+
actor: this.actor,
|
|
60
|
+
metadata: this.metadata ? {
|
|
61
|
+
...this.metadata,
|
|
62
|
+
...record.metadata
|
|
63
|
+
} : record.metadata
|
|
64
|
+
};
|
|
65
|
+
this.records.push(fullRecord);
|
|
66
|
+
}
|
|
67
|
+
getRecords() {
|
|
68
|
+
return [...this.records];
|
|
69
|
+
}
|
|
70
|
+
async flush(trx) {
|
|
71
|
+
if (this.records.length === 0) return;
|
|
72
|
+
const recordsToFlush = [...this.records];
|
|
73
|
+
this.records = [];
|
|
74
|
+
const transactionToUse = trx ?? this.transaction;
|
|
75
|
+
await this.storage.write(recordsToFlush, transactionToUse);
|
|
76
|
+
}
|
|
77
|
+
setTransaction(trx) {
|
|
78
|
+
this.transaction = trx;
|
|
79
|
+
}
|
|
80
|
+
getTransaction() {
|
|
81
|
+
return this.transaction;
|
|
82
|
+
}
|
|
83
|
+
clear() {
|
|
84
|
+
this.records = [];
|
|
85
|
+
}
|
|
86
|
+
addMetadata(metadata) {
|
|
87
|
+
this.metadata = this.metadata ? {
|
|
88
|
+
...this.metadata,
|
|
89
|
+
...metadata
|
|
90
|
+
} : metadata;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
//#endregion
|
|
94
|
+
exports.DefaultAuditor = DefaultAuditor;
|
|
2
95
|
|
|
3
|
-
|
|
96
|
+
//# sourceMappingURL=DefaultAuditor.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DefaultAuditor.cjs","names":[],"sources":["../src/DefaultAuditor.ts"],"sourcesContent":["import { nanoid } from 'nanoid';\nimport type { Auditor } from './Auditor';\nimport type { AuditStorage } from './storage';\nimport type {\n\tAuditActor,\n\tAuditableAction,\n\tAuditMetadata,\n\tAuditOptions,\n\tAuditRecord,\n\tExtractAuditPayload,\n\tExtractAuditType,\n} from './types';\n\n/**\n * Configuration for DefaultAuditor.\n */\nexport interface DefaultAuditorConfig {\n\t/** The actor performing audits (set at construction, immutable) */\n\tactor: AuditActor;\n\t/** Storage backend for persisting audits */\n\tstorage: AuditStorage;\n\t/** Optional metadata to attach to all audits */\n\tmetadata?: AuditMetadata;\n\t/** Optional custom ID generator (defaults to nanoid) */\n\tgenerateId?: () => string;\n}\n\n/**\n * Default implementation of the Auditor interface.\n * Collects audit records in memory and flushes to storage.\n *\n * @template TAuditAction - Union of all allowed audit action types\n * @template TTransaction - Transaction type (e.g., Kysely Transaction)\n *\n * @example\n * ```typescript\n * const auditor = new DefaultAuditor<AppAuditAction>({\n * actor: { id: 'user-123', type: 'user' },\n * storage: auditStorage,\n * metadata: { requestId: 'req-456', endpoint: '/users' },\n * });\n *\n * auditor.audit('user.created', { userId: '789', email: 'test@example.com' });\n *\n * // Flush inside transaction\n * await auditor.flush(trx);\n * ```\n */\nexport class DefaultAuditor<\n\tTAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n\t\tstring,\n\t\tunknown\n\t>,\n\tTTransaction = unknown,\n> implements Auditor<TAuditAction, TTransaction>\n{\n\treadonly actor: AuditActor;\n\tprivate readonly storage: AuditStorage;\n\tprivate metadata?: AuditMetadata;\n\tprivate readonly generateId: () => string;\n\tprivate records: AuditRecord[] = [];\n\tprivate transaction?: TTransaction;\n\n\tconstructor(config: DefaultAuditorConfig) {\n\t\tthis.actor = config.actor;\n\t\tthis.storage = config.storage;\n\t\tthis.metadata = config.metadata;\n\t\tthis.generateId = config.generateId ?? (() => nanoid());\n\t}\n\n\taudit<TType extends ExtractAuditType<TAuditAction>>(\n\t\ttype: TType,\n\t\tpayload: ExtractAuditPayload<TAuditAction, TType>,\n\t\toptions?: AuditOptions,\n\t): void {\n\t\tconst record: AuditRecord = {\n\t\t\tid: this.generateId(),\n\t\t\ttype,\n\t\t\toperation: options?.operation ?? 'CUSTOM',\n\t\t\ttable: options?.table,\n\t\t\tentityId: options?.entityId,\n\t\t\toldValues: options?.oldValues,\n\t\t\tnewValues: options?.newValues,\n\t\t\tpayload,\n\t\t\ttimestamp: new Date(),\n\t\t\tactor: this.actor,\n\t\t\tmetadata: this.metadata,\n\t\t};\n\n\t\tthis.records.push(record);\n\t}\n\n\trecord(record: Omit<AuditRecord, 'id' | 'timestamp' | 'actor'>): void {\n\t\tconst fullRecord: AuditRecord = {\n\t\t\t...record,\n\t\t\tid: this.generateId(),\n\t\t\ttimestamp: new Date(),\n\t\t\tactor: this.actor,\n\t\t\tmetadata: this.metadata\n\t\t\t\t? { ...this.metadata, ...record.metadata }\n\t\t\t\t: record.metadata,\n\t\t};\n\n\t\tthis.records.push(fullRecord);\n\t}\n\n\tgetRecords(): AuditRecord[] {\n\t\treturn [...this.records];\n\t}\n\n\tasync flush(trx?: TTransaction): Promise<void> {\n\t\tif (this.records.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst recordsToFlush = [...this.records];\n\t\tthis.records = [];\n\n\t\t// Use explicitly passed transaction, or fall back to stored transaction\n\t\tconst transactionToUse = trx ?? this.transaction;\n\t\tawait this.storage.write(recordsToFlush, transactionToUse);\n\t}\n\n\tsetTransaction(trx: TTransaction): void {\n\t\tthis.transaction = trx;\n\t}\n\n\tgetTransaction(): TTransaction | undefined {\n\t\treturn this.transaction;\n\t}\n\n\tclear(): void {\n\t\tthis.records = [];\n\t}\n\n\taddMetadata(metadata: AuditMetadata): void {\n\t\tthis.metadata = this.metadata\n\t\t\t? { ...this.metadata, ...metadata }\n\t\t\t: metadata;\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAgDA,IAAa,iBAAb,MAOA;CACC;CACA;CACA;CACA;CACA,UAAiC,CAAC;CAClC;CAEA,YAAY,QAA8B;EACzC,KAAK,QAAQ,OAAO;EACpB,KAAK,UAAU,OAAO;EACtB,KAAK,WAAW,OAAO;EACvB,KAAK,aAAa,OAAO,sBAAA,GAAqB,OAAA,OAAA,CAAO;CACtD;CAEA,MACC,MACA,SACA,SACO;EACP,MAAM,SAAsB;GAC3B,IAAI,KAAK,WAAW;GACpB;GACA,WAAW,SAAS,aAAa;GACjC,OAAO,SAAS;GAChB,UAAU,SAAS;GACnB,WAAW,SAAS;GACpB,WAAW,SAAS;GACpB;GACA,2BAAW,IAAI,KAAK;GACpB,OAAO,KAAK;GACZ,UAAU,KAAK;EAChB;EAEA,KAAK,QAAQ,KAAK,MAAM;CACzB;CAEA,OAAO,QAA+D;EACrE,MAAM,aAA0B;GAC/B,GAAG;GACH,IAAI,KAAK,WAAW;GACpB,2BAAW,IAAI,KAAK;GACpB,OAAO,KAAK;GACZ,UAAU,KAAK,WACZ;IAAE,GAAG,KAAK;IAAU,GAAG,OAAO;GAAS,IACvC,OAAO;EACX;EAEA,KAAK,QAAQ,KAAK,UAAU;CAC7B;CAEA,aAA4B;EAC3B,OAAO,CAAC,GAAG,KAAK,OAAO;CACxB;CAEA,MAAM,MAAM,KAAmC;EAC9C,IAAI,KAAK,QAAQ,WAAW,GAC3B;EAGD,MAAM,iBAAiB,CAAC,GAAG,KAAK,OAAO;EACvC,KAAK,UAAU,CAAC;EAGhB,MAAM,mBAAmB,OAAO,KAAK;EACrC,MAAM,KAAK,QAAQ,MAAM,gBAAgB,gBAAgB;CAC1D;CAEA,eAAe,KAAyB;EACvC,KAAK,cAAc;CACpB;CAEA,iBAA2C;EAC1C,OAAO,KAAK;CACb;CAEA,QAAc;EACb,KAAK,UAAU,CAAC;CACjB;CAEA,YAAY,UAA+B;EAC1C,KAAK,WAAW,KAAK,WAClB;GAAE,GAAG,KAAK;GAAU,GAAG;EAAS,IAChC;CACJ;AACD"}
|
|
@@ -1,3 +1,55 @@
|
|
|
1
|
-
import "./Auditor-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { a as AuditOptions, c as ExtractAuditPayload, l as ExtractAuditType, m as AuditStorage, n as AuditActor, o as AuditRecord, r as AuditMetadata, s as AuditableAction, t as Auditor } from "./Auditor-BBXXCD0v.cjs";
|
|
2
|
+
//#region src/DefaultAuditor.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Configuration for DefaultAuditor.
|
|
5
|
+
*/
|
|
6
|
+
export interface DefaultAuditorConfig {
|
|
7
|
+
/** The actor performing audits (set at construction, immutable) */
|
|
8
|
+
actor: AuditActor;
|
|
9
|
+
/** Storage backend for persisting audits */
|
|
10
|
+
storage: AuditStorage;
|
|
11
|
+
/** Optional metadata to attach to all audits */
|
|
12
|
+
metadata?: AuditMetadata;
|
|
13
|
+
/** Optional custom ID generator (defaults to nanoid) */
|
|
14
|
+
generateId?: () => string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Default implementation of the Auditor interface.
|
|
18
|
+
* Collects audit records in memory and flushes to storage.
|
|
19
|
+
*
|
|
20
|
+
* @template TAuditAction - Union of all allowed audit action types
|
|
21
|
+
* @template TTransaction - Transaction type (e.g., Kysely Transaction)
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* const auditor = new DefaultAuditor<AppAuditAction>({
|
|
26
|
+
* actor: { id: 'user-123', type: 'user' },
|
|
27
|
+
* storage: auditStorage,
|
|
28
|
+
* metadata: { requestId: 'req-456', endpoint: '/users' },
|
|
29
|
+
* });
|
|
30
|
+
*
|
|
31
|
+
* auditor.audit('user.created', { userId: '789', email: 'test@example.com' });
|
|
32
|
+
*
|
|
33
|
+
* // Flush inside transaction
|
|
34
|
+
* await auditor.flush(trx);
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export declare class DefaultAuditor<TAuditAction extends AuditableAction<string, unknown> = AuditableAction<string, unknown>, TTransaction = unknown> implements Auditor<TAuditAction, TTransaction> {
|
|
38
|
+
readonly actor: AuditActor;
|
|
39
|
+
private readonly storage;
|
|
40
|
+
private metadata?;
|
|
41
|
+
private readonly generateId;
|
|
42
|
+
private records;
|
|
43
|
+
private transaction?;
|
|
44
|
+
constructor(config: DefaultAuditorConfig);
|
|
45
|
+
audit<TType extends ExtractAuditType<TAuditAction>>(type: TType, payload: ExtractAuditPayload<TAuditAction, TType>, options?: AuditOptions): void;
|
|
46
|
+
record(record: Omit<AuditRecord, 'id' | 'timestamp' | 'actor'>): void;
|
|
47
|
+
getRecords(): AuditRecord[];
|
|
48
|
+
flush(trx?: TTransaction): Promise<void>;
|
|
49
|
+
setTransaction(trx: TTransaction): void;
|
|
50
|
+
getTransaction(): TTransaction | undefined;
|
|
51
|
+
clear(): void;
|
|
52
|
+
addMetadata(metadata: AuditMetadata): void;
|
|
53
|
+
}
|
|
54
|
+
//#endregion
|
|
55
|
+
//# sourceMappingURL=DefaultAuditor.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DefaultAuditor.d.cts","names":[],"sources":["../src/DefaultAuditor.ts"],"mappings":";;;;;iBAgBiB;;EAEhB,OAAO;;EAEP,SAAS;;EAET,WAAW;;EAEX;;;;;;;;;;;;;;;;;;;;;;;qBAwBY,eACZ,qBAAqB,mCAAmC,kCAIxD,mCACY,QAAQ,cAAc;WAEzB,OAAO;mBACC;UACT;mBACS;UACT;UACA;EAER,YAAY,QAAQ;EAOpB,MAAM,cAAc,iBAAiB,eACpC,MAAM,OACN,SAAS,oBAAoB,cAAc,QAC3C,UAAU;EAmBX,OAAO,QAAQ,KAAK;EAcpB,cAAc;EAIR,MAAM,MAAM,eAAe;EAajC,eAAe,KAAK;EAIpB,kBAAkB;EAIlB;EAIA,YAAY,UAAU"}
|
|
@@ -1,3 +1,55 @@
|
|
|
1
|
-
import "./Auditor-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { a as AuditOptions, c as ExtractAuditPayload, l as ExtractAuditType, m as AuditStorage, n as AuditActor, o as AuditRecord, r as AuditMetadata, s as AuditableAction, t as Auditor } from "./Auditor-BBXXCD0v.mjs";
|
|
2
|
+
//#region src/DefaultAuditor.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Configuration for DefaultAuditor.
|
|
5
|
+
*/
|
|
6
|
+
export interface DefaultAuditorConfig {
|
|
7
|
+
/** The actor performing audits (set at construction, immutable) */
|
|
8
|
+
actor: AuditActor;
|
|
9
|
+
/** Storage backend for persisting audits */
|
|
10
|
+
storage: AuditStorage;
|
|
11
|
+
/** Optional metadata to attach to all audits */
|
|
12
|
+
metadata?: AuditMetadata;
|
|
13
|
+
/** Optional custom ID generator (defaults to nanoid) */
|
|
14
|
+
generateId?: () => string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Default implementation of the Auditor interface.
|
|
18
|
+
* Collects audit records in memory and flushes to storage.
|
|
19
|
+
*
|
|
20
|
+
* @template TAuditAction - Union of all allowed audit action types
|
|
21
|
+
* @template TTransaction - Transaction type (e.g., Kysely Transaction)
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* const auditor = new DefaultAuditor<AppAuditAction>({
|
|
26
|
+
* actor: { id: 'user-123', type: 'user' },
|
|
27
|
+
* storage: auditStorage,
|
|
28
|
+
* metadata: { requestId: 'req-456', endpoint: '/users' },
|
|
29
|
+
* });
|
|
30
|
+
*
|
|
31
|
+
* auditor.audit('user.created', { userId: '789', email: 'test@example.com' });
|
|
32
|
+
*
|
|
33
|
+
* // Flush inside transaction
|
|
34
|
+
* await auditor.flush(trx);
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export declare class DefaultAuditor<TAuditAction extends AuditableAction<string, unknown> = AuditableAction<string, unknown>, TTransaction = unknown> implements Auditor<TAuditAction, TTransaction> {
|
|
38
|
+
readonly actor: AuditActor;
|
|
39
|
+
private readonly storage;
|
|
40
|
+
private metadata?;
|
|
41
|
+
private readonly generateId;
|
|
42
|
+
private records;
|
|
43
|
+
private transaction?;
|
|
44
|
+
constructor(config: DefaultAuditorConfig);
|
|
45
|
+
audit<TType extends ExtractAuditType<TAuditAction>>(type: TType, payload: ExtractAuditPayload<TAuditAction, TType>, options?: AuditOptions): void;
|
|
46
|
+
record(record: Omit<AuditRecord, 'id' | 'timestamp' | 'actor'>): void;
|
|
47
|
+
getRecords(): AuditRecord[];
|
|
48
|
+
flush(trx?: TTransaction): Promise<void>;
|
|
49
|
+
setTransaction(trx: TTransaction): void;
|
|
50
|
+
getTransaction(): TTransaction | undefined;
|
|
51
|
+
clear(): void;
|
|
52
|
+
addMetadata(metadata: AuditMetadata): void;
|
|
53
|
+
}
|
|
54
|
+
//#endregion
|
|
55
|
+
//# sourceMappingURL=DefaultAuditor.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DefaultAuditor.d.mts","names":[],"sources":["../src/DefaultAuditor.ts"],"mappings":";;;;;iBAgBiB;;EAEhB,OAAO;;EAEP,SAAS;;EAET,WAAW;;EAEX;;;;;;;;;;;;;;;;;;;;;;;qBAwBY,eACZ,qBAAqB,mCAAmC,kCAIxD,mCACY,QAAQ,cAAc;WAEzB,OAAO;mBACC;UACT;mBACS;UACT;UACA;EAER,YAAY,QAAQ;EAOpB,MAAM,cAAc,iBAAiB,eACpC,MAAM,OACN,SAAS,oBAAoB,cAAc,QAC3C,UAAU;EAmBX,OAAO,QAAQ,KAAK;EAcpB,cAAc;EAIR,MAAM,MAAM,eAAe;EAajC,eAAe,KAAK;EAIpB,kBAAkB;EAIlB;EAIA,YAAY,UAAU"}
|
package/dist/DefaultAuditor.mjs
CHANGED
|
@@ -1,3 +1,95 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { nanoid } from "nanoid";
|
|
2
|
+
//#region src/DefaultAuditor.ts
|
|
3
|
+
/**
|
|
4
|
+
* Default implementation of the Auditor interface.
|
|
5
|
+
* Collects audit records in memory and flushes to storage.
|
|
6
|
+
*
|
|
7
|
+
* @template TAuditAction - Union of all allowed audit action types
|
|
8
|
+
* @template TTransaction - Transaction type (e.g., Kysely Transaction)
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* const auditor = new DefaultAuditor<AppAuditAction>({
|
|
13
|
+
* actor: { id: 'user-123', type: 'user' },
|
|
14
|
+
* storage: auditStorage,
|
|
15
|
+
* metadata: { requestId: 'req-456', endpoint: '/users' },
|
|
16
|
+
* });
|
|
17
|
+
*
|
|
18
|
+
* auditor.audit('user.created', { userId: '789', email: 'test@example.com' });
|
|
19
|
+
*
|
|
20
|
+
* // Flush inside transaction
|
|
21
|
+
* await auditor.flush(trx);
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
var DefaultAuditor = class {
|
|
25
|
+
actor;
|
|
26
|
+
storage;
|
|
27
|
+
metadata;
|
|
28
|
+
generateId;
|
|
29
|
+
records = [];
|
|
30
|
+
transaction;
|
|
31
|
+
constructor(config) {
|
|
32
|
+
this.actor = config.actor;
|
|
33
|
+
this.storage = config.storage;
|
|
34
|
+
this.metadata = config.metadata;
|
|
35
|
+
this.generateId = config.generateId ?? (() => nanoid());
|
|
36
|
+
}
|
|
37
|
+
audit(type, payload, options) {
|
|
38
|
+
const record = {
|
|
39
|
+
id: this.generateId(),
|
|
40
|
+
type,
|
|
41
|
+
operation: options?.operation ?? "CUSTOM",
|
|
42
|
+
table: options?.table,
|
|
43
|
+
entityId: options?.entityId,
|
|
44
|
+
oldValues: options?.oldValues,
|
|
45
|
+
newValues: options?.newValues,
|
|
46
|
+
payload,
|
|
47
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
48
|
+
actor: this.actor,
|
|
49
|
+
metadata: this.metadata
|
|
50
|
+
};
|
|
51
|
+
this.records.push(record);
|
|
52
|
+
}
|
|
53
|
+
record(record) {
|
|
54
|
+
const fullRecord = {
|
|
55
|
+
...record,
|
|
56
|
+
id: this.generateId(),
|
|
57
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
58
|
+
actor: this.actor,
|
|
59
|
+
metadata: this.metadata ? {
|
|
60
|
+
...this.metadata,
|
|
61
|
+
...record.metadata
|
|
62
|
+
} : record.metadata
|
|
63
|
+
};
|
|
64
|
+
this.records.push(fullRecord);
|
|
65
|
+
}
|
|
66
|
+
getRecords() {
|
|
67
|
+
return [...this.records];
|
|
68
|
+
}
|
|
69
|
+
async flush(trx) {
|
|
70
|
+
if (this.records.length === 0) return;
|
|
71
|
+
const recordsToFlush = [...this.records];
|
|
72
|
+
this.records = [];
|
|
73
|
+
const transactionToUse = trx ?? this.transaction;
|
|
74
|
+
await this.storage.write(recordsToFlush, transactionToUse);
|
|
75
|
+
}
|
|
76
|
+
setTransaction(trx) {
|
|
77
|
+
this.transaction = trx;
|
|
78
|
+
}
|
|
79
|
+
getTransaction() {
|
|
80
|
+
return this.transaction;
|
|
81
|
+
}
|
|
82
|
+
clear() {
|
|
83
|
+
this.records = [];
|
|
84
|
+
}
|
|
85
|
+
addMetadata(metadata) {
|
|
86
|
+
this.metadata = this.metadata ? {
|
|
87
|
+
...this.metadata,
|
|
88
|
+
...metadata
|
|
89
|
+
} : metadata;
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
//#endregion
|
|
93
|
+
export { DefaultAuditor };
|
|
2
94
|
|
|
3
|
-
|
|
95
|
+
//# sourceMappingURL=DefaultAuditor.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DefaultAuditor.mjs","names":[],"sources":["../src/DefaultAuditor.ts"],"sourcesContent":["import { nanoid } from 'nanoid';\nimport type { Auditor } from './Auditor';\nimport type { AuditStorage } from './storage';\nimport type {\n\tAuditActor,\n\tAuditableAction,\n\tAuditMetadata,\n\tAuditOptions,\n\tAuditRecord,\n\tExtractAuditPayload,\n\tExtractAuditType,\n} from './types';\n\n/**\n * Configuration for DefaultAuditor.\n */\nexport interface DefaultAuditorConfig {\n\t/** The actor performing audits (set at construction, immutable) */\n\tactor: AuditActor;\n\t/** Storage backend for persisting audits */\n\tstorage: AuditStorage;\n\t/** Optional metadata to attach to all audits */\n\tmetadata?: AuditMetadata;\n\t/** Optional custom ID generator (defaults to nanoid) */\n\tgenerateId?: () => string;\n}\n\n/**\n * Default implementation of the Auditor interface.\n * Collects audit records in memory and flushes to storage.\n *\n * @template TAuditAction - Union of all allowed audit action types\n * @template TTransaction - Transaction type (e.g., Kysely Transaction)\n *\n * @example\n * ```typescript\n * const auditor = new DefaultAuditor<AppAuditAction>({\n * actor: { id: 'user-123', type: 'user' },\n * storage: auditStorage,\n * metadata: { requestId: 'req-456', endpoint: '/users' },\n * });\n *\n * auditor.audit('user.created', { userId: '789', email: 'test@example.com' });\n *\n * // Flush inside transaction\n * await auditor.flush(trx);\n * ```\n */\nexport class DefaultAuditor<\n\tTAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n\t\tstring,\n\t\tunknown\n\t>,\n\tTTransaction = unknown,\n> implements Auditor<TAuditAction, TTransaction>\n{\n\treadonly actor: AuditActor;\n\tprivate readonly storage: AuditStorage;\n\tprivate metadata?: AuditMetadata;\n\tprivate readonly generateId: () => string;\n\tprivate records: AuditRecord[] = [];\n\tprivate transaction?: TTransaction;\n\n\tconstructor(config: DefaultAuditorConfig) {\n\t\tthis.actor = config.actor;\n\t\tthis.storage = config.storage;\n\t\tthis.metadata = config.metadata;\n\t\tthis.generateId = config.generateId ?? (() => nanoid());\n\t}\n\n\taudit<TType extends ExtractAuditType<TAuditAction>>(\n\t\ttype: TType,\n\t\tpayload: ExtractAuditPayload<TAuditAction, TType>,\n\t\toptions?: AuditOptions,\n\t): void {\n\t\tconst record: AuditRecord = {\n\t\t\tid: this.generateId(),\n\t\t\ttype,\n\t\t\toperation: options?.operation ?? 'CUSTOM',\n\t\t\ttable: options?.table,\n\t\t\tentityId: options?.entityId,\n\t\t\toldValues: options?.oldValues,\n\t\t\tnewValues: options?.newValues,\n\t\t\tpayload,\n\t\t\ttimestamp: new Date(),\n\t\t\tactor: this.actor,\n\t\t\tmetadata: this.metadata,\n\t\t};\n\n\t\tthis.records.push(record);\n\t}\n\n\trecord(record: Omit<AuditRecord, 'id' | 'timestamp' | 'actor'>): void {\n\t\tconst fullRecord: AuditRecord = {\n\t\t\t...record,\n\t\t\tid: this.generateId(),\n\t\t\ttimestamp: new Date(),\n\t\t\tactor: this.actor,\n\t\t\tmetadata: this.metadata\n\t\t\t\t? { ...this.metadata, ...record.metadata }\n\t\t\t\t: record.metadata,\n\t\t};\n\n\t\tthis.records.push(fullRecord);\n\t}\n\n\tgetRecords(): AuditRecord[] {\n\t\treturn [...this.records];\n\t}\n\n\tasync flush(trx?: TTransaction): Promise<void> {\n\t\tif (this.records.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst recordsToFlush = [...this.records];\n\t\tthis.records = [];\n\n\t\t// Use explicitly passed transaction, or fall back to stored transaction\n\t\tconst transactionToUse = trx ?? this.transaction;\n\t\tawait this.storage.write(recordsToFlush, transactionToUse);\n\t}\n\n\tsetTransaction(trx: TTransaction): void {\n\t\tthis.transaction = trx;\n\t}\n\n\tgetTransaction(): TTransaction | undefined {\n\t\treturn this.transaction;\n\t}\n\n\tclear(): void {\n\t\tthis.records = [];\n\t}\n\n\taddMetadata(metadata: AuditMetadata): void {\n\t\tthis.metadata = this.metadata\n\t\t\t? { ...this.metadata, ...metadata }\n\t\t\t: metadata;\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAgDA,IAAa,iBAAb,MAOA;CACC;CACA;CACA;CACA;CACA,UAAiC,CAAC;CAClC;CAEA,YAAY,QAA8B;EACzC,KAAK,QAAQ,OAAO;EACpB,KAAK,UAAU,OAAO;EACtB,KAAK,WAAW,OAAO;EACvB,KAAK,aAAa,OAAO,qBAAqB,OAAO;CACtD;CAEA,MACC,MACA,SACA,SACO;EACP,MAAM,SAAsB;GAC3B,IAAI,KAAK,WAAW;GACpB;GACA,WAAW,SAAS,aAAa;GACjC,OAAO,SAAS;GAChB,UAAU,SAAS;GACnB,WAAW,SAAS;GACpB,WAAW,SAAS;GACpB;GACA,2BAAW,IAAI,KAAK;GACpB,OAAO,KAAK;GACZ,UAAU,KAAK;EAChB;EAEA,KAAK,QAAQ,KAAK,MAAM;CACzB;CAEA,OAAO,QAA+D;EACrE,MAAM,aAA0B;GAC/B,GAAG;GACH,IAAI,KAAK,WAAW;GACpB,2BAAW,IAAI,KAAK;GACpB,OAAO,KAAK;GACZ,UAAU,KAAK,WACZ;IAAE,GAAG,KAAK;IAAU,GAAG,OAAO;GAAS,IACvC,OAAO;EACX;EAEA,KAAK,QAAQ,KAAK,UAAU;CAC7B;CAEA,aAA4B;EAC3B,OAAO,CAAC,GAAG,KAAK,OAAO;CACxB;CAEA,MAAM,MAAM,KAAmC;EAC9C,IAAI,KAAK,QAAQ,WAAW,GAC3B;EAGD,MAAM,iBAAiB,CAAC,GAAG,KAAK,OAAO;EACvC,KAAK,UAAU,CAAC;EAGhB,MAAM,mBAAmB,OAAO,KAAK;EACrC,MAAM,KAAK,QAAQ,MAAM,gBAAgB,gBAAgB;CAC1D;CAEA,eAAe,KAAyB;EACvC,KAAK,cAAc;CACpB;CAEA,iBAA2C;EAC1C,OAAO,KAAK;CACb;CAEA,QAAc;EACb,KAAK,UAAU,CAAC;CACjB;CAEA,YAAY,UAA+B;EAC1C,KAAK,WAAW,KAAK,WAClB;GAAE,GAAG,KAAK;GAAU,GAAG;EAAS,IAChC;CACJ;AACD"}
|
package/dist/cache.cjs
CHANGED
|
@@ -1,3 +1,167 @@
|
|
|
1
|
-
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region src/cache.ts
|
|
3
|
+
/**
|
|
4
|
+
* Cache-based audit storage implementation.
|
|
5
|
+
* Uses any @geekmidas/cache implementation for storage.
|
|
6
|
+
*
|
|
7
|
+
* Best suited for:
|
|
8
|
+
* - Development and testing
|
|
9
|
+
* - Temporary audit logs that don't need persistence
|
|
10
|
+
* - Applications with existing cache infrastructure
|
|
11
|
+
* - Distributed systems needing shared audit state (with Redis/Upstash)
|
|
12
|
+
*
|
|
13
|
+
* Note: Query performance may degrade with large numbers of records
|
|
14
|
+
* since filtering happens in memory after fetching all records.
|
|
15
|
+
*
|
|
16
|
+
* @template TAuditAction - Optional type parameter for type-safe audit actions.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* import { CacheAuditStorage } from '@geekmidas/audit/cache';
|
|
21
|
+
* import { InMemoryCache } from '@geekmidas/cache/memory';
|
|
22
|
+
* import { UpstashCache } from '@geekmidas/cache/upstash';
|
|
23
|
+
*
|
|
24
|
+
* // With in-memory cache (development/testing)
|
|
25
|
+
* const storage = new CacheAuditStorage({
|
|
26
|
+
* cache: new InMemoryCache(),
|
|
27
|
+
* ttl: 86400, // 24 hours
|
|
28
|
+
* });
|
|
29
|
+
*
|
|
30
|
+
* // With Upstash Redis (production)
|
|
31
|
+
* const storage = new CacheAuditStorage({
|
|
32
|
+
* cache: new UpstashCache({
|
|
33
|
+
* url: process.env.UPSTASH_REDIS_URL,
|
|
34
|
+
* token: process.env.UPSTASH_REDIS_TOKEN,
|
|
35
|
+
* }),
|
|
36
|
+
* ttl: 604800, // 7 days
|
|
37
|
+
* });
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
var CacheAuditStorage = class {
|
|
41
|
+
cache;
|
|
42
|
+
prefix;
|
|
43
|
+
ttl;
|
|
44
|
+
indexKey;
|
|
45
|
+
constructor(config) {
|
|
46
|
+
this.cache = config.cache;
|
|
47
|
+
this.prefix = config.prefix ?? "audit";
|
|
48
|
+
this.ttl = config.ttl;
|
|
49
|
+
this.indexKey = `${this.prefix}:__index__`;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Write audit records to cache.
|
|
53
|
+
*/
|
|
54
|
+
async write(records) {
|
|
55
|
+
if (records.length === 0) return;
|
|
56
|
+
const existingIds = await this.cache.get(this.indexKey) ?? [];
|
|
57
|
+
const newIds = [];
|
|
58
|
+
for (const record of records) {
|
|
59
|
+
const key = this.getRecordKey(record.id);
|
|
60
|
+
const serialized = this.serializeRecord(record);
|
|
61
|
+
await this.cache.set(key, serialized, this.ttl);
|
|
62
|
+
newIds.push(record.id);
|
|
63
|
+
}
|
|
64
|
+
const updatedIds = [...existingIds, ...newIds];
|
|
65
|
+
await this.cache.set(this.indexKey, updatedIds, this.ttl);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Query audit records from cache.
|
|
69
|
+
*/
|
|
70
|
+
async query(options) {
|
|
71
|
+
const allRecords = await this.getAllRecords();
|
|
72
|
+
let results = this.applyFilters(allRecords, options);
|
|
73
|
+
const orderBy = options.orderBy ?? "timestamp";
|
|
74
|
+
const orderDirection = options.orderDirection ?? "desc";
|
|
75
|
+
results.sort((a, b) => {
|
|
76
|
+
const aValue = orderBy === "timestamp" ? a.timestamp.getTime() : a.type;
|
|
77
|
+
const bValue = orderBy === "timestamp" ? b.timestamp.getTime() : b.type;
|
|
78
|
+
if (aValue < bValue) return orderDirection === "asc" ? -1 : 1;
|
|
79
|
+
if (aValue > bValue) return orderDirection === "asc" ? 1 : -1;
|
|
80
|
+
return 0;
|
|
81
|
+
});
|
|
82
|
+
if (options.offset !== void 0) results = results.slice(options.offset);
|
|
83
|
+
if (options.limit !== void 0) results = results.slice(0, options.limit);
|
|
84
|
+
return results;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Count audit records matching filters.
|
|
88
|
+
*/
|
|
89
|
+
async count(options) {
|
|
90
|
+
const allRecords = await this.getAllRecords();
|
|
91
|
+
return this.applyFilters(allRecords, options).length;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Get all stored records (for testing/debugging).
|
|
95
|
+
*/
|
|
96
|
+
async getRecords() {
|
|
97
|
+
return this.getAllRecords();
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Clear all stored records.
|
|
101
|
+
*/
|
|
102
|
+
async clear() {
|
|
103
|
+
const ids = await this.cache.get(this.indexKey) ?? [];
|
|
104
|
+
for (const id of ids) await this.cache.delete(this.getRecordKey(id));
|
|
105
|
+
await this.cache.delete(this.indexKey);
|
|
106
|
+
}
|
|
107
|
+
getRecordKey(id) {
|
|
108
|
+
return `${this.prefix}:${id}`;
|
|
109
|
+
}
|
|
110
|
+
async getAllRecords() {
|
|
111
|
+
const ids = await this.cache.get(this.indexKey) ?? [];
|
|
112
|
+
const records = [];
|
|
113
|
+
const validIds = [];
|
|
114
|
+
for (const id of ids) {
|
|
115
|
+
const key = this.getRecordKey(id);
|
|
116
|
+
const serialized = await this.cache.get(key);
|
|
117
|
+
if (serialized) {
|
|
118
|
+
records.push(this.deserializeRecord(serialized));
|
|
119
|
+
validIds.push(id);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (validIds.length !== ids.length) await this.cache.set(this.indexKey, validIds, this.ttl);
|
|
123
|
+
return records;
|
|
124
|
+
}
|
|
125
|
+
serializeRecord(record) {
|
|
126
|
+
return {
|
|
127
|
+
...record,
|
|
128
|
+
timestamp: record.timestamp.toISOString()
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
deserializeRecord(serialized) {
|
|
132
|
+
return {
|
|
133
|
+
...serialized,
|
|
134
|
+
timestamp: new Date(serialized.timestamp)
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
applyFilters(records, options) {
|
|
138
|
+
return records.filter((record) => {
|
|
139
|
+
if (options.type !== void 0) {
|
|
140
|
+
if (Array.isArray(options.type)) {
|
|
141
|
+
if (!options.type.includes(record.type)) return false;
|
|
142
|
+
} else if (record.type !== options.type) return false;
|
|
143
|
+
}
|
|
144
|
+
if (options.entityId !== void 0) {
|
|
145
|
+
const entityId = typeof options.entityId === "string" ? options.entityId : JSON.stringify(options.entityId);
|
|
146
|
+
if ((typeof record.entityId === "string" ? record.entityId : JSON.stringify(record.entityId)) !== entityId) return false;
|
|
147
|
+
}
|
|
148
|
+
if (options.table !== void 0) {
|
|
149
|
+
if (record.table !== options.table) return false;
|
|
150
|
+
}
|
|
151
|
+
if (options.actorId !== void 0) {
|
|
152
|
+
if (record.actor?.id !== options.actorId) return false;
|
|
153
|
+
}
|
|
154
|
+
if (options.from !== void 0) {
|
|
155
|
+
if (record.timestamp < options.from) return false;
|
|
156
|
+
}
|
|
157
|
+
if (options.to !== void 0) {
|
|
158
|
+
if (record.timestamp > options.to) return false;
|
|
159
|
+
}
|
|
160
|
+
return true;
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
//#endregion
|
|
165
|
+
exports.CacheAuditStorage = CacheAuditStorage;
|
|
2
166
|
|
|
3
|
-
|
|
167
|
+
//# sourceMappingURL=cache.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.cjs","names":[],"sources":["../src/cache.ts"],"sourcesContent":["import type { Cache } from '@geekmidas/cache';\nimport type { AuditQueryOptions, AuditStorage } from './storage';\nimport type { AuditableAction, AuditRecord } from './types';\n\n/**\n * Configuration for CacheAuditStorage.\n */\nexport interface CacheAuditStorageConfig {\n\t/** Cache instance to use for storage */\n\tcache: Cache;\n\t/**\n\t * Key prefix for audit records.\n\t * Records are stored as `${prefix}:${id}`.\n\t * @default 'audit'\n\t */\n\tprefix?: string;\n\t/**\n\t * TTL (time-to-live) in seconds for audit records.\n\t * If not set, records use the cache's default TTL.\n\t */\n\tttl?: number;\n}\n\n/**\n * Cache-based audit storage implementation.\n * Uses any @geekmidas/cache implementation for storage.\n *\n * Best suited for:\n * - Development and testing\n * - Temporary audit logs that don't need persistence\n * - Applications with existing cache infrastructure\n * - Distributed systems needing shared audit state (with Redis/Upstash)\n *\n * Note: Query performance may degrade with large numbers of records\n * since filtering happens in memory after fetching all records.\n *\n * @template TAuditAction - Optional type parameter for type-safe audit actions.\n *\n * @example\n * ```typescript\n * import { CacheAuditStorage } from '@geekmidas/audit/cache';\n * import { InMemoryCache } from '@geekmidas/cache/memory';\n * import { UpstashCache } from '@geekmidas/cache/upstash';\n *\n * // With in-memory cache (development/testing)\n * const storage = new CacheAuditStorage({\n * cache: new InMemoryCache(),\n * ttl: 86400, // 24 hours\n * });\n *\n * // With Upstash Redis (production)\n * const storage = new CacheAuditStorage({\n * cache: new UpstashCache({\n * url: process.env.UPSTASH_REDIS_URL,\n * token: process.env.UPSTASH_REDIS_TOKEN,\n * }),\n * ttl: 604800, // 7 days\n * });\n * ```\n */\nexport class CacheAuditStorage<\n\tTAuditAction extends AuditableAction<string, unknown> = AuditableAction<\n\t\tstring,\n\t\tunknown\n\t>,\n> implements AuditStorage<TAuditAction>\n{\n\tprivate readonly cache: Cache;\n\tprivate readonly prefix: string;\n\tprivate readonly ttl?: number;\n\tprivate readonly indexKey: string;\n\n\tconstructor(config: CacheAuditStorageConfig) {\n\t\tthis.cache = config.cache;\n\t\tthis.prefix = config.prefix ?? 'audit';\n\t\tthis.ttl = config.ttl;\n\t\tthis.indexKey = `${this.prefix}:__index__`;\n\t}\n\n\t/**\n\t * Write audit records to cache.\n\t */\n\tasync write(records: AuditRecord[]): Promise<void> {\n\t\tif (records.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Get existing index\n\t\tconst existingIds = (await this.cache.get<string[]>(this.indexKey)) ?? [];\n\t\tconst newIds: string[] = [];\n\n\t\t// Write each record\n\t\tfor (const record of records) {\n\t\t\tconst key = this.getRecordKey(record.id);\n\t\t\t// Serialize Date to ISO string for cache storage\n\t\t\tconst serialized = this.serializeRecord(record);\n\t\t\tawait this.cache.set(key, serialized, this.ttl);\n\t\t\tnewIds.push(record.id);\n\t\t}\n\n\t\t// Update index with new IDs\n\t\tconst updatedIds = [...existingIds, ...newIds];\n\t\tawait this.cache.set(this.indexKey, updatedIds, this.ttl);\n\t}\n\n\t/**\n\t * Query audit records from cache.\n\t */\n\tasync query(options: AuditQueryOptions): Promise<AuditRecord[]> {\n\t\tconst allRecords = await this.getAllRecords();\n\t\tlet results = this.applyFilters(allRecords, options);\n\n\t\t// Ordering\n\t\tconst orderBy = options.orderBy ?? 'timestamp';\n\t\tconst orderDirection = options.orderDirection ?? 'desc';\n\t\tresults.sort((a, b) => {\n\t\t\tconst aValue = orderBy === 'timestamp' ? a.timestamp.getTime() : a.type;\n\t\t\tconst bValue = orderBy === 'timestamp' ? b.timestamp.getTime() : b.type;\n\t\t\tif (aValue < bValue) return orderDirection === 'asc' ? -1 : 1;\n\t\t\tif (aValue > bValue) return orderDirection === 'asc' ? 1 : -1;\n\t\t\treturn 0;\n\t\t});\n\n\t\t// Pagination\n\t\tif (options.offset !== undefined) {\n\t\t\tresults = results.slice(options.offset);\n\t\t}\n\t\tif (options.limit !== undefined) {\n\t\t\tresults = results.slice(0, options.limit);\n\t\t}\n\n\t\treturn results;\n\t}\n\n\t/**\n\t * Count audit records matching filters.\n\t */\n\tasync count(\n\t\toptions: Omit<AuditQueryOptions, 'limit' | 'offset'>,\n\t): Promise<number> {\n\t\tconst allRecords = await this.getAllRecords();\n\t\treturn this.applyFilters(allRecords, options).length;\n\t}\n\n\t/**\n\t * Get all stored records (for testing/debugging).\n\t */\n\tasync getRecords(): Promise<AuditRecord[]> {\n\t\treturn this.getAllRecords();\n\t}\n\n\t/**\n\t * Clear all stored records.\n\t */\n\tasync clear(): Promise<void> {\n\t\tconst ids = (await this.cache.get<string[]>(this.indexKey)) ?? [];\n\n\t\t// Delete all records\n\t\tfor (const id of ids) {\n\t\t\tawait this.cache.delete(this.getRecordKey(id));\n\t\t}\n\n\t\t// Delete index\n\t\tawait this.cache.delete(this.indexKey);\n\t}\n\n\tprivate getRecordKey(id: string): string {\n\t\treturn `${this.prefix}:${id}`;\n\t}\n\n\tprivate async getAllRecords(): Promise<AuditRecord[]> {\n\t\tconst ids = (await this.cache.get<string[]>(this.indexKey)) ?? [];\n\t\tconst records: AuditRecord[] = [];\n\t\tconst validIds: string[] = [];\n\n\t\tfor (const id of ids) {\n\t\t\tconst key = this.getRecordKey(id);\n\t\t\tconst serialized = await this.cache.get<SerializedAuditRecord>(key);\n\t\t\tif (serialized) {\n\t\t\t\trecords.push(this.deserializeRecord(serialized));\n\t\t\t\tvalidIds.push(id);\n\t\t\t}\n\t\t}\n\n\t\t// Clean up index if some records expired\n\t\tif (validIds.length !== ids.length) {\n\t\t\tawait this.cache.set(this.indexKey, validIds, this.ttl);\n\t\t}\n\n\t\treturn records;\n\t}\n\n\tprivate serializeRecord(record: AuditRecord): SerializedAuditRecord {\n\t\treturn {\n\t\t\t...record,\n\t\t\ttimestamp: record.timestamp.toISOString(),\n\t\t};\n\t}\n\n\tprivate deserializeRecord(serialized: SerializedAuditRecord): AuditRecord {\n\t\treturn {\n\t\t\t...serialized,\n\t\t\ttimestamp: new Date(serialized.timestamp),\n\t\t};\n\t}\n\n\tprivate applyFilters(\n\t\trecords: AuditRecord[],\n\t\toptions: AuditQueryOptions,\n\t): AuditRecord[] {\n\t\treturn records.filter((record) => {\n\t\t\t// Type filter\n\t\t\tif (options.type !== undefined) {\n\t\t\t\tif (Array.isArray(options.type)) {\n\t\t\t\t\tif (!options.type.includes(record.type)) return false;\n\t\t\t\t} else {\n\t\t\t\t\tif (record.type !== options.type) return false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Entity ID filter\n\t\t\tif (options.entityId !== undefined) {\n\t\t\t\tconst entityId =\n\t\t\t\t\ttypeof options.entityId === 'string'\n\t\t\t\t\t\t? options.entityId\n\t\t\t\t\t\t: JSON.stringify(options.entityId);\n\t\t\t\tconst recordEntityId =\n\t\t\t\t\ttypeof record.entityId === 'string'\n\t\t\t\t\t\t? record.entityId\n\t\t\t\t\t\t: JSON.stringify(record.entityId);\n\t\t\t\tif (recordEntityId !== entityId) return false;\n\t\t\t}\n\n\t\t\t// Table filter\n\t\t\tif (options.table !== undefined) {\n\t\t\t\tif (record.table !== options.table) return false;\n\t\t\t}\n\n\t\t\t// Actor ID filter\n\t\t\tif (options.actorId !== undefined) {\n\t\t\t\tif (record.actor?.id !== options.actorId) return false;\n\t\t\t}\n\n\t\t\t// Date range filters\n\t\t\tif (options.from !== undefined) {\n\t\t\t\tif (record.timestamp < options.from) return false;\n\t\t\t}\n\t\t\tif (options.to !== undefined) {\n\t\t\t\tif (record.timestamp > options.to) return false;\n\t\t\t}\n\n\t\t\treturn true;\n\t\t});\n\t}\n}\n\n/**\n * Serialized version of AuditRecord for cache storage.\n * Dates are stored as ISO strings.\n */\ntype SerializedAuditRecord = Omit<AuditRecord, 'timestamp'> & {\n\ttimestamp: string;\n};\n"],"mappings":"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"}
|