@geekmidas/audit 2.1.0 → 2.2.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/CHANGELOG.md +18 -0
- package/README.md +74 -2
- package/dist/{Auditor-_Dn2dp8d.d.mts → Auditor-CW2NrfHS.d.mts} +30 -2
- package/dist/Auditor-CW2NrfHS.d.mts.map +1 -0
- package/dist/{Auditor-sW7YAJIA.d.cts → Auditor-DpBHXIJM.d.cts} +30 -2
- package/dist/Auditor-DpBHXIJM.d.cts.map +1 -0
- package/dist/Auditor.d.cts +1 -1
- package/dist/Auditor.d.mts +1 -1
- package/dist/{DefaultAuditor-BSYMwojG.d.cts → DefaultAuditor-DlJ1ENfx.d.mts} +2 -2
- package/dist/{DefaultAuditor-BSYMwojG.d.cts.map → DefaultAuditor-DlJ1ENfx.d.mts.map} +1 -1
- package/dist/{DefaultAuditor-CYE-uAry.d.mts → DefaultAuditor-GRFI86N_.d.cts} +2 -2
- package/dist/{DefaultAuditor-CYE-uAry.d.mts.map → DefaultAuditor-GRFI86N_.d.cts.map} +1 -1
- package/dist/DefaultAuditor.d.cts +2 -2
- package/dist/DefaultAuditor.d.mts +2 -2
- package/dist/{cache-2VI80Vao.d.mts → cache-Bih6HxY6.d.cts} +2 -2
- package/dist/{cache-2VI80Vao.d.mts.map → cache-Bih6HxY6.d.cts.map} +1 -1
- package/dist/{cache-CDHqXqcl.d.cts → cache-wET57t6d.d.mts} +2 -2
- package/dist/{cache-CDHqXqcl.d.cts.map → cache-wET57t6d.d.mts.map} +1 -1
- package/dist/cache.d.cts +2 -2
- package/dist/cache.d.mts +2 -2
- package/dist/index.d.cts +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/knex.cjs +233 -0
- package/dist/knex.cjs.map +1 -0
- package/dist/knex.d.cts +178 -0
- package/dist/knex.d.cts.map +1 -0
- package/dist/knex.d.mts +178 -0
- package/dist/knex.d.mts.map +1 -0
- package/dist/knex.mjs +231 -0
- package/dist/knex.mjs.map +1 -0
- package/dist/kysely.cjs.map +1 -1
- package/dist/kysely.d.cts +1 -29
- package/dist/kysely.d.cts.map +1 -1
- package/dist/kysely.d.mts +1 -29
- package/dist/kysely.d.mts.map +1 -1
- package/dist/kysely.mjs.map +1 -1
- package/dist/memory.d.cts +2 -2
- package/dist/memory.d.mts +2 -2
- package/dist/storage.d.cts +2 -2
- package/dist/storage.d.mts +2 -2
- package/dist/types.d.cts +1 -1
- package/dist/types.d.mts +1 -1
- package/package.json +16 -1
- package/src/__tests__/KnexAuditStorage.integration.spec.ts +739 -0
- package/src/knex.ts +430 -0
- package/src/kysely.ts +6 -28
- package/src/storage.ts +28 -0
- package/dist/Auditor-_Dn2dp8d.d.mts.map +0 -1
- package/dist/Auditor-sW7YAJIA.d.cts.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# @geekmidas/audit
|
|
2
2
|
|
|
3
|
+
## 2.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- ✨ [#10](https://github.com/geekmidas/toolbox/pull/10) [`ae678fe`](https://github.com/geekmidas/toolbox/commit/ae678fe6fbc89307d052335468f1b955b306a604) Thanks [@geekmidas](https://github.com/geekmidas)! - Add Knex audit storage via a new `@geekmidas/audit/knex` entry point.
|
|
8
|
+
|
|
9
|
+
`KnexAuditStorage` mirrors `KyselyAuditStorage` — same config (`db`,
|
|
10
|
+
`tableName`, `databaseServiceName`, `autoId`), same `query()`/`count()`
|
|
11
|
+
filters, and the same transaction semantics. A `withAuditableTransaction`
|
|
12
|
+
helper is included; passing an existing transaction reuses it instead of
|
|
13
|
+
opening a savepoint, so audits roll back with the outer transaction.
|
|
14
|
+
|
|
15
|
+
Because it implements `withTransaction()`, `getDatabase()` and
|
|
16
|
+
`databaseServiceName`, endpoints wrap handlers and audit flushes in a single
|
|
17
|
+
transaction with Knex just as they do with Kysely.
|
|
18
|
+
|
|
19
|
+
`knex` is an optional peer dependency, so Kysely-only users are unaffected.
|
|
20
|
+
|
|
3
21
|
## 2.1.0
|
|
4
22
|
|
|
5
23
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
- **Type-safe Audit Actions**: Define audit types with TypeScript for compile-time safety
|
|
12
12
|
- **Transactional Support**: Flush audits atomically within database transactions
|
|
13
|
-
- **Flexible Storage**: Pluggable storage interface (Kysely, in-memory, cache)
|
|
13
|
+
- **Flexible Storage**: Pluggable storage interface (Kysely, Knex, in-memory, cache)
|
|
14
14
|
- **Actor Tracking**: Record who performed each action (users, services, systems)
|
|
15
15
|
- **Rich Metadata**: Attach request context, entity references, and custom data
|
|
16
16
|
- **Query Support**: Query audit logs with filters, pagination, and sorting
|
|
@@ -70,6 +70,17 @@ const storage = new KyselyAuditStorage<Database>({
|
|
|
70
70
|
});
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
+
**For Production (KnexAuditStorage):**
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
import { KnexAuditStorage } from '@geekmidas/audit/knex';
|
|
77
|
+
|
|
78
|
+
const storage = new KnexAuditStorage({
|
|
79
|
+
db: knexDb,
|
|
80
|
+
tableName: 'audit_logs',
|
|
81
|
+
});
|
|
82
|
+
```
|
|
83
|
+
|
|
73
84
|
### 3. Create an Auditor
|
|
74
85
|
|
|
75
86
|
```typescript
|
|
@@ -275,6 +286,67 @@ const count = await storage.count({
|
|
|
275
286
|
});
|
|
276
287
|
```
|
|
277
288
|
|
|
289
|
+
### `KnexAuditStorage`
|
|
290
|
+
|
|
291
|
+
Built-in Knex storage implementation. It mirrors `KyselyAuditStorage` — same
|
|
292
|
+
config, same `query()`/`count()` filters, same transaction semantics:
|
|
293
|
+
|
|
294
|
+
```typescript
|
|
295
|
+
import { KnexAuditStorage } from '@geekmidas/audit/knex';
|
|
296
|
+
|
|
297
|
+
const storage = new KnexAuditStorage({
|
|
298
|
+
db: knexDb,
|
|
299
|
+
tableName: 'audit_logs',
|
|
300
|
+
databaseServiceName: 'database', // Optional: for automatic transaction injection
|
|
301
|
+
autoId: false, // Optional: let database generate IDs
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
const audits = await storage.query({
|
|
305
|
+
type: 'user.created',
|
|
306
|
+
actorId: 'user-123',
|
|
307
|
+
from: new Date('2024-01-01'),
|
|
308
|
+
limit: 100,
|
|
309
|
+
orderBy: 'timestamp',
|
|
310
|
+
orderDirection: 'desc',
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
const count = await storage.count({
|
|
314
|
+
type: ['user.created', 'user.updated'],
|
|
315
|
+
actorId: 'user-123',
|
|
316
|
+
});
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
Column names are camelCase, matching the Kysely storage. If your database uses
|
|
320
|
+
snake_case columns, configure Knex with a case mapper:
|
|
321
|
+
|
|
322
|
+
```typescript
|
|
323
|
+
import { knexSnakeCaseMappers } from 'objection';
|
|
324
|
+
|
|
325
|
+
const knexDb = knex({
|
|
326
|
+
client: 'pg',
|
|
327
|
+
connection: process.env.DATABASE_URL,
|
|
328
|
+
...knexSnakeCaseMappers(),
|
|
329
|
+
});
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
Transactions work the same way as the Kysely storage:
|
|
333
|
+
|
|
334
|
+
```typescript
|
|
335
|
+
import { withAuditableTransaction } from '@geekmidas/audit/knex';
|
|
336
|
+
|
|
337
|
+
const user = await withAuditableTransaction(knexDb, auditor, async (trx) => {
|
|
338
|
+
const [user] = await trx('users').insert(data).returning('*');
|
|
339
|
+
|
|
340
|
+
auditor.audit('user.created', { userId: user.id, email: user.email });
|
|
341
|
+
|
|
342
|
+
return user;
|
|
343
|
+
});
|
|
344
|
+
// Audits are flushed inside the transaction, before it commits
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
Passing a transaction as the first argument reuses it instead of opening a
|
|
348
|
+
savepoint, so audits roll back with the outer transaction.
|
|
349
|
+
|
|
278
350
|
### `InMemoryAuditStorage`
|
|
279
351
|
|
|
280
352
|
Convenience wrapper around `CacheAuditStorage` with `InMemoryCache`. Useful for testing and development:
|
|
@@ -332,7 +404,7 @@ await storage.clear();
|
|
|
332
404
|
|
|
333
405
|
## Database Schema
|
|
334
406
|
|
|
335
|
-
Create an `audit_logs` table for `KyselyAuditStorage`:
|
|
407
|
+
Create an `audit_logs` table for `KyselyAuditStorage` or `KnexAuditStorage`:
|
|
336
408
|
|
|
337
409
|
```sql
|
|
338
410
|
CREATE TABLE audit_logs (
|
|
@@ -2,6 +2,34 @@ import { InferStandardSchema } from "@geekmidas/schema";
|
|
|
2
2
|
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
3
3
|
|
|
4
4
|
//#region src/storage.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Minimal interface for transaction-aware audit flushing.
|
|
8
|
+
* Use this when you need to flush audits within a database transaction.
|
|
9
|
+
*
|
|
10
|
+
* @template TTransaction - Transaction type (e.g., Kysely `Transaction`, Knex `Transaction`)
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import { withAuditableTransaction } from '@geekmidas/audit/kysely';
|
|
15
|
+
* import type { TransactionAwareAuditor } from '@geekmidas/audit/kysely';
|
|
16
|
+
*
|
|
17
|
+
* const result = await withAuditableTransaction(
|
|
18
|
+
* db,
|
|
19
|
+
* auditor as TransactionAwareAuditor<Transaction<DB>>,
|
|
20
|
+
* async (trx) => {
|
|
21
|
+
* // Your transactional operations
|
|
22
|
+
* return result;
|
|
23
|
+
* },
|
|
24
|
+
* );
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
interface TransactionAwareAuditor<TTransaction = unknown> {
|
|
28
|
+
/** Register the transaction with the auditor for use during flush */
|
|
29
|
+
setTransaction(trx: TTransaction): void;
|
|
30
|
+
/** Flush all pending audits, optionally within a transaction */
|
|
31
|
+
flush(trx?: TTransaction): Promise<void>;
|
|
32
|
+
}
|
|
5
33
|
/**
|
|
6
34
|
* Options for querying audit records.
|
|
7
35
|
*/
|
|
@@ -422,5 +450,5 @@ interface Auditor<TAuditAction extends AuditableAction<string, unknown> = Audita
|
|
|
422
450
|
//# sourceMappingURL=Auditor.d.ts.map
|
|
423
451
|
|
|
424
452
|
//#endregion
|
|
425
|
-
export { AuditActor, AuditMetadata, AuditOperation, AuditOptions, AuditQueryOptions, AuditRecord, AuditStorage, AuditableAction, Auditor, ExtractAuditPayload, ExtractAuditType, ExtractAuditorAction, ExtractStorageAuditAction, MappedAudit };
|
|
426
|
-
//# sourceMappingURL=Auditor-
|
|
453
|
+
export { AuditActor, AuditMetadata, AuditOperation, AuditOptions, AuditQueryOptions, AuditRecord, AuditStorage, AuditableAction, Auditor, ExtractAuditPayload, ExtractAuditType, ExtractAuditorAction, ExtractStorageAuditAction, MappedAudit, TransactionAwareAuditor };
|
|
454
|
+
//# sourceMappingURL=Auditor-CW2NrfHS.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Auditor-CW2NrfHS.d.mts","names":[],"sources":["../src/storage.ts","../src/types.ts","../src/Auditor.ts"],"sourcesContent":[],"mappings":"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"}
|
|
@@ -2,6 +2,34 @@ import { InferStandardSchema } from "@geekmidas/schema";
|
|
|
2
2
|
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
3
3
|
|
|
4
4
|
//#region src/storage.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Minimal interface for transaction-aware audit flushing.
|
|
8
|
+
* Use this when you need to flush audits within a database transaction.
|
|
9
|
+
*
|
|
10
|
+
* @template TTransaction - Transaction type (e.g., Kysely `Transaction`, Knex `Transaction`)
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import { withAuditableTransaction } from '@geekmidas/audit/kysely';
|
|
15
|
+
* import type { TransactionAwareAuditor } from '@geekmidas/audit/kysely';
|
|
16
|
+
*
|
|
17
|
+
* const result = await withAuditableTransaction(
|
|
18
|
+
* db,
|
|
19
|
+
* auditor as TransactionAwareAuditor<Transaction<DB>>,
|
|
20
|
+
* async (trx) => {
|
|
21
|
+
* // Your transactional operations
|
|
22
|
+
* return result;
|
|
23
|
+
* },
|
|
24
|
+
* );
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
interface TransactionAwareAuditor<TTransaction = unknown> {
|
|
28
|
+
/** Register the transaction with the auditor for use during flush */
|
|
29
|
+
setTransaction(trx: TTransaction): void;
|
|
30
|
+
/** Flush all pending audits, optionally within a transaction */
|
|
31
|
+
flush(trx?: TTransaction): Promise<void>;
|
|
32
|
+
}
|
|
5
33
|
/**
|
|
6
34
|
* Options for querying audit records.
|
|
7
35
|
*/
|
|
@@ -422,5 +450,5 @@ interface Auditor<TAuditAction extends AuditableAction<string, unknown> = Audita
|
|
|
422
450
|
//# sourceMappingURL=Auditor.d.ts.map
|
|
423
451
|
|
|
424
452
|
//#endregion
|
|
425
|
-
export { AuditActor, AuditMetadata, AuditOperation, AuditOptions, AuditQueryOptions, AuditRecord, AuditStorage, AuditableAction, Auditor, ExtractAuditPayload, ExtractAuditType, ExtractAuditorAction, ExtractStorageAuditAction, MappedAudit };
|
|
426
|
-
//# sourceMappingURL=Auditor-
|
|
453
|
+
export { AuditActor, AuditMetadata, AuditOperation, AuditOptions, AuditQueryOptions, AuditRecord, AuditStorage, AuditableAction, Auditor, ExtractAuditPayload, ExtractAuditType, ExtractAuditorAction, ExtractStorageAuditAction, MappedAudit, TransactionAwareAuditor };
|
|
454
|
+
//# sourceMappingURL=Auditor-DpBHXIJM.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Auditor-DpBHXIJM.d.cts","names":[],"sources":["../src/storage.ts","../src/types.ts","../src/Auditor.ts"],"sourcesContent":[],"mappings":"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"}
|
package/dist/Auditor.d.cts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Auditor } from "./Auditor-
|
|
1
|
+
import { Auditor } from "./Auditor-DpBHXIJM.cjs";
|
|
2
2
|
export { Auditor };
|
package/dist/Auditor.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Auditor } from "./Auditor-
|
|
1
|
+
import { Auditor } from "./Auditor-CW2NrfHS.mjs";
|
|
2
2
|
export { Auditor };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AuditActor, AuditMetadata, AuditOptions, AuditRecord, AuditStorage, AuditableAction, Auditor, ExtractAuditPayload, ExtractAuditType } from "./Auditor-
|
|
1
|
+
import { AuditActor, AuditMetadata, AuditOptions, AuditRecord, AuditStorage, AuditableAction, Auditor, ExtractAuditPayload, ExtractAuditType } from "./Auditor-CW2NrfHS.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/DefaultAuditor.d.ts
|
|
4
4
|
|
|
@@ -56,4 +56,4 @@ declare class DefaultAuditor<TAuditAction extends AuditableAction<string, unknow
|
|
|
56
56
|
//# sourceMappingURL=DefaultAuditor.d.ts.map
|
|
57
57
|
//#endregion
|
|
58
58
|
export { DefaultAuditor, DefaultAuditorConfig };
|
|
59
|
-
//# sourceMappingURL=DefaultAuditor-
|
|
59
|
+
//# sourceMappingURL=DefaultAuditor-DlJ1ENfx.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DefaultAuditor-
|
|
1
|
+
{"version":3,"file":"DefaultAuditor-DlJ1ENfx.d.mts","names":[],"sources":["../src/DefaultAuditor.ts"],"sourcesContent":[],"mappings":";;;;AAgBA;;;AAIU,UAJO,oBAAA,CAIP;EAAY;EAEG,KAAA,EAJjB,UAIiB;EA0BZ;EAAc,OAAA,EA5BjB,YA4BiB;EAAA;EACU,QAAoB,CAAA,EA3B7C,aA2B6C;EAAe;EAKvC,UAAE,CAAA,EAAA,GAAA,GAAA,MAAA;;;;;;;;;;;;;;;;;;;AAAf;;;;cANP,oCACS,mCAAmC,qEAK5C,QAAQ,cAAc;kBAElB;;;;;;sBAOI;sBAOA,iBAAiB,qBAC9B,gBACG,oBAAoB,cAAc,kBACjC;iBAmBI,KAAK;gBAcN;cAII,eAAe;sBAab;oBAIF;;wBAQI"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AuditActor, AuditMetadata, AuditOptions, AuditRecord, AuditStorage, AuditableAction, Auditor, ExtractAuditPayload, ExtractAuditType } from "./Auditor-
|
|
1
|
+
import { AuditActor, AuditMetadata, AuditOptions, AuditRecord, AuditStorage, AuditableAction, Auditor, ExtractAuditPayload, ExtractAuditType } from "./Auditor-DpBHXIJM.cjs";
|
|
2
2
|
|
|
3
3
|
//#region src/DefaultAuditor.d.ts
|
|
4
4
|
|
|
@@ -56,4 +56,4 @@ declare class DefaultAuditor<TAuditAction extends AuditableAction<string, unknow
|
|
|
56
56
|
//# sourceMappingURL=DefaultAuditor.d.ts.map
|
|
57
57
|
//#endregion
|
|
58
58
|
export { DefaultAuditor, DefaultAuditorConfig };
|
|
59
|
-
//# sourceMappingURL=DefaultAuditor-
|
|
59
|
+
//# sourceMappingURL=DefaultAuditor-GRFI86N_.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DefaultAuditor-
|
|
1
|
+
{"version":3,"file":"DefaultAuditor-GRFI86N_.d.cts","names":[],"sources":["../src/DefaultAuditor.ts"],"sourcesContent":[],"mappings":";;;;AAgBA;;;AAIU,UAJO,oBAAA,CAIP;EAAY;EAEG,KAAA,EAJjB,UAIiB;EA0BZ;EAAc,OAAA,EA5BjB,YA4BiB;EAAA;EACU,QAAoB,CAAA,EA3B7C,aA2B6C;EAAe;EAKvC,UAAE,CAAA,EAAA,GAAA,GAAA,MAAA;;;;;;;;;;;;;;;;;;;AAAf;;;;cANP,oCACS,mCAAmC,qEAK5C,QAAQ,cAAc;kBAElB;;;;;;sBAOI;sBAOA,iBAAiB,qBAC9B,gBACG,oBAAoB,cAAc,kBACjC;iBAmBI,KAAK;gBAcN;cAII,eAAe;sBAab;oBAIF;;wBAQI"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import "./Auditor-
|
|
2
|
-
import { DefaultAuditor, DefaultAuditorConfig } from "./DefaultAuditor-
|
|
1
|
+
import "./Auditor-DpBHXIJM.cjs";
|
|
2
|
+
import { DefaultAuditor, DefaultAuditorConfig } from "./DefaultAuditor-GRFI86N_.cjs";
|
|
3
3
|
export { DefaultAuditor, DefaultAuditorConfig };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import "./Auditor-
|
|
2
|
-
import { DefaultAuditor, DefaultAuditorConfig } from "./DefaultAuditor-
|
|
1
|
+
import "./Auditor-CW2NrfHS.mjs";
|
|
2
|
+
import { DefaultAuditor, DefaultAuditorConfig } from "./DefaultAuditor-DlJ1ENfx.mjs";
|
|
3
3
|
export { DefaultAuditor, DefaultAuditorConfig };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AuditQueryOptions, AuditRecord, AuditStorage, AuditableAction } from "./Auditor-
|
|
1
|
+
import { AuditQueryOptions, AuditRecord, AuditStorage, AuditableAction } from "./Auditor-DpBHXIJM.cjs";
|
|
2
2
|
import { Cache } from "@geekmidas/cache";
|
|
3
3
|
|
|
4
4
|
//#region src/cache.d.ts
|
|
@@ -93,4 +93,4 @@ declare class CacheAuditStorage<TAuditAction extends AuditableAction<string, unk
|
|
|
93
93
|
//# sourceMappingURL=cache.d.ts.map
|
|
94
94
|
//#endregion
|
|
95
95
|
export { CacheAuditStorage, CacheAuditStorageConfig };
|
|
96
|
-
//# sourceMappingURL=cache-
|
|
96
|
+
//# sourceMappingURL=cache-Bih6HxY6.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache-
|
|
1
|
+
{"version":3,"file":"cache-Bih6HxY6.d.cts","names":[],"sources":["../src/cache.ts"],"sourcesContent":[],"mappings":";;;;;;AAOA;AAqDA;AAA8B,UArDb,uBAAA,CAqDa;EAAA;EACO,KAAoB,EApDjD,KAoDiD;EAAe;;;;;EA+CjC,MAAW,CAAA,EAAA,MAAA;EAAW;;;;EA+BlD,GAQkB,CAAA,EAAA,MAAA;;;;AAlFJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cALZ,uCACS,mCAAmC,6CAI5C,aAAa;;;;;sBAOL;;;;iBAUC,gBAAgB;;;;iBA0BhB,oBAAoB,QAAQ;;;;iBA8BvC,KAAK,yCACZ;;;;gBAQiB,QAAQ;;;;WAOb"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AuditQueryOptions, AuditRecord, AuditStorage, AuditableAction } from "./Auditor-
|
|
1
|
+
import { AuditQueryOptions, AuditRecord, AuditStorage, AuditableAction } from "./Auditor-CW2NrfHS.mjs";
|
|
2
2
|
import { Cache } from "@geekmidas/cache";
|
|
3
3
|
|
|
4
4
|
//#region src/cache.d.ts
|
|
@@ -93,4 +93,4 @@ declare class CacheAuditStorage<TAuditAction extends AuditableAction<string, unk
|
|
|
93
93
|
//# sourceMappingURL=cache.d.ts.map
|
|
94
94
|
//#endregion
|
|
95
95
|
export { CacheAuditStorage, CacheAuditStorageConfig };
|
|
96
|
-
//# sourceMappingURL=cache-
|
|
96
|
+
//# sourceMappingURL=cache-wET57t6d.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache-
|
|
1
|
+
{"version":3,"file":"cache-wET57t6d.d.mts","names":[],"sources":["../src/cache.ts"],"sourcesContent":[],"mappings":";;;;;;AAOA;AAqDA;AAA8B,UArDb,uBAAA,CAqDa;EAAA;EACO,KAAoB,EApDjD,KAoDiD;EAAe;;;;;EA+CjC,MAAW,CAAA,EAAA,MAAA;EAAW;;;;EA+BlD,GAQkB,CAAA,EAAA,MAAA;;;;AAlFJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cALZ,uCACS,mCAAmC,6CAI5C,aAAa;;;;;sBAOL;;;;iBAUC,gBAAgB;;;;iBA0BhB,oBAAoB,QAAQ;;;;iBA8BvC,KAAK,yCACZ;;;;gBAQiB,QAAQ;;;;WAOb"}
|
package/dist/cache.d.cts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import "./Auditor-
|
|
2
|
-
import { CacheAuditStorage, CacheAuditStorageConfig } from "./cache-
|
|
1
|
+
import "./Auditor-DpBHXIJM.cjs";
|
|
2
|
+
import { CacheAuditStorage, CacheAuditStorageConfig } from "./cache-Bih6HxY6.cjs";
|
|
3
3
|
export { CacheAuditStorage, CacheAuditStorageConfig };
|
package/dist/cache.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import "./Auditor-
|
|
2
|
-
import { CacheAuditStorage, CacheAuditStorageConfig } from "./cache-
|
|
1
|
+
import "./Auditor-CW2NrfHS.mjs";
|
|
2
|
+
import { CacheAuditStorage, CacheAuditStorageConfig } from "./cache-wET57t6d.mjs";
|
|
3
3
|
export { CacheAuditStorage, CacheAuditStorageConfig };
|
package/dist/index.d.cts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { AuditActor, AuditMetadata, AuditOperation, AuditOptions, AuditQueryOptions, AuditRecord, AuditStorage, AuditableAction, Auditor, ExtractAuditPayload, ExtractAuditType, ExtractAuditorAction, ExtractStorageAuditAction, MappedAudit } from "./Auditor-
|
|
2
|
-
import { DefaultAuditor, DefaultAuditorConfig } from "./DefaultAuditor-
|
|
1
|
+
import { AuditActor, AuditMetadata, AuditOperation, AuditOptions, AuditQueryOptions, AuditRecord, AuditStorage, AuditableAction, Auditor, ExtractAuditPayload, ExtractAuditType, ExtractAuditorAction, ExtractStorageAuditAction, MappedAudit } from "./Auditor-DpBHXIJM.cjs";
|
|
2
|
+
import { DefaultAuditor, DefaultAuditorConfig } from "./DefaultAuditor-GRFI86N_.cjs";
|
|
3
3
|
export { AuditActor, AuditMetadata, AuditOperation, AuditOptions, AuditQueryOptions, AuditRecord, AuditStorage, AuditableAction, Auditor, DefaultAuditor, DefaultAuditorConfig, ExtractAuditPayload, ExtractAuditType, ExtractAuditorAction, ExtractStorageAuditAction, MappedAudit };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { AuditActor, AuditMetadata, AuditOperation, AuditOptions, AuditQueryOptions, AuditRecord, AuditStorage, AuditableAction, Auditor, ExtractAuditPayload, ExtractAuditType, ExtractAuditorAction, ExtractStorageAuditAction, MappedAudit } from "./Auditor-
|
|
2
|
-
import { DefaultAuditor, DefaultAuditorConfig } from "./DefaultAuditor-
|
|
1
|
+
import { AuditActor, AuditMetadata, AuditOperation, AuditOptions, AuditQueryOptions, AuditRecord, AuditStorage, AuditableAction, Auditor, ExtractAuditPayload, ExtractAuditType, ExtractAuditorAction, ExtractStorageAuditAction, MappedAudit } from "./Auditor-CW2NrfHS.mjs";
|
|
2
|
+
import { DefaultAuditor, DefaultAuditorConfig } from "./DefaultAuditor-DlJ1ENfx.mjs";
|
|
3
3
|
export { AuditActor, AuditMetadata, AuditOperation, AuditOptions, AuditQueryOptions, AuditRecord, AuditStorage, AuditableAction, Auditor, DefaultAuditor, DefaultAuditorConfig, ExtractAuditPayload, ExtractAuditType, ExtractAuditorAction, ExtractStorageAuditAction, MappedAudit };
|
package/dist/knex.cjs
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
const require_chunk = require('./chunk-CUT6urMc.cjs');
|
|
2
|
+
const nanoid = require_chunk.__toESM(require("nanoid"));
|
|
3
|
+
|
|
4
|
+
//#region src/knex.ts
|
|
5
|
+
/**
|
|
6
|
+
* Type guard for an active Knex transaction.
|
|
7
|
+
*
|
|
8
|
+
* Knex marks transaction instances with `isTransaction`, and a completed
|
|
9
|
+
* transaction can no longer be used, so a settled transaction is treated as a
|
|
10
|
+
* plain connection.
|
|
11
|
+
*/
|
|
12
|
+
function isActiveTransaction(connection) {
|
|
13
|
+
return connection.isTransaction === true && !connection.isCompleted();
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Execute a callback within a database transaction with automatic audit handling.
|
|
17
|
+
*
|
|
18
|
+
* This wrapper ensures that:
|
|
19
|
+
* 1. The transaction is automatically registered with the auditor
|
|
20
|
+
* 2. Manual audits (via `auditor.audit()`) are flushed BEFORE the transaction commits
|
|
21
|
+
* 3. If audit flush fails, the entire transaction rolls back
|
|
22
|
+
* 4. If the callback fails, audits are NOT written (atomic consistency)
|
|
23
|
+
*
|
|
24
|
+
* **Note:** Declarative audits (defined via `.audit([...])` on the endpoint builder)
|
|
25
|
+
* are processed AFTER the handler returns, so they run outside this transaction.
|
|
26
|
+
* If you need all audits to be atomic with your database operations, use manual
|
|
27
|
+
* audits via `auditor.audit()` inside this wrapper.
|
|
28
|
+
*
|
|
29
|
+
* @param db - Database connection (Knex instance or Transaction)
|
|
30
|
+
* @param auditor - Auditor instance that will receive the transaction
|
|
31
|
+
* @param cb - Callback to execute within the transaction
|
|
32
|
+
* @param settings - Optional transaction settings (isolation level)
|
|
33
|
+
* @returns The result of the callback
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* import { withAuditableTransaction } from '@geekmidas/audit/knex';
|
|
38
|
+
*
|
|
39
|
+
* const result = await withAuditableTransaction(
|
|
40
|
+
* services.database,
|
|
41
|
+
* auditor,
|
|
42
|
+
* async (trx) => {
|
|
43
|
+
* const [user] = await trx('users').insert(data).returning('*');
|
|
44
|
+
*
|
|
45
|
+
* // Manual audits are atomic with the transaction
|
|
46
|
+
* auditor.audit('user.created', { userId: user.id, email: user.email });
|
|
47
|
+
*
|
|
48
|
+
* return user;
|
|
49
|
+
* },
|
|
50
|
+
* );
|
|
51
|
+
* // Audits are automatically flushed inside the transaction before commit
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
async function withAuditableTransaction(db, auditor, cb, settings) {
|
|
55
|
+
const execute = async (trx) => {
|
|
56
|
+
auditor.setTransaction(trx);
|
|
57
|
+
const result = await cb(trx);
|
|
58
|
+
await auditor.flush(trx);
|
|
59
|
+
return result;
|
|
60
|
+
};
|
|
61
|
+
if (isActiveTransaction(db)) return execute(db);
|
|
62
|
+
return db.transaction(execute, settings);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Knex-based audit storage implementation.
|
|
66
|
+
* Stores audit records in a database table using Knex.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```typescript
|
|
70
|
+
* const storage = new KnexAuditStorage({
|
|
71
|
+
* db: knexDb,
|
|
72
|
+
* tableName: 'audit_logs',
|
|
73
|
+
* });
|
|
74
|
+
*
|
|
75
|
+
* const auditor = new DefaultAuditor({
|
|
76
|
+
* actor: { id: 'user-123', type: 'user' },
|
|
77
|
+
* storage,
|
|
78
|
+
* });
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
var KnexAuditStorage = class {
|
|
82
|
+
db;
|
|
83
|
+
tableName;
|
|
84
|
+
autoId;
|
|
85
|
+
databaseServiceName;
|
|
86
|
+
constructor(config) {
|
|
87
|
+
this.db = config.db;
|
|
88
|
+
this.tableName = config.tableName;
|
|
89
|
+
this.databaseServiceName = config.databaseServiceName;
|
|
90
|
+
this.autoId = config.autoId ?? false;
|
|
91
|
+
}
|
|
92
|
+
async write(records, trx) {
|
|
93
|
+
if (records.length === 0) return;
|
|
94
|
+
const db = trx ?? this.db;
|
|
95
|
+
const rows = records.map((record) => this.toRow(record));
|
|
96
|
+
await db(this.tableName).insert(rows);
|
|
97
|
+
}
|
|
98
|
+
async query(options) {
|
|
99
|
+
let query = this.db(this.tableName).select("*");
|
|
100
|
+
query = this.applyFilters(query, options);
|
|
101
|
+
const orderBy = options.orderBy ?? "timestamp";
|
|
102
|
+
const orderDirection = options.orderDirection ?? "desc";
|
|
103
|
+
query = query.orderBy(orderBy === "timestamp" ? "timestamp" : "type", orderDirection);
|
|
104
|
+
if (options.limit !== void 0) query = query.limit(options.limit);
|
|
105
|
+
if (options.offset !== void 0) query = query.offset(options.offset);
|
|
106
|
+
const rows = await query;
|
|
107
|
+
return rows.map((row) => this.fromRow(row));
|
|
108
|
+
}
|
|
109
|
+
async count(options) {
|
|
110
|
+
let query = this.db(this.tableName).count({ count: "id" });
|
|
111
|
+
query = this.applyFilters(query, options);
|
|
112
|
+
const result = await query.first();
|
|
113
|
+
return Number(result?.count ?? 0);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Get the Knex database instance for transactional operations.
|
|
117
|
+
* Used by endpoint adaptors to automatically wrap handlers in transactions.
|
|
118
|
+
*/
|
|
119
|
+
getDatabase() {
|
|
120
|
+
return this.db;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Execute a callback within a Knex transaction with automatic audit handling.
|
|
124
|
+
* The auditor is registered with the transaction and audits are flushed
|
|
125
|
+
* before the transaction commits.
|
|
126
|
+
*
|
|
127
|
+
* If the provided db connection is already a transaction, it will be reused
|
|
128
|
+
* instead of opening a savepoint.
|
|
129
|
+
*/
|
|
130
|
+
async withTransaction(auditor, callback, db) {
|
|
131
|
+
const connection = db ?? this.db;
|
|
132
|
+
if (isActiveTransaction(connection)) {
|
|
133
|
+
auditor.setTransaction(connection);
|
|
134
|
+
const result = await callback();
|
|
135
|
+
await auditor.flush(connection);
|
|
136
|
+
return result;
|
|
137
|
+
}
|
|
138
|
+
return connection.transaction(async (trx) => {
|
|
139
|
+
auditor.setTransaction(trx);
|
|
140
|
+
const result = await callback();
|
|
141
|
+
await auditor.flush(trx);
|
|
142
|
+
return result;
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
applyFilters(query, options) {
|
|
146
|
+
if (options.type !== void 0) if (Array.isArray(options.type)) query = query.whereIn("type", options.type);
|
|
147
|
+
else query = query.where("type", options.type);
|
|
148
|
+
if (options.entityId !== void 0) {
|
|
149
|
+
const entityId = typeof options.entityId === "string" ? options.entityId : JSON.stringify(options.entityId);
|
|
150
|
+
query = query.where("entityId", entityId);
|
|
151
|
+
}
|
|
152
|
+
if (options.table !== void 0) query = query.where("table", options.table);
|
|
153
|
+
if (options.actorId !== void 0) query = query.where("actorId", options.actorId);
|
|
154
|
+
if (options.from !== void 0) query = query.where("timestamp", ">=", options.from);
|
|
155
|
+
if (options.to !== void 0) query = query.where("timestamp", "<=", options.to);
|
|
156
|
+
return query;
|
|
157
|
+
}
|
|
158
|
+
toRow(record) {
|
|
159
|
+
const id = this.autoId ? void 0 : record.id || (0, nanoid.nanoid)();
|
|
160
|
+
return {
|
|
161
|
+
...id && { id },
|
|
162
|
+
type: record.type,
|
|
163
|
+
operation: record.operation,
|
|
164
|
+
table: record.table ?? null,
|
|
165
|
+
entityId: record.entityId === void 0 ? null : typeof record.entityId === "string" ? record.entityId : JSON.stringify(record.entityId),
|
|
166
|
+
oldValues: this.toJsonColumn(record.oldValues),
|
|
167
|
+
newValues: this.toJsonColumn(record.newValues),
|
|
168
|
+
payload: this.toJsonColumn(record.payload),
|
|
169
|
+
timestamp: record.timestamp,
|
|
170
|
+
actorId: record.actor?.id ?? null,
|
|
171
|
+
actorType: record.actor?.type ?? null,
|
|
172
|
+
actorData: record.actor !== void 0 ? this.toJsonColumn(this.getActorData(record.actor)) : null,
|
|
173
|
+
metadata: this.toJsonColumn(record.metadata)
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
fromRow(row) {
|
|
177
|
+
const actor = row.actorId !== null || row.actorType !== null ? {
|
|
178
|
+
id: row.actorId ?? void 0,
|
|
179
|
+
type: row.actorType ?? void 0,
|
|
180
|
+
...row.actorData ? this.parseJson(row.actorData) : {}
|
|
181
|
+
} : void 0;
|
|
182
|
+
return {
|
|
183
|
+
id: row.id,
|
|
184
|
+
type: row.type,
|
|
185
|
+
operation: row.operation,
|
|
186
|
+
table: row.table ?? void 0,
|
|
187
|
+
entityId: row.entityId ? this.parseEntityId(row.entityId) : void 0,
|
|
188
|
+
oldValues: row.oldValues ? this.parseJson(row.oldValues) : void 0,
|
|
189
|
+
newValues: row.newValues ? this.parseJson(row.newValues) : void 0,
|
|
190
|
+
payload: row.payload ? this.parseJson(row.payload) : void 0,
|
|
191
|
+
timestamp: row.timestamp,
|
|
192
|
+
actor,
|
|
193
|
+
metadata: row.metadata ? this.parseJson(row.metadata) : void 0
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Serialize a JSON value for insertion.
|
|
198
|
+
*
|
|
199
|
+
* Unlike Kysely, Knex has no per-column type information to tell a json/jsonb
|
|
200
|
+
* column from an object it should bind as a composite value, so plain objects
|
|
201
|
+
* are stringified before they reach the driver.
|
|
202
|
+
*/
|
|
203
|
+
toJsonColumn(value) {
|
|
204
|
+
if (value === void 0 || value === null) return null;
|
|
205
|
+
return JSON.stringify(value);
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Parse a JSON value that may already be parsed (e.g., from jsonb columns).
|
|
209
|
+
*/
|
|
210
|
+
parseJson(value) {
|
|
211
|
+
if (typeof value === "object" && value !== null) return value;
|
|
212
|
+
if (typeof value === "string") return JSON.parse(value);
|
|
213
|
+
return {};
|
|
214
|
+
}
|
|
215
|
+
getActorData(actor) {
|
|
216
|
+
const { id, type,...rest } = actor;
|
|
217
|
+
return rest;
|
|
218
|
+
}
|
|
219
|
+
parseEntityId(entityId) {
|
|
220
|
+
try {
|
|
221
|
+
const parsed = JSON.parse(entityId);
|
|
222
|
+
if (typeof parsed === "object" && parsed !== null) return parsed;
|
|
223
|
+
return entityId;
|
|
224
|
+
} catch {
|
|
225
|
+
return entityId;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
//#endregion
|
|
231
|
+
exports.KnexAuditStorage = KnexAuditStorage;
|
|
232
|
+
exports.withAuditableTransaction = withAuditableTransaction;
|
|
233
|
+
//# sourceMappingURL=knex.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"knex.cjs","names":["connection: DatabaseConnection","db: DatabaseConnection","auditor: TransactionAwareAuditor<Knex.Transaction>","cb: (trx: Knex.Transaction) => Promise<T>","settings?: TransactionSettings","trx: Knex.Transaction","config: KnexAuditStorageConfig","records: AuditRecord[]","trx?: unknown","options: AuditQueryOptions","row: AuditLogTable","options: Omit<AuditQueryOptions, 'limit' | 'offset'>","callback: () => Promise<T>","db?: DatabaseConnection","query: any","record: AuditRecord","value: unknown","actor: NonNullable<AuditRecord['actor']>","entityId: string"],"sources":["../src/knex.ts"],"sourcesContent":["import type { Knex } from 'knex';\nimport { nanoid } from 'nanoid';\nimport type {\n\tAuditQueryOptions,\n\tAuditStorage,\n\tTransactionAwareAuditor,\n} from './storage';\nimport type { AuditRecord } from './types';\n\nexport type { TransactionAwareAuditor };\n\nexport interface TransactionSettings {\n\tisolationLevel?: Knex.IsolationLevels;\n}\n\nexport type DatabaseConnection = Knex | Knex.Transaction;\n\n/**\n * Type guard for an active Knex transaction.\n *\n * Knex marks transaction instances with `isTransaction`, and a completed\n * transaction can no longer be used, so a settled transaction is treated as a\n * plain connection.\n */\nfunction isActiveTransaction(\n\tconnection: DatabaseConnection,\n): connection is Knex.Transaction {\n\treturn (\n\t\tconnection.isTransaction === true &&\n\t\t!(connection as Knex.Transaction).isCompleted()\n\t);\n}\n\n/**\n * Execute a callback within a database transaction with automatic audit handling.\n *\n * This wrapper ensures that:\n * 1. The transaction is automatically registered with the auditor\n * 2. Manual audits (via `auditor.audit()`) are flushed BEFORE the transaction commits\n * 3. If audit flush fails, the entire transaction rolls back\n * 4. If the callback fails, audits are NOT written (atomic consistency)\n *\n * **Note:** Declarative audits (defined via `.audit([...])` on the endpoint builder)\n * are processed AFTER the handler returns, so they run outside this transaction.\n * If you need all audits to be atomic with your database operations, use manual\n * audits via `auditor.audit()` inside this wrapper.\n *\n * @param db - Database connection (Knex instance or Transaction)\n * @param auditor - Auditor instance that will receive the transaction\n * @param cb - Callback to execute within the transaction\n * @param settings - Optional transaction settings (isolation level)\n * @returns The result of the callback\n *\n * @example\n * ```typescript\n * import { withAuditableTransaction } from '@geekmidas/audit/knex';\n *\n * const result = await withAuditableTransaction(\n * services.database,\n * auditor,\n * async (trx) => {\n * const [user] = await trx('users').insert(data).returning('*');\n *\n * // Manual audits are atomic with the transaction\n * auditor.audit('user.created', { userId: user.id, email: user.email });\n *\n * return user;\n * },\n * );\n * // Audits are automatically flushed inside the transaction before commit\n * ```\n */\nexport async function withAuditableTransaction<T>(\n\tdb: DatabaseConnection,\n\tauditor: TransactionAwareAuditor<Knex.Transaction>,\n\tcb: (trx: Knex.Transaction) => Promise<T>,\n\tsettings?: TransactionSettings,\n): Promise<T> {\n\tconst execute = async (trx: Knex.Transaction): Promise<T> => {\n\t\t// Register transaction with auditor\n\t\tauditor.setTransaction(trx);\n\n\t\t// Execute the callback\n\t\tconst result = await cb(trx);\n\n\t\t// Flush audits BEFORE transaction commits\n\t\t// If this fails, the transaction will roll back\n\t\tawait auditor.flush(trx);\n\n\t\treturn result;\n\t};\n\n\t// If already in a transaction, just run with it.\n\t// Knex would otherwise open a savepoint, which commits independently.\n\tif (isActiveTransaction(db)) {\n\t\treturn execute(db);\n\t}\n\n\treturn db.transaction(execute, settings);\n}\n\n/**\n * Shape of a row in the audit log table.\n * Use this to describe your audit table when declaring Knex table types.\n *\n * Property names are camelCase to match the Kysely storage. Pair this with\n * `knexSnakeCaseMappers()` if your database columns are snake_case.\n *\n * @example\n * ```typescript\n * import { knexSnakeCaseMappers } from 'objection';\n *\n * const db = knex({\n * client: 'pg',\n * connection: process.env.DATABASE_URL,\n * ...knexSnakeCaseMappers(),\n * });\n *\n * declare module 'knex/types/tables' {\n * interface Tables {\n * audit_logs: AuditLogTable;\n * }\n * }\n * ```\n */\nexport interface AuditLogTable {\n\tid: string;\n\ttype: string;\n\toperation: string;\n\ttable: string | null;\n\tentityId: string | null;\n\toldValues: unknown | null;\n\tnewValues: unknown | null;\n\tpayload: unknown | null;\n\ttimestamp: Date;\n\tactorId: string | null;\n\tactorType: string | null;\n\tactorData: unknown | null;\n\tmetadata: unknown | null;\n}\n\n/**\n * Insertable version of AuditLogTable where id is optional.\n * Use this when your database auto-generates IDs or when using the autoId option.\n */\nexport type InsertableAuditLogTable = Omit<AuditLogTable, 'id'> & {\n\tid?: string;\n};\n\n/**\n * Configuration for KnexAuditStorage.\n */\nexport interface KnexAuditStorageConfig {\n\t/** Knex database instance */\n\tdb: Knex;\n\t/** Table name for audit logs */\n\ttableName: string;\n\t/**\n\t * Service name of the database service.\n\t * When set, endpoint adaptors will automatically use the audit transaction as `db`\n\t * in the handler context if the endpoint's database service has the same name.\n\t */\n\tdatabaseServiceName?: string;\n\t/**\n\t * Let the database auto-generate IDs (e.g., via DEFAULT gen_random_uuid()).\n\t * When true, the ID field is omitted from inserts if not provided.\n\t * When false (default), IDs are generated using nanoid if not provided.\n\t * @default false\n\t */\n\tautoId?: boolean;\n}\n\n/**\n * Knex-based audit storage implementation.\n * Stores audit records in a database table using Knex.\n *\n * @example\n * ```typescript\n * const storage = new KnexAuditStorage({\n * db: knexDb,\n * tableName: 'audit_logs',\n * });\n *\n * const auditor = new DefaultAuditor({\n * actor: { id: 'user-123', type: 'user' },\n * storage,\n * });\n * ```\n */\nexport class KnexAuditStorage implements AuditStorage {\n\tprivate readonly db: Knex;\n\tprivate readonly tableName: string;\n\tprivate readonly autoId: boolean;\n\treadonly databaseServiceName?: string;\n\n\tconstructor(config: KnexAuditStorageConfig) {\n\t\tthis.db = config.db;\n\t\tthis.tableName = config.tableName;\n\t\tthis.databaseServiceName = config.databaseServiceName;\n\t\tthis.autoId = config.autoId ?? false;\n\t}\n\n\tasync write(records: AuditRecord[], trx?: unknown): Promise<void> {\n\t\tif (records.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst db = (trx as Knex.Transaction) ?? this.db;\n\t\tconst rows = records.map((record) => this.toRow(record));\n\n\t\tawait db(this.tableName).insert(rows);\n\t}\n\n\tasync query(options: AuditQueryOptions): Promise<AuditRecord[]> {\n\t\tlet query = this.db(this.tableName).select('*');\n\n\t\tquery = this.applyFilters(query, options);\n\n\t\t// Ordering\n\t\tconst orderBy = options.orderBy ?? 'timestamp';\n\t\tconst orderDirection = options.orderDirection ?? 'desc';\n\t\tquery = query.orderBy(\n\t\t\torderBy === 'timestamp' ? 'timestamp' : 'type',\n\t\t\torderDirection,\n\t\t);\n\n\t\t// Pagination\n\t\tif (options.limit !== undefined) {\n\t\t\tquery = query.limit(options.limit);\n\t\t}\n\t\tif (options.offset !== undefined) {\n\t\t\tquery = query.offset(options.offset);\n\t\t}\n\n\t\tconst rows = await query;\n\t\treturn rows.map((row: AuditLogTable) => this.fromRow(row));\n\t}\n\n\tasync count(\n\t\toptions: Omit<AuditQueryOptions, 'limit' | 'offset'>,\n\t): Promise<number> {\n\t\tlet query = this.db(this.tableName).count({ count: 'id' });\n\n\t\tquery = this.applyFilters(query, options);\n\n\t\tconst result = await query.first();\n\t\treturn Number(result?.count ?? 0);\n\t}\n\n\t/**\n\t * Get the Knex database instance for transactional operations.\n\t * Used by endpoint adaptors to automatically wrap handlers in transactions.\n\t */\n\tgetDatabase(): Knex {\n\t\treturn this.db;\n\t}\n\n\t/**\n\t * Execute a callback within a Knex transaction with automatic audit handling.\n\t * The auditor is registered with the transaction and audits are flushed\n\t * before the transaction commits.\n\t *\n\t * If the provided db connection is already a transaction, it will be reused\n\t * instead of opening a savepoint.\n\t */\n\tasync withTransaction<T>(\n\t\tauditor: TransactionAwareAuditor<Knex.Transaction>,\n\t\tcallback: () => Promise<T>,\n\t\tdb?: DatabaseConnection,\n\t): Promise<T> {\n\t\tconst connection = db ?? this.db;\n\n\t\t// If already in a transaction, reuse it\n\t\tif (isActiveTransaction(connection)) {\n\t\t\tauditor.setTransaction(connection);\n\t\t\tconst result = await callback();\n\t\t\tawait auditor.flush(connection);\n\t\t\treturn result;\n\t\t}\n\n\t\t// Create new transaction\n\t\treturn connection.transaction(async (trx) => {\n\t\t\tauditor.setTransaction(trx);\n\t\t\tconst result = await callback();\n\t\t\tawait auditor.flush(trx);\n\t\t\treturn result;\n\t\t});\n\t}\n\n\tprivate applyFilters(query: any, options: AuditQueryOptions): any {\n\t\t// Type filter\n\t\tif (options.type !== undefined) {\n\t\t\tif (Array.isArray(options.type)) {\n\t\t\t\tquery = query.whereIn('type', options.type);\n\t\t\t} else {\n\t\t\t\tquery = query.where('type', options.type);\n\t\t\t}\n\t\t}\n\n\t\t// Entity ID filter\n\t\tif (options.entityId !== undefined) {\n\t\t\tconst entityId =\n\t\t\t\ttypeof options.entityId === 'string'\n\t\t\t\t\t? options.entityId\n\t\t\t\t\t: JSON.stringify(options.entityId);\n\t\t\tquery = query.where('entityId', entityId);\n\t\t}\n\n\t\t// Table filter\n\t\tif (options.table !== undefined) {\n\t\t\tquery = query.where('table', options.table);\n\t\t}\n\n\t\t// Actor ID filter\n\t\tif (options.actorId !== undefined) {\n\t\t\tquery = query.where('actorId', options.actorId);\n\t\t}\n\n\t\t// Date range filters\n\t\tif (options.from !== undefined) {\n\t\t\tquery = query.where('timestamp', '>=', options.from);\n\t\t}\n\t\tif (options.to !== undefined) {\n\t\t\tquery = query.where('timestamp', '<=', options.to);\n\t\t}\n\n\t\treturn query;\n\t}\n\n\tprivate toRow(record: AuditRecord): AuditLogTable {\n\t\t// If autoId is true, let database generate ID (ignore record.id)\n\t\t// If autoId is false (default), use record.id or generate with nanoid\n\t\tconst id = this.autoId ? undefined : record.id || nanoid();\n\n\t\treturn {\n\t\t\t...(id && { id }),\n\t\t\ttype: record.type,\n\t\t\toperation: record.operation,\n\t\t\ttable: record.table ?? null,\n\t\t\tentityId:\n\t\t\t\trecord.entityId === undefined\n\t\t\t\t\t? null\n\t\t\t\t\t: typeof 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\toldValues: this.toJsonColumn(record.oldValues),\n\t\t\tnewValues: this.toJsonColumn(record.newValues),\n\t\t\tpayload: this.toJsonColumn(record.payload),\n\t\t\ttimestamp: record.timestamp,\n\t\t\tactorId: record.actor?.id ?? null,\n\t\t\tactorType: record.actor?.type ?? null,\n\t\t\tactorData:\n\t\t\t\trecord.actor !== undefined\n\t\t\t\t\t? this.toJsonColumn(this.getActorData(record.actor))\n\t\t\t\t\t: null,\n\t\t\tmetadata: this.toJsonColumn(record.metadata),\n\t\t} as AuditLogTable;\n\t}\n\n\tprivate fromRow(row: AuditLogTable): AuditRecord {\n\t\tconst actor =\n\t\t\trow.actorId !== null || row.actorType !== null\n\t\t\t\t? {\n\t\t\t\t\t\tid: row.actorId ?? undefined,\n\t\t\t\t\t\ttype: row.actorType ?? undefined,\n\t\t\t\t\t\t...(row.actorData ? this.parseJson(row.actorData) : {}),\n\t\t\t\t\t}\n\t\t\t\t: undefined;\n\n\t\treturn {\n\t\t\tid: row.id,\n\t\t\ttype: row.type,\n\t\t\toperation: row.operation as AuditRecord['operation'],\n\t\t\ttable: row.table ?? undefined,\n\t\t\tentityId: row.entityId ? this.parseEntityId(row.entityId) : undefined,\n\t\t\toldValues: row.oldValues ? this.parseJson(row.oldValues) : undefined,\n\t\t\tnewValues: row.newValues ? this.parseJson(row.newValues) : undefined,\n\t\t\tpayload: row.payload ? this.parseJson(row.payload) : undefined,\n\t\t\ttimestamp: row.timestamp,\n\t\t\tactor,\n\t\t\tmetadata: row.metadata ? this.parseJson(row.metadata) : undefined,\n\t\t};\n\t}\n\n\t/**\n\t * Serialize a JSON value for insertion.\n\t *\n\t * Unlike Kysely, Knex has no per-column type information to tell a json/jsonb\n\t * column from an object it should bind as a composite value, so plain objects\n\t * are stringified before they reach the driver.\n\t */\n\tprivate toJsonColumn(value: unknown): string | null {\n\t\tif (value === undefined || value === null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn JSON.stringify(value);\n\t}\n\n\t/**\n\t * Parse a JSON value that may already be parsed (e.g., from jsonb columns).\n\t */\n\tprivate parseJson(value: unknown): Record<string, unknown> {\n\t\tif (typeof value === 'object' && value !== null) {\n\t\t\treturn value as Record<string, unknown>;\n\t\t}\n\t\tif (typeof value === 'string') {\n\t\t\treturn JSON.parse(value);\n\t\t}\n\t\treturn {};\n\t}\n\n\tprivate getActorData(\n\t\tactor: NonNullable<AuditRecord['actor']>,\n\t): Record<string, unknown> {\n\t\tconst { id, type, ...rest } = actor;\n\t\treturn rest;\n\t}\n\n\tprivate parseEntityId(entityId: string): string | Record<string, unknown> {\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(entityId);\n\t\t\tif (typeof parsed === 'object' && parsed !== null) {\n\t\t\t\treturn parsed;\n\t\t\t}\n\t\t\treturn entityId;\n\t\t} catch {\n\t\t\treturn entityId;\n\t\t}\n\t}\n}\n"],"mappings":"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"}
|