@geekmidas/audit 0.1.0 → 0.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.
Files changed (55) hide show
  1. package/dist/{Auditor-DrR0ImvJ.d.cts → Auditor-_Dn2dp8d.d.mts} +4 -1
  2. package/dist/Auditor-_Dn2dp8d.d.mts.map +1 -0
  3. package/dist/{Auditor-Xf4Tp63p.d.mts → Auditor-sW7YAJIA.d.cts} +4 -1
  4. package/dist/Auditor-sW7YAJIA.d.cts.map +1 -0
  5. package/dist/Auditor.d.cts +1 -1
  6. package/dist/Auditor.d.mts +1 -1
  7. package/dist/DefaultAuditor-BAVnNmRh.mjs.map +1 -1
  8. package/dist/{DefaultAuditor-3Q1zVd1b.d.mts → DefaultAuditor-BSYMwojG.d.cts} +3 -2
  9. package/dist/DefaultAuditor-BSYMwojG.d.cts.map +1 -0
  10. package/dist/{DefaultAuditor-BaZa4u_m.d.cts → DefaultAuditor-CYE-uAry.d.mts} +3 -2
  11. package/dist/DefaultAuditor-CYE-uAry.d.mts.map +1 -0
  12. package/dist/DefaultAuditor-JbZ_BQfh.cjs.map +1 -1
  13. package/dist/DefaultAuditor.d.cts +2 -2
  14. package/dist/DefaultAuditor.d.mts +2 -2
  15. package/dist/{cache-0AjJ0zis.d.cts → cache-2VI80Vao.d.mts} +3 -2
  16. package/dist/cache-2VI80Vao.d.mts.map +1 -0
  17. package/dist/cache-BbIl31RL.mjs.map +1 -1
  18. package/dist/{cache-DBbGcCEq.d.mts → cache-CDHqXqcl.d.cts} +3 -2
  19. package/dist/cache-CDHqXqcl.d.cts.map +1 -0
  20. package/dist/cache-l7jAptBl.cjs.map +1 -1
  21. package/dist/cache.d.cts +2 -2
  22. package/dist/cache.d.mts +2 -2
  23. package/dist/index.d.cts +2 -2
  24. package/dist/index.d.mts +2 -2
  25. package/dist/kysely.cjs.map +1 -1
  26. package/dist/kysely.d.cts +2 -1
  27. package/dist/kysely.d.cts.map +1 -0
  28. package/dist/kysely.d.mts +2 -1
  29. package/dist/kysely.d.mts.map +1 -0
  30. package/dist/kysely.mjs.map +1 -1
  31. package/dist/memory.cjs.map +1 -1
  32. package/dist/memory.d.cts +3 -2
  33. package/dist/memory.d.cts.map +1 -0
  34. package/dist/memory.d.mts +3 -2
  35. package/dist/memory.d.mts.map +1 -0
  36. package/dist/memory.mjs.map +1 -1
  37. package/dist/storage.d.cts +1 -1
  38. package/dist/storage.d.mts +1 -1
  39. package/dist/types.d.cts +1 -1
  40. package/dist/types.d.mts +1 -1
  41. package/package.json +3 -3
  42. package/src/Auditor.ts +121 -121
  43. package/src/DefaultAuditor.ts +91 -91
  44. package/src/__tests__/CacheAuditStorage.spec.ts +375 -375
  45. package/src/__tests__/DefaultAuditor.spec.ts +520 -462
  46. package/src/__tests__/InMemoryAuditStorage.spec.ts +311 -311
  47. package/src/__tests__/KyselyAuditStorage.integration.spec.ts +496 -496
  48. package/src/__tests__/KyselyAuditStorage.spec.ts +433 -433
  49. package/src/cache.ts +179 -179
  50. package/src/index.ts +14 -15
  51. package/src/kysely.ts +292 -292
  52. package/src/memory.ts +11 -11
  53. package/src/storage.ts +131 -131
  54. package/src/types.ts +73 -74
  55. package/tsconfig.json +9 -0
