@willyim/drizzle-audit 0.4.0 → 0.6.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 (43) hide show
  1. package/README.md +118 -16
  2. package/dist/src/context/index.d.ts +42 -0
  3. package/dist/src/context/index.d.ts.map +1 -0
  4. package/dist/src/context/index.js +94 -0
  5. package/dist/src/d1/audit-log-schema.d.ts +3 -2
  6. package/dist/src/d1/audit-log-schema.d.ts.map +1 -1
  7. package/dist/src/d1/audit-log-schema.js +14 -4
  8. package/dist/src/d1/index.d.ts +2 -1
  9. package/dist/src/d1/index.d.ts.map +1 -1
  10. package/dist/src/d1/runtime.d.ts +11 -11
  11. package/dist/src/d1/runtime.d.ts.map +1 -1
  12. package/dist/src/d1/runtime.js +26 -9
  13. package/dist/src/d1/sql.d.ts +2 -2
  14. package/dist/src/d1/sql.d.ts.map +1 -1
  15. package/dist/src/d1/sql.js +61 -29
  16. package/dist/src/d1/types.d.ts +10 -2
  17. package/dist/src/d1/types.d.ts.map +1 -1
  18. package/dist/src/d1-runtime/with-audit.d.ts +3 -2
  19. package/dist/src/d1-runtime/with-audit.d.ts.map +1 -1
  20. package/dist/src/d1-runtime/with-audit.js +12 -7
  21. package/dist/src/index.d.ts +2 -1
  22. package/dist/src/index.d.ts.map +1 -1
  23. package/dist/src/index.js +1 -1
  24. package/dist/src/postgres/audit-log-schema.d.ts +3 -2
  25. package/dist/src/postgres/audit-log-schema.d.ts.map +1 -1
  26. package/dist/src/postgres/audit-log-schema.js +14 -4
  27. package/dist/src/postgres/index.d.ts +3 -2
  28. package/dist/src/postgres/index.d.ts.map +1 -1
  29. package/dist/src/postgres/index.js +1 -1
  30. package/dist/src/postgres/runtime.d.ts +6 -8
  31. package/dist/src/postgres/runtime.d.ts.map +1 -1
  32. package/dist/src/postgres/runtime.js +15 -3
  33. package/dist/src/postgres/sql.d.ts +10 -7
  34. package/dist/src/postgres/sql.d.ts.map +1 -1
  35. package/dist/src/postgres/sql.js +72 -50
  36. package/dist/src/postgres/types.d.ts +10 -2
  37. package/dist/src/postgres/types.d.ts.map +1 -1
  38. package/dist/test/context.test.d.ts +2 -0
  39. package/dist/test/context.test.d.ts.map +1 -0
  40. package/dist/test/context.test.js +98 -0
  41. package/dist/test/d1.integration.test.js +71 -4
  42. package/dist/test/sqlite.integration.test.js +65 -2
  43. package/package.json +2 -1
