@geekmidas/audit 0.0.8 → 0.1.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.
Files changed (45) hide show
  1. package/README.md +397 -0
  2. package/dist/{Auditor-D3me-qKX.d.mts → Auditor-DrR0ImvJ.d.cts} +43 -1
  3. package/dist/{Auditor-QYUMGJCH.d.cts → Auditor-Xf4Tp63p.d.mts} +43 -1
  4. package/dist/Auditor.d.cts +1 -1
  5. package/dist/Auditor.d.mts +1 -1
  6. package/dist/{DefaultAuditor-BTuMMiWh.d.cts → DefaultAuditor-3Q1zVd1b.d.mts} +2 -2
  7. package/dist/{DefaultAuditor-C1FWrJg6.d.mts → DefaultAuditor-BaZa4u_m.d.cts} +2 -2
  8. package/dist/DefaultAuditor.d.cts +2 -2
  9. package/dist/DefaultAuditor.d.mts +2 -2
  10. package/dist/cache-0AjJ0zis.d.cts +95 -0
  11. package/dist/cache-BbIl31RL.mjs +167 -0
  12. package/dist/cache-BbIl31RL.mjs.map +1 -0
  13. package/dist/cache-DBbGcCEq.d.mts +95 -0
  14. package/dist/cache-l7jAptBl.cjs +173 -0
  15. package/dist/cache-l7jAptBl.cjs.map +1 -0
  16. package/dist/cache.cjs +3 -0
  17. package/dist/cache.d.cts +3 -0
  18. package/dist/cache.d.mts +3 -0
  19. package/dist/cache.mjs +3 -0
  20. package/dist/index.d.cts +2 -2
  21. package/dist/index.d.mts +2 -2
  22. package/dist/kysely.cjs +24 -0
  23. package/dist/kysely.cjs.map +1 -1
  24. package/dist/kysely.d.cts +10 -1
  25. package/dist/kysely.d.mts +10 -1
  26. package/dist/kysely.mjs +24 -0
  27. package/dist/kysely.mjs.map +1 -1
  28. package/dist/memory.cjs +49 -0
  29. package/dist/memory.cjs.map +1 -0
  30. package/dist/memory.d.cts +43 -0
  31. package/dist/memory.d.mts +43 -0
  32. package/dist/memory.mjs +48 -0
  33. package/dist/memory.mjs.map +1 -0
  34. package/dist/storage.d.cts +1 -1
  35. package/dist/storage.d.mts +1 -1
  36. package/dist/types.d.cts +1 -1
  37. package/dist/types.d.mts +1 -1
  38. package/package.json +33 -5
  39. package/src/__tests__/CacheAuditStorage.spec.ts +382 -0
  40. package/src/__tests__/InMemoryAuditStorage.spec.ts +317 -0
  41. package/src/__tests__/KyselyAuditStorage.integration.spec.ts +24 -20
  42. package/src/cache.ts +263 -0
  43. package/src/kysely.ts +33 -0
  44. package/src/memory.ts +50 -0
  45. package/src/storage.ts +47 -0