package/src/storage.ts CHANGED
@@ -1,29 +1,29 @@
1
- import type { AuditRecord, AuditableAction } from './types';
1
+ import type { AuditableAction, AuditRecord } from './types';
2
2
 
3
3
  /**
4
4
  * Options for querying audit records.
5
5
  */
6
6
  export interface AuditQueryOptions {
7
- /** Filter by audit type */
8
- type?: string | string[];
9
- /** Filter by entity ID */
10
- entityId?: string | Record<string, unknown>;
11
- /** Filter by table name */
12
- table?: string;
13
- /** Filter by actor ID */
14
- actorId?: string;
15
- /** Filter by date range (start) */
16
- from?: Date;
17
- /** Filter by date range (end) */
18
- to?: Date;
19
- /** Limit number of results */
20
- limit?: number;
21
- /** Offset for pagination */
22
- offset?: number;
23
- /** Sort order */
24
- orderBy?: 'timestamp' | 'type';
25
- /** Sort direction */
26
- orderDirection?: 'asc' | 'desc';
7
+ /** Filter by audit type */
8
+ type?: string | string[];
9
+ /** Filter by entity ID */
10
+ entityId?: string | Record<string, unknown>;
11
+ /** Filter by table name */
12
+ table?: string;
13
+ /** Filter by actor ID */
14
+ actorId?: string;
15
+ /** Filter by date range (start) */
16
+ from?: Date;
17
+ /** Filter by date range (end) */
18
+ to?: Date;
19
+ /** Limit number of results */
20
+ limit?: number;
21
+ /** Offset for pagination */
22
+ offset?: number;
23
+ /** Sort order */
24
+ orderBy?: 'timestamp' | 'type';
25
+ /** Sort direction */
26
+ orderDirection?: 'asc' | 'desc';
27
27
  }
28
28
 
29
29
  /**
@@ -56,120 +56,120 @@ export interface AuditQueryOptions {
56
56
  * extracted by EndpointBuilder to provide type inference for `.audit([...])`.
57
57
  */
58
58
  export interface AuditStorage<
