@explita/prisma-audit-log 0.2.0 → 0.2.2
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 +3 -2
- package/dist/core/create.d.ts +2 -2
- package/dist/core/create.js +2 -2
- package/dist/core/update-many.js +3 -1
- package/dist/core/update.d.ts +2 -2
- package/dist/core/update.js +27 -22
- package/dist/core/upsert.d.ts +2 -0
- package/dist/core/upsert.js +26 -0
- package/dist/lib/prisma-extension.js +6 -3
- package/dist/types.d.ts +9 -3
- package/package.json +10 -1
package/README.md
CHANGED
|
@@ -102,7 +102,7 @@ const prisma = new PrismaClient().$extends(
|
|
|
102
102
|
},
|
|
103
103
|
|
|
104
104
|
// Timestamp-only updates are skipped automatically, so no extra config needed
|
|
105
|
-
})
|
|
105
|
+
}),
|
|
106
106
|
);
|
|
107
107
|
```
|
|
108
108
|
|
|
@@ -164,10 +164,11 @@ route.put("/test/:id", async (request, reply) => {
|
|
|
164
164
|
| `maskValue` | `any` | Value to use for masked fields (default: `[REDACTED]`) |
|
|
165
165
|
| `maxStringLength` | `number` | Truncate long strings |
|
|
166
166
|
| `maxArrayLength` | `number` | Truncate large arrays |
|
|
167
|
+
| `enabled` | `boolean` | Enable or disable audit logging (defaults to `true`) |
|
|
167
168
|
| `maxPayloadBytes` | `number` | Maximum JSON payload size (before truncation) |
|
|
168
169
|
| `fieldFilters` | `{ [model: string]: { include?: string[]; exclude?: string[] } }` | Configure field inclusion/exclusion per model. Use `include` to whitelist fields or `exclude` to blacklist them. |
|
|
169
170
|
| `skip` | `(params: { model: string; operation: string; args: any }) => boolean \| Promise<boolean>` | Skip logging for specific operations |
|
|
170
|
-
| `logger` | `(log: AuditLog
|
|
171
|
+
| `logger` | `(log: AuditLog[]) => void \| Promise<void>` | Custom logger function for audit logs |
|
|
171
172
|
|
|
172
173
|
## License
|
|
173
174
|
|
package/dist/core/create.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type { HandlerArgs } from "../types.js";
|
|
2
|
-
export declare function handleCreate(opts: HandlerArgs): Promise<any>;
|
|
1
|
+
import type { AuditLog, HandlerArgs } from "../types.js";
|
|
2
|
+
export declare function handleCreate(opts: HandlerArgs, action?: AuditLog["action"]): Promise<any>;
|
package/dist/core/create.js
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.handleCreate = handleCreate;
|
|
4
4
|
const process_js_1 = require("./process.js");
|
|
5
|
-
async function handleCreate(opts) {
|
|
5
|
+
async function handleCreate(opts, action = "CREATE") {
|
|
6
6
|
const { args, prisma, query, options, modelName } = opts;
|
|
7
7
|
const result = await query(args);
|
|
8
8
|
const auditLog = {
|
|
9
|
-
action
|
|
9
|
+
action,
|
|
10
10
|
model: modelName,
|
|
11
11
|
recordId: result.id,
|
|
12
12
|
newData: result,
|
package/dist/core/update-many.js
CHANGED
|
@@ -16,7 +16,7 @@ async function handleUpdateMany(opts) {
|
|
|
16
16
|
const ids = currentRecords.map((row) => row.id);
|
|
17
17
|
const result = await query(args);
|
|
18
18
|
//updated records
|
|
19
|
-
const updatedRecords = operation == "
|
|
19
|
+
const updatedRecords = operation == "updateManyAndReturn"
|
|
20
20
|
? result
|
|
21
21
|
: await prisma[modelName].findMany({
|
|
22
22
|
where: { id: { in: ids } },
|
|
@@ -28,6 +28,8 @@ async function handleUpdateMany(opts) {
|
|
|
28
28
|
if (!updated)
|
|
29
29
|
continue;
|
|
30
30
|
const changedFields = (0, utils_js_1.getChangedFields)(current, updated);
|
|
31
|
+
if (changedFields.length === 0)
|
|
32
|
+
continue;
|
|
31
33
|
if (changedFields.length === 1 &&
|
|
32
34
|
(changedFields[0] === "updatedAt" || changedFields[0] === "updated_at")) {
|
|
33
35
|
continue;
|
package/dist/core/update.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type { HandlerArgs } from "../types.js";
|
|
2
|
-
export declare function handleUpdate(opts: HandlerArgs): Promise<any>;
|
|
1
|
+
import type { AuditLog, HandlerArgs } from "../types.js";
|
|
2
|
+
export declare function handleUpdate(opts: HandlerArgs, action?: AuditLog["action"]): Promise<any>;
|
package/dist/core/update.js
CHANGED
|
@@ -3,29 +3,34 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.handleUpdate = handleUpdate;
|
|
4
4
|
const utils_js_1 = require("../lib/utils.js");
|
|
5
5
|
const process_js_1 = require("./process.js");
|
|
6
|
-
async function handleUpdate(opts) {
|
|
7
|
-
const { args, prisma, query, options, modelName } = opts;
|
|
8
|
-
//
|
|
9
|
-
const current =
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
async function handleUpdate(opts, action = "UPDATE") {
|
|
7
|
+
const { args, prisma, query, options, modelName, existingRecord } = opts;
|
|
8
|
+
// Use provided existingRecord or fetch it if not provided
|
|
9
|
+
const current = existingRecord ||
|
|
10
|
+
(await prisma[modelName].findUnique({
|
|
11
|
+
where: args["where"],
|
|
12
|
+
}));
|
|
13
|
+
if (!current) {
|
|
14
|
+
return query(args);
|
|
15
|
+
}
|
|
12
16
|
const result = await query(args);
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const auditLog = {
|
|
21
|
-
action: "UPDATE",
|
|
22
|
-
model: modelName,
|
|
23
|
-
recordId: result.id,
|
|
24
|
-
oldData,
|
|
25
|
-
newData,
|
|
26
|
-
changedFields,
|
|
27
|
-
};
|
|
28
|
-
await (0, process_js_1.saveAuditLogs)(prisma, [auditLog], options);
|
|
17
|
+
const changedFields = (0, utils_js_1.getChangedFields)(current, result);
|
|
18
|
+
if (changedFields.length === 0)
|
|
19
|
+
return result;
|
|
20
|
+
// Skip if only timestamps were updated
|
|
21
|
+
if (changedFields.length === 1 &&
|
|
22
|
+
(changedFields[0] === "updatedAt" || changedFields[0] === "updated_at")) {
|
|
23
|
+
return result;
|
|
29
24
|
}
|
|
25
|
+
const { oldData, newData } = (0, utils_js_1.buildSnapshot)(changedFields, current, result);
|
|
26
|
+
const auditLog = {
|
|
27
|
+
action,
|
|
28
|
+
model: modelName,
|
|
29
|
+
recordId: result.id,
|
|
30
|
+
oldData,
|
|
31
|
+
newData,
|
|
32
|
+
changedFields,
|
|
33
|
+
};
|
|
34
|
+
await (0, process_js_1.saveAuditLogs)(prisma, [auditLog], options);
|
|
30
35
|
return result;
|
|
31
36
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handleUpsert = handleUpsert;
|
|
4
|
+
const create_js_1 = require("./create.js");
|
|
5
|
+
const update_js_1 = require("./update.js");
|
|
6
|
+
async function handleUpsert(opts) {
|
|
7
|
+
const { args, prisma, modelName } = opts;
|
|
8
|
+
// Check if the record exists before performing the upsert
|
|
9
|
+
const existingRecord = await prisma[modelName].findUnique({
|
|
10
|
+
where: args["where"],
|
|
11
|
+
});
|
|
12
|
+
if (existingRecord) {
|
|
13
|
+
// Handle update case with the existing record to avoid extra query
|
|
14
|
+
// Pass a custom action to handleUpdate to indicate this is from an upsert
|
|
15
|
+
return await (0, update_js_1.handleUpdate)({
|
|
16
|
+
...opts,
|
|
17
|
+
existingRecord,
|
|
18
|
+
}, "UPDATE_upsert");
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
// Handle create case with custom action
|
|
22
|
+
return await (0, create_js_1.handleCreate)({
|
|
23
|
+
...opts,
|
|
24
|
+
}, "CREATE_upsert");
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -9,10 +9,11 @@ const update_many_js_1 = require("../core/update-many.js");
|
|
|
9
9
|
const delete_js_1 = require("../core/delete.js");
|
|
10
10
|
const delete_many_js_1 = require("../core/delete-many.js");
|
|
11
11
|
const update_js_1 = require("../core/update.js");
|
|
12
|
+
const upsert_js_1 = require("../core/upsert.js");
|
|
12
13
|
/**
|
|
13
14
|
* Creates a Prisma extension that adds audit logging
|
|
14
15
|
*/
|
|
15
|
-
function auditLogExtension(options = {}) {
|
|
16
|
+
function auditLogExtension(options = { enabled: true }) {
|
|
16
17
|
return extension_1.Prisma.defineExtension((prisma) => {
|
|
17
18
|
return prisma.$extends({
|
|
18
19
|
name: "auditLogExtension",
|
|
@@ -24,8 +25,8 @@ function auditLogExtension(options = {}) {
|
|
|
24
25
|
if (["auditLog", "AuditLog"].includes(modelName !== null && modelName !== void 0 ? modelName : "")) {
|
|
25
26
|
return query(args);
|
|
26
27
|
}
|
|
27
|
-
// Skip if model is excluded or not included
|
|
28
|
-
if ((0, utils_js_1.shouldSkipModel)(modelName, options)) {
|
|
28
|
+
// Skip if model is excluded or not included or disabled
|
|
29
|
+
if (!options.enabled || (0, utils_js_1.shouldSkipModel)(modelName, options)) {
|
|
29
30
|
return query(args);
|
|
30
31
|
}
|
|
31
32
|
// Check if the operation should be skipped via the skip callback
|
|
@@ -63,6 +64,8 @@ function auditLogExtension(options = {}) {
|
|
|
63
64
|
case "updateMany":
|
|
64
65
|
case "updateManyAndReturn":
|
|
65
66
|
return (0, update_many_js_1.handleUpdateMany)(queryArgs);
|
|
67
|
+
case "upsert":
|
|
68
|
+
return (0, upsert_js_1.handleUpsert)(queryArgs);
|
|
66
69
|
default:
|
|
67
70
|
return query(args);
|
|
68
71
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import type { JsArgs } from "@prisma/client/runtime/client";
|
|
2
2
|
export interface AuditLogOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Enable or disable audit logging
|
|
5
|
+
* @default true
|
|
6
|
+
*/
|
|
7
|
+
enabled?: boolean;
|
|
3
8
|
/**
|
|
4
9
|
* Function to determine if audit logging should be skipped for the current operation
|
|
5
10
|
* @returns true to skip logging, false or undefined to continue with logging
|
|
@@ -37,7 +42,7 @@ export interface AuditLogOptions {
|
|
|
37
42
|
* Custom logger function
|
|
38
43
|
* If not provided, logs will be written to console
|
|
39
44
|
*/
|
|
40
|
-
logger?: (log: AuditLog
|
|
45
|
+
logger?: (log: AuditLog[]) => void | Promise<void>;
|
|
41
46
|
/**
|
|
42
47
|
* Keys to mask in oldData/newData/metadata. Exact match on property name.
|
|
43
48
|
*/
|
|
@@ -57,7 +62,7 @@ export interface AuditLogOptions {
|
|
|
57
62
|
}
|
|
58
63
|
export interface AuditLog {
|
|
59
64
|
id: string;
|
|
60
|
-
action: "CREATE" | "UPDATE" | "DELETE";
|
|
65
|
+
action: "CREATE" | "UPDATE" | "DELETE" | "CREATE_upsert" | "UPDATE_upsert";
|
|
61
66
|
model: string;
|
|
62
67
|
recordId: string;
|
|
63
68
|
oldData?: Record<string, any>;
|
|
@@ -83,7 +88,8 @@ export type HandlerArgs = {
|
|
|
83
88
|
args: JsArgs;
|
|
84
89
|
query: (args: JsArgs) => Promise<any>;
|
|
85
90
|
options: AuditLogOptions;
|
|
86
|
-
operation
|
|
91
|
+
operation: string;
|
|
92
|
+
existingRecord?: any;
|
|
87
93
|
};
|
|
88
94
|
export type FieldFilterConfig = {
|
|
89
95
|
include?: string[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@explita/prisma-audit-log",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "A Prisma extension for automatic audit logging",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -12,11 +12,20 @@
|
|
|
12
12
|
],
|
|
13
13
|
"license": "MIT",
|
|
14
14
|
"author": "Explita",
|
|
15
|
+
"sideEffects": false,
|
|
15
16
|
"scripts": {
|
|
16
17
|
"clean": "rimraf dist",
|
|
17
18
|
"build": "npm run clean && tsc",
|
|
18
19
|
"prepublishOnly": "npm run build"
|
|
19
20
|
},
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/explita/prisma-audit-log.git"
|
|
24
|
+
},
|
|
25
|
+
"bugs": {
|
|
26
|
+
"url": "https://github.com/explita/prisma-audit-log/issues"
|
|
27
|
+
},
|
|
28
|
+
"homepage": "https://github.com/explita/prisma-audit-log#readme",
|
|
20
29
|
"peerDependencies": {
|
|
21
30
|
"@prisma/client": "^7"
|
|
22
31
|
},
|