package/README.md ADDED
@@ -0,0 +1,397 @@
1
+ # @geekmidas/audit
2
+
3
+ > Type-safe audit logging with database integration for tracking application events and user actions
4
+
5
+ ## Overview
6
+
7
+ `@geekmidas/audit` provides a comprehensive solution for recording and persisting audit trails in your application. It supports type-safe audit actions, transactional writes, and flexible storage backends.
8
+
9
+ ## Features
10
+
11
+ - **Type-safe Audit Actions**: Define audit types with TypeScript for compile-time safety
12
+ - **Transactional Support**: Flush audits atomically within database transactions
13
+ - **Flexible Storage**: Pluggable storage interface (Kysely, in-memory, cache)
14
+ - **Actor Tracking**: Record who performed each action (users, services, systems)
15
+ - **Rich Metadata**: Attach request context, entity references, and custom data
16
+ - **Query Support**: Query audit logs with filters, pagination, and sorting
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ npm install @geekmidas/audit
22
+ # or
23
+ pnpm add @geekmidas/audit
24
+ ```
25
+
26
+ ## Quick Start
27
+
28
+ ### 1. Define Your Audit Actions
29
+
30
+ ```typescript
31
+ import type { AuditableAction } from '@geekmidas/audit';
32
+
33
+ // Define type-safe audit actions
34
+ type AppAuditAction =
35
+ | AuditableAction<'user.created', { userId: string; email: string }>
36
+ | AuditableAction<'user.updated', { userId: string; changes: string[] }>
37
+ | AuditableAction<'order.placed', { orderId: string; total: number }>;
38
+ ```
39
+
40
+ ### 2. Set Up Storage
41
+
42
+ **For Development/Testing (InMemoryAuditStorage):**
43
+
44
+ ```typescript
45
+ import { InMemoryAuditStorage } from '@geekmidas/audit/memory';
46
+
47
+ const storage = new InMemoryAuditStorage<AppAuditAction>();
48
+
49
+ // Query stored records
50
+ const records = await storage.query({ type: 'user.created' });
51
+
52
+ // Clear all records (useful in tests)
53
+ storage.clear();
54
+ ```
55
+
56
+ **For Production (KyselyAuditStorage):**
57
+
58
+ ```typescript
59
+ import { KyselyAuditStorage } from '@geekmidas/audit/kysely';
60
+
61
+ // Define your database schema
62
+ interface Database {
63
+ audit_logs: AuditLogTable;
64
+ // ... other tables
65
+ }
66
+
67
+ const storage = new KyselyAuditStorage<Database>({
68
+ db: kyselyDb,
69
+ tableName: 'audit_logs',
70
+ });
71
+ ```
72
+
73
+ ### 3. Create an Auditor
74
+
75
+ ```typescript
76
+ import { DefaultAuditor } from '@geekmidas/audit';
77
+
78
+ const auditor = new DefaultAuditor<AppAuditAction>({
79
+ actor: { id: 'user-123', type: 'user' },
80
+ storage,
81
+ metadata: {
82
+ requestId: 'req-456',
83
+ endpoint: '/api/users',
84
+ },
85
+ });
86
+ ```
87
+
88
+ ### 4. Record Audits
89
+
90
+ ```typescript
91
+ // Type-safe audit calls - TypeScript enforces correct payload shapes
92
+ auditor.audit('user.created', {
93
+ userId: '789',
94
+ email: 'test@example.com',
95
+ }); // OK
96
+
97
+ auditor.audit('user.created', {
98
+ orderId: '123', // Type error - wrong payload shape
99
+ });
100
+
101
+ // Flush to storage
102
+ await auditor.flush();
103
+ ```
104
+
105
+ ## Transactional Audits
106
+
107
+ Use `withAuditableTransaction` to ensure audits are atomic with your database operations:
108
+
109
+ ```typescript
110
+ import { withAuditableTransaction } from '@geekmidas/audit/kysely';
111
+
112
+ const result = await withAuditableTransaction(
113
+ db,
114
+ auditor,
115
+ async (trx) => {
116
+ // Database operations
117
+ const user = await trx
118
+ .insertInto('users')
119
+ .values({ name: 'John', email: 'john@example.com' })
120
+ .returningAll()
121
+ .executeTakeFirstOrThrow();
122
+
123
+ // Audit is recorded
124
+ auditor.audit('user.created', {
125
+ userId: user.id,
126
+ email: user.email,
127
+ });
128
+
129
+ return user;
130
+ },
131
+ );
132
+ // Audits are automatically flushed before transaction commits
133
+ // If flush fails, the entire transaction rolls back
134
+ ```
135
+
136
+ ## API Reference
137
+
138
+ ### Core Types
139
+
140
+ #### `AuditableAction<TType, TPayload>`
141
+
142
+ Defines an auditable action with a type and payload:
143
+
144
+ ```typescript
145
+ type UserAction = AuditableAction<'user.created', { userId: string }>;
146
+ ```
147
+
148
+ #### `AuditRecord`
149
+
150
+ Complete audit record with all metadata:
151
+
152
+ ```typescript
153
+ interface AuditRecord<TPayload = unknown> {
154
+ id: string;
155
+ type: string;
156
+ operation: AuditOperation;
157
+ table?: string;
158
+ entityId?: string | Record<string, unknown>;
159
+ oldValues?: Record<string, unknown>;
160
+ newValues?: Record<string, unknown>;
161
+ payload?: TPayload;
162
+ timestamp: Date;
163
+ actor?: AuditActor;
164
+ metadata?: AuditMetadata;
165
+ }
166
+ ```
167
+
168
+ #### `AuditActor`
169
+
170
+ Represents who performed the action:
171
+
172
+ ```typescript
173
+ interface AuditActor {
174
+ id?: string;
175
+ type?: string;
176
+ [key: string]: unknown;
177
+ }
178
+ ```
179
+
180
+ #### `AuditMetadata`
181
+
182
+ Request context and additional data:
183
+
184
+ ```typescript
185
+ interface AuditMetadata {
186
+ requestId?: string;
187
+ endpoint?: string;
188
+ method?: string;
189
+ ip?: string;
190
+ userAgent?: string;
191
+ [key: string]: unknown;
192
+ }
193
+ ```
194
+
195
+ ### `Auditor` Interface
196
+
197
+ ```typescript
198
+ interface Auditor<TAuditAction, TTransaction> {
199
+ readonly actor: AuditActor;
200
+
201
+ // Type-safe audit recording
202
+ audit<TType extends ExtractAuditType<TAuditAction>>(
203
+ type: TType,
204
+ payload: ExtractAuditPayload<TAuditAction, TType>,
205
+ options?: AuditOptions,
206
+ ): void;
207
+
208
+ // Raw record insertion
209
+ record(record: Omit<AuditRecord, 'id' | 'timestamp' | 'actor'>): void;
210
+
211
+ // Get collected records
212
+ getRecords(): AuditRecord[];
213
+
214
+ // Flush to storage
215
+ flush(trx?: TTransaction): Promise<void>;
216
+
217
+ // Clear without flushing
218
+ clear(): void;
219
+
220
+ // Add metadata to future records
221
+ addMetadata(metadata: AuditMetadata): void;
222
+
223
+ // Transaction management
224
+ setTransaction(trx: TTransaction): void;
225
+ getTransaction(): TTransaction | undefined;
226
+ }
227
+ ```
228
+
229
+ ### `AuditStorage` Interface
230
+
231
+ Implement this interface for custom storage backends:
232
+
233
+ ```typescript
234
+ interface AuditStorage<TAuditAction> {
235
+ // Required: Write records
236
+ write(records: AuditRecord[], trx?: unknown): Promise<void>;
237
+
238
+ // Optional: Query records
239
+ query?(options: AuditQueryOptions): Promise<AuditRecord[]>;
240
+
241
+ // Optional: Count records
242
+ count?(options: Omit<AuditQueryOptions, 'limit' | 'offset'>): Promise<number>;
243
+
244
+ // Optional: Get database for transactions
245
+ getDatabase?(): unknown;
246
+ }
247
+ ```
248
+
249
+ ### `KyselyAuditStorage`
250
+
251
+ Built-in Kysely storage implementation:
252
+
253
+ ```typescript
254
+ const storage = new KyselyAuditStorage({
255
+ db: kyselyDb,
256
+ tableName: 'audit_logs',
257
+ databaseServiceName: 'database', // Optional: for automatic transaction injection
258
+ autoId: false, // Optional: let database generate IDs
259
+ });
260
+
261
+ // Query audits
262
+ const audits = await storage.query({
263
+ type: 'user.created',
264
+ actorId: 'user-123',
265
+ from: new Date('2024-01-01'),
266
+ limit: 100,
267
+ orderBy: 'timestamp',
268
+ orderDirection: 'desc',
269
+ });
270
+
271
+ // Count audits
272
+ const count = await storage.count({
273
+ type: ['user.created', 'user.updated'],
274
+ actorId: 'user-123',
275
+ });
276
+ ```
277
+
278
+ ### `InMemoryAuditStorage`
279
+
280
+ Convenience wrapper around `CacheAuditStorage` with `InMemoryCache`. Useful for testing and development:
281
+
282
+ ```typescript
283
+ import { InMemoryAuditStorage } from '@geekmidas/audit/memory';
284
+
285
+ const storage = new InMemoryAuditStorage<AppAuditAction>();
286
+
287
+ // Query audits (same API as other storages)
288
+ const audits = await storage.query({
289
+ type: 'user.created',
290
+ limit: 10,
291
+ });
292
+
293
+ // Get all records (for assertions in tests)
294
+ const allRecords = await storage.getRecords();
295
+
296
+ // Clear all records (reset for next test)
297
+ await storage.clear();
298
+ ```
299
+
300
+ ### `CacheAuditStorage`
301
+
302
+ Cache-based storage using any `@geekmidas/cache` implementation:
303
+
304
+ ```typescript
305
+ import { CacheAuditStorage } from '@geekmidas/audit/cache';
306
+ import { InMemoryCache } from '@geekmidas/cache/memory';
307
+ import { UpstashCache } from '@geekmidas/cache/upstash';
308
+
309
+ // With in-memory cache (development/testing)
310
+ const storage = new CacheAuditStorage({
311
+ cache: new InMemoryCache(),
312
+ ttl: 86400, // 24 hours
313
+ });
314
+
315
+ // With Upstash Redis (production - distributed systems)
316
+ const storage = new CacheAuditStorage({
317
+ cache: new UpstashCache({
318
+ url: process.env.UPSTASH_REDIS_URL,
319
+ token: process.env.UPSTASH_REDIS_TOKEN,
320
+ }),
321
+ prefix: 'audit', // Optional key prefix
322
+ ttl: 604800, // 7 days
323
+ });
324
+
325
+ // Query and count work the same as other storages
326
+ const audits = await storage.query({ type: 'user.created' });
327
+ const count = await storage.count({ actorId: 'user-123' });
328
+
329
+ // Clear all records
330
+ await storage.clear();
331
+ ```
332
+
333
+ ## Database Schema
334
+
335
+ Create an `audit_logs` table for `KyselyAuditStorage`:
336
+
337
+ ```sql
338
+ CREATE TABLE audit_logs (
339
+ id VARCHAR(21) PRIMARY KEY, -- or use gen_random_uuid() with autoId: true
340
+ type VARCHAR(255) NOT NULL,
341
+ operation VARCHAR(20) NOT NULL,
342
+ "table" VARCHAR(255),
343
+ "entityId" VARCHAR(255),
344
+ "oldValues" JSONB,
345
+ "newValues" JSONB,
346
+ payload JSONB,
347
+ timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW(),
348
+ "actorId" VARCHAR(255),
349
+ "actorType" VARCHAR(50),
350
+ "actorData" JSONB,
351
+ metadata JSONB
352
+ );
353
+
354
+ -- Recommended indexes
355
+ CREATE INDEX idx_audit_logs_type ON audit_logs(type);
356
+ CREATE INDEX idx_audit_logs_timestamp ON audit_logs(timestamp);
357
+ CREATE INDEX idx_audit_logs_actor_id ON audit_logs("actorId");
358
+ CREATE INDEX idx_audit_logs_entity_id ON audit_logs("entityId");
359
+ ```
360
+
361
+ ## Integration with @geekmidas/constructs
362
+
363
+ The audit package integrates seamlessly with `@geekmidas/constructs` endpoints:
364
+
365
+ ```typescript
366
+ import { e } from '@geekmidas/constructs/endpoints';
367
+
368
+ const endpoint = e
369
+ .post('/users')
370
+ .body(UserSchema)
371
+ .output(UserResponseSchema)
372
+ .audit([
373
+ {
374
+ type: 'user.created',
375
+ payload: (response) => ({
376
+ userId: response.id,
377
+ email: response.email,
378
+ }),
379
+ },
380
+ ])
381
+ .handle(async ({ body, auditor }) => {
382
+ // Audits are automatically recorded and flushed
383
+ return { id: '123', ...body };
384
+ });
385
+ ```
386
+
387
+ ## Best Practices
388
+
389
+ 1. **Define all audit actions upfront**: Create a union type of all possible audit actions for your application
390
+ 2. **Use transactions**: Wrap database operations and audits in transactions for consistency
391
+ 3. **Include entity references**: Use `entityId` and `table` options for easier querying
392
+ 4. **Add request context**: Include request IDs, endpoints, and IPs in metadata
393
+ 5. **Use meaningful types**: Name audit types with domain context (e.g., `order.shipped` not `update`)
394
+
395
+ ## License
396
+
397
+ MIT
@@ -117,6 +117,48 @@ interface AuditStorage<TAuditAction extends AuditableAction<string, unknown> = A
117
117
  * ```