59
- TAuditAction extends AuditableAction<string, unknown> = AuditableAction<
60
- string,
61
- unknown
62
- >,
59
+ TAuditAction extends AuditableAction<string, unknown> = AuditableAction<
60
+ string,
61
+ unknown
62
+ >,
63
63
  > {
64
- /** @internal Type marker for extracting audit action type */
65
- readonly __auditActionType?: TAuditAction;
66
- /**
67
- * Write audit records to storage.
68
- * Called by Auditor.flush() to persist collected audits.
69
- *
70
- * @param records - The audit records to write
71
- * @param trx - Optional transaction context (for same-DB storage)
72
- */
73
- write(records: AuditRecord[], trx?: unknown): Promise<void>;
64
+ /** @internal Type marker for extracting audit action type */
65
+ readonly __auditActionType?: TAuditAction;
66
+ /**
67
+ * Write audit records to storage.
68
+ * Called by Auditor.flush() to persist collected audits.
69
+ *
70
+ * @param records - The audit records to write
71
+ * @param trx - Optional transaction context (for same-DB storage)
72
+ */
73
+ write(records: AuditRecord[], trx?: unknown): Promise<void>;
74
74
 
75
- /**
76
- * Optional: Query audit records for retrieval.
77
- * Implement this for audit log viewing/searching.
78
- *
79
- * @param options - Query filters and pagination
80
- * @returns Matching audit records
81
- */
82
- query?(options: AuditQueryOptions): Promise<AuditRecord[]>;
75
+ /**
76
+ * Optional: Query audit records for retrieval.
77
+ * Implement this for audit log viewing/searching.
78
+ *
79
+ * @param options - Query filters and pagination
80
+ * @returns Matching audit records
81
+ */
82
+ query?(options: AuditQueryOptions): Promise<AuditRecord[]>;
83
83
 
84
- /**
85
- * Optional: Count audit records matching filters.
86
- * Useful for pagination.
87
- *
88
- * @param options - Query filters (limit/offset ignored)
89
- * @returns Count of matching records
90
- */
91
- count?(options: Omit<AuditQueryOptions, 'limit' | 'offset'>): Promise<number>;
84
+ /**
85
+ * Optional: Count audit records matching filters.
86
+ * Useful for pagination.
87
+ *
88
+ * @param options - Query filters (limit/offset ignored)
89
+ * @returns Count of matching records
90
+ */
91
+ count?(options: Omit<AuditQueryOptions, 'limit' | 'offset'>): Promise<number>;
92
92
 
93
- /**
94
- * Optional: Get the database connection for transactional audit writes.
95
- * When implemented, the endpoint adaptor can automatically wrap handlers
96
- * in a transaction, ensuring audits are atomic with other database operations.
97
- *
98
- * @returns Database connection (e.g., Kysely instance)
99
- *
100
- * @example
101
- * ```typescript
102
- * class KyselyAuditStorage implements AuditStorage {
103
- * constructor(private db: Kysely<DB>) {}
104
- *
105
- * getDatabase() {
106
- * return this.db;
107
- * }
108
- * }
109
- * ```
110
- */
111
- getDatabase?(): unknown;
93
+ /**
94
+ * Optional: Get the database connection for transactional audit writes.
95
+ * When implemented, the endpoint adaptor can automatically wrap handlers
96
+ * in a transaction, ensuring audits are atomic with other database operations.
97
+ *
98
+ * @returns Database connection (e.g., Kysely instance)
99
+ *
100
+ * @example
101
+ * ```typescript
102
+ * class KyselyAuditStorage implements AuditStorage {
103
+ * constructor(private db: Kysely<DB>) {}
104
+ *
105
+ * getDatabase() {
106
+ * return this.db;
107
+ * }
108
+ * }
109
+ * ```
110
+ */
111
+ getDatabase?(): unknown;
112
112
 
113
- /**
114
- * Optional: The service name of the database service used by this storage.
115
- * When set, endpoint adaptors will automatically use the audit transaction as `db`
116
- * in the handler context if the endpoint's database service has the same name.
117
- *
118
- * @example
119
- * ```typescript
120
- * const storage = new KyselyAuditStorage({
121
- * db,
122
- * tableName: 'audit_logs',
123
- * databaseServiceName: 'database', // Matches databaseService.serviceName
124
- * });
125
- * ```
126
- */
127
- databaseServiceName?: string;
113
+ /**
114
+ * Optional: The service name of the database service used by this storage.
115
+ * When set, endpoint adaptors will automatically use the audit transaction as `db`
116
+ * in the handler context if the endpoint's database service has the same name.
117
+ *
118
+ * @example
119
+ * ```typescript
120
+ * const storage = new KyselyAuditStorage({
121
+ * db,
122
+ * tableName: 'audit_logs',
123
+ * databaseServiceName: 'database', // Matches databaseService.serviceName
124
+ * });
125
+ * ```
126
+ */
127
+ databaseServiceName?: string;
128
128
 
129
- /**
130
- * Optional: Execute a callback within a database transaction.
131
- * The auditor is registered with the transaction and audits are flushed
132
- * before the transaction commits.
133
- *
134
- * This is database-agnostic - each storage implementation provides its own
135
- * transaction handling based on the underlying database.
136
- *
137
- * If a database connection is provided, it should be used instead of the
138
- * storage's internal connection. If the connection is already a transaction,
139
- * it should be reused instead of creating a nested transaction.
140
- *
141
- * @param auditor - The auditor to register with the transaction
142
- * @param callback - The callback to execute within the transaction
143
- * @param db - Optional database connection (may already be a transaction)
144
- * @returns The result of the callback
145
- *
146
- * @example
147
- * ```typescript
148
- * // KyselyAuditStorage implementation
149
- * async withTransaction<T>(auditor, callback, db) {
150
- * const connection = db ?? this.db;
151
- * if (connection.isTransaction) {
152
- * // Reuse existing transaction
153
- * auditor.setTransaction(connection);
154
- * const result = await callback();
155
- * await auditor.flush(connection);
156
- * return result;
157
- * }
158
- * return connection.transaction().execute(async (trx) => {
159
- * auditor.setTransaction(trx);
160
- * const result = await callback();
161
- * await auditor.flush(trx);
162
- * return result;
163
- * });
164
- * }
165
- * ```
166
- */
167
- withTransaction?<T>(
168
- auditor: {
169
- setTransaction(trx: unknown): void;
170
- flush(trx?: unknown): Promise<void>;
171
- },
172
- callback: () => Promise<T>,
173
- db?: unknown,
174
- ): Promise<T>;
129
+ /**
130
+ * Optional: Execute a callback within a database transaction.
131
+ * The auditor is registered with the transaction and audits are flushed
132
+ * before the transaction commits.
133
+ *
134
+ * This is database-agnostic - each storage implementation provides its own
135
+ * transaction handling based on the underlying database.
136
+ *
137
+ * If a database connection is provided, it should be used instead of the
138
+ * storage's internal connection. If the connection is already a transaction,
139
+ * it should be reused instead of creating a nested transaction.
140
+ *
141
+ * @param auditor - The auditor to register with the transaction
142
+ * @param callback - The callback to execute within the transaction
143
+ * @param db - Optional database connection (may already be a transaction)
144
+ * @returns The result of the callback
145
+ *
146
+ * @example
147
+ * ```typescript
148
+ * // KyselyAuditStorage implementation
149
+ * async withTransaction<T>(auditor, callback, db) {
150
+ * const connection = db ?? this.db;
151
+ * if (connection.isTransaction) {
152
+ * // Reuse existing transaction
153
+ * auditor.setTransaction(connection);
154
+ * const result = await callback();
155
+ * await auditor.flush(connection);
156
+ * return result;
157
+ * }
158
+ * return connection.transaction().execute(async (trx) => {
159
+ * auditor.setTransaction(trx);
160
+ * const result = await callback();
161
+ * await auditor.flush(trx);
162
+ * return result;
163
+ * });
164
+ * }
165
+ * ```
166
+ */
167
+ withTransaction?<T>(
168
+ auditor: {
169
+ setTransaction(trx: unknown): void;
170
+ flush(trx?: unknown): Promise<void>;
171
+ },
172
+ callback: () => Promise<T>,
173
+ db?: unknown,
174
+ ): Promise<T>;
175
175
  }
