@willyim/drizzle-audit 0.3.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 +102 -21
- 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 +15 -11
- package/dist/src/d1-runtime/with-audit.d.ts.map +1 -1
- package/dist/src/d1-runtime/with-audit.js +53 -60
- 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 +7 -14
- 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-async.integration.test.d.ts +13 -0
- package/dist/test/d1-async.integration.test.d.ts.map +1 -0
- package/dist/test/d1-async.integration.test.js +159 -0
- package/dist/test/d1.integration.test.js +71 -4
- package/dist/test/sqlite.integration.test.d.ts +2 -0
- package/dist/test/sqlite.integration.test.d.ts.map +1 -0
- package/dist/test/{d1-runtime.integration.test.js → sqlite.integration.test.js} +82 -25
- package/package.json +2 -1
- package/dist/test/d1-runtime.integration.test.d.ts +0 -2
- package/dist/test/d1-runtime.integration.test.d.ts.map +0 -1
- package/dist/test/postgres.integration.test.d.ts +0 -2
- package/dist/test/postgres.integration.test.d.ts.map +0 -1
- package/dist/test/postgres.integration.test.js +0 -286
|
@@ -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;
|
|
@@ -22,37 +23,40 @@ export type DrizzleSQLiteDb = {
|
|
|
22
23
|
update: (table: any) => any;
|
|
23
24
|
delete: (table: any) => any;
|
|
24
25
|
select: (fields?: any) => any;
|
|
25
|
-
transaction: (cb: (tx: any) => any) => any;
|
|
26
26
|
};
|
|
27
27
|
export type AuditedDb<TDb extends DrizzleSQLiteDb> = {
|
|
28
28
|
/**
|
|
29
29
|
* Insert a row and log an INSERT audit event.
|
|
30
30
|
* Returns the inserted row.
|
|
31
31
|
*/
|
|
32
|
-
insert: <T extends SQLiteTable>(table: T, data: InferInsertModel<T>) => InferSelectModel<T
|
|
32
|
+
insert: <T extends SQLiteTable>(table: T, data: InferInsertModel<T>) => Promise<InferSelectModel<T>>;
|
|
33
33
|
/**
|
|
34
34
|
* Update rows matching `where` and log an UPDATE audit event for each affected row.
|
|
35
35
|
* Captures old_data (before) and new_data (after).
|
|
36
36
|
* Returns the updated rows.
|
|
37
37
|
*/
|
|
38
|
-
update: <T extends SQLiteTable>(table: T, where: SQL, data: Partial<InferInsertModel<T>>) => InferSelectModel<T>[]
|
|
38
|
+
update: <T extends SQLiteTable>(table: T, where: SQL, data: Partial<InferInsertModel<T>>) => Promise<InferSelectModel<T>[]>;
|
|
39
39
|
/**
|
|
40
40
|
* Delete rows matching `where` and log a DELETE audit event for each affected row.
|
|
41
41
|
* Captures old_data.
|
|
42
42
|
* Returns the deleted rows.
|
|
43
43
|
*/
|
|
44
|
-
delete: <T extends SQLiteTable>(table: T, where: SQL) => InferSelectModel<T>[]
|
|
44
|
+
delete: <T extends SQLiteTable>(table: T, where: SQL) => Promise<InferSelectModel<T>[]>;
|
|
45
45
|
/** Access the underlying db for non-audited operations. */
|
|
46
46
|
db: TDb;
|
|
47
47
|
};
|
|
48
48
|
/**
|
|
49
49
|
* Creates an audited wrapper around a Drizzle SQLite database.
|
|
50
|
-
* Each insert/update/delete
|
|
51
|
-
*
|
|
50
|
+
* Each insert/update/delete runs the data write and audit log insert sequentially
|
|
51
|
+
* as individual statements (no transaction). This works with both D1 (async) and
|
|
52
|
+
* better-sqlite3 (sync), but writes are best-effort: a failure between the data
|
|
53
|
+
* write and the audit insert can leave one without the other.
|
|
54
|
+
*
|
|
55
|
+
* For atomic auditing on D1, use the trigger-based approach from `@willyim/drizzle-audit/d1`.
|
|
52
56
|
*
|
|
53
57
|
* @param db - A Drizzle SQLite database instance (D1, better-sqlite3, libsql)
|
|
54
58
|
* @param auditTable - The Drizzle table definition for audit_logs
|
|
55
|
-
* @param context - The audit context (userId, optional
|
|
59
|
+
* @param context - The audit context (userId, optional context columns)
|
|
56
60
|
*
|
|
57
61
|
* @example
|
|
58
62
|
* import { withAudit } from "drizzle-audit/d1-runtime"
|
|
@@ -62,13 +66,13 @@ export type AuditedDb<TDb extends DrizzleSQLiteDb> = {
|
|
|
62
66
|
* const audited = withAudit(db, auditLogs, { userId: session.userId })
|
|
63
67
|
*
|
|
64
68
|
* // Audited insert
|
|
65
|
-
* audited.insert(users, { id: "u1", name: "Ada" })
|
|
69
|
+
* await audited.insert(users, { id: "u1", name: "Ada" })
|
|
66
70
|
*
|
|
67
71
|
* // Audited update — captures old + new data
|
|
68
|
-
* audited.update(users, eq(users.id, "u1"), { name: "Ada Lovelace" })
|
|
72
|
+
* await audited.update(users, eq(users.id, "u1"), { name: "Ada Lovelace" })
|
|
69
73
|
*
|
|
70
74
|
* // Audited delete — captures deleted data
|
|
71
|
-
* audited.delete(users, eq(users.id, "u1"))
|
|
75
|
+
* await audited.delete(users, eq(users.id, "u1"))
|
|
72
76
|
*
|
|
73
77
|
* // Non-audited access
|
|
74
78
|
* audited.db.select().from(users).all()
|
|
@@ -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"}
|
|
@@ -12,12 +12,16 @@ function getRowId(row, pk) {
|
|
|
12
12
|
}
|
|
13
13
|
/**
|
|
14
14
|
* Creates an audited wrapper around a Drizzle SQLite database.
|
|
15
|
-
* Each insert/update/delete
|
|
16
|
-
*
|
|
15
|
+
* Each insert/update/delete runs the data write and audit log insert sequentially
|
|
16
|
+
* as individual statements (no transaction). This works with both D1 (async) and
|
|
17
|
+
* better-sqlite3 (sync), but writes are best-effort: a failure between the data
|
|
18
|
+
* write and the audit insert can leave one without the other.
|
|
19
|
+
*
|
|
20
|
+
* For atomic auditing on D1, use the trigger-based approach from `@willyim/drizzle-audit/d1`.
|
|
17
21
|
*
|
|
18
22
|
* @param db - A Drizzle SQLite database instance (D1, better-sqlite3, libsql)
|
|
19
23
|
* @param auditTable - The Drizzle table definition for audit_logs
|
|
20
|
-
* @param context - The audit context (userId, optional
|
|
24
|
+
* @param context - The audit context (userId, optional context columns)
|
|
21
25
|
*
|
|
22
26
|
* @example
|
|
23
27
|
* import { withAudit } from "drizzle-audit/d1-runtime"
|
|
@@ -27,19 +31,19 @@ function getRowId(row, pk) {
|
|
|
27
31
|
* const audited = withAudit(db, auditLogs, { userId: session.userId })
|
|
28
32
|
*
|
|
29
33
|
* // Audited insert
|
|
30
|
-
* audited.insert(users, { id: "u1", name: "Ada" })
|
|
34
|
+
* await audited.insert(users, { id: "u1", name: "Ada" })
|
|
31
35
|
*
|
|
32
36
|
* // Audited update — captures old + new data
|
|
33
|
-
* audited.update(users, eq(users.id, "u1"), { name: "Ada Lovelace" })
|
|
37
|
+
* await audited.update(users, eq(users.id, "u1"), { name: "Ada Lovelace" })
|
|
34
38
|
*
|
|
35
39
|
* // Audited delete — captures deleted data
|
|
36
|
-
* audited.delete(users, eq(users.id, "u1"))
|
|
40
|
+
* await audited.delete(users, eq(users.id, "u1"))
|
|
37
41
|
*
|
|
38
42
|
* // Non-audited access
|
|
39
43
|
* audited.db.select().from(users).all()
|
|
40
44
|
*/
|
|
41
45
|
export function withAudit(db, auditTable, context) {
|
|
42
|
-
const
|
|
46
|
+
const extraColumns = (() => {
|
|
43
47
|
const cols = getTableColumns(auditTable);
|
|
44
48
|
const known = new Set([
|
|
45
49
|
"id",
|
|
@@ -51,10 +55,17 @@ export function withAudit(db, auditTable, context) {
|
|
|
51
55
|
"new_data",
|
|
52
56
|
"created_at",
|
|
53
57
|
]);
|
|
54
|
-
|
|
55
|
-
return extra ?? null;
|
|
58
|
+
return Object.keys(cols).filter((k) => !known.has(k));
|
|
56
59
|
})();
|
|
60
|
+
const contextValues = { ...(context.context ?? {}) };
|
|
57
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
|
+
}
|
|
58
69
|
return {
|
|
59
70
|
table_name: tableName,
|
|
60
71
|
operation,
|
|
@@ -62,69 +73,51 @@ export function withAudit(db, auditTable, context) {
|
|
|
62
73
|
user_id: context.userId,
|
|
63
74
|
old_data: oldData ? JSON.stringify(oldData) : null,
|
|
64
75
|
new_data: newData ? JSON.stringify(newData) : null,
|
|
65
|
-
...
|
|
66
|
-
? { [workspaceIdColumn]: context.workspaceId }
|
|
67
|
-
: {}),
|
|
76
|
+
...extra,
|
|
68
77
|
};
|
|
69
78
|
}
|
|
70
79
|
return {
|
|
71
80
|
db,
|
|
72
|
-
insert(table, data) {
|
|
81
|
+
async insert(table, data) {
|
|
73
82
|
const tableName = getTableName(table);
|
|
74
83
|
const pk = getPrimaryKeyColumn(table);
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
});
|
|
84
|
+
const [row] = await db.insert(table).values(data).returning().all();
|
|
85
|
+
const rowId = getRowId(row, pk);
|
|
86
|
+
await db
|
|
87
|
+
.insert(auditTable)
|
|
88
|
+
.values(buildAuditRow(tableName, "INSERT", rowId, null, row))
|
|
89
|
+
.run();
|
|
90
|
+
return row;
|
|
83
91
|
},
|
|
84
|
-
update(table, where, data) {
|
|
92
|
+
async update(table, where, data) {
|
|
85
93
|
const tableName = getTableName(table);
|
|
86
94
|
const pk = getPrimaryKeyColumn(table);
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
.
|
|
95
|
-
.
|
|
96
|
-
.
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
for (let i = 0; i < newRows.length; i++) {
|
|
100
|
-
const oldRow = oldRows[i] ?? null;
|
|
101
|
-
const newRow = newRows[i];
|
|
102
|
-
const rowId = getRowId(newRow, pk);
|
|
103
|
-
tx.insert(auditTable)
|
|
104
|
-
.values(buildAuditRow(tableName, "UPDATE", rowId, oldRow, newRow))
|
|
105
|
-
.run();
|
|
106
|
-
}
|
|
107
|
-
return newRows;
|
|
108
|
-
});
|
|
95
|
+
const oldRows = await db.select().from(table).where(where).all();
|
|
96
|
+
const newRows = await db.update(table).set(data).where(where).returning().all();
|
|
97
|
+
for (let i = 0; i < newRows.length; i++) {
|
|
98
|
+
const oldRow = oldRows[i] ?? null;
|
|
99
|
+
const newRow = newRows[i];
|
|
100
|
+
const rowId = getRowId(newRow, pk);
|
|
101
|
+
await db
|
|
102
|
+
.insert(auditTable)
|
|
103
|
+
.values(buildAuditRow(tableName, "UPDATE", rowId, oldRow, newRow))
|
|
104
|
+
.run();
|
|
105
|
+
}
|
|
106
|
+
return newRows;
|
|
109
107
|
},
|
|
110
|
-
delete(table, where) {
|
|
108
|
+
async delete(table, where) {
|
|
111
109
|
const tableName = getTableName(table);
|
|
112
110
|
const pk = getPrimaryKeyColumn(table);
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
.
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
.values(buildAuditRow(tableName, "DELETE", rowId, oldRow, null))
|
|
124
|
-
.run();
|
|
125
|
-
}
|
|
126
|
-
return oldRows;
|
|
127
|
-
});
|
|
111
|
+
const oldRows = await db.select().from(table).where(where).all();
|
|
112
|
+
await db.delete(table).where(where).run();
|
|
113
|
+
for (const oldRow of oldRows) {
|
|
114
|
+
const rowId = getRowId(oldRow, pk);
|
|
115
|
+
await db
|
|
116
|
+
.insert(auditTable)
|
|
117
|
+
.values(buildAuditRow(tableName, "DELETE", rowId, oldRow, null))
|
|
118
|
+
.run();
|
|
119
|
+
}
|
|
120
|
+
return oldRows;
|
|
128
121
|
},
|
|
129
122
|
};
|
|
130
123
|
}
|
package/dist/src/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export * from "./postgres/index.js";
|
|
2
|
-
export
|
|
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
|
package/dist/src/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAA;AACnC,
|
|
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
|
|
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
|
-
/**
|
|
3
|
-
|
|
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";
|
|
@@ -20,7 +21,6 @@ export declare function pgAuditLogTable(options?: PgAuditLogTableOptions): impor
|
|
|
20
21
|
enumValues: undefined;
|
|
21
22
|
identity: undefined;
|
|
22
23
|
generated: undefined;
|
|
23
|
-
insertType: unknown;
|
|
24
24
|
}>;
|
|
25
25
|
new_data: import("drizzle-orm/pg-core").PgBuildColumn<"audit_logs", import("drizzle-orm/pg-core").PgJsonbBuilder, {
|
|
26
26
|
name: string;
|
|
@@ -36,7 +36,6 @@ export declare function pgAuditLogTable(options?: PgAuditLogTableOptions): impor
|
|
|
36
36
|
enumValues: undefined;
|
|
37
37
|
identity: undefined;
|
|
38
38
|
generated: undefined;
|
|
39
|
-
insertType: unknown;
|
|
40
39
|
}>;
|
|
41
40
|
created_at: import("drizzle-orm/pg-core").PgBuildColumn<"audit_logs", import("drizzle-orm/pg-core").SetNotNull<import("drizzle-orm/pg-core").SetHasDefault<import("drizzle-orm/pg-core").PgTimestampBuilder>>, {
|
|
42
41
|
name: string;
|
|
@@ -52,7 +51,6 @@ export declare function pgAuditLogTable(options?: PgAuditLogTableOptions): impor
|
|
|
52
51
|
enumValues: undefined;
|
|
53
52
|
identity: undefined;
|
|
54
53
|
generated: undefined;
|
|
55
|
-
insertType: Date | undefined;
|
|
56
54
|
}>;
|
|
57
55
|
id: import("drizzle-orm/pg-core").PgBuildColumn<"audit_logs", import("drizzle-orm/pg-core").SetIsPrimaryKey<import("drizzle-orm/pg-core").PgBigSerial53Builder>, {
|
|
58
56
|
name: string;
|
|
@@ -68,9 +66,8 @@ export declare function pgAuditLogTable(options?: PgAuditLogTableOptions): impor
|
|
|
68
66
|
enumValues: undefined;
|
|
69
67
|
identity: undefined;
|
|
70
68
|
generated: undefined;
|
|
71
|
-
insertType: number | undefined;
|
|
72
69
|
}>;
|
|
73
|
-
table_name: import("drizzle-orm/pg-core").PgBuildColumn<"audit_logs", import("drizzle-orm/pg-core").SetNotNull<import("drizzle-orm/pg-core").PgTextBuilder<
|
|
70
|
+
table_name: import("drizzle-orm/pg-core").PgBuildColumn<"audit_logs", import("drizzle-orm/pg-core").SetNotNull<import("drizzle-orm/pg-core").PgTextBuilder<[string, ...string[]]>>, {
|
|
74
71
|
name: string;
|
|
75
72
|
tableName: "audit_logs";
|
|
76
73
|
dataType: "string";
|
|
@@ -84,9 +81,8 @@ export declare function pgAuditLogTable(options?: PgAuditLogTableOptions): impor
|
|
|
84
81
|
enumValues: undefined;
|
|
85
82
|
identity: undefined;
|
|
86
83
|
generated: undefined;
|
|
87
|
-
insertType: string;
|
|
88
84
|
}>;
|
|
89
|
-
operation: import("drizzle-orm/pg-core").PgBuildColumn<"audit_logs", import("drizzle-orm/pg-core").SetNotNull<import("drizzle-orm/pg-core").PgTextBuilder<
|
|
85
|
+
operation: import("drizzle-orm/pg-core").PgBuildColumn<"audit_logs", import("drizzle-orm/pg-core").SetNotNull<import("drizzle-orm/pg-core").PgTextBuilder<[string, ...string[]]>>, {
|
|
90
86
|
name: string;
|
|
91
87
|
tableName: "audit_logs";
|
|
92
88
|
dataType: "string";
|
|
@@ -100,9 +96,8 @@ export declare function pgAuditLogTable(options?: PgAuditLogTableOptions): impor
|
|
|
100
96
|
enumValues: undefined;
|
|
101
97
|
identity: undefined;
|
|
102
98
|
generated: undefined;
|
|
103
|
-
insertType: string;
|
|
104
99
|
}>;
|
|
105
|
-
row_id: import("drizzle-orm/pg-core").PgBuildColumn<"audit_logs", import("drizzle-orm/pg-core").PgTextBuilder<
|
|
100
|
+
row_id: import("drizzle-orm/pg-core").PgBuildColumn<"audit_logs", import("drizzle-orm/pg-core").PgTextBuilder<[string, ...string[]]>, {
|
|
106
101
|
name: string;
|
|
107
102
|
tableName: "audit_logs";
|
|
108
103
|
dataType: "string";
|
|
@@ -116,9 +111,8 @@ export declare function pgAuditLogTable(options?: PgAuditLogTableOptions): impor
|
|
|
116
111
|
enumValues: undefined;
|
|
117
112
|
identity: undefined;
|
|
118
113
|
generated: undefined;
|
|
119
|
-
insertType: string | null | undefined;
|
|
120
114
|
}>;
|
|
121
|
-
user_id: import("drizzle-orm/pg-core").PgBuildColumn<"audit_logs", import("drizzle-orm/pg-core").PgTextBuilder<
|
|
115
|
+
user_id: import("drizzle-orm/pg-core").PgBuildColumn<"audit_logs", import("drizzle-orm/pg-core").PgTextBuilder<[string, ...string[]]>, {
|
|
122
116
|
name: string;
|
|
123
117
|
tableName: "audit_logs";
|
|
124
118
|
dataType: "string";
|
|
@@ -132,7 +126,6 @@ export declare function pgAuditLogTable(options?: PgAuditLogTableOptions): impor
|
|
|
132
126
|
enumValues: undefined;
|
|
133
127
|
identity: undefined;
|
|
134
128
|
generated: undefined;
|
|
135
|
-
insertType: string | null | undefined;
|
|
136
129
|
}>;
|
|
137
130
|
};
|
|
138
131
|
dialect: "pg";
|
|
@@ -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
|
|
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
|
|
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
|
-
...(
|
|
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,
|
|
3
|
+
export { createAttachAuditTriggerSql, createAttachAuditTriggersSql, createAuditAddContextColumnsSql, createAuditInstallSql, } from "./sql.js";
|
|
4
4
|
export { setAuditContext, withAuditedTransaction } from "./runtime.js";
|
|
5
|
-
export type {
|
|
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,
|
|
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,
|
|
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
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}
|
|
6
|
-
export declare function
|
|
7
|
-
|
|
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;
|
|
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
|
-
|
|
11
|
-
|
|
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
|
|
7
|
-
* existing audit_logs table. Use in a new migration when adding
|
|
8
|
-
* the initial install.
|
|
9
|
-
*
|
|
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
|
|
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,
|
|
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"}
|