@geekmidas/audit 2.2.1 → 10.0.0-alpha.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/README.md +2 -2
- package/package.json +8 -5
- package/CHANGELOG.md +0 -79
- package/TECHNICAL.md +0 -937
- package/src/Auditor.ts +0 -157
- package/src/DefaultAuditor.ts +0 -141
- package/src/__tests__/CacheAuditStorage.spec.ts +0 -382
- package/src/__tests__/DefaultAuditor.spec.ts +0 -529
- package/src/__tests__/InMemoryAuditStorage.spec.ts +0 -317
- package/src/__tests__/KnexAuditStorage.integration.spec.ts +0 -739
- package/src/__tests__/KyselyAuditStorage.integration.spec.ts +0 -518
- package/src/__tests__/KyselyAuditStorage.spec.ts +0 -443
- package/src/cache.ts +0 -263
- package/src/index.ts +0 -23
- package/src/knex.ts +0 -430
- package/src/kysely.ts +0 -424
- package/src/memory.ts +0 -50
- package/src/storage.ts +0 -203
- package/src/types.ts +0 -154
- package/tsconfig.json +0 -9
|
@@ -1,529 +0,0 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
-
import { DefaultAuditor } from '../DefaultAuditor';
|
|
3
|
-
import type { AuditStorage } from '../storage';
|
|
4
|
-
import type { AuditableAction, AuditRecord } from '../types';
|
|
5
|
-
|
|
6
|
-
// Define test audit actions
|
|
7
|
-
type TestAuditAction =
|
|
8
|
-
| AuditableAction<'user.created', { userId: string; email: string }>
|
|
9
|
-
| AuditableAction<'user.updated', { userId: string; changes: string[] }>
|
|
10
|
-
| AuditableAction<'order.placed', { orderId: string; total: number }>;
|
|
11
|
-
|
|
12
|
-
describe('DefaultAuditor', () => {
|
|
13
|
-
let storage: AuditStorage;
|
|
14
|
-
let writtenRecords: AuditRecord[];
|
|
15
|
-
|
|
16
|
-
beforeEach(() => {
|
|
17
|
-
writtenRecords = [];
|
|
18
|
-
storage = {
|
|
19
|
-
write: vi.fn(async (records: AuditRecord[]) => {
|
|
20
|
-
writtenRecords.push(...records);
|
|
21
|
-
}),
|
|
22
|
-
};
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
describe('constructor', () => {
|
|
26
|
-
it('should set actor from config', () => {
|
|
27
|
-
const auditor = new DefaultAuditor<TestAuditAction>({
|
|
28
|
-
actor: { id: 'user-123', type: 'user' },
|
|
29
|
-
storage,
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
expect(auditor.actor).toEqual({ id: 'user-123', type: 'user' });
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it('should use custom ID generator when provided', () => {
|
|
36
|
-
let counter = 0;
|
|
37
|
-
const auditor = new DefaultAuditor<TestAuditAction>({
|
|
38
|
-
actor: { id: 'user-123', type: 'user' },
|
|
39
|
-
storage,
|
|
40
|
-
generateId: () => `custom-${++counter}`,
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
auditor.audit('user.created', {
|
|
44
|
-
userId: '123',
|
|
45
|
-
email: 'test@example.com',
|
|
46
|
-
});
|
|
47
|
-
auditor.audit('user.updated', { userId: '123', changes: ['name'] });
|
|
48
|
-
|
|
49
|
-
const records = auditor.getRecords();
|
|
50
|
-
expect(records[0].id).toBe('custom-1');
|
|
51
|
-
expect(records[1].id).toBe('custom-2');
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
describe('audit', () => {
|
|
56
|
-
it('should create audit record with type and payload', () => {
|
|
57
|
-
const auditor = new DefaultAuditor<TestAuditAction>({
|
|
58
|
-
actor: { id: 'user-123', type: 'user' },
|
|
59
|
-
storage,
|
|
60
|
-
generateId: () => 'test-id',
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
auditor.audit('user.created', {
|
|
64
|
-
userId: '456',
|
|
65
|
-
email: 'test@example.com',
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
const records = auditor.getRecords();
|
|
69
|
-
expect(records).toHaveLength(1);
|
|
70
|
-
expect(records[0]).toMatchObject({
|
|
71
|
-
id: 'test-id',
|
|
72
|
-
type: 'user.created',
|
|
73
|
-
operation: 'CUSTOM',
|
|
74
|
-
payload: { userId: '456', email: 'test@example.com' },
|
|
75
|
-
actor: { id: 'user-123', type: 'user' },
|
|
76
|
-
});
|
|
77
|
-
expect(records[0].timestamp).toBeInstanceOf(Date);
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
it('should include options in audit record', () => {
|
|
81
|
-
const auditor = new DefaultAuditor<TestAuditAction>({
|
|
82
|
-
actor: { id: 'user-123', type: 'user' },
|
|
83
|
-
storage,
|
|
84
|
-
generateId: () => 'test-id',
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
auditor.audit(
|
|
88
|
-
'user.updated',
|
|
89
|
-
{ userId: '456', changes: ['email', 'name'] },
|
|
90
|
-
{
|
|
91
|
-
operation: 'UPDATE',
|
|
92
|
-
table: 'users',
|
|
93
|
-
entityId: '456',
|
|
94
|
-
oldValues: { email: 'old@example.com' },
|
|
95
|
-
newValues: { email: 'new@example.com' },
|
|
96
|
-
},
|
|
97
|
-
);
|
|
98
|
-
|
|
99
|
-
const records = auditor.getRecords();
|
|
100
|
-
expect(records[0]).toMatchObject({
|
|
101
|
-
type: 'user.updated',
|
|
102
|
-
operation: 'UPDATE',
|
|
103
|
-
table: 'users',
|
|
104
|
-
entityId: '456',
|
|
105
|
-
oldValues: { email: 'old@example.com' },
|
|
106
|
-
newValues: { email: 'new@example.com' },
|
|
107
|
-
});
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
it('should include metadata from config', () => {
|
|
111
|
-
const auditor = new DefaultAuditor<TestAuditAction>({
|
|
112
|
-
actor: { id: 'user-123', type: 'user' },
|
|
113
|
-
storage,
|
|
114
|
-
metadata: { requestId: 'req-789', endpoint: '/users' },
|
|
115
|
-
generateId: () => 'test-id',
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
auditor.audit('user.created', {
|
|
119
|
-
userId: '456',
|
|
120
|
-
email: 'test@example.com',
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
const records = auditor.getRecords();
|
|
124
|
-
expect(records[0].metadata).toEqual({
|
|
125
|
-
requestId: 'req-789',
|
|
126
|
-
endpoint: '/users',
|
|
127
|
-
});
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
describe('record', () => {
|
|
132
|
-
it('should create raw audit record', () => {
|
|
133
|
-
const auditor = new DefaultAuditor<TestAuditAction>({
|
|
134
|
-
actor: { id: 'user-123', type: 'user' },
|
|
135
|
-
storage,
|
|
136
|
-
generateId: () => 'test-id',
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
auditor.record({
|
|
140
|
-
type: 'custom.event',
|
|
141
|
-
operation: 'CUSTOM',
|
|
142
|
-
payload: { custom: 'data' },
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
const records = auditor.getRecords();
|
|
146
|
-
expect(records).toHaveLength(1);
|
|
147
|
-
expect(records[0]).toMatchObject({
|
|
148
|
-
id: 'test-id',
|
|
149
|
-
type: 'custom.event',
|
|
150
|
-
operation: 'CUSTOM',
|
|
151
|
-
payload: { custom: 'data' },
|
|
152
|
-
actor: { id: 'user-123', type: 'user' },
|
|
153
|
-
});
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
it('should merge metadata from config and record', () => {
|
|
157
|
-
const auditor = new DefaultAuditor<TestAuditAction>({
|
|
158
|
-
actor: { id: 'user-123', type: 'user' },
|
|
159
|
-
storage,
|
|
160
|
-
metadata: { requestId: 'req-789', endpoint: '/users' },
|
|
161
|
-
generateId: () => 'test-id',
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
auditor.record({
|
|
165
|
-
type: 'custom.event',
|
|
166
|
-
operation: 'CUSTOM',
|
|
167
|
-
metadata: { custom: 'value', endpoint: '/custom' },
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
const records = auditor.getRecords();
|
|
171
|
-
expect(records[0].metadata).toEqual({
|
|
172
|
-
requestId: 'req-789',
|
|
173
|
-
endpoint: '/custom', // Record metadata overrides config
|
|
174
|
-
custom: 'value',
|
|
175
|
-
});
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
it('should use record metadata when no config metadata', () => {
|
|
179
|
-
const auditor = new DefaultAuditor<TestAuditAction>({
|
|
180
|
-
actor: { id: 'user-123', type: 'user' },
|
|
181
|
-
storage,
|
|
182
|
-
generateId: () => 'test-id',
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
auditor.record({
|
|
186
|
-
type: 'custom.event',
|
|
187
|
-
operation: 'CUSTOM',
|
|
188
|
-
metadata: { custom: 'value' },
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
const records = auditor.getRecords();
|
|
192
|
-
expect(records[0].metadata).toEqual({ custom: 'value' });
|
|
193
|
-
});
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
describe('getRecords', () => {
|
|
197
|
-
it('should return copy of records', () => {
|
|
198
|
-
const auditor = new DefaultAuditor<TestAuditAction>({
|
|
199
|
-
actor: { id: 'user-123', type: 'user' },
|
|
200
|
-
storage,
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
auditor.audit('user.created', {
|
|
204
|
-
userId: '456',
|
|
205
|
-
email: 'test@example.com',
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
const records1 = auditor.getRecords();
|
|
209
|
-
const records2 = auditor.getRecords();
|
|
210
|
-
|
|
211
|
-
expect(records1).not.toBe(records2);
|
|
212
|
-
expect(records1).toEqual(records2);
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
it('should return empty array when no records', () => {
|
|
216
|
-
const auditor = new DefaultAuditor<TestAuditAction>({
|
|
217
|
-
actor: { id: 'user-123', type: 'user' },
|
|
218
|
-
storage,
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
expect(auditor.getRecords()).toEqual([]);
|
|
222
|
-
});
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
describe('flush', () => {
|
|
226
|
-
it('should write records to storage', async () => {
|
|
227
|
-
const auditor = new DefaultAuditor<TestAuditAction>({
|
|
228
|
-
actor: { id: 'user-123', type: 'user' },
|
|
229
|
-
storage,
|
|
230
|
-
generateId: () => 'test-id',
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
auditor.audit('user.created', {
|
|
234
|
-
userId: '456',
|
|
235
|
-
email: 'test@example.com',
|
|
236
|
-
});
|
|
237
|
-
auditor.audit('order.placed', { orderId: 'order-789', total: 99.99 });
|
|
238
|
-
|
|
239
|
-
await auditor.flush();
|
|
240
|
-
|
|
241
|
-
expect(storage.write).toHaveBeenCalledTimes(1);
|
|
242
|
-
expect(writtenRecords).toHaveLength(2);
|
|
243
|
-
expect(writtenRecords[0].type).toBe('user.created');
|
|
244
|
-
expect(writtenRecords[1].type).toBe('order.placed');
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
it('should pass transaction to storage', async () => {
|
|
248
|
-
const auditor = new DefaultAuditor<TestAuditAction>({
|
|
249
|
-
actor: { id: 'user-123', type: 'user' },
|
|
250
|
-
storage,
|
|
251
|
-
});
|
|
252
|
-
|
|
253
|
-
auditor.audit('user.created', {
|
|
254
|
-
userId: '456',
|
|
255
|
-
email: 'test@example.com',
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
const mockTrx = { isTrx: true };
|
|
259
|
-
await auditor.flush(mockTrx);
|
|
260
|
-
|
|
261
|
-
expect(storage.write).toHaveBeenCalledWith(expect.any(Array), mockTrx);
|
|
262
|
-
});
|
|
263
|
-
|
|
264
|
-
it('should clear records after flush', async () => {
|
|
265
|
-
const auditor = new DefaultAuditor<TestAuditAction>({
|
|
266
|
-
actor: { id: 'user-123', type: 'user' },
|
|
267
|
-
storage,
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
auditor.audit('user.created', {
|
|
271
|
-
userId: '456',
|
|
272
|
-
email: 'test@example.com',
|
|
273
|
-
});
|
|
274
|
-
await auditor.flush();
|
|
275
|
-
|
|
276
|
-
expect(auditor.getRecords()).toEqual([]);
|
|
277
|
-
});
|
|
278
|
-
|
|
279
|
-
it('should do nothing when no records to flush', async () => {
|
|
280
|
-
const auditor = new DefaultAuditor<TestAuditAction>({
|
|
281
|
-
actor: { id: 'user-123', type: 'user' },
|
|
282
|
-
storage,
|
|
283
|
-
});
|
|
284
|
-
|
|
285
|
-
await auditor.flush();
|
|
286
|
-
|
|
287
|
-
expect(storage.write).not.toHaveBeenCalled();
|
|
288
|
-
});
|
|
289
|
-
|
|
290
|
-
it('should handle multiple flushes', async () => {
|
|
291
|
-
const auditor = new DefaultAuditor<TestAuditAction>({
|
|
292
|
-
actor: { id: 'user-123', type: 'user' },
|
|
293
|
-
storage,
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
auditor.audit('user.created', {
|
|
297
|
-
userId: '1',
|
|
298
|
-
email: 'first@example.com',
|
|
299
|
-
});
|
|
300
|
-
await auditor.flush();
|
|
301
|
-
|
|
302
|
-
auditor.audit('user.created', {
|
|
303
|
-
userId: '2',
|
|
304
|
-
email: 'second@example.com',
|
|
305
|
-
});
|
|
306
|
-
await auditor.flush();
|
|
307
|
-
|
|
308
|
-
expect(storage.write).toHaveBeenCalledTimes(2);
|
|
309
|
-
expect(writtenRecords).toHaveLength(2);
|
|
310
|
-
});
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
describe('clear', () => {
|
|
314
|
-
it('should remove all records without flushing', async () => {
|
|
315
|
-
const auditor = new DefaultAuditor<TestAuditAction>({
|
|
316
|
-
actor: { id: 'user-123', type: 'user' },
|
|
317
|
-
storage,
|
|
318
|
-
});
|
|
319
|
-
|
|
320
|
-
auditor.audit('user.created', {
|
|
321
|
-
userId: '456',
|
|
322
|
-
email: 'test@example.com',
|
|
323
|
-
});
|
|
324
|
-
auditor.audit('order.placed', { orderId: 'order-789', total: 99.99 });
|
|
325
|
-
|
|
326
|
-
auditor.clear();
|
|
327
|
-
|
|
328
|
-
expect(auditor.getRecords()).toEqual([]);
|
|
329
|
-
expect(storage.write).not.toHaveBeenCalled();
|
|
330
|
-
});
|
|
331
|
-
});
|
|
332
|
-
|
|
333
|
-
describe('type safety', () => {
|
|
334
|
-
it('should enforce correct payload types', () => {
|
|
335
|
-
const auditor = new DefaultAuditor<TestAuditAction>({
|
|
336
|
-
actor: { id: 'user-123', type: 'user' },
|
|
337
|
-
storage,
|
|
338
|
-
});
|
|
339
|
-
|
|
340
|
-
// These should compile without errors
|
|
341
|
-
auditor.audit('user.created', {
|
|
342
|
-
userId: '123',
|
|
343
|
-
email: 'test@example.com',
|
|
344
|
-
});
|
|
345
|
-
auditor.audit('user.updated', { userId: '123', changes: ['name'] });
|
|
346
|
-
auditor.audit('order.placed', { orderId: 'order-1', total: 50.0 });
|
|
347
|
-
|
|
348
|
-
// TypeScript would catch these at compile time:
|
|
349
|
-
// auditor.audit('user.created', { orderId: '123' }); // Wrong payload
|
|
350
|
-
// auditor.audit('unknown.type', {}); // Unknown type
|
|
351
|
-
|
|
352
|
-
expect(auditor.getRecords()).toHaveLength(3);
|
|
353
|
-
});
|
|
354
|
-
});
|
|
355
|
-
|
|
356
|
-
describe('setTransaction and getTransaction', () => {
|
|
357
|
-
it('should set and get transaction', () => {
|
|
358
|
-
const auditor = new DefaultAuditor<TestAuditAction>({
|
|
359
|
-
actor: { id: 'user-123', type: 'user' },
|
|
360
|
-
storage,
|
|
361
|
-
});
|
|
362
|
-
|
|
363
|
-
expect(auditor.getTransaction()).toBeUndefined();
|
|
364
|
-
|
|
365
|
-
const mockTrx = { isTrx: true };
|
|
366
|
-
auditor.setTransaction(mockTrx);
|
|
367
|
-
|
|
368
|
-
expect(auditor.getTransaction()).toBe(mockTrx);
|
|
369
|
-
});
|
|
370
|
-
|
|
371
|
-
it('should use stored transaction in flush when no explicit transaction', async () => {
|
|
372
|
-
const auditor = new DefaultAuditor<TestAuditAction>({
|
|
373
|
-
actor: { id: 'user-123', type: 'user' },
|
|
374
|
-
storage,
|
|
375
|
-
});
|
|
376
|
-
|
|
377
|
-
auditor.audit('user.created', {
|
|
378
|
-
userId: '456',
|
|
379
|
-
email: 'test@example.com',
|
|
380
|
-
});
|
|
381
|
-
|
|
382
|
-
const mockTrx = { isTrx: true };
|
|
383
|
-
auditor.setTransaction(mockTrx);
|
|
384
|
-
|
|
385
|
-
await auditor.flush();
|
|
386
|
-
|
|
387
|
-
expect(storage.write).toHaveBeenCalledWith(expect.any(Array), mockTrx);
|
|
388
|
-
});
|
|
389
|
-
|
|
390
|
-
it('should override stored transaction with explicit transaction in flush', async () => {
|
|
391
|
-
const auditor = new DefaultAuditor<TestAuditAction>({
|
|
392
|
-
actor: { id: 'user-123', type: 'user' },
|
|
393
|
-
storage,
|
|
394
|
-
});
|
|
395
|
-
|
|
396
|
-
auditor.audit('user.created', {
|
|
397
|
-
userId: '456',
|
|
398
|
-
email: 'test@example.com',
|
|
399
|
-
});
|
|
400
|
-
|
|
401
|
-
const storedTrx = { stored: true };
|
|
402
|
-
const explicitTrx = { explicit: true };
|
|
403
|
-
|
|
404
|
-
auditor.setTransaction(storedTrx);
|
|
405
|
-
await auditor.flush(explicitTrx);
|
|
406
|
-
|
|
407
|
-
expect(storage.write).toHaveBeenCalledWith(
|
|
408
|
-
expect.any(Array),
|
|
409
|
-
explicitTrx,
|
|
410
|
-
);
|
|
411
|
-
});
|
|
412
|
-
});
|
|
413
|
-
|
|
414
|
-
describe('addMetadata', () => {
|
|
415
|
-
it('should add metadata when none exists', () => {
|
|
416
|
-
const auditor = new DefaultAuditor<TestAuditAction>({
|
|
417
|
-
actor: { id: 'user-123', type: 'user' },
|
|
418
|
-
storage,
|
|
419
|
-
generateId: () => 'test-id',
|
|
420
|
-
});
|
|
421
|
-
|
|
422
|
-
auditor.addMetadata({ requestId: 'req-123', endpoint: '/users' });
|
|
423
|
-
auditor.audit('user.created', {
|
|
424
|
-
userId: '456',
|
|
425
|
-
email: 'test@example.com',
|
|
426
|
-
});
|
|
427
|
-
|
|
428
|
-
const records = auditor.getRecords();
|
|
429
|
-
expect(records[0].metadata).toEqual({
|
|
430
|
-
requestId: 'req-123',
|
|
431
|
-
endpoint: '/users',
|
|
432
|
-
});
|
|
433
|
-
});
|
|
434
|
-
|
|
435
|
-
it('should merge with existing metadata', () => {
|
|
436
|
-
const auditor = new DefaultAuditor<TestAuditAction>({
|
|
437
|
-
actor: { id: 'user-123', type: 'user' },
|
|
438
|
-
storage,
|
|
439
|
-
metadata: { requestId: 'req-123' },
|
|
440
|
-
generateId: () => 'test-id',
|
|
441
|
-
});
|
|
442
|
-
|
|
443
|
-
auditor.addMetadata({ endpoint: '/users', method: 'POST' });
|
|
444
|
-
auditor.audit('user.created', {
|
|
445
|
-
userId: '456',
|
|
446
|
-
email: 'test@example.com',
|
|
447
|
-
});
|
|
448
|
-
|
|
449
|
-
const records = auditor.getRecords();
|
|
450
|
-
expect(records[0].metadata).toEqual({
|
|
451
|
-
requestId: 'req-123',
|
|
452
|
-
endpoint: '/users',
|
|
453
|
-
method: 'POST',
|
|
454
|
-
});
|
|
455
|
-
});
|
|
456
|
-
|
|
457
|
-
it('should override existing metadata values', () => {
|
|
458
|
-
const auditor = new DefaultAuditor<TestAuditAction>({
|
|
459
|
-
actor: { id: 'user-123', type: 'user' },
|
|
460
|
-
storage,
|
|
461
|
-
metadata: { requestId: 'old-req', endpoint: '/old' },
|
|
462
|
-
generateId: () => 'test-id',
|
|
463
|
-
});
|
|
464
|
-
|
|
465
|
-
auditor.addMetadata({ endpoint: '/new', ip: '192.168.1.1' });
|
|
466
|
-
auditor.audit('user.created', {
|
|
467
|
-
userId: '456',
|
|
468
|
-
email: 'test@example.com',
|
|
469
|
-
});
|
|
470
|
-
|
|
471
|
-
const records = auditor.getRecords();
|
|
472
|
-
expect(records[0].metadata).toEqual({
|
|
473
|
-
requestId: 'old-req',
|
|
474
|
-
endpoint: '/new',
|
|
475
|
-
ip: '192.168.1.1',
|
|
476
|
-
});
|
|
477
|
-
});
|
|
478
|
-
|
|
479
|
-
it('should apply to all future audits', () => {
|
|
480
|
-
const auditor = new DefaultAuditor<TestAuditAction>({
|
|
481
|
-
actor: { id: 'user-123', type: 'user' },
|
|
482
|
-
storage,
|
|
483
|
-
generateId: () => 'test-id',
|
|
484
|
-
});
|
|
485
|
-
|
|
486
|
-
// Audit before adding metadata
|
|
487
|
-
auditor.audit('user.created', {
|
|
488
|
-
userId: '1',
|
|
489
|
-
email: 'first@example.com',
|
|
490
|
-
});
|
|
491
|
-
|
|
492
|
-
// Add metadata
|
|
493
|
-
auditor.addMetadata({ requestId: 'req-123' });
|
|
494
|
-
|
|
495
|
-
// Audit after adding metadata
|
|
496
|
-
auditor.audit('user.created', {
|
|
497
|
-
userId: '2',
|
|
498
|
-
email: 'second@example.com',
|
|
499
|
-
});
|
|
500
|
-
|
|
501
|
-
const records = auditor.getRecords();
|
|
502
|
-
expect(records[0].metadata).toBeUndefined();
|
|
503
|
-
expect(records[1].metadata).toEqual({ requestId: 'req-123' });
|
|
504
|
-
});
|
|
505
|
-
|
|
506
|
-
it('should allow multiple addMetadata calls', () => {
|
|
507
|
-
const auditor = new DefaultAuditor<TestAuditAction>({
|
|
508
|
-
actor: { id: 'user-123', type: 'user' },
|
|
509
|
-
storage,
|
|
510
|
-
generateId: () => 'test-id',
|
|
511
|
-
});
|
|
512
|
-
|
|
513
|
-
auditor.addMetadata({ requestId: 'req-123' });
|
|
514
|
-
auditor.addMetadata({ endpoint: '/users' });
|
|
515
|
-
auditor.addMetadata({ method: 'POST' });
|
|
516
|
-
auditor.audit('user.created', {
|
|
517
|
-
userId: '456',
|
|
518
|
-
email: 'test@example.com',
|
|
519
|
-
});
|
|
520
|
-
|
|
521
|
-
const records = auditor.getRecords();
|
|
522
|
-
expect(records[0].metadata).toEqual({
|
|
523
|
-
requestId: 'req-123',
|
|
524
|
-
endpoint: '/users',
|
|
525
|
-
method: 'POST',
|
|
526
|
-
});
|
|
527
|
-
});
|
|
528
|
-
});
|
|
529
|
-
});
|