package/src/types.ts CHANGED
@@ -17,22 +17,22 @@ import type { StandardSchemaV1 } from '@standard-schema/spec';
17
17
  * ```
18
18
  */
19
19
  export type AuditableAction<TType extends string, TPayload = unknown> = {
20
- type: TType;
21
- payload: TPayload;
20
+ type: TType;
21
+ payload: TPayload;
22
22
  };
23
23
 
24
24
  /**
25
25
  * Extract the type string from an AuditableAction union.
26
26
  */
27
27
  export type ExtractAuditType<T extends AuditableAction<string, unknown>> =
28
- T extends AuditableAction<infer TType, unknown> ? TType : never;
28
+ T extends AuditableAction<infer TType, unknown> ? TType : never;
29
29
 
30
30
  /**
31
31
  * Extract the payload for a specific audit type from an AuditableAction union.
32
32
  */
33
33
  export type ExtractAuditPayload<
34
- T extends AuditableAction<string, unknown>,
35
- TType extends ExtractAuditType<T>,
34
+ T extends AuditableAction<string, unknown>,
35
+ TType extends ExtractAuditType<T>,
36
36
  > = T extends AuditableAction<TType, infer TPayload> ? TPayload : never;
37
37
 
38
38
  /**
@@ -44,74 +44,74 @@ export type AuditOperation = 'INSERT' | 'UPDATE' | 'DELETE' | 'CUSTOM';
44
44
  * Represents the actor who performed an audited action.
45
45
  */
46
46
  export interface AuditActor {
47
- /** Unique identifier for the actor (user ID, service ID, etc.) */
48
- id?: string;
49
- /** Type of actor ('user', 'system', 'service', etc.) */
50
- type?: string;
51
- /** Additional actor properties */
52
- [key: string]: unknown;
47
+ /** Unique identifier for the actor (user ID, service ID, etc.) */
48
+ id?: string;
49
+ /** Type of actor ('user', 'system', 'service', etc.) */
50
+ type?: string;
51
+ /** Additional actor properties */
52
+ [key: string]: unknown;
53
53
  }
54
54
 
55
55
  /**
56
56
  * Metadata associated with an audit record.
57
57
  */
58
58
  export interface AuditMetadata {
59
- /** Request correlation ID */
60
- requestId?: string;
61
- /** Which endpoint was called */
62
- endpoint?: string;
63
- /** HTTP method */
64
- method?: string;
65
- /** Client IP address */
66
- ip?: string;
67
- /** Client user agent */
68
- userAgent?: string;
69
- /** Additional metadata */
70
- [key: string]: unknown;
59
+ /** Request correlation ID */
60
+ requestId?: string;
61
+ /** Which endpoint was called */
62
+ endpoint?: string;
63
+ /** HTTP method */
64
+ method?: string;
65
+ /** Client IP address */
66
+ ip?: string;
67
+ /** Client user agent */
68
+ userAgent?: string;
69
+ /** Additional metadata */
70
+ [key: string]: unknown;
71
71
  }
72
72
 
73
73
  /**
74
74
  * A complete audit record representing a tracked action.
75
75
  */
76
76
  export interface AuditRecord<TPayload = unknown> {
77
- /** Unique identifier for this audit record */
78
- id: string;
79
- /** Audit type (e.g., 'user.created', 'order.placed') */
80
- type: string;
81
- /** Operation type for database audits */
82
- operation: AuditOperation;
83
- /** Database table name (for database operations) */
84
- table?: string;
85
- /** Entity primary key(s) */
86
- entityId?: string | Record<string, unknown>;
87
- /** Previous state (for UPDATE/DELETE) */
88
- oldValues?: Record<string, unknown>;
89
- /** New state (for INSERT/UPDATE) */
90
- newValues?: Record<string, unknown>;
91
- /** Custom payload (for CUSTOM operations) */
92
- payload?: TPayload;
93
- /** When the audit was recorded */
94
- timestamp: Date;
95
- /** Who performed the action */
96
- actor?: AuditActor;
97
- /** Request context */
98
- metadata?: AuditMetadata;
77
+ /** Unique identifier for this audit record */
78
+ id: string;
79
+ /** Audit type (e.g., 'user.created', 'order.placed') */
80
+ type: string;
81
+ /** Operation type for database audits */
82
+ operation: AuditOperation;
83
+ /** Database table name (for database operations) */
84
+ table?: string;
85
+ /** Entity primary key(s) */
86
+ entityId?: string | Record<string, unknown>;
87
+ /** Previous state (for UPDATE/DELETE) */
88
+ oldValues?: Record<string, unknown>;
89
+ /** New state (for INSERT/UPDATE) */
90
+ newValues?: Record<string, unknown>;
91
+ /** Custom payload (for CUSTOM operations) */
92
+ payload?: TPayload;
93
+ /** When the audit was recorded */
94
+ timestamp: Date;
95
+ /** Who performed the action */
96
+ actor?: AuditActor;
97
+ /** Request context */
98
+ metadata?: AuditMetadata;
99
99
  }
100
100
 
101
101
  /**
102
102
  * Options for manual audit calls.
103
103
  */
104
104
  export interface AuditOptions {
105
- /** Entity primary key(s) for easier querying */
106
- entityId?: string | Record<string, unknown>;
107
- /** Database table name */
108
- table?: string;
109
- /** Operation type (defaults to 'CUSTOM') */
110
- operation?: AuditOperation;
111
- /** Previous state */
112
- oldValues?: Record<string, unknown>;
113
- /** New state */
114
- newValues?: Record<string, unknown>;
105
+ /** Entity primary key(s) for easier querying */
106
+ entityId?: string | Record<string, unknown>;
107
+ /** Database table name */
108
+ table?: string;
109
+ /** Operation type (defaults to 'CUSTOM') */
110
+ operation?: AuditOperation;
111
+ /** Previous state */
112
+ oldValues?: Record<string, unknown>;
113
+ /** New state */
114
+ newValues?: Record<string, unknown>;
115
115
  }
116
116
 
117
117
  /**
@@ -119,23 +119,23 @@ export interface AuditOptions {
119
119
  * Similar to MappedEvent in @geekmidas/events.
120
120
  */
121
121
  export interface MappedAudit<
122
- TAuditAction extends AuditableAction<string, unknown>,
123
- TOutput extends StandardSchemaV1 | undefined = undefined,
122
+ TAuditAction extends AuditableAction<string, unknown>,
123
+ TOutput extends StandardSchemaV1 | undefined = undefined,
124
124
  > {
125
- /** The audit type - must be a valid type from the AuditableAction union */
126
- type: ExtractAuditType<TAuditAction>;
127
- /** Function to extract payload from the response */
128
- payload: (
129
- response: InferStandardSchema<TOutput>,
130
- ) => ExtractAuditPayload<TAuditAction, ExtractAuditType<TAuditAction>>;
131
- /** Optional condition - only audit if this returns true */
132
- when?: (response: InferStandardSchema<TOutput>) => boolean;
133
- /** Optional entity ID extractor for easier querying */
134
- entityId?: (
135
- response: InferStandardSchema<TOutput>,
136
- ) => string | Record<string, unknown>;
137
- /** Optional table name for database association */
138
- table?: string;
125
+ /** The audit type - must be a valid type from the AuditableAction union */
126
+ type: ExtractAuditType<TAuditAction>;
127
+ /** Function to extract payload from the response */
128
+ payload: (
129
+ response: InferStandardSchema<TOutput>,
130
+ ) => ExtractAuditPayload<TAuditAction, ExtractAuditType<TAuditAction>>;
131
+ /** Optional condition - only audit if this returns true */
132
+ when?: (response: InferStandardSchema<TOutput>) => boolean;
133
+ /** Optional entity ID extractor for easier querying */
134
+ entityId?: (
135
+ response: InferStandardSchema<TOutput>,
136
+ ) => string | Record<string, unknown>;
137
+ /** Optional table name for database association */
138
+ table?: string;
139
139
  }
140
140
 
141
141
  /**
@@ -146,9 +146,8 @@ export type ExtractAuditorAction<T> = T extends Auditor<infer A> ? A : never;
146
146
  /**
147
147
  * Extract the AuditableAction type from an AuditStorage.
148
148
  */
149
- export type ExtractStorageAuditAction<T> = T extends AuditStorage<infer A>
150
- ? A
151
- : AuditableAction<string, unknown>;
149
+ export type ExtractStorageAuditAction<T> =
150
+ T extends AuditStorage<infer A> ? A : AuditableAction<string, unknown>;
152
151
 
153
152
  // Forward declaration for Auditor type extraction
154
153
  import type { Auditor } from './Auditor';
package/tsconfig.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "outDir": "./dist",
5
+ "rootDir": "./src",
6
+ "composite": true
7
+ },
8
+ "include": ["src/**/*"]
9
+ }