@willyim/drizzle-audit 0.1.3 → 0.3.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.
@@ -0,0 +1,15 @@
1
+ export type DiffEntry = {
2
+ field: string;
3
+ old: unknown;
4
+ new: unknown;
5
+ };
6
+ export type DiffResult = {
7
+ operation: string;
8
+ changes: DiffEntry[];
9
+ };
10
+ export type ComputeDiffOptions = {
11
+ /** Fields to exclude from the diff (default: ["updated_at", "created_at"]) */
12
+ ignoreFields?: string[];
13
+ };
14
+ export declare function computeDiff(operation: string, oldData: Record<string, unknown> | null, newData: Record<string, unknown> | null, options?: ComputeDiffOptions): DiffResult;
15
+ //# sourceMappingURL=compute-diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compute-diff.d.ts","sourceRoot":"","sources":["../../src/compute-diff.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,OAAO,CAAC;IACb,GAAG,EAAE,OAAO,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,SAAS,EAAE,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,8EAA8E;IAC9E,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB,CAAC;AAQF,wBAAgB,WAAW,CACzB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EACvC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EACvC,OAAO,CAAC,EAAE,kBAAkB,GAC3B,UAAU,CAyBZ"}
@@ -0,0 +1,22 @@
1
+ const DEFAULT_IGNORE = ["updated_at", "created_at"];
2
+ function deepEqual(a, b) {
3
+ return JSON.stringify(a) === JSON.stringify(b);
4
+ }
5
+ export function computeDiff(operation, oldData, newData, options) {
6
+ const ignore = options?.ignoreFields ?? DEFAULT_IGNORE;
7
+ if (oldData === null && newData === null) {
8
+ return { operation, changes: [] };
9
+ }
10
+ const allKeys = Array.from(new Set([...Object.keys(oldData ?? {}), ...Object.keys(newData ?? {})]))
11
+ .filter((k) => !ignore.includes(k))
12
+ .sort();
13
+ const changes = [];
14
+ for (const field of allKeys) {
15
+ const oldVal = oldData?.[field] ?? null;
16
+ const newVal = newData?.[field] ?? null;
17
+ if (!deepEqual(oldVal, newVal)) {
18
+ changes.push({ field, old: oldVal, new: newVal });
19
+ }
20
+ }
21
+ return { operation, changes };
22
+ }
@@ -1,4 +1,5 @@
1
1
  export * from "./postgres/index.js";
2
2
  export * from "./d1/index.js";
3
3
  export * from "./d1-runtime/index.js";
4
+ export * from "./compute-diff.js";
4
5
  //# 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"}
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"}
package/dist/src/index.js CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from "./postgres/index.js";
2
2
  export * from "./d1/index.js";
3
3
  export * from "./d1-runtime/index.js";
4
+ export * from "./compute-diff.js";
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=compute-diff.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compute-diff.test.d.ts","sourceRoot":"","sources":["../../test/compute-diff.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,60 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+ import { computeDiff } from "../src/compute-diff.js";
4
+ test("UPDATE — only changed fields are emitted", () => {
5
+ const result = computeDiff("UPDATE", { name: "Juan", phone: "809", status: "current" }, { name: "Juan Carlos", phone: "809", status: "current" });
6
+ assert.deepEqual(result, {
7
+ operation: "UPDATE",
8
+ changes: [{ field: "name", old: "Juan", new: "Juan Carlos" }],
9
+ });
10
+ });
11
+ test("UPDATE — ignores updated_at by default", () => {
12
+ const result = computeDiff("UPDATE", { name: "A", updated_at: "2026-01-01" }, { name: "B", updated_at: "2026-04-15" });
13
+ assert.deepEqual(result, {
14
+ operation: "UPDATE",
15
+ changes: [{ field: "name", old: "A", new: "B" }],
16
+ });
17
+ });
18
+ test("UPDATE — ignores created_at by default", () => {
19
+ const result = computeDiff("UPDATE", { name: "A", created_at: "2026-01-01" }, { name: "A", created_at: "2026-04-15" });
20
+ assert.deepEqual(result, { operation: "UPDATE", changes: [] });
21
+ });
22
+ test("INSERT — all fields with old: null", () => {
23
+ const result = computeDiff("INSERT", null, { name: "María", phone: "809" });
24
+ assert.deepEqual(result, {
25
+ operation: "INSERT",
26
+ changes: [
27
+ { field: "name", old: null, new: "María" },
28
+ { field: "phone", old: null, new: "809" },
29
+ ],
30
+ });
31
+ });
32
+ test("DELETE — all fields with new: null", () => {
33
+ const result = computeDiff("DELETE", { name: "Pedro", phone: "809" }, null);
34
+ assert.deepEqual(result, {
35
+ operation: "DELETE",
36
+ changes: [
37
+ { field: "name", old: "Pedro", new: null },
38
+ { field: "phone", old: "809", new: null },
39
+ ],
40
+ });
41
+ });
42
+ test("custom ignoreFields", () => {
43
+ const result = computeDiff("UPDATE", { a: 1, b: 2 }, { a: 1, b: 3 }, { ignoreFields: ["b"] });
44
+ assert.deepEqual(result, { operation: "UPDATE", changes: [] });
45
+ });
46
+ test("deep equality for nested objects", () => {
47
+ const result = computeDiff("UPDATE", { payload: { x: 1 } }, { payload: { x: 2 } });
48
+ assert.deepEqual(result, {
49
+ operation: "UPDATE",
50
+ changes: [{ field: "payload", old: { x: 1 }, new: { x: 2 } }],
51
+ });
52
+ });
53
+ test("both null — returns empty changes", () => {
54
+ const result = computeDiff("UPDATE", null, null);
55
+ assert.deepEqual(result, { operation: "UPDATE", changes: [] });
56
+ });
57
+ test("changes are sorted alphabetically by field", () => {
58
+ const result = computeDiff("UPDATE", { zebra: 1, apple: 2, mango: 3 }, { zebra: 2, apple: 3, mango: 4 });
59
+ assert.deepEqual(result.changes.map((c) => c.field), ["apple", "mango", "zebra"]);
60
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@willyim/drizzle-audit",
3
- "version": "0.1.3",
3
+ "version": "0.3.0",
4
4
  "description": "Lightweight audit logging for Drizzle ORM using database triggers (Postgres + D1/SQLite)",
5
5
  "type": "module",
6
6
  "main": "./dist/src/index.js",