@usebetterdev/audit-drizzle 0.4.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +858 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +404 -0
- package/dist/index.d.ts +404 -0
- package/dist/index.js +845 -0
- package/dist/index.js.map +1 -0
- package/package.json +62 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
import { AuditDatabaseAdapter, CaptureLogInput, AuditQueryFilters } from '@usebetterdev/audit-core';
|
|
2
|
+
import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
|
|
3
|
+
import { InferSelectModel, InferInsertModel, SQL } from 'drizzle-orm';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Minimal shape for a Drizzle pg database that supports insert and select operations.
|
|
7
|
+
* Duck-typed so callers don't need the full Drizzle generic types.
|
|
8
|
+
*/
|
|
9
|
+
interface DrizzlePgDatabase {
|
|
10
|
+
insert(table: unknown): {
|
|
11
|
+
values(data: unknown): {
|
|
12
|
+
execute(): Promise<unknown>;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
select(): unknown;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Creates an `AuditDatabaseAdapter` backed by a Drizzle pg database.
|
|
19
|
+
*
|
|
20
|
+
* Implements `writeLog` for inserting audit entries and `queryLogs` for
|
|
21
|
+
* filtered, cursor-paginated queries.
|
|
22
|
+
*/
|
|
23
|
+
declare function drizzleAuditAdapter(db: DrizzlePgDatabase): AuditDatabaseAdapter;
|
|
24
|
+
|
|
25
|
+
type MissingRecordIdBehavior = "warn" | "skip" | "throw";
|
|
26
|
+
interface AuditProxyOptions {
|
|
27
|
+
/**
|
|
28
|
+
* Fallback column name for extracting `recordId` when the primary key
|
|
29
|
+
* cannot be auto-detected from the Drizzle table schema. Defaults to `"id"`.
|
|
30
|
+
*
|
|
31
|
+
* In most cases this is not needed — the proxy reads `.primaryKey()` metadata
|
|
32
|
+
* from Drizzle column objects at runtime.
|
|
33
|
+
*/
|
|
34
|
+
primaryKey?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Called when audit capture fails. Falls back to `console.error` if not set.
|
|
37
|
+
*/
|
|
38
|
+
onError?: (error: unknown) => void;
|
|
39
|
+
/**
|
|
40
|
+
* What to do when the `recordId` cannot be determined.
|
|
41
|
+
*
|
|
42
|
+
* - `"warn"` (default) — log via `onError`, proceed with `recordId: "unknown"`
|
|
43
|
+
* - `"skip"` — silently drop the audit entry
|
|
44
|
+
* - `"throw"` — throw an error (caught by the proxy's outer error handler)
|
|
45
|
+
*/
|
|
46
|
+
onMissingRecordId?: MissingRecordIdBehavior;
|
|
47
|
+
/**
|
|
48
|
+
* Table names for which the pre-mutation SELECT should be skipped.
|
|
49
|
+
* Use this for high-throughput tables where the extra query is too expensive.
|
|
50
|
+
*/
|
|
51
|
+
skipBeforeState?: string[];
|
|
52
|
+
/**
|
|
53
|
+
* Safety limit: if the pre-mutation SELECT returns more rows than this,
|
|
54
|
+
* skip the before-state capture and warn. Defaults to 1000.
|
|
55
|
+
*/
|
|
56
|
+
maxBeforeStateRows?: number;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Wraps a Drizzle database (or transaction) with a transparent proxy that
|
|
60
|
+
* intercepts `db.insert()`, `db.update()`, `db.delete()` and calls
|
|
61
|
+
* `captureLog()` after each successful mutation.
|
|
62
|
+
*
|
|
63
|
+
* The proxy also intercepts `db.transaction()` so that the `tx` handle
|
|
64
|
+
* passed to the callback is itself proxied — this is what makes it work
|
|
65
|
+
* with `better-tenant`, where all user code runs inside a transaction.
|
|
66
|
+
*
|
|
67
|
+
* Filtering by audited tables is NOT done here — `captureLog` (from
|
|
68
|
+
* `betterAudit`) already skips tables not in `auditTables`, so there is
|
|
69
|
+
* a single source of truth for which tables are audited.
|
|
70
|
+
*/
|
|
71
|
+
declare function withAuditProxy<TDb extends {}>(db: TDb, captureLog: (input: CaptureLogInput) => Promise<void>, options?: AuditProxyOptions): TDb;
|
|
72
|
+
|
|
73
|
+
declare const auditLogs: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
74
|
+
name: "audit_logs";
|
|
75
|
+
schema: undefined;
|
|
76
|
+
columns: {
|
|
77
|
+
id: drizzle_orm_pg_core.PgColumn<{
|
|
78
|
+
name: "id";
|
|
79
|
+
tableName: "audit_logs";
|
|
80
|
+
dataType: "string";
|
|
81
|
+
columnType: "PgUUID";
|
|
82
|
+
data: string;
|
|
83
|
+
driverParam: string;
|
|
84
|
+
notNull: true;
|
|
85
|
+
hasDefault: true;
|
|
86
|
+
isPrimaryKey: true;
|
|
87
|
+
isAutoincrement: false;
|
|
88
|
+
hasRuntimeDefault: false;
|
|
89
|
+
enumValues: undefined;
|
|
90
|
+
baseColumn: never;
|
|
91
|
+
identity: undefined;
|
|
92
|
+
generated: undefined;
|
|
93
|
+
}, {}, {}>;
|
|
94
|
+
timestamp: drizzle_orm_pg_core.PgColumn<{
|
|
95
|
+
name: "timestamp";
|
|
96
|
+
tableName: "audit_logs";
|
|
97
|
+
dataType: "date";
|
|
98
|
+
columnType: "PgTimestamp";
|
|
99
|
+
data: Date;
|
|
100
|
+
driverParam: string;
|
|
101
|
+
notNull: true;
|
|
102
|
+
hasDefault: true;
|
|
103
|
+
isPrimaryKey: false;
|
|
104
|
+
isAutoincrement: false;
|
|
105
|
+
hasRuntimeDefault: false;
|
|
106
|
+
enumValues: undefined;
|
|
107
|
+
baseColumn: never;
|
|
108
|
+
identity: undefined;
|
|
109
|
+
generated: undefined;
|
|
110
|
+
}, {}, {}>;
|
|
111
|
+
tableName: drizzle_orm_pg_core.PgColumn<{
|
|
112
|
+
name: "table_name";
|
|
113
|
+
tableName: "audit_logs";
|
|
114
|
+
dataType: "string";
|
|
115
|
+
columnType: "PgText";
|
|
116
|
+
data: string;
|
|
117
|
+
driverParam: string;
|
|
118
|
+
notNull: true;
|
|
119
|
+
hasDefault: false;
|
|
120
|
+
isPrimaryKey: false;
|
|
121
|
+
isAutoincrement: false;
|
|
122
|
+
hasRuntimeDefault: false;
|
|
123
|
+
enumValues: [string, ...string[]];
|
|
124
|
+
baseColumn: never;
|
|
125
|
+
identity: undefined;
|
|
126
|
+
generated: undefined;
|
|
127
|
+
}, {}, {}>;
|
|
128
|
+
operation: drizzle_orm_pg_core.PgColumn<{
|
|
129
|
+
name: "operation";
|
|
130
|
+
tableName: "audit_logs";
|
|
131
|
+
dataType: "string";
|
|
132
|
+
columnType: "PgText";
|
|
133
|
+
data: string;
|
|
134
|
+
driverParam: string;
|
|
135
|
+
notNull: true;
|
|
136
|
+
hasDefault: false;
|
|
137
|
+
isPrimaryKey: false;
|
|
138
|
+
isAutoincrement: false;
|
|
139
|
+
hasRuntimeDefault: false;
|
|
140
|
+
enumValues: [string, ...string[]];
|
|
141
|
+
baseColumn: never;
|
|
142
|
+
identity: undefined;
|
|
143
|
+
generated: undefined;
|
|
144
|
+
}, {}, {}>;
|
|
145
|
+
recordId: drizzle_orm_pg_core.PgColumn<{
|
|
146
|
+
name: "record_id";
|
|
147
|
+
tableName: "audit_logs";
|
|
148
|
+
dataType: "string";
|
|
149
|
+
columnType: "PgText";
|
|
150
|
+
data: string;
|
|
151
|
+
driverParam: string;
|
|
152
|
+
notNull: true;
|
|
153
|
+
hasDefault: false;
|
|
154
|
+
isPrimaryKey: false;
|
|
155
|
+
isAutoincrement: false;
|
|
156
|
+
hasRuntimeDefault: false;
|
|
157
|
+
enumValues: [string, ...string[]];
|
|
158
|
+
baseColumn: never;
|
|
159
|
+
identity: undefined;
|
|
160
|
+
generated: undefined;
|
|
161
|
+
}, {}, {}>;
|
|
162
|
+
actorId: drizzle_orm_pg_core.PgColumn<{
|
|
163
|
+
name: "actor_id";
|
|
164
|
+
tableName: "audit_logs";
|
|
165
|
+
dataType: "string";
|
|
166
|
+
columnType: "PgText";
|
|
167
|
+
data: string;
|
|
168
|
+
driverParam: string;
|
|
169
|
+
notNull: false;
|
|
170
|
+
hasDefault: false;
|
|
171
|
+
isPrimaryKey: false;
|
|
172
|
+
isAutoincrement: false;
|
|
173
|
+
hasRuntimeDefault: false;
|
|
174
|
+
enumValues: [string, ...string[]];
|
|
175
|
+
baseColumn: never;
|
|
176
|
+
identity: undefined;
|
|
177
|
+
generated: undefined;
|
|
178
|
+
}, {}, {}>;
|
|
179
|
+
beforeData: drizzle_orm_pg_core.PgColumn<{
|
|
180
|
+
name: "before_data";
|
|
181
|
+
tableName: "audit_logs";
|
|
182
|
+
dataType: "json";
|
|
183
|
+
columnType: "PgJsonb";
|
|
184
|
+
data: unknown;
|
|
185
|
+
driverParam: unknown;
|
|
186
|
+
notNull: false;
|
|
187
|
+
hasDefault: false;
|
|
188
|
+
isPrimaryKey: false;
|
|
189
|
+
isAutoincrement: false;
|
|
190
|
+
hasRuntimeDefault: false;
|
|
191
|
+
enumValues: undefined;
|
|
192
|
+
baseColumn: never;
|
|
193
|
+
identity: undefined;
|
|
194
|
+
generated: undefined;
|
|
195
|
+
}, {}, {}>;
|
|
196
|
+
afterData: drizzle_orm_pg_core.PgColumn<{
|
|
197
|
+
name: "after_data";
|
|
198
|
+
tableName: "audit_logs";
|
|
199
|
+
dataType: "json";
|
|
200
|
+
columnType: "PgJsonb";
|
|
201
|
+
data: unknown;
|
|
202
|
+
driverParam: unknown;
|
|
203
|
+
notNull: false;
|
|
204
|
+
hasDefault: false;
|
|
205
|
+
isPrimaryKey: false;
|
|
206
|
+
isAutoincrement: false;
|
|
207
|
+
hasRuntimeDefault: false;
|
|
208
|
+
enumValues: undefined;
|
|
209
|
+
baseColumn: never;
|
|
210
|
+
identity: undefined;
|
|
211
|
+
generated: undefined;
|
|
212
|
+
}, {}, {}>;
|
|
213
|
+
diff: drizzle_orm_pg_core.PgColumn<{
|
|
214
|
+
name: "diff";
|
|
215
|
+
tableName: "audit_logs";
|
|
216
|
+
dataType: "json";
|
|
217
|
+
columnType: "PgJsonb";
|
|
218
|
+
data: unknown;
|
|
219
|
+
driverParam: unknown;
|
|
220
|
+
notNull: false;
|
|
221
|
+
hasDefault: false;
|
|
222
|
+
isPrimaryKey: false;
|
|
223
|
+
isAutoincrement: false;
|
|
224
|
+
hasRuntimeDefault: false;
|
|
225
|
+
enumValues: undefined;
|
|
226
|
+
baseColumn: never;
|
|
227
|
+
identity: undefined;
|
|
228
|
+
generated: undefined;
|
|
229
|
+
}, {}, {}>;
|
|
230
|
+
label: drizzle_orm_pg_core.PgColumn<{
|
|
231
|
+
name: "label";
|
|
232
|
+
tableName: "audit_logs";
|
|
233
|
+
dataType: "string";
|
|
234
|
+
columnType: "PgText";
|
|
235
|
+
data: string;
|
|
236
|
+
driverParam: string;
|
|
237
|
+
notNull: false;
|
|
238
|
+
hasDefault: false;
|
|
239
|
+
isPrimaryKey: false;
|
|
240
|
+
isAutoincrement: false;
|
|
241
|
+
hasRuntimeDefault: false;
|
|
242
|
+
enumValues: [string, ...string[]];
|
|
243
|
+
baseColumn: never;
|
|
244
|
+
identity: undefined;
|
|
245
|
+
generated: undefined;
|
|
246
|
+
}, {}, {}>;
|
|
247
|
+
description: drizzle_orm_pg_core.PgColumn<{
|
|
248
|
+
name: "description";
|
|
249
|
+
tableName: "audit_logs";
|
|
250
|
+
dataType: "string";
|
|
251
|
+
columnType: "PgText";
|
|
252
|
+
data: string;
|
|
253
|
+
driverParam: string;
|
|
254
|
+
notNull: false;
|
|
255
|
+
hasDefault: false;
|
|
256
|
+
isPrimaryKey: false;
|
|
257
|
+
isAutoincrement: false;
|
|
258
|
+
hasRuntimeDefault: false;
|
|
259
|
+
enumValues: [string, ...string[]];
|
|
260
|
+
baseColumn: never;
|
|
261
|
+
identity: undefined;
|
|
262
|
+
generated: undefined;
|
|
263
|
+
}, {}, {}>;
|
|
264
|
+
severity: drizzle_orm_pg_core.PgColumn<{
|
|
265
|
+
name: "severity";
|
|
266
|
+
tableName: "audit_logs";
|
|
267
|
+
dataType: "string";
|
|
268
|
+
columnType: "PgText";
|
|
269
|
+
data: string;
|
|
270
|
+
driverParam: string;
|
|
271
|
+
notNull: false;
|
|
272
|
+
hasDefault: false;
|
|
273
|
+
isPrimaryKey: false;
|
|
274
|
+
isAutoincrement: false;
|
|
275
|
+
hasRuntimeDefault: false;
|
|
276
|
+
enumValues: [string, ...string[]];
|
|
277
|
+
baseColumn: never;
|
|
278
|
+
identity: undefined;
|
|
279
|
+
generated: undefined;
|
|
280
|
+
}, {}, {}>;
|
|
281
|
+
compliance: drizzle_orm_pg_core.PgColumn<{
|
|
282
|
+
name: "compliance";
|
|
283
|
+
tableName: "audit_logs";
|
|
284
|
+
dataType: "json";
|
|
285
|
+
columnType: "PgJsonb";
|
|
286
|
+
data: unknown;
|
|
287
|
+
driverParam: unknown;
|
|
288
|
+
notNull: false;
|
|
289
|
+
hasDefault: false;
|
|
290
|
+
isPrimaryKey: false;
|
|
291
|
+
isAutoincrement: false;
|
|
292
|
+
hasRuntimeDefault: false;
|
|
293
|
+
enumValues: undefined;
|
|
294
|
+
baseColumn: never;
|
|
295
|
+
identity: undefined;
|
|
296
|
+
generated: undefined;
|
|
297
|
+
}, {}, {}>;
|
|
298
|
+
notify: drizzle_orm_pg_core.PgColumn<{
|
|
299
|
+
name: "notify";
|
|
300
|
+
tableName: "audit_logs";
|
|
301
|
+
dataType: "boolean";
|
|
302
|
+
columnType: "PgBoolean";
|
|
303
|
+
data: boolean;
|
|
304
|
+
driverParam: boolean;
|
|
305
|
+
notNull: false;
|
|
306
|
+
hasDefault: false;
|
|
307
|
+
isPrimaryKey: false;
|
|
308
|
+
isAutoincrement: false;
|
|
309
|
+
hasRuntimeDefault: false;
|
|
310
|
+
enumValues: undefined;
|
|
311
|
+
baseColumn: never;
|
|
312
|
+
identity: undefined;
|
|
313
|
+
generated: undefined;
|
|
314
|
+
}, {}, {}>;
|
|
315
|
+
reason: drizzle_orm_pg_core.PgColumn<{
|
|
316
|
+
name: "reason";
|
|
317
|
+
tableName: "audit_logs";
|
|
318
|
+
dataType: "string";
|
|
319
|
+
columnType: "PgText";
|
|
320
|
+
data: string;
|
|
321
|
+
driverParam: string;
|
|
322
|
+
notNull: false;
|
|
323
|
+
hasDefault: false;
|
|
324
|
+
isPrimaryKey: false;
|
|
325
|
+
isAutoincrement: false;
|
|
326
|
+
hasRuntimeDefault: false;
|
|
327
|
+
enumValues: [string, ...string[]];
|
|
328
|
+
baseColumn: never;
|
|
329
|
+
identity: undefined;
|
|
330
|
+
generated: undefined;
|
|
331
|
+
}, {}, {}>;
|
|
332
|
+
metadata: drizzle_orm_pg_core.PgColumn<{
|
|
333
|
+
name: "metadata";
|
|
334
|
+
tableName: "audit_logs";
|
|
335
|
+
dataType: "json";
|
|
336
|
+
columnType: "PgJsonb";
|
|
337
|
+
data: unknown;
|
|
338
|
+
driverParam: unknown;
|
|
339
|
+
notNull: false;
|
|
340
|
+
hasDefault: false;
|
|
341
|
+
isPrimaryKey: false;
|
|
342
|
+
isAutoincrement: false;
|
|
343
|
+
hasRuntimeDefault: false;
|
|
344
|
+
enumValues: undefined;
|
|
345
|
+
baseColumn: never;
|
|
346
|
+
identity: undefined;
|
|
347
|
+
generated: undefined;
|
|
348
|
+
}, {}, {}>;
|
|
349
|
+
redactedFields: drizzle_orm_pg_core.PgColumn<{
|
|
350
|
+
name: "redacted_fields";
|
|
351
|
+
tableName: "audit_logs";
|
|
352
|
+
dataType: "json";
|
|
353
|
+
columnType: "PgJsonb";
|
|
354
|
+
data: unknown;
|
|
355
|
+
driverParam: unknown;
|
|
356
|
+
notNull: false;
|
|
357
|
+
hasDefault: false;
|
|
358
|
+
isPrimaryKey: false;
|
|
359
|
+
isAutoincrement: false;
|
|
360
|
+
hasRuntimeDefault: false;
|
|
361
|
+
enumValues: undefined;
|
|
362
|
+
baseColumn: never;
|
|
363
|
+
identity: undefined;
|
|
364
|
+
generated: undefined;
|
|
365
|
+
}, {}, {}>;
|
|
366
|
+
};
|
|
367
|
+
dialect: "pg";
|
|
368
|
+
}>;
|
|
369
|
+
type AuditLogRow = InferSelectModel<typeof auditLogs>;
|
|
370
|
+
type NewAuditLogRow = InferInsertModel<typeof auditLogs>;
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Translates `AuditQueryFilters` into a Drizzle `SQL` condition (combined with AND).
|
|
374
|
+
* Returns `undefined` when no filters are active — callers should omit `.where()`.
|
|
375
|
+
*/
|
|
376
|
+
declare function buildWhereConditions(filters: AuditQueryFilters): SQL | undefined;
|
|
377
|
+
/**
|
|
378
|
+
* Builds a cursor-based pagination condition.
|
|
379
|
+
*
|
|
380
|
+
* Uses `(timestamp, id)` as the cursor key pair for stable ordering.
|
|
381
|
+
* - DESC: `(ts < cursor.ts) OR (ts = cursor.ts AND id < cursor.id)`
|
|
382
|
+
* - ASC: `(ts > cursor.ts) OR (ts = cursor.ts AND id > cursor.id)`
|
|
383
|
+
*/
|
|
384
|
+
declare function buildCursorCondition(cursor: string, sortOrder: "asc" | "desc"): SQL | undefined;
|
|
385
|
+
/**
|
|
386
|
+
* Returns the `orderBy` columns for the given sort direction.
|
|
387
|
+
* Default is descending (newest first).
|
|
388
|
+
*/
|
|
389
|
+
declare function buildOrderBy(sortOrder: "asc" | "desc"): SQL<unknown>[];
|
|
390
|
+
/**
|
|
391
|
+
* Encodes a cursor from a timestamp and id.
|
|
392
|
+
* Format: base64(JSON.stringify({ t: iso_string, i: id }))
|
|
393
|
+
*/
|
|
394
|
+
declare function encodeCursor(timestamp: Date, id: string): string;
|
|
395
|
+
/**
|
|
396
|
+
* Decodes an opaque cursor string back to timestamp + id.
|
|
397
|
+
* Throws on invalid input.
|
|
398
|
+
*/
|
|
399
|
+
declare function decodeCursor(cursor: string): {
|
|
400
|
+
timestamp: Date;
|
|
401
|
+
id: string;
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
export { type AuditLogRow, type AuditProxyOptions, type DrizzlePgDatabase, type MissingRecordIdBehavior, type NewAuditLogRow, auditLogs, buildCursorCondition, buildOrderBy, buildWhereConditions, decodeCursor, drizzleAuditAdapter, encodeCursor, withAuditProxy };
|