118
118
  */
119
119
  databaseServiceName?: string;
120
+ /**
121
+ * Optional: Execute a callback within a database transaction.
122
+ * The auditor is registered with the transaction and audits are flushed
123
+ * before the transaction commits.
124
+ *
125
+ * This is database-agnostic - each storage implementation provides its own
126
+ * transaction handling based on the underlying database.
127
+ *
128
+ * If a database connection is provided, it should be used instead of the
129
+ * storage's internal connection. If the connection is already a transaction,
130
+ * it should be reused instead of creating a nested transaction.
131
+ *
132
+ * @param auditor - The auditor to register with the transaction
133
+ * @param callback - The callback to execute within the transaction
134
+ * @param db - Optional database connection (may already be a transaction)
135
+ * @returns The result of the callback
136
+ *
137
+ * @example
138
+ * ```typescript
139
+ * // KyselyAuditStorage implementation
140
+ * async withTransaction<T>(auditor, callback, db) {
141
+ * const connection = db ?? this.db;
142
+ * if (connection.isTransaction) {
143
+ * // Reuse existing transaction
144
+ * auditor.setTransaction(connection);
145
+ * const result = await callback();
146
+ * await auditor.flush(connection);
147
+ * return result;
148
+ * }
149
+ * return connection.transaction().execute(async (trx) => {
150
+ * auditor.setTransaction(trx);
151
+ * const result = await callback();
152
+ * await auditor.flush(trx);
153
+ * return result;
154
+ * });
155
+ * }
156
+ * ```
157
+ */
158
+ withTransaction?<T>(auditor: {
159
+ setTransaction(trx: unknown): void;
160
+ flush(trx?: unknown): Promise<void>;
161
+ }, callback: () => Promise<T>, db?: unknown): Promise<T>;
120
162
  }
