@willyim/drizzle-audit 0.4.0 → 0.5.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 +52 -16
- package/dist/src/d1/audit-log-schema.d.ts +3 -2
- package/dist/src/d1/audit-log-schema.d.ts.map +1 -1
- package/dist/src/d1/audit-log-schema.js +14 -4
- package/dist/src/d1/index.d.ts +2 -1
- package/dist/src/d1/index.d.ts.map +1 -1
- package/dist/src/d1/runtime.d.ts +11 -11
- package/dist/src/d1/runtime.d.ts.map +1 -1
- package/dist/src/d1/runtime.js +26 -9
- package/dist/src/d1/sql.d.ts +2 -2
- package/dist/src/d1/sql.d.ts.map +1 -1
- package/dist/src/d1/sql.js +61 -29
- package/dist/src/d1/types.d.ts +10 -2
- package/dist/src/d1/types.d.ts.map +1 -1
- package/dist/src/d1-runtime/with-audit.d.ts +3 -2
- package/dist/src/d1-runtime/with-audit.d.ts.map +1 -1
- package/dist/src/d1-runtime/with-audit.js +12 -7
- package/dist/src/index.d.ts +2 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/postgres/audit-log-schema.d.ts +3 -2
- package/dist/src/postgres/audit-log-schema.d.ts.map +1 -1
- package/dist/src/postgres/audit-log-schema.js +14 -4
- package/dist/src/postgres/index.d.ts +3 -2
- package/dist/src/postgres/index.d.ts.map +1 -1
- package/dist/src/postgres/index.js +1 -1
- package/dist/src/postgres/runtime.d.ts +6 -8
- package/dist/src/postgres/runtime.d.ts.map +1 -1
- package/dist/src/postgres/runtime.js +15 -3
- package/dist/src/postgres/sql.d.ts +10 -7
- package/dist/src/postgres/sql.d.ts.map +1 -1
- package/dist/src/postgres/sql.js +72 -50
- package/dist/src/postgres/types.d.ts +10 -2
- package/dist/src/postgres/types.d.ts.map +1 -1
- package/dist/test/d1.integration.test.js +71 -4
- package/dist/test/sqlite.integration.test.js +65 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -120,47 +120,62 @@ sqlite.exec(createAttachD1AuditTriggersSqlWithColumns([
|
|
|
120
120
|
]))
|
|
121
121
|
```
|
|
122
122
|
|
|
123
|
-
##
|
|
123
|
+
## Context Columns
|
|
124
124
|
|
|
125
|
-
|
|
125
|
+
Beyond `user_id`, you can declare arbitrary extra context columns (e.g.
|
|
126
|
+
`workspace_id`, `tenant_id`, `request_id`). Each is an extra `TEXT` column on
|
|
127
|
+
`audit_logs`, populated at write-time from a named runtime context value (a
|
|
128
|
+
Postgres session GUC, or a `_audit_context` KV row in D1).
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
type AuditContextColumn = {
|
|
132
|
+
column: string // audit table column (TEXT, nullable)
|
|
133
|
+
sessionKey?: string // Postgres GUC the trigger reads — default `app.${column}`
|
|
134
|
+
// D1: the _audit_context key — default `${column}`
|
|
135
|
+
index?: boolean // create an index on the column — default true
|
|
136
|
+
}
|
|
137
|
+
```
|
|
126
138
|
|
|
127
139
|
### Postgres
|
|
128
140
|
|
|
129
141
|
```ts
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
142
|
+
const contextColumns = [{ column: "workspace_id" }, { column: "tenant_id" }]
|
|
143
|
+
|
|
144
|
+
createAuditInstallSql({ contextColumns })
|
|
145
|
+
export const auditLogs = pgAuditLogTable({ contextColumns })
|
|
133
146
|
|
|
134
|
-
// Pass
|
|
147
|
+
// Pass context at runtime (GUC name → value)
|
|
135
148
|
await withAuditedTransaction(
|
|
136
149
|
db, userId, async (tx) => { /* ... */ },
|
|
137
150
|
"app.user_id",
|
|
138
|
-
{
|
|
151
|
+
{ context: { "app.workspace_id": "ws_1", "app.tenant_id": "t_1" } },
|
|
139
152
|
)
|
|
140
153
|
```
|
|
141
154
|
|
|
142
|
-
To add
|
|
155
|
+
To add context columns to an existing install, use
|
|
156
|
+
`createAuditAddContextColumnsSql({ contextColumns })` — it adds each column and
|
|
157
|
+
regenerates the trigger over the full set. Pass the complete list of columns the
|
|
158
|
+
table should have.
|
|
143
159
|
|
|
144
160
|
### D1 Runtime
|
|
145
161
|
|
|
146
162
|
```ts
|
|
147
163
|
const audit = withAudit(db, auditLogs, {
|
|
148
164
|
userId: "user_1",
|
|
149
|
-
|
|
165
|
+
context: { workspace_id: "ws_1", tenant_id: "t_1" },
|
|
150
166
|
})
|
|
151
167
|
```
|
|
152
168
|
|
|
153
169
|
### D1 Triggers
|
|
154
170
|
|
|
155
171
|
```ts
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
)
|
|
172
|
+
const contextColumns = [{ column: "workspace_id" }, { column: "tenant_id" }]
|
|
173
|
+
|
|
174
|
+
createD1AuditInstallSql({ contextColumns })
|
|
175
|
+
createAttachD1AuditTriggersSql([{ table: "users" }], { contextColumns })
|
|
161
176
|
|
|
162
177
|
withD1AuditedTransaction(db, "user_1", (tx) => { /* ... */ }, {
|
|
163
|
-
|
|
178
|
+
context: { workspace_id: "ws_1", tenant_id: "t_1" },
|
|
164
179
|
})
|
|
165
180
|
```
|
|
166
181
|
|
|
@@ -202,7 +217,7 @@ export function createAuditSql() {
|
|
|
202
217
|
| `createAuditInstallSql(options?)` | SQL to create the audit table, indexes, and trigger function |
|
|
203
218
|
| `createAttachAuditTriggerSql(target, options?)` | SQL to attach audit trigger to one table |
|
|
204
219
|
| `createAttachAuditTriggersSql(targets, options?)` | Same, for multiple tables |
|
|
205
|
-
| `
|
|
220
|
+
| `createAuditAddContextColumnsSql(options)` | SQL to add context columns + regenerate trigger on existing install |
|
|
206
221
|
| `setAuditContext(db, actorId, contextKey?, options?)` | Set actor context in current transaction |
|
|
207
222
|
| `withAuditedTransaction(db, actorId, callback, contextKey?, options?)` | Transaction wrapper with actor context |
|
|
208
223
|
|
|
@@ -318,6 +333,27 @@ CREATE TABLE audit_logs (
|
|
|
318
333
|
| **Bypass risk** | Low (DB-level) | Medium (must use wrapper) | Low (DB-level) |
|
|
319
334
|
| **Best for** | Postgres apps | D1/Cloudflare Workers | SQLite apps needing DB-level guarantees |
|
|
320
335
|
|
|
336
|
+
## Migrating from 0.2.x → 0.3.0
|
|
337
|
+
|
|
338
|
+
The `workspace_id`-specific options were removed in favor of the generic
|
|
339
|
+
[Context Columns](#context-columns) API. Mechanical replacements:
|
|
340
|
+
|
|
341
|
+
| Removed | Replacement |
|
|
342
|
+
|---|---|
|
|
343
|
+
| `pgAuditLogTable({ workspaceIdColumn: "workspace_id" })` | `pgAuditLogTable({ contextColumns: [{ column: "workspace_id" }] })` |
|
|
344
|
+
| `d1AuditLogTable({ workspaceIdColumn: "workspace_id" })` | `d1AuditLogTable({ contextColumns: [{ column: "workspace_id" }] })` |
|
|
345
|
+
| `createAuditInstallSql({ workspaceIdColumn: "workspace_id" })` | `createAuditInstallSql({ contextColumns: [{ column: "workspace_id" }] })` |
|
|
346
|
+
| `createD1AuditInstallSql({ workspaceIdColumn })` | `createD1AuditInstallSql({ contextColumns: [{ column }] })` |
|
|
347
|
+
| `createAttachD1AuditTriggersSql(targets, { workspaceIdColumn })` | `createAttachD1AuditTriggersSql(targets, { contextColumns: [{ column }] })` |
|
|
348
|
+
| `createAuditAddWorkspaceColumnSql(options)` | `createAuditAddContextColumnsSql({ contextColumns: [...] })` |
|
|
349
|
+
| Postgres runtime `{ workspaceId: v }` | `{ context: { "app.workspace_id": v } }` |
|
|
350
|
+
| Postgres runtime `{ workspaceId: v, workspaceContextKey: "app.tenant_id" }` | `{ context: { "app.tenant_id": v } }` |
|
|
351
|
+
| D1 runtime `{ workspaceId: v }` | `{ context: { workspace_id: v } }` |
|
|
352
|
+
| `withAudit(db, table, { userId, workspaceId: v })` | `withAudit(db, table, { userId, context: { workspace_id: v } })` |
|
|
353
|
+
|
|
354
|
+
The on-disk column name (`workspace_id`) is unchanged, so no data migration is
|
|
355
|
+
needed — only call sites change.
|
|
356
|
+
|
|
321
357
|
## License
|
|
322
358
|
|
|
323
359
|
MIT
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import type { AuditContextColumn } from "./types.js";
|
|
1
2
|
export type D1AuditLogTableOptions = {
|
|
2
|
-
/**
|
|
3
|
-
|
|
3
|
+
/** Extra context columns to include in the table definition, matching the install. */
|
|
4
|
+
contextColumns?: AuditContextColumn[];
|
|
4
5
|
};
|
|
5
6
|
export declare function d1AuditLogTable(options?: D1AuditLogTableOptions): import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
|
|
6
7
|
name: "audit_logs";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit-log-schema.d.ts","sourceRoot":"","sources":["../../../src/d1/audit-log-schema.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,sBAAsB,GAAG;IACnC,
|
|
1
|
+
{"version":3,"file":"audit-log-schema.d.ts","sourceRoot":"","sources":["../../../src/d1/audit-log-schema.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAEpD,MAAM,MAAM,sBAAsB,GAAG;IACnC,sFAAsF;IACtF,cAAc,CAAC,EAAE,kBAAkB,EAAE,CAAA;CACtC,CAAA;AAiBD,wBAAgB,eAAe,CAAC,OAAO,CAAC,EAAE,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuB/D;AAED,wBAAgB,mBAAmB,CAAC,OAAO,CAAC,EAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAMtE"}
|
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
import { index, integer, sqliteTable, text, } from "drizzle-orm/sqlite-core";
|
|
2
|
+
function resolveColumns(options) {
|
|
3
|
+
const columns = [];
|
|
4
|
+
const seen = new Set();
|
|
5
|
+
for (const entry of options?.contextColumns ?? []) {
|
|
6
|
+
const column = entry.column?.trim();
|
|
7
|
+
if (column && !seen.has(column)) {
|
|
8
|
+
seen.add(column);
|
|
9
|
+
columns.push(column);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
return columns;
|
|
13
|
+
}
|
|
2
14
|
export function d1AuditLogTable(options) {
|
|
3
|
-
const
|
|
15
|
+
const contextColumns = resolveColumns(options);
|
|
4
16
|
const columns = {
|
|
5
17
|
id: integer("id").primaryKey({ autoIncrement: true }),
|
|
6
18
|
table_name: text("table_name").notNull(),
|
|
7
19
|
operation: text("operation").notNull(),
|
|
8
20
|
row_id: text("row_id"),
|
|
9
21
|
user_id: text("user_id"),
|
|
10
|
-
...(
|
|
11
|
-
? { [workspaceIdColumn]: text(workspaceIdColumn) }
|
|
12
|
-
: {}),
|
|
22
|
+
...Object.fromEntries(contextColumns.map((c) => [c, text(c)])),
|
|
13
23
|
old_data: text("old_data"),
|
|
14
24
|
new_data: text("new_data"),
|
|
15
25
|
created_at: text("created_at").notNull().default("(datetime('now'))"),
|
package/dist/src/d1/index.d.ts
CHANGED
|
@@ -3,5 +3,6 @@ export type { D1AuditLogTableOptions } from "./audit-log-schema.js";
|
|
|
3
3
|
export { createAttachD1AuditTriggerSql, createAttachD1AuditTriggersSql, createAttachD1AuditTriggerSqlWithColumns, createAttachD1AuditTriggersSqlWithColumns, createD1AuditInstallSql, } from "./sql.js";
|
|
4
4
|
export type { D1AuditTriggerTargetWithColumns } from "./sql.js";
|
|
5
5
|
export { clearD1AuditContext, setD1AuditContext, withD1AuditedTransaction, } from "./runtime.js";
|
|
6
|
-
export type {
|
|
6
|
+
export type { D1AuditContextOptions } from "./runtime.js";
|
|
7
|
+
export type { AuditContextColumn, D1AuditInstallOptions, D1AuditSqlExecutor, D1AuditTriggerTarget, } from "./types.js";
|
|
7
8
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/d1/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAC5E,YAAY,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAA;AACnE,OAAO,EACL,6BAA6B,EAC7B,8BAA8B,EAC9B,wCAAwC,EACxC,yCAAyC,EACzC,uBAAuB,GACxB,MAAM,UAAU,CAAA;AACjB,YAAY,EAAE,+BAA+B,EAAE,MAAM,UAAU,CAAA;AAC/D,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,wBAAwB,GACzB,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/d1/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAC5E,YAAY,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAA;AACnE,OAAO,EACL,6BAA6B,EAC7B,8BAA8B,EAC9B,wCAAwC,EACxC,yCAAyC,EACzC,uBAAuB,GACxB,MAAM,UAAU,CAAA;AACjB,YAAY,EAAE,+BAA+B,EAAE,MAAM,UAAU,CAAA;AAC/D,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,wBAAwB,GACzB,MAAM,cAAc,CAAA;AACrB,YAAY,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AAEzD,YAAY,EACV,kBAAkB,EAClB,qBAAqB,EACrB,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,YAAY,CAAA"}
|
package/dist/src/d1/runtime.d.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import type { D1AuditSqlExecutor } from "./types.js";
|
|
2
|
+
export type D1AuditContextOptions = {
|
|
3
|
+
/** Map of context key → value written as KV rows the triggers read. */
|
|
4
|
+
context?: Record<string, string>;
|
|
5
|
+
contextTable?: string;
|
|
6
|
+
};
|
|
2
7
|
/**
|
|
3
8
|
* Sets the audit context for the current transaction by writing to the
|
|
4
9
|
* _audit_context table. Must be called inside a transaction before any
|
|
@@ -6,17 +11,15 @@ import type { D1AuditSqlExecutor } from "./types.js";
|
|
|
6
11
|
*
|
|
7
12
|
* D1/SQLite has no session variables, so triggers read context from this table.
|
|
8
13
|
*/
|
|
9
|
-
export declare function setD1AuditContext(db: D1AuditSqlExecutor, actorId: string, options?:
|
|
10
|
-
workspaceId?: string;
|
|
11
|
-
contextTable?: string;
|
|
12
|
-
}): Promise<unknown> | undefined;
|
|
14
|
+
export declare function setD1AuditContext(db: D1AuditSqlExecutor, actorId: string, options?: D1AuditContextOptions): Promise<unknown> | undefined;
|
|
13
15
|
/**
|
|
14
16
|
* Clears the audit context after a transaction completes.
|
|
15
17
|
* Called automatically by withD1AuditedTransaction.
|
|
18
|
+
*
|
|
19
|
+
* Clears `user_id` plus any keys set via `context` so the next transaction
|
|
20
|
+
* starts clean.
|
|
16
21
|
*/
|
|
17
|
-
export declare function clearD1AuditContext(db: D1AuditSqlExecutor, options?:
|
|
18
|
-
contextTable?: string;
|
|
19
|
-
}): unknown;
|
|
22
|
+
export declare function clearD1AuditContext(db: D1AuditSqlExecutor, options?: D1AuditContextOptions): unknown;
|
|
20
23
|
/**
|
|
21
24
|
* Wraps a Drizzle SQLite transaction with audit context. Sets the actor
|
|
22
25
|
* before the callback and clears the context after (success or failure).
|
|
@@ -37,8 +40,5 @@ export declare function clearD1AuditContext(db: D1AuditSqlExecutor, options?: {
|
|
|
37
40
|
*/
|
|
38
41
|
export declare function withD1AuditedTransaction<TDb extends D1AuditSqlExecutor, TResult>(db: TDb & {
|
|
39
42
|
transaction: (cb: (tx: any) => TResult) => TResult;
|
|
40
|
-
}, actorId: string, callback: (tx: TDb) => TResult, options?:
|
|
41
|
-
workspaceId?: string;
|
|
42
|
-
contextTable?: string;
|
|
43
|
-
}): TResult;
|
|
43
|
+
}, actorId: string, callback: (tx: TDb) => TResult, options?: D1AuditContextOptions): TResult;
|
|
44
44
|
//# sourceMappingURL=runtime.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../src/d1/runtime.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAUpD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,EAAE,EAAE,kBAAkB,EACtB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../src/d1/runtime.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAUpD,MAAM,MAAM,qBAAqB,GAAG;IAClC,uEAAuE;IACvE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAkBD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,EAAE,EAAE,kBAAkB,EACtB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,qBAAqB,gCAwBhC;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,EAAE,EAAE,kBAAkB,EACtB,OAAO,CAAC,EAAE,qBAAqB,WAYhC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,SAAS,kBAAkB,EAAE,OAAO,EAC9E,EAAE,EAAE,GAAG,GAAG;IAAE,WAAW,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,GAAG,KAAK,OAAO,KAAK,OAAO,CAAA;CAAE,EAChE,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,CAAC,EAAE,EAAE,GAAG,KAAK,OAAO,EAC9B,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CAWT"}
|
package/dist/src/d1/runtime.js
CHANGED
|
@@ -5,6 +5,19 @@ function assertActorId(actorId) {
|
|
|
5
5
|
throw new Error("actorId must not be empty");
|
|
6
6
|
}
|
|
7
7
|
}
|
|
8
|
+
/**
|
|
9
|
+
* Builds the KV map (key → value) to write. Empty/undefined values are dropped
|
|
10
|
+
* so the corresponding column stays NULL.
|
|
11
|
+
*/
|
|
12
|
+
function resolveContext(options) {
|
|
13
|
+
const context = {};
|
|
14
|
+
for (const [key, value] of Object.entries(options?.context ?? {})) {
|
|
15
|
+
if (value !== undefined && value !== "") {
|
|
16
|
+
context[key] = value;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return context;
|
|
20
|
+
}
|
|
8
21
|
/**
|
|
9
22
|
* Sets the audit context for the current transaction by writing to the
|
|
10
23
|
* _audit_context table. Must be called inside a transaction before any
|
|
@@ -15,26 +28,30 @@ function assertActorId(actorId) {
|
|
|
15
28
|
export function setD1AuditContext(db, actorId, options) {
|
|
16
29
|
assertActorId(actorId);
|
|
17
30
|
const table = options?.contextTable ?? DEFAULT_CONTEXT_TABLE;
|
|
18
|
-
const
|
|
31
|
+
const context = resolveContext(options);
|
|
32
|
+
const writeKv = (key, value) => db.run(sql `INSERT OR REPLACE INTO ${sql.identifier(table)} (key, value) VALUES (${key}, ${value})`);
|
|
33
|
+
const result = writeKv("user_id", actorId);
|
|
19
34
|
// Handle async drivers (D1) by chaining if result is a Promise
|
|
20
35
|
if (result && typeof result.then === "function") {
|
|
21
|
-
return
|
|
22
|
-
if (options?.workspaceId !== undefined && options.workspaceId !== "") {
|
|
23
|
-
return db.run(sql `INSERT OR REPLACE INTO ${sql.identifier(table)} (key, value) VALUES ('workspace_id', ${options.workspaceId})`);
|
|
24
|
-
}
|
|
25
|
-
});
|
|
36
|
+
return Object.entries(context).reduce((prev, [key, value]) => prev.then(() => writeKv(key, value)), result);
|
|
26
37
|
}
|
|
27
|
-
|
|
28
|
-
|
|
38
|
+
for (const [key, value] of Object.entries(context)) {
|
|
39
|
+
writeKv(key, value);
|
|
29
40
|
}
|
|
30
41
|
}
|
|
31
42
|
/**
|
|
32
43
|
* Clears the audit context after a transaction completes.
|
|
33
44
|
* Called automatically by withD1AuditedTransaction.
|
|
45
|
+
*
|
|
46
|
+
* Clears `user_id` plus any keys set via `context` so the next transaction
|
|
47
|
+
* starts clean.
|
|
34
48
|
*/
|
|
35
49
|
export function clearD1AuditContext(db, options) {
|
|
36
50
|
const table = options?.contextTable ?? DEFAULT_CONTEXT_TABLE;
|
|
37
|
-
|
|
51
|
+
const keys = ["user_id", ...Object.keys(options?.context ?? {})];
|
|
52
|
+
const uniqueKeys = [...new Set(keys)];
|
|
53
|
+
const keyList = sql.join(uniqueKeys.map((k) => sql `${k}`), sql `, `);
|
|
54
|
+
return db.run(sql `DELETE FROM ${sql.identifier(table)} WHERE key IN (${keyList})`);
|
|
38
55
|
}
|
|
39
56
|
/**
|
|
40
57
|
* Wraps a Drizzle SQLite transaction with audit context. Sets the actor
|
package/dist/src/d1/sql.d.ts
CHANGED
|
@@ -2,8 +2,8 @@ import type { D1AuditInstallOptions, D1AuditTriggerTarget } from "./types.js";
|
|
|
2
2
|
/**
|
|
3
3
|
* Generates SQL to install the audit_logs table and _audit_context table.
|
|
4
4
|
*
|
|
5
|
-
* The _audit_context table stores user_id (and
|
|
6
|
-
* the current transaction. Since D1/SQLite has no session variables, triggers
|
|
5
|
+
* The _audit_context table stores user_id (and any configured context columns)
|
|
6
|
+
* for the current transaction. Since D1/SQLite has no session variables, triggers
|
|
7
7
|
* read context from this table instead.
|
|
8
8
|
*/
|
|
9
9
|
export declare function createD1AuditInstallSql(options?: D1AuditInstallOptions): string;
|
package/dist/src/d1/sql.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sql.d.ts","sourceRoot":"","sources":["../../../src/d1/sql.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"sql.d.ts","sourceRoot":"","sources":["../../../src/d1/sql.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,qBAAqB,EACrB,oBAAoB,EACrB,MAAM,YAAY,CAAA;AAyEnB;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,GAAE,qBAA0B,UA8C1E;AAoHD;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,oBAAoB,EAC5B,OAAO,GAAE,qBAA0B,UAOpC;AAED,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,oBAAoB,EAAE,EAC/B,OAAO,GAAE,qBAA0B,UAQpC;AAID,MAAM,MAAM,+BAA+B,GAAG,oBAAoB,GAAG;IACnE,kEAAkE;IAClE,OAAO,EAAE,MAAM,EAAE,CAAA;CAClB,CAAA;AA4HD;;;;;;;;;;;GAWG;AACH,wBAAgB,wCAAwC,CACtD,MAAM,EAAE,+BAA+B,EACvC,OAAO,GAAE,qBAA0B,UAUpC;AAED,wBAAgB,yCAAyC,CACvD,OAAO,EAAE,+BAA+B,EAAE,EAC1C,OAAO,GAAE,qBAA0B,UAQpC"}
|
package/dist/src/d1/sql.js
CHANGED
|
@@ -13,29 +13,63 @@ function assertNonEmpty(value, label) {
|
|
|
13
13
|
}
|
|
14
14
|
return value;
|
|
15
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* Normalizes the context columns from the install options, de-duplicating by
|
|
18
|
+
* column name. For D1 the KV key defaults to the column name itself.
|
|
19
|
+
*/
|
|
20
|
+
function normalizeContextColumns(options) {
|
|
21
|
+
const resolved = [];
|
|
22
|
+
const seen = new Set();
|
|
23
|
+
for (const entry of options.contextColumns ?? []) {
|
|
24
|
+
const column = entry.column?.trim();
|
|
25
|
+
if (!column) {
|
|
26
|
+
throw new Error("contextColumns[].column must not be empty");
|
|
27
|
+
}
|
|
28
|
+
if (seen.has(column)) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
seen.add(column);
|
|
32
|
+
resolved.push({
|
|
33
|
+
column,
|
|
34
|
+
sessionKey: entry.sessionKey?.trim() || column,
|
|
35
|
+
index: entry.index ?? true,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return resolved;
|
|
39
|
+
}
|
|
40
|
+
/** Builds the column-name suffix for an INSERT column list. */
|
|
41
|
+
function contextColsClause(contextColumns) {
|
|
42
|
+
return contextColumns.map((c) => `, ${quoteIdent(c.column)}`).join("");
|
|
43
|
+
}
|
|
44
|
+
/** Builds the matching VALUES suffix that reads each KV row from the context table. */
|
|
45
|
+
function contextValuesClause(contextColumns, contextTable) {
|
|
46
|
+
return contextColumns
|
|
47
|
+
.map((c) => `,\n (SELECT value FROM ${quoteIdent(contextTable)} WHERE key = ${quoteLiteral(c.sessionKey)})`)
|
|
48
|
+
.join("");
|
|
49
|
+
}
|
|
16
50
|
/**
|
|
17
51
|
* Generates SQL to install the audit_logs table and _audit_context table.
|
|
18
52
|
*
|
|
19
|
-
* The _audit_context table stores user_id (and
|
|
20
|
-
* the current transaction. Since D1/SQLite has no session variables, triggers
|
|
53
|
+
* The _audit_context table stores user_id (and any configured context columns)
|
|
54
|
+
* for the current transaction. Since D1/SQLite has no session variables, triggers
|
|
21
55
|
* read context from this table instead.
|
|
22
56
|
*/
|
|
23
57
|
export function createD1AuditInstallSql(options = {}) {
|
|
24
58
|
const auditTable = assertNonEmpty(options.auditTable ?? DEFAULT_AUDIT_TABLE, "auditTable");
|
|
25
59
|
const contextTable = assertNonEmpty(options.contextTable ?? DEFAULT_CONTEXT_TABLE, "contextTable");
|
|
26
|
-
const
|
|
60
|
+
const contextColumns = normalizeContextColumns(options);
|
|
27
61
|
const auditColumns = [
|
|
28
62
|
"id INTEGER PRIMARY KEY AUTOINCREMENT",
|
|
29
63
|
"table_name TEXT NOT NULL",
|
|
30
64
|
"operation TEXT NOT NULL CHECK (operation IN ('INSERT', 'UPDATE', 'DELETE'))",
|
|
31
65
|
"row_id TEXT",
|
|
32
66
|
"user_id TEXT",
|
|
33
|
-
...(
|
|
67
|
+
...contextColumns.map((c) => `${quoteIdent(c.column)} TEXT`),
|
|
34
68
|
"old_data TEXT",
|
|
35
69
|
"new_data TEXT",
|
|
36
70
|
"created_at TEXT NOT NULL DEFAULT (datetime('now'))",
|
|
37
71
|
];
|
|
38
|
-
const
|
|
72
|
+
const contextTableColumns = [
|
|
39
73
|
"key TEXT PRIMARY KEY",
|
|
40
74
|
"value TEXT",
|
|
41
75
|
];
|
|
@@ -43,16 +77,14 @@ export function createD1AuditInstallSql(options = {}) {
|
|
|
43
77
|
`CREATE INDEX IF NOT EXISTS ${quoteIdent(`${auditTable}_table_name_idx`)} ON ${quoteIdent(auditTable)} (table_name);`,
|
|
44
78
|
`CREATE INDEX IF NOT EXISTS ${quoteIdent(`${auditTable}_row_id_idx`)} ON ${quoteIdent(auditTable)} (row_id);`,
|
|
45
79
|
`CREATE INDEX IF NOT EXISTS ${quoteIdent(`${auditTable}_user_id_idx`)} ON ${quoteIdent(auditTable)} (user_id);`,
|
|
46
|
-
...
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
]
|
|
50
|
-
: []),
|
|
80
|
+
...contextColumns
|
|
81
|
+
.filter((c) => c.index)
|
|
82
|
+
.map((c) => `CREATE INDEX IF NOT EXISTS ${quoteIdent(`${auditTable}_${c.column}_idx`)} ON ${quoteIdent(auditTable)} (${quoteIdent(c.column)});`),
|
|
51
83
|
`CREATE INDEX IF NOT EXISTS ${quoteIdent(`${auditTable}_created_at_idx`)} ON ${quoteIdent(auditTable)} (created_at);`,
|
|
52
84
|
];
|
|
53
85
|
return [
|
|
54
86
|
`CREATE TABLE IF NOT EXISTS ${quoteIdent(auditTable)} (\n ${auditColumns.join(",\n ")}\n);`,
|
|
55
|
-
`CREATE TABLE IF NOT EXISTS ${quoteIdent(contextTable)} (\n ${
|
|
87
|
+
`CREATE TABLE IF NOT EXISTS ${quoteIdent(contextTable)} (\n ${contextTableColumns.join(",\n ")}\n);`,
|
|
56
88
|
...indexStatements,
|
|
57
89
|
].join("\n\n");
|
|
58
90
|
}
|
|
@@ -63,7 +95,7 @@ function buildInsertTriggerSql(target, options) {
|
|
|
63
95
|
const contextTable = assertNonEmpty(options.contextTable ?? DEFAULT_CONTEXT_TABLE, "contextTable");
|
|
64
96
|
const triggerPrefix = target.triggerPrefix ?? table;
|
|
65
97
|
const triggerName = `${triggerPrefix}_audit_insert`;
|
|
66
|
-
const
|
|
98
|
+
const contextColumns = normalizeContextColumns(options);
|
|
67
99
|
return `
|
|
68
100
|
DROP TRIGGER IF EXISTS ${quoteIdent(triggerName)};
|
|
69
101
|
|
|
@@ -71,12 +103,12 @@ CREATE TRIGGER ${quoteIdent(triggerName)}
|
|
|
71
103
|
AFTER INSERT ON ${quoteIdent(table)}
|
|
72
104
|
FOR EACH ROW
|
|
73
105
|
BEGIN
|
|
74
|
-
INSERT INTO ${quoteIdent(auditTable)} (table_name, operation, row_id, user_id${
|
|
106
|
+
INSERT INTO ${quoteIdent(auditTable)} (table_name, operation, row_id, user_id${contextColsClause(contextColumns)})
|
|
75
107
|
VALUES (
|
|
76
108
|
${quoteLiteral(table)},
|
|
77
109
|
'INSERT',
|
|
78
110
|
NEW.${quoteIdent(rowIdColumn)},
|
|
79
|
-
(SELECT value FROM ${quoteIdent(contextTable)} WHERE key = 'user_id')${
|
|
111
|
+
(SELECT value FROM ${quoteIdent(contextTable)} WHERE key = 'user_id')${contextValuesClause(contextColumns, contextTable)}
|
|
80
112
|
);
|
|
81
113
|
END;`.trim();
|
|
82
114
|
}
|
|
@@ -87,7 +119,7 @@ function buildUpdateTriggerSql(target, options) {
|
|
|
87
119
|
const contextTable = assertNonEmpty(options.contextTable ?? DEFAULT_CONTEXT_TABLE, "contextTable");
|
|
88
120
|
const triggerPrefix = target.triggerPrefix ?? table;
|
|
89
121
|
const triggerName = `${triggerPrefix}_audit_update`;
|
|
90
|
-
const
|
|
122
|
+
const contextColumns = normalizeContextColumns(options);
|
|
91
123
|
return `
|
|
92
124
|
DROP TRIGGER IF EXISTS ${quoteIdent(triggerName)};
|
|
93
125
|
|
|
@@ -95,12 +127,12 @@ CREATE TRIGGER ${quoteIdent(triggerName)}
|
|
|
95
127
|
AFTER UPDATE ON ${quoteIdent(table)}
|
|
96
128
|
FOR EACH ROW
|
|
97
129
|
BEGIN
|
|
98
|
-
INSERT INTO ${quoteIdent(auditTable)} (table_name, operation, row_id, user_id${
|
|
130
|
+
INSERT INTO ${quoteIdent(auditTable)} (table_name, operation, row_id, user_id${contextColsClause(contextColumns)})
|
|
99
131
|
VALUES (
|
|
100
132
|
${quoteLiteral(table)},
|
|
101
133
|
'UPDATE',
|
|
102
134
|
NEW.${quoteIdent(rowIdColumn)},
|
|
103
|
-
(SELECT value FROM ${quoteIdent(contextTable)} WHERE key = 'user_id')${
|
|
135
|
+
(SELECT value FROM ${quoteIdent(contextTable)} WHERE key = 'user_id')${contextValuesClause(contextColumns, contextTable)}
|
|
104
136
|
);
|
|
105
137
|
END;`.trim();
|
|
106
138
|
}
|
|
@@ -111,7 +143,7 @@ function buildDeleteTriggerSql(target, options) {
|
|
|
111
143
|
const contextTable = assertNonEmpty(options.contextTable ?? DEFAULT_CONTEXT_TABLE, "contextTable");
|
|
112
144
|
const triggerPrefix = target.triggerPrefix ?? table;
|
|
113
145
|
const triggerName = `${triggerPrefix}_audit_delete`;
|
|
114
|
-
const
|
|
146
|
+
const contextColumns = normalizeContextColumns(options);
|
|
115
147
|
return `
|
|
116
148
|
DROP TRIGGER IF EXISTS ${quoteIdent(triggerName)};
|
|
117
149
|
|
|
@@ -119,12 +151,12 @@ CREATE TRIGGER ${quoteIdent(triggerName)}
|
|
|
119
151
|
AFTER DELETE ON ${quoteIdent(table)}
|
|
120
152
|
FOR EACH ROW
|
|
121
153
|
BEGIN
|
|
122
|
-
INSERT INTO ${quoteIdent(auditTable)} (table_name, operation, row_id, user_id${
|
|
154
|
+
INSERT INTO ${quoteIdent(auditTable)} (table_name, operation, row_id, user_id${contextColsClause(contextColumns)})
|
|
123
155
|
VALUES (
|
|
124
156
|
${quoteLiteral(table)},
|
|
125
157
|
'DELETE',
|
|
126
158
|
OLD.${quoteIdent(rowIdColumn)},
|
|
127
|
-
(SELECT value FROM ${quoteIdent(contextTable)} WHERE key = 'user_id')${
|
|
159
|
+
(SELECT value FROM ${quoteIdent(contextTable)} WHERE key = 'user_id')${contextValuesClause(contextColumns, contextTable)}
|
|
128
160
|
);
|
|
129
161
|
END;`.trim();
|
|
130
162
|
}
|
|
@@ -160,7 +192,7 @@ function buildInsertTriggerWithColumnsSql(target, options) {
|
|
|
160
192
|
const contextTable = assertNonEmpty(options.contextTable ?? DEFAULT_CONTEXT_TABLE, "contextTable");
|
|
161
193
|
const triggerPrefix = target.triggerPrefix ?? table;
|
|
162
194
|
const triggerName = `${triggerPrefix}_audit_insert`;
|
|
163
|
-
const
|
|
195
|
+
const contextColumns = normalizeContextColumns(options);
|
|
164
196
|
return `
|
|
165
197
|
DROP TRIGGER IF EXISTS ${quoteIdent(triggerName)};
|
|
166
198
|
|
|
@@ -168,12 +200,12 @@ CREATE TRIGGER ${quoteIdent(triggerName)}
|
|
|
168
200
|
AFTER INSERT ON ${quoteIdent(table)}
|
|
169
201
|
FOR EACH ROW
|
|
170
202
|
BEGIN
|
|
171
|
-
INSERT INTO ${quoteIdent(auditTable)} (table_name, operation, row_id, user_id${
|
|
203
|
+
INSERT INTO ${quoteIdent(auditTable)} (table_name, operation, row_id, user_id${contextColsClause(contextColumns)}, new_data)
|
|
172
204
|
VALUES (
|
|
173
205
|
${quoteLiteral(table)},
|
|
174
206
|
'INSERT',
|
|
175
207
|
NEW.${quoteIdent(rowIdColumn)},
|
|
176
|
-
(SELECT value FROM ${quoteIdent(contextTable)} WHERE key = 'user_id')${
|
|
208
|
+
(SELECT value FROM ${quoteIdent(contextTable)} WHERE key = 'user_id')${contextValuesClause(contextColumns, contextTable)},
|
|
177
209
|
${buildJsonObjectExpr(target.columns, "NEW")}
|
|
178
210
|
);
|
|
179
211
|
END;`.trim();
|
|
@@ -185,7 +217,7 @@ function buildUpdateTriggerWithColumnsSql(target, options) {
|
|
|
185
217
|
const contextTable = assertNonEmpty(options.contextTable ?? DEFAULT_CONTEXT_TABLE, "contextTable");
|
|
186
218
|
const triggerPrefix = target.triggerPrefix ?? table;
|
|
187
219
|
const triggerName = `${triggerPrefix}_audit_update`;
|
|
188
|
-
const
|
|
220
|
+
const contextColumns = normalizeContextColumns(options);
|
|
189
221
|
return `
|
|
190
222
|
DROP TRIGGER IF EXISTS ${quoteIdent(triggerName)};
|
|
191
223
|
|
|
@@ -193,12 +225,12 @@ CREATE TRIGGER ${quoteIdent(triggerName)}
|
|
|
193
225
|
AFTER UPDATE ON ${quoteIdent(table)}
|
|
194
226
|
FOR EACH ROW
|
|
195
227
|
BEGIN
|
|
196
|
-
INSERT INTO ${quoteIdent(auditTable)} (table_name, operation, row_id, user_id${
|
|
228
|
+
INSERT INTO ${quoteIdent(auditTable)} (table_name, operation, row_id, user_id${contextColsClause(contextColumns)}, old_data, new_data)
|
|
197
229
|
VALUES (
|
|
198
230
|
${quoteLiteral(table)},
|
|
199
231
|
'UPDATE',
|
|
200
232
|
NEW.${quoteIdent(rowIdColumn)},
|
|
201
|
-
(SELECT value FROM ${quoteIdent(contextTable)} WHERE key = 'user_id')${
|
|
233
|
+
(SELECT value FROM ${quoteIdent(contextTable)} WHERE key = 'user_id')${contextValuesClause(contextColumns, contextTable)},
|
|
202
234
|
${buildJsonObjectExpr(target.columns, "OLD")},
|
|
203
235
|
${buildJsonObjectExpr(target.columns, "NEW")}
|
|
204
236
|
);
|
|
@@ -211,7 +243,7 @@ function buildDeleteTriggerWithColumnsSql(target, options) {
|
|
|
211
243
|
const contextTable = assertNonEmpty(options.contextTable ?? DEFAULT_CONTEXT_TABLE, "contextTable");
|
|
212
244
|
const triggerPrefix = target.triggerPrefix ?? table;
|
|
213
245
|
const triggerName = `${triggerPrefix}_audit_delete`;
|
|
214
|
-
const
|
|
246
|
+
const contextColumns = normalizeContextColumns(options);
|
|
215
247
|
return `
|
|
216
248
|
DROP TRIGGER IF EXISTS ${quoteIdent(triggerName)};
|
|
217
249
|
|
|
@@ -219,12 +251,12 @@ CREATE TRIGGER ${quoteIdent(triggerName)}
|
|
|
219
251
|
AFTER DELETE ON ${quoteIdent(table)}
|
|
220
252
|
FOR EACH ROW
|
|
221
253
|
BEGIN
|
|
222
|
-
INSERT INTO ${quoteIdent(auditTable)} (table_name, operation, row_id, user_id${
|
|
254
|
+
INSERT INTO ${quoteIdent(auditTable)} (table_name, operation, row_id, user_id${contextColsClause(contextColumns)}, old_data)
|
|
223
255
|
VALUES (
|
|
224
256
|
${quoteLiteral(table)},
|
|
225
257
|
'DELETE',
|
|
226
258
|
OLD.${quoteIdent(rowIdColumn)},
|
|
227
|
-
(SELECT value FROM ${quoteIdent(contextTable)} WHERE key = 'user_id')${
|
|
259
|
+
(SELECT value FROM ${quoteIdent(contextTable)} WHERE key = 'user_id')${contextValuesClause(contextColumns, contextTable)},
|
|
228
260
|
${buildJsonObjectExpr(target.columns, "OLD")}
|
|
229
261
|
);
|
|
230
262
|
END;`.trim();
|
package/dist/src/d1/types.d.ts
CHANGED
|
@@ -6,13 +6,21 @@ import type { SQL } from "drizzle-orm";
|
|
|
6
6
|
export type D1AuditSqlExecutor = {
|
|
7
7
|
run: (query: SQL) => unknown;
|
|
8
8
|
};
|
|
9
|
+
export type AuditContextColumn = {
|
|
10
|
+
/** Column added to the audit table (TEXT, nullable). */
|
|
11
|
+
column: string;
|
|
12
|
+
/** The `_audit_context` key the trigger reads. Default `${column}`. */
|
|
13
|
+
sessionKey?: string;
|
|
14
|
+
/** Create an index on the column. Default true. */
|
|
15
|
+
index?: boolean;
|
|
16
|
+
};
|
|
9
17
|
export type D1AuditInstallOptions = {
|
|
10
18
|
/** Name of the audit log table (default: "audit_logs") */
|
|
11
19
|
auditTable?: string;
|
|
12
20
|
/** Name of the context table used to pass user_id to triggers (default: "_audit_context") */
|
|
13
21
|
contextTable?: string;
|
|
14
|
-
/**
|
|
15
|
-
|
|
22
|
+
/** Extra context columns added to the audit table and populated by triggers from the _audit_context KV table. */
|
|
23
|
+
contextColumns?: AuditContextColumn[];
|
|
16
24
|
};
|
|
17
25
|
export type D1AuditTriggerTarget = {
|
|
18
26
|
table: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/d1/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,aAAa,CAAA;AAEtC;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,GAAG,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAA;CAC7B,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,0DAA0D;IAC1D,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,6FAA6F;IAC7F,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/d1/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,aAAa,CAAA;AAEtC;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,GAAG,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAA;CAC7B,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,wDAAwD;IACxD,MAAM,EAAE,MAAM,CAAA;IACd,uEAAuE;IACvE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,mDAAmD;IACnD,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,0DAA0D;IAC1D,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,6FAA6F;IAC7F,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,iHAAiH;IACjH,cAAc,CAAC,EAAE,kBAAkB,EAAE,CAAA;CACtC,CAAA;AAED,MAAM,MAAM,oBAAoB,GAAG;IACjC,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB,CAAA"}
|
|
@@ -2,7 +2,8 @@ import { type InferInsertModel, type InferSelectModel, type SQL } from "drizzle-
|
|
|
2
2
|
import type { SQLiteTable } from "drizzle-orm/sqlite-core";
|
|
3
3
|
export type AuditContext = {
|
|
4
4
|
userId: string;
|
|
5
|
-
|
|
5
|
+
/** Map of extra audit context column name → value (matching contextColumns). */
|
|
6
|
+
context?: Record<string, string>;
|
|
6
7
|
};
|
|
7
8
|
export type AuditLogInsertShape = {
|
|
8
9
|
table_name: string;
|
|
@@ -55,7 +56,7 @@ export type AuditedDb<TDb extends DrizzleSQLiteDb> = {
|
|
|
55
56
|
*
|
|
56
57
|
* @param db - A Drizzle SQLite database instance (D1, better-sqlite3, libsql)
|
|
57
58
|
* @param auditTable - The Drizzle table definition for audit_logs
|
|
58
|
-
* @param context - The audit context (userId, optional
|
|
59
|
+
* @param context - The audit context (userId, optional context columns)
|
|
59
60
|
*
|
|
60
61
|
* @example
|
|
61
62
|
* import { withAudit } from "drizzle-audit/d1-runtime"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"with-audit.d.ts","sourceRoot":"","sources":["../../../src/d1-runtime/with-audit.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,GAAG,EACT,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EAAgB,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAIxE,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,MAAM,CAAA;IACd,
|
|
1
|
+
{"version":3,"file":"with-audit.d.ts","sourceRoot":"","sources":["../../../src/d1-runtime/with-audit.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,GAAG,EACT,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EAAgB,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAIxE,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,MAAM,CAAA;IACd,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACjC,CAAA;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB,CAAA;AAED;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,GAAG,CAAA;IAC3B,MAAM,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,GAAG,CAAA;IAC3B,MAAM,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,GAAG,CAAA;IAC3B,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE,GAAG,KAAK,GAAG,CAAA;CAC9B,CAAA;AAgBD,MAAM,MAAM,SAAS,CAAC,GAAG,SAAS,eAAe,IAAI;IACnD;;;OAGG;IACH,MAAM,EAAE,CAAC,CAAC,SAAS,WAAW,EAC5B,KAAK,EAAE,CAAC,EACR,IAAI,EAAE,gBAAgB,CAAC,CAAC,CAAC,KACtB,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAA;IAEjC;;;;OAIG;IACH,MAAM,EAAE,CAAC,CAAC,SAAS,WAAW,EAC5B,KAAK,EAAE,CAAC,EACR,KAAK,EAAE,GAAG,EACV,IAAI,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,KAC/B,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;IAEnC;;;;OAIG;IACH,MAAM,EAAE,CAAC,CAAC,SAAS,WAAW,EAC5B,KAAK,EAAE,CAAC,EACR,KAAK,EAAE,GAAG,KACP,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;IAEnC,2DAA2D;IAC3D,EAAE,EAAE,GAAG,CAAA;CACR,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,SAAS,CAAC,GAAG,SAAS,eAAe,EACnD,EAAE,EAAE,GAAG,EACP,UAAU,EAAE,WAAW,EACvB,OAAO,EAAE,YAAY,GACpB,SAAS,CAAC,GAAG,CAAC,CAqGhB"}
|