@@ -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 optionally workspace_id) for
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 workspaceIdColumn = options.workspaceIdColumn?.trim();
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
- ...(workspaceIdColumn ? [`${quoteIdent(workspaceIdColumn)} TEXT`] : []),
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 contextColumns = [
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
- ...(workspaceIdColumn
47
- ? [
48
- `CREATE INDEX IF NOT EXISTS ${quoteIdent(`${auditTable}_${workspaceIdColumn}_idx`)} ON ${quoteIdent(auditTable)} (${quoteIdent(workspaceIdColumn)});`,
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 ${contextColumns.join(",\n ")}\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 workspaceIdColumn = options.workspaceIdColumn?.trim();
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${workspaceIdColumn ? `, ${quoteIdent(workspaceIdColumn)}` : ""})
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')${workspaceIdColumn ? `,\n (SELECT value FROM ${quoteIdent(contextTable)} WHERE key = 'workspace_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 workspaceIdColumn = options.workspaceIdColumn?.trim();
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${workspaceIdColumn ? `, ${quoteIdent(workspaceIdColumn)}` : ""})
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')${workspaceIdColumn ? `,\n (SELECT value FROM ${quoteIdent(contextTable)} WHERE key = 'workspace_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 workspaceIdColumn = options.workspaceIdColumn?.trim();
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${workspaceIdColumn ? `, ${quoteIdent(workspaceIdColumn)}` : ""})
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')${workspaceIdColumn ? `,\n (SELECT value FROM ${quoteIdent(contextTable)} WHERE key = 'workspace_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 workspaceIdColumn = options.workspaceIdColumn?.trim();
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${workspaceIdColumn ? `, ${quoteIdent(workspaceIdColumn)}` : ""}, new_data)
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')${workspaceIdColumn ? `,\n (SELECT value FROM ${quoteIdent(contextTable)} WHERE key = 'workspace_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 workspaceIdColumn = options.workspaceIdColumn?.trim();
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${workspaceIdColumn ? `, ${quoteIdent(workspaceIdColumn)}` : ""}, old_data, new_data)
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')${workspaceIdColumn ? `,\n (SELECT value FROM ${quoteIdent(contextTable)} WHERE key = 'workspace_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 workspaceIdColumn = options.workspaceIdColumn?.trim();
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${workspaceIdColumn ? `, ${quoteIdent(workspaceIdColumn)}` : ""}, old_data)
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')${workspaceIdColumn ? `,\n (SELECT value FROM ${quoteIdent(contextTable)} WHERE key = 'workspace_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();
@@ -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
- /** Optional workspace column name (e.g. "workspace_id") */
15
- workspaceIdColumn?: string;
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,2DAA2D;IAC3D,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC3B,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"}
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
- workspaceId?: string;
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 workspaceId)
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,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,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,CA8FhB"}
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"}
@@ -21,7 +21,7 @@ function getRowId(row, pk) {
21
21
  *
22
22
  * @param db - A Drizzle SQLite database instance (D1, better-sqlite3, libsql)
23
23
  * @param auditTable - The Drizzle table definition for audit_logs
24
- * @param context - The audit context (userId, optional workspaceId)
24
+ * @param context - The audit context (userId, optional context columns)
25
25
  *
26
26
  * @example
27
27
  * import { withAudit } from "drizzle-audit/d1-runtime"
@@ -43,7 +43,7 @@ function getRowId(row, pk) {
43
43
  * audited.db.select().from(users).all()
44
44
  */
45
45
  export function withAudit(db, auditTable, context) {
46
- const workspaceIdColumn = (() => {
46
+ const extraColumns = (() => {
47
47
  const cols = getTableColumns(auditTable);
48
48
  const known = new Set([
49
49
  "id",
@@ -55,10 +55,17 @@ export function withAudit(db, auditTable, context) {
55
55
  "new_data",
56
56
  "created_at",
57
57
  ]);
58
- const extra = Object.keys(cols).find((k) => !known.has(k));
59
- return extra ?? null;
58
+ return Object.keys(cols).filter((k) => !known.has(k));
60
59
  })();
60
+ const contextValues = { ...(context.context ?? {}) };
61
61
  function buildAuditRow(tableName, operation, rowId, oldData, newData) {
62
+ const extra = {};
63
+ for (const column of extraColumns) {
64
+ const value = contextValues[column];
65
+ if (value !== undefined && value !== "") {
66
+ extra[column] = value;
67
+ }
68
+ }
62
69
  return {
63
70
  table_name: tableName,
64
71
  operation,
@@ -66,9 +73,7 @@ export function withAudit(db, auditTable, context) {
66
73
  user_id: context.userId,
67
74
  old_data: oldData ? JSON.stringify(oldData) : null,
68
75
  new_data: newData ? JSON.stringify(newData) : null,
69
- ...(workspaceIdColumn && context.workspaceId
70
- ? { [workspaceIdColumn]: context.workspaceId }
71
- : {}),
76
+ ...extra,
72
77
  };
73
78
  }
74
79
  return {
@@ -1,5 +1,6 @@
1
1
  export * from "./postgres/index.js";
2
- export * from "./d1/index.js";
2
+ export { clearD1AuditContext, createAttachD1AuditTriggerSql, createAttachD1AuditTriggersSql, createAttachD1AuditTriggerSqlWithColumns, createAttachD1AuditTriggersSqlWithColumns, createD1AuditInstallSql, d1AuditContextTable, d1AuditLogTable, setD1AuditContext, withD1AuditedTransaction, } from "./d1/index.js";
3
+ export type { D1AuditContextOptions, D1AuditInstallOptions, D1AuditLogTableOptions, D1AuditSqlExecutor, D1AuditTriggerTarget, D1AuditTriggerTargetWithColumns, } from "./d1/index.js";
3
4
  export * from "./d1-runtime/index.js";
4
5
  export * from "./compute-diff.js";
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAA;AACnC,cAAc,eAAe,CAAA;AAC7B,cAAc,uBAAuB,CAAA;AACrC,cAAc,mBAAmB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAA;AACnC,OAAO,EACL,mBAAmB,EACnB,6BAA6B,EAC7B,8BAA8B,EAC9B,wCAAwC,EACxC,yCAAyC,EACzC,uBAAuB,EACvB,mBAAmB,EACnB,eAAe,EACf,iBAAiB,EACjB,wBAAwB,GACzB,MAAM,eAAe,CAAA;AACtB,YAAY,EACV,qBAAqB,EACrB,qBAAqB,EACrB,sBAAsB,EACtB,kBAAkB,EAClB,oBAAoB,EACpB,+BAA+B,GAChC,MAAM,eAAe,CAAA;AACtB,cAAc,uBAAuB,CAAA;AACrC,cAAc,mBAAmB,CAAA"}
package/dist/src/index.js CHANGED
@@ -1,4 +1,4 @@
1
1
  export * from "./postgres/index.js";
2
- export * from "./d1/index.js";
2
+ export { clearD1AuditContext, createAttachD1AuditTriggerSql, createAttachD1AuditTriggersSql, createAttachD1AuditTriggerSqlWithColumns, createAttachD1AuditTriggersSqlWithColumns, createD1AuditInstallSql, d1AuditContextTable, d1AuditLogTable, setD1AuditContext, withD1AuditedTransaction, } from "./d1/index.js";
3
3
  export * from "./d1-runtime/index.js";
4
4
  export * from "./compute-diff.js";
@@ -1,6 +1,7 @@
1
+ import type { AuditContextColumn } from "./types.js";
1
2
  export type PgAuditLogTableOptions = {
2
- /** When set (e.g. "workspace_id"), the table definition includes this optional column to match the install. */
3
- workspaceIdColumn?: string;
3
+ /** Extra context columns to include in the table definition, matching the install. */
4
+ contextColumns?: AuditContextColumn[];
4
5
  };
5
6
  export declare function pgAuditLogTable(options?: PgAuditLogTableOptions): import("drizzle-orm/pg-core").PgTableWithColumns<{
6
7
  name: "audit_logs";
@@ -1 +1 @@
1
- {"version":3,"file":"audit-log-schema.d.ts","sourceRoot":"","sources":["../../../src/postgres/audit-log-schema.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,sBAAsB,GAAG;IACnC,+GAA+G;IAC/G,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC3B,CAAA;AAED,wBAAgB,eAAe,CAAC,OAAO,CAAC,EAAE,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2B/D"}
1
+ {"version":3,"file":"audit-log-schema.d.ts","sourceRoot":"","sources":["../../../src/postgres/audit-log-schema.ts"],"names":[],"mappings":"AASA,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyB/D"}
@@ -1,15 +1,25 @@
1
1
  import { bigserial, index, jsonb, pgTable, text, timestamp, } from "drizzle-orm/pg-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 pgAuditLogTable(options) {
3
- const workspaceIdColumn = options?.workspaceIdColumn?.trim();
15
+ const contextColumns = resolveColumns(options);
4
16
  const columns = {
5
17
  id: bigserial("id", { mode: "number" }).primaryKey(),
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
- ...(workspaceIdColumn
11
- ? { [workspaceIdColumn]: text(workspaceIdColumn) }
12
- : {}),
22
+ ...Object.fromEntries(contextColumns.map((c) => [c, text(c)])),
13
23
  old_data: jsonb("old_data"),
14
24
  new_data: jsonb("new_data"),
15
25
  created_at: timestamp("created_at", { withTimezone: true })
@@ -1,6 +1,7 @@
1
1
  export { pgAuditLogTable } from "./audit-log-schema.js";
2
2
  export type { PgAuditLogTableOptions } from "./audit-log-schema.js";
3
- export { createAttachAuditTriggerSql, createAttachAuditTriggersSql, createAuditAddWorkspaceColumnSql, createAuditInstallSql, } from "./sql.js";
3
+ export { createAttachAuditTriggerSql, createAttachAuditTriggersSql, createAuditAddContextColumnsSql, createAuditInstallSql, } from "./sql.js";
4
4
  export { setAuditContext, withAuditedTransaction } from "./runtime.js";
5
- export type { AuditInstallOptions, AuditSqlExecutor, AuditTransactionCapable, AuditTriggerTarget, } from "./types.js";
5
+ export type { AuditContextOptions } from "./runtime.js";
6
+ export type { AuditContextColumn, AuditInstallOptions, AuditSqlExecutor, AuditTransactionCapable, AuditTriggerTarget, } from "./types.js";
6
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/postgres/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AACvD,YAAY,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAA;AACnE,OAAO,EACL,2BAA2B,EAC3B,4BAA4B,EAC5B,gCAAgC,EAChC,qBAAqB,GACtB,MAAM,UAAU,CAAA;AACjB,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAA;AAEtE,YAAY,EACV,mBAAmB,EACnB,gBAAgB,EAChB,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,YAAY,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/postgres/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AACvD,YAAY,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAA;AACnE,OAAO,EACL,2BAA2B,EAC3B,4BAA4B,EAC5B,+BAA+B,EAC/B,qBAAqB,GACtB,MAAM,UAAU,CAAA;AACjB,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAA;AACtE,YAAY,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AAEvD,YAAY,EACV,kBAAkB,EAClB,mBAAmB,EACnB,gBAAgB,EAChB,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,YAAY,CAAA"}
@@ -1,3 +1,3 @@
1
1
  export { pgAuditLogTable } from "./audit-log-schema.js";
2
- export { createAttachAuditTriggerSql, createAttachAuditTriggersSql, createAuditAddWorkspaceColumnSql, createAuditInstallSql, } from "./sql.js";
2
+ export { createAttachAuditTriggerSql, createAttachAuditTriggersSql, createAuditAddContextColumnsSql, createAuditInstallSql, } from "./sql.js";
3
3
  export { setAuditContext, withAuditedTransaction } from "./runtime.js";
@@ -1,10 +1,8 @@
1
1
  import type { AuditSqlExecutor, AuditTransactionCapable } from "./types.js";
2
- export declare function setAuditContext(db: AuditSqlExecutor, actorId: string, contextKey?: string, options?: {
3
- workspaceId?: string;
4
- workspaceContextKey?: string;
5
- }): Promise<void>;
6
- export declare function withAuditedTransaction<TTransaction extends AuditSqlExecutor, TResult>(db: AuditTransactionCapable<TTransaction>, actorId: string, callback: (tx: TTransaction) => Promise<TResult> | TResult, contextKey?: string, options?: {
7
- workspaceId?: string;
8
- workspaceContextKey?: string;
9
- }): Promise<TResult>;
2
+ export type AuditContextOptions = {
3
+ /** Map of session GUC name → value to set for the transaction. */
4
+ context?: Record<string, string>;
5
+ };
6
+ export declare function setAuditContext(db: AuditSqlExecutor, actorId: string, contextKey?: string, options?: AuditContextOptions): Promise<void>;
7
+ export declare function withAuditedTransaction<TTransaction extends AuditSqlExecutor, TResult>(db: AuditTransactionCapable<TTransaction>, actorId: string, callback: (tx: TTransaction) => Promise<TResult> | TResult, contextKey?: string, options?: AuditContextOptions): Promise<TResult>;
10
8
  //# sourceMappingURL=runtime.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../src/postgres/runtime.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,gBAAgB,EAChB,uBAAuB,EACxB,MAAM,YAAY,CAAA;AAQnB,wBAAsB,eAAe,CACnC,EAAE,EAAE,gBAAgB,EACpB,OAAO,EAAE,MAAM,EACf,UAAU,SAAgB,EAC1B,OAAO,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAAE,iBAajE;AAED,wBAAsB,sBAAsB,CAC1C,YAAY,SAAS,gBAAgB,EACrC,OAAO,EAEP,EAAE,EAAE,uBAAuB,CAAC,YAAY,CAAC,EACzC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,CAAC,EAAE,EAAE,YAAY,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,EAC1D,UAAU,SAAgB,EAC1B,OAAO,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAAE,oBAQjE"}
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../src/postgres/runtime.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,gBAAgB,EAChB,uBAAuB,EACxB,MAAM,YAAY,CAAA;AAwBnB,MAAM,MAAM,mBAAmB,GAAG;IAChC,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACjC,CAAA;AAED,wBAAsB,eAAe,CACnC,EAAE,EAAE,gBAAgB,EACpB,OAAO,EAAE,MAAM,EACf,UAAU,SAAgB,EAC1B,OAAO,CAAC,EAAE,mBAAmB,iBAa9B;AAED,wBAAsB,sBAAsB,CAC1C,YAAY,SAAS,gBAAgB,EACrC,OAAO,EAEP,EAAE,EAAE,uBAAuB,CAAC,YAAY,CAAC,EACzC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,CAAC,EAAE,EAAE,YAAY,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,EAC1D,UAAU,SAAgB,EAC1B,OAAO,CAAC,EAAE,mBAAmB,oBAQ9B"}
@@ -4,12 +4,24 @@ function assertActorId(actorId) {
4
4
  throw new Error("actorId must not be empty");
5
5
  }
6
6
  }
7
+ /**
8
+ * Builds the `context` GUC map from a set of options. Empty/undefined values
9
+ * are dropped so the trigger's NULLIF yields NULL.
10
+ */
11
+ function resolveContext(options) {
12
+ const context = {};
13
+ for (const [key, value] of Object.entries(options?.context ?? {})) {
14
+ if (value !== undefined && value !== "") {
15
+ context[key] = value;
16
+ }
17
+ }
18
+ return context;
19
+ }
7
20
  export async function setAuditContext(db, actorId, contextKey = "app.user_id", options) {
8
21
  assertActorId(actorId);
9
22
  await db.execute(sql `select set_config(${contextKey}, ${actorId}, true) as audit_context`);
10
- if (options?.workspaceId !== undefined && options.workspaceId !== "") {
11
- const wsKey = options.workspaceContextKey ?? "app.workspace_id";
12
- await db.execute(sql `select set_config(${wsKey}, ${options.workspaceId}, true) as workspace_context`);
23
+ for (const [key, value] of Object.entries(resolveContext(options))) {
24
+ await db.execute(sql `select set_config(${key}, ${value}, true) as audit_context`);
13
25
  }
14
26
  }
15
27
  export async function withAuditedTransaction(db, actorId, callback, contextKey = "app.user_id", options) {
@@ -3,12 +3,15 @@ export declare function createAuditInstallSql(options?: AuditInstallOptions): st
3
3
  export declare function createAttachAuditTriggerSql(target: AuditTriggerTarget, options?: AuditInstallOptions): string;
4
4
  export declare function createAttachAuditTriggersSql(targets: AuditTriggerTarget[], options?: AuditInstallOptions): string;
5
5
  /**
6
- * Generates SQL to add the workspace column and replace the trigger function on an
7
- * existing audit_logs table. Use in a new migration when adding workspace_id after
8
- * the initial install. Options must match your install (auditSchema, auditTable,
9
- * triggerFunctionName, contextKey, workspaceIdColumn).
6
+ * Generates SQL to add context columns and regenerate the trigger function on an
7
+ * existing audit_logs table. Use in a new migration when adding context columns
8
+ * after the initial install.
9
+ *
10
+ * Pass the FULL set of context columns the audit table should have (the trigger is
11
+ * a single CREATE OR REPLACE, so it must reference every column). Columns are added
12
+ * with `ADD COLUMN IF NOT EXISTS`, so already-present columns are left untouched.
13
+ * Options must match your install (auditSchema, auditTable, triggerFunctionName,
14
+ * contextKey).
10
15
  */
11
- export declare function createAuditAddWorkspaceColumnSql(options: AuditInstallOptions & {
12
- workspaceIdColumn: string;
13
- }): string;
16
+ export declare function createAuditAddContextColumnsSql(options?: AuditInstallOptions): string;
14
17
  //# sourceMappingURL=sql.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sql.d.ts","sourceRoot":"","sources":["../../../src/postgres/sql.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAqHzE,wBAAgB,qBAAqB,CAAC,OAAO,GAAE,mBAAwB,UA6DtE;AAED,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,kBAAkB,EAC1B,OAAO,GAAE,mBAAwB,UAiClC;AAED,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,kBAAkB,EAAE,EAC7B,OAAO,GAAE,mBAAwB,UASlC;AAED;;;;;GAKG;AACH,wBAAgB,gCAAgC,CAC9C,OAAO,EAAE,mBAAmB,GAAG;IAAE,iBAAiB,EAAE,MAAM,CAAA;CAAE,UAkC7D"}
1
+ {"version":3,"file":"sql.d.ts","sourceRoot":"","sources":["../../../src/postgres/sql.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,mBAAmB,EACnB,kBAAkB,EACnB,MAAM,YAAY,CAAA;AAkJnB,wBAAgB,qBAAqB,CAAC,OAAO,GAAE,mBAAwB,UA8DtE;AAED,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,kBAAkB,EAC1B,OAAO,GAAE,mBAAwB,UAiClC;AAED,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,kBAAkB,EAAE,EAC7B,OAAO,GAAE,mBAAwB,UASlC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,+BAA+B,CAAC,OAAO,GAAE,mBAAwB,UA2ChF"}