121
163
  //#endregion
122
164
  //#region src/types.d.ts
@@ -378,4 +420,4 @@ interface Auditor<TAuditAction extends AuditableAction<string, unknown> = Audita
378
420
  }
379
421
  //#endregion
380
422
  export { AuditActor, AuditMetadata, AuditOperation, AuditOptions, AuditQueryOptions, AuditRecord, AuditStorage, AuditableAction, Auditor, ExtractAuditPayload, ExtractAuditType, ExtractAuditorAction, ExtractStorageAuditAction, MappedAudit };
381
- //# sourceMappingURL=Auditor-D3me-qKX.d.mts.map
423
+ //# sourceMappingURL=Auditor-DrR0ImvJ.d.cts.map
@@ -117,6 +117,48 @@ interface AuditStorage<TAuditAction extends AuditableAction<string, unknown> = A
117
117
  * ```
118
118
  */
119
119
  databaseServiceName?: string;
120
+ /**
121
+ * Optional: Execute a callback within a database transaction.
122
+ * The auditor is registered with the transaction and audits are flushed
123
+ * before the transaction commits.
124
+ *
125
+ * This is database-agnostic - each storage implementation provides its own
126
+ * transaction handling based on the underlying database.
127
+ *
128
+ * If a database connection is provided, it should be used instead of the
129
+ * storage's internal connection. If the connection is already a transaction,
130
+ * it should be reused instead of creating a nested transaction.
131
+ *
132
+ * @param auditor - The auditor to register with the transaction
133
+ * @param callback - The callback to execute within the transaction
134
+ * @param db - Optional database connection (may already be a transaction)
135
+ * @returns The result of the callback
136
+ *
137
+ * @example
138
+ * ```typescript
139
+ * // KyselyAuditStorage implementation
140
+ * async withTransaction<T>(auditor, callback, db) {
141
+ * const connection = db ?? this.db;
142
+ * if (connection.isTransaction) {
143
+ * // Reuse existing transaction
144
+ * auditor.setTransaction(connection);
145
+ * const result = await callback();
146
+ * await auditor.flush(connection);
147
+ * return result;
148
+ * }
149
+ * return connection.transaction().execute(async (trx) => {
150
+ * auditor.setTransaction(trx);
151
+ * const result = await callback();
152
+ * await auditor.flush(trx);
153
+ * return result;
154
+ * });
155
+ * }
156
+ * ```
157
+ */
158
+ withTransaction?<T>(auditor: {
159
+ setTransaction(trx: unknown): void;
160
+ flush(trx?: unknown): Promise<void>;
161
+ }, callback: () => Promise<T>, db?: unknown): Promise<T>;
120
162
  }
121
163
  //#endregion
122
164
  //#region src/types.d.ts
@@ -378,4 +420,4 @@ interface Auditor<TAuditAction extends AuditableAction<string, unknown> = Audita
378
420
  }
379
421
  //#endregion
380
422
  export { AuditActor, AuditMetadata, AuditOperation, AuditOptions, AuditQueryOptions, AuditRecord, AuditStorage, AuditableAction, Auditor, ExtractAuditPayload, ExtractAuditType, ExtractAuditorAction, ExtractStorageAuditAction, MappedAudit };
381
- //# sourceMappingURL=Auditor-QYUMGJCH.d.cts.map
423
+ //# sourceMappingURL=Auditor-Xf4Tp63p.d.mts.map
@@ -1,2 +1,2 @@
1
- import { Auditor } from "./Auditor-QYUMGJCH.cjs";
1
+ import { Auditor } from "./Auditor-DrR0ImvJ.cjs";
2
2
  export { Auditor };
@@ -1,2 +1,2 @@
1
- import { Auditor } from "./Auditor-D3me-qKX.mjs";
1
+ import { Auditor } from "./Auditor-Xf4Tp63p.mjs";
2
2
  export { Auditor };
@@ -1,4 +1,4 @@
1
- import { AuditActor, AuditMetadata, AuditOptions, AuditRecord, AuditStorage, AuditableAction, Auditor, ExtractAuditPayload, ExtractAuditType } from "./Auditor-QYUMGJCH.cjs";
1
+ import { AuditActor, AuditMetadata, AuditOptions, AuditRecord, AuditStorage, AuditableAction, Auditor, ExtractAuditPayload, ExtractAuditType } from "./Auditor-Xf4Tp63p.mjs";
2
2
 
3
3
  //#region src/DefaultAuditor.d.ts
4
4
 
@@ -55,4 +55,4 @@ declare class DefaultAuditor<TAuditAction extends AuditableAction<string, unknow
55
55
  }
56
56
  //#endregion
57
57
  export { DefaultAuditor, DefaultAuditorConfig };
58
- //# sourceMappingURL=DefaultAuditor-BTuMMiWh.d.cts.map
58
+ //# sourceMappingURL=DefaultAuditor-3Q1zVd1b.d.mts.map
@@ -1,4 +1,4 @@
1
- import { AuditActor, AuditMetadata, AuditOptions, AuditRecord, AuditStorage, AuditableAction, Auditor, ExtractAuditPayload, ExtractAuditType } from "./Auditor-D3me-qKX.mjs";
1
+ import { AuditActor, AuditMetadata, AuditOptions, AuditRecord, AuditStorage, AuditableAction, Auditor, ExtractAuditPayload, ExtractAuditType } from "./Auditor-DrR0ImvJ.cjs";
2
2
 
3
3
  //#region src/DefaultAuditor.d.ts
4
4
 
@@ -55,4 +55,4 @@ declare class DefaultAuditor<TAuditAction extends AuditableAction<string, unknow
55
55
  }
56
56
  //#endregion
57
57
  export { DefaultAuditor, DefaultAuditorConfig };
58
- //# sourceMappingURL=DefaultAuditor-C1FWrJg6.d.mts.map
58
+ //# sourceMappingURL=DefaultAuditor-BaZa4u_m.d.cts.map
@@ -1,3 +1,3 @@
1
- import "./Auditor-QYUMGJCH.cjs";
2
- import { DefaultAuditor, DefaultAuditorConfig } from "./DefaultAuditor-BTuMMiWh.cjs";
1
+ import "./Auditor-DrR0ImvJ.cjs";
2
+ import { DefaultAuditor, DefaultAuditorConfig } from "./DefaultAuditor-BaZa4u_m.cjs";
3
3
  export { DefaultAuditor, DefaultAuditorConfig };
@@ -1,3 +1,3 @@
1
- import "./Auditor-D3me-qKX.mjs";
2
- import { DefaultAuditor, DefaultAuditorConfig } from "./DefaultAuditor-C1FWrJg6.mjs";
1
+ import "./Auditor-Xf4Tp63p.mjs";
2
+ import { DefaultAuditor, DefaultAuditorConfig } from "./DefaultAuditor-3Q1zVd1b.mjs";
3
3
  export { DefaultAuditor, DefaultAuditorConfig };
@@ -0,0 +1,95 @@
1
+ import { AuditQueryOptions, AuditRecord, AuditStorage, AuditableAction } from "./Auditor-DrR0ImvJ.cjs";
2
+ import { Cache } from "@geekmidas/cache";
3
+
4
+ //#region src/cache.d.ts
5
+
6
+ /**
7
+ * Configuration for CacheAuditStorage.
8
+ */
9
+ interface CacheAuditStorageConfig {
10
+ /** Cache instance to use for storage */
11
+ cache: Cache;
12
+ /**
13
+ * Key prefix for audit records.
14
+ * Records are stored as `${prefix}:${id}`.
15
+ * @default 'audit'
16
+ */
17
+ prefix?: string;
18
+ /**
19
+ * TTL (time-to-live) in seconds for audit records.
20
+ * If not set, records use the cache's default TTL.
21
+ */
22
+ ttl?: number;
23
+ }
24
+ /**
25
+ * Cache-based audit storage implementation.
26
+ * Uses any @geekmidas/cache implementation for storage.
27
+ *
28
+ * Best suited for:
29
+ * - Development and testing
30
+ * - Temporary audit logs that don't need persistence
31
+ * - Applications with existing cache infrastructure
32
+ * - Distributed systems needing shared audit state (with Redis/Upstash)
33
+ *
34
+ * Note: Query performance may degrade with large numbers of records
35
+ * since filtering happens in memory after fetching all records.
36
+ *
37
+ * @template TAuditAction - Optional type parameter for type-safe audit actions.
38
+ *
39
+ * @example
40
+ * ```typescript
41
+ * import { CacheAuditStorage } from '@geekmidas/audit/cache';
42
+ * import { InMemoryCache } from '@geekmidas/cache/memory';
43
+ * import { UpstashCache } from '@geekmidas/cache/upstash';
44
+ *
45
+ * // With in-memory cache (development/testing)
46
+ * const storage = new CacheAuditStorage({
47
+ * cache: new InMemoryCache(),
48
+ * ttl: 86400, // 24 hours
49
+ * });
50
+ *
51
+ * // With Upstash Redis (production)
52
+ * const storage = new CacheAuditStorage({
53
+ * cache: new UpstashCache({
54
+ * url: process.env.UPSTASH_REDIS_URL,
55
+ * token: process.env.UPSTASH_REDIS_TOKEN,
56
+ * }),
57
+ * ttl: 604800, // 7 days
58
+ * });
59
+ * ```
60
+ */
61
+ declare class CacheAuditStorage<TAuditAction extends AuditableAction<string, unknown> = AuditableAction<string, unknown>> implements AuditStorage<TAuditAction> {
62
+ private readonly cache;
63
+ private readonly prefix;
64
+ private readonly ttl?;
65
+ private readonly indexKey;
66
+ constructor(config: CacheAuditStorageConfig);
67
+ /**
68
+ * Write audit records to cache.
69
+ */
70
+ write(records: AuditRecord[]): Promise<void>;
71
+ /**
72
+ * Query audit records from cache.
73
+ */
74
+ query(options: AuditQueryOptions): Promise<AuditRecord[]>;
75
+ /**
76
+ * Count audit records matching filters.
77
+ */
78
+ count(options: Omit<AuditQueryOptions, 'limit' | 'offset'>): Promise<number>;
79
+ /**
80
+ * Get all stored records (for testing/debugging).
81
+ */
82
+ getRecords(): Promise<AuditRecord[]>;
83
+ /**
84
+ * Clear all stored records.
85
+ */
86
+ clear(): Promise<void>;
87
+ private getRecordKey;
88
+ private getAllRecords;
89
+ private serializeRecord;
90
+ private deserializeRecord;
91
+ private applyFilters;
92
+ }
93
+ //#endregion
94
+ export { CacheAuditStorage, CacheAuditStorageConfig };
95
+ //# sourceMappingURL=cache-0AjJ0zis.d.cts.map