@nest-toolbox/typeorm-audit-log 1.8.1
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/LICENSE +21 -0
- package/README.md +283 -0
- package/dist/audit-context.d.ts +67 -0
- package/dist/audit-context.js +96 -0
- package/dist/audit-context.js.map +1 -0
- package/dist/audit-context.middleware.d.ts +76 -0
- package/dist/audit-context.middleware.js +91 -0
- package/dist/audit-context.middleware.js.map +1 -0
- package/dist/audit-log.entity.d.ts +56 -0
- package/dist/audit-log.entity.js +89 -0
- package/dist/audit-log.entity.js.map +1 -0
- package/dist/audit-log.module.d.ts +56 -0
- package/dist/audit-log.module.js +130 -0
- package/dist/audit-log.module.js.map +1 -0
- package/dist/audit-log.service.d.ts +43 -0
- package/dist/audit-log.service.js +177 -0
- package/dist/audit-log.service.js.map +1 -0
- package/dist/audit-log.subscriber.d.ts +66 -0
- package/dist/audit-log.subscriber.js +135 -0
- package/dist/audit-log.subscriber.js.map +1 -0
- package/dist/constants.d.ts +32 -0
- package/dist/constants.js +49 -0
- package/dist/constants.js.map +1 -0
- package/dist/decorators.d.ts +109 -0
- package/dist/decorators.js +161 -0
- package/dist/decorators.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/dist/types.d.ts +161 -0
- package/dist/types.js +16 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/diff.d.ts +16 -0
- package/dist/utils/diff.js +142 -0
- package/dist/utils/diff.js.map +1 -0
- package/dist/utils/mask.d.ts +15 -0
- package/dist/utils/mask.js +69 -0
- package/dist/utils/mask.js.map +1 -0
- package/package.json +63 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.AuditLogSubscriber = void 0;
|
|
10
|
+
const common_1 = require("@nestjs/common");
|
|
11
|
+
const decorators_1 = require("./decorators");
|
|
12
|
+
const types_1 = require("./types");
|
|
13
|
+
/**
|
|
14
|
+
* TypeORM event subscriber that captures entity changes and logs them.
|
|
15
|
+
* Automatically detects entities decorated with @Auditable() and creates
|
|
16
|
+
* audit log entries for INSERT, UPDATE, and DELETE operations.
|
|
17
|
+
*
|
|
18
|
+
* This subscriber is designed to be instantiated by NestJS DI and then
|
|
19
|
+
* registered with the TypeORM DataSource.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* // In your module
|
|
24
|
+
* @Module({
|
|
25
|
+
* providers: [
|
|
26
|
+
* {
|
|
27
|
+
* provide: AuditLogSubscriber,
|
|
28
|
+
* useFactory: (dataSource: DataSource, auditLogService: AuditLogService) => {
|
|
29
|
+
* const subscriber = new AuditLogSubscriber(auditLogService);
|
|
30
|
+
* dataSource.subscribers.push(subscriber);
|
|
31
|
+
* return subscriber;
|
|
32
|
+
* },
|
|
33
|
+
* inject: [DataSource, AuditLogService],
|
|
34
|
+
* },
|
|
35
|
+
* ],
|
|
36
|
+
* })
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
let AuditLogSubscriber = class AuditLogSubscriber {
|
|
40
|
+
constructor() {
|
|
41
|
+
this.auditLogService = null;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Set the audit log service. Called during module initialization.
|
|
45
|
+
*/
|
|
46
|
+
setAuditLogService(service) {
|
|
47
|
+
this.auditLogService = service;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Register this subscriber with a TypeORM DataSource.
|
|
51
|
+
*/
|
|
52
|
+
registerWithDataSource(dataSource) {
|
|
53
|
+
if (!dataSource.subscribers.includes(this)) {
|
|
54
|
+
dataSource.subscribers.push(this);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Handle entity insertion events.
|
|
59
|
+
*/
|
|
60
|
+
afterInsert(event) {
|
|
61
|
+
this.handleEvent(event, types_1.AuditAction.CREATE);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Handle entity update events.
|
|
65
|
+
*/
|
|
66
|
+
afterUpdate(event) {
|
|
67
|
+
this.handleEvent(event, types_1.AuditAction.UPDATE, event.databaseEntity);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Handle entity removal events.
|
|
71
|
+
*/
|
|
72
|
+
afterRemove(event) {
|
|
73
|
+
this.handleEvent(event, types_1.AuditAction.DELETE, event.databaseEntity);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Common handler for all entity events.
|
|
77
|
+
*/
|
|
78
|
+
handleEvent(event, action,
|
|
79
|
+
// biome-ignore lint/suspicious/noExplicitAny: old values can be any entity type
|
|
80
|
+
oldValues) {
|
|
81
|
+
const entity = event.entity;
|
|
82
|
+
// Skip if no entity or service not initialized
|
|
83
|
+
if (!entity || !this.auditLogService) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
// Skip if entity is not marked as auditable
|
|
87
|
+
if (!(0, decorators_1.isAuditable)(entity.constructor)) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
// Get entity name (custom or class name)
|
|
91
|
+
const entityName = (0, decorators_1.getAuditEntityName)(entity.constructor);
|
|
92
|
+
// Get entity ID from primary key
|
|
93
|
+
const entityId = this.getEntityId(event, entity);
|
|
94
|
+
// Log the audit entry (fire and forget - don't block the transaction)
|
|
95
|
+
this.auditLogService
|
|
96
|
+
.log({
|
|
97
|
+
action,
|
|
98
|
+
entity,
|
|
99
|
+
entityName,
|
|
100
|
+
entityId,
|
|
101
|
+
oldValues,
|
|
102
|
+
})
|
|
103
|
+
.catch((error) => {
|
|
104
|
+
// Log error but don't throw - audit failures shouldn't break the app
|
|
105
|
+
console.error('[AuditLogSubscriber] Failed to log audit entry:', error);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Extract the entity ID from the event or entity.
|
|
110
|
+
*/
|
|
111
|
+
getEntityId(event,
|
|
112
|
+
// biome-ignore lint/suspicious/noExplicitAny: entity can be any type
|
|
113
|
+
entity) {
|
|
114
|
+
var _a, _b, _c;
|
|
115
|
+
// Try to get ID from entity metadata (primary columns)
|
|
116
|
+
const primaryColumns = event.metadata.primaryColumns;
|
|
117
|
+
if (primaryColumns.length === 1) {
|
|
118
|
+
const primaryColumn = primaryColumns[0];
|
|
119
|
+
const value = entity[primaryColumn.propertyName];
|
|
120
|
+
return String(value !== null && value !== void 0 ? value : 'unknown');
|
|
121
|
+
}
|
|
122
|
+
// For composite keys, join them
|
|
123
|
+
if (primaryColumns.length > 1) {
|
|
124
|
+
const ids = primaryColumns.map((col) => entity[col.propertyName]);
|
|
125
|
+
return ids.join(':');
|
|
126
|
+
}
|
|
127
|
+
// Fallback: try common ID property names
|
|
128
|
+
return String((_c = (_b = (_a = entity.id) !== null && _a !== void 0 ? _a : entity.uuid) !== null && _b !== void 0 ? _b : entity._id) !== null && _c !== void 0 ? _c : 'unknown');
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
exports.AuditLogSubscriber = AuditLogSubscriber;
|
|
132
|
+
exports.AuditLogSubscriber = AuditLogSubscriber = __decorate([
|
|
133
|
+
(0, common_1.Injectable)()
|
|
134
|
+
], AuditLogSubscriber);
|
|
135
|
+
//# sourceMappingURL=audit-log.subscriber.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-log.subscriber.js","sourceRoot":"","sources":["../src/audit-log.subscriber.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constants for @nest-toolbox/typeorm-audit-log
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Metadata key for @Auditable() decorator
|
|
6
|
+
*/
|
|
7
|
+
export declare const AUDITABLE_KEY = "audit:auditable";
|
|
8
|
+
/**
|
|
9
|
+
* Metadata key for @AuditIgnore() decorator
|
|
10
|
+
*/
|
|
11
|
+
export declare const AUDIT_IGNORE_KEY = "audit:ignore";
|
|
12
|
+
/**
|
|
13
|
+
* Metadata key for @AuditMask() decorator
|
|
14
|
+
*/
|
|
15
|
+
export declare const AUDIT_MASK_KEY = "audit:mask";
|
|
16
|
+
/**
|
|
17
|
+
* Metadata key for auditable options
|
|
18
|
+
*/
|
|
19
|
+
export declare const AUDITABLE_OPTIONS_KEY = "audit:auditable:options";
|
|
20
|
+
/**
|
|
21
|
+
* Injection token for module options
|
|
22
|
+
*/
|
|
23
|
+
export declare const AUDIT_LOG_OPTIONS = "AUDIT_LOG_OPTIONS";
|
|
24
|
+
/**
|
|
25
|
+
* Default table name for audit logs
|
|
26
|
+
*/
|
|
27
|
+
export declare const DEFAULT_TABLE_NAME = "audit_logs";
|
|
28
|
+
/**
|
|
29
|
+
* Default mask function - masks middle characters
|
|
30
|
+
* Example: "john@email.com" -> "jo***ail.com"
|
|
31
|
+
*/
|
|
32
|
+
export declare const DEFAULT_MASK_FN: (value: any) => string;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Constants for @nest-toolbox/typeorm-audit-log
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.DEFAULT_MASK_FN = exports.DEFAULT_TABLE_NAME = exports.AUDIT_LOG_OPTIONS = exports.AUDITABLE_OPTIONS_KEY = exports.AUDIT_MASK_KEY = exports.AUDIT_IGNORE_KEY = exports.AUDITABLE_KEY = void 0;
|
|
7
|
+
/**
|
|
8
|
+
* Metadata key for @Auditable() decorator
|
|
9
|
+
*/
|
|
10
|
+
exports.AUDITABLE_KEY = 'audit:auditable';
|
|
11
|
+
/**
|
|
12
|
+
* Metadata key for @AuditIgnore() decorator
|
|
13
|
+
*/
|
|
14
|
+
exports.AUDIT_IGNORE_KEY = 'audit:ignore';
|
|
15
|
+
/**
|
|
16
|
+
* Metadata key for @AuditMask() decorator
|
|
17
|
+
*/
|
|
18
|
+
exports.AUDIT_MASK_KEY = 'audit:mask';
|
|
19
|
+
/**
|
|
20
|
+
* Metadata key for auditable options
|
|
21
|
+
*/
|
|
22
|
+
exports.AUDITABLE_OPTIONS_KEY = 'audit:auditable:options';
|
|
23
|
+
/**
|
|
24
|
+
* Injection token for module options
|
|
25
|
+
*/
|
|
26
|
+
exports.AUDIT_LOG_OPTIONS = 'AUDIT_LOG_OPTIONS';
|
|
27
|
+
/**
|
|
28
|
+
* Default table name for audit logs
|
|
29
|
+
*/
|
|
30
|
+
exports.DEFAULT_TABLE_NAME = 'audit_logs';
|
|
31
|
+
/**
|
|
32
|
+
* Default mask function - masks middle characters
|
|
33
|
+
* Example: "john@email.com" -> "jo***ail.com"
|
|
34
|
+
*/
|
|
35
|
+
// biome-ignore lint/suspicious/noExplicitAny: mask function accepts any value type
|
|
36
|
+
const DEFAULT_MASK_FN = (value) => {
|
|
37
|
+
if (value === null || value === undefined) {
|
|
38
|
+
return String(value);
|
|
39
|
+
}
|
|
40
|
+
const str = String(value);
|
|
41
|
+
if (str.length <= 4) {
|
|
42
|
+
return '***';
|
|
43
|
+
}
|
|
44
|
+
const visibleStart = Math.ceil(str.length * 0.2);
|
|
45
|
+
const visibleEnd = Math.ceil(str.length * 0.2);
|
|
46
|
+
return `${str.slice(0, visibleStart)}***${str.slice(str.length - visibleEnd)}`;
|
|
47
|
+
};
|
|
48
|
+
exports.DEFAULT_MASK_FN = DEFAULT_MASK_FN;
|
|
49
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAEH;;GAEG;AACU,QAAA,aAAa,GAAG,iBAAiB,CAAC;AAE/C;;GAEG;AACU,QAAA,gBAAgB,GAAG,cAAc,CAAC;AAE/C;;GAEG;AACU,QAAA,cAAc,GAAG,YAAY,CAAC;AAE3C;;GAEG;AACU,QAAA,qBAAqB,GAAG,yBAAyB,CAAC;AAE/D;;GAEG;AACU,QAAA,iBAAiB,GAAG,mBAAmB,CAAC;AAErD;;GAEG;AACU,QAAA,kBAAkB,GAAG,YAAY,CAAC;AAE/C;;;GAGG;AACH,mFAAmF;AAC5E,MAAM,eAAe,GAAG,CAAC,KAAU,EAAU,EAAE;IACpD,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QAC1C,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;IAED,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC1B,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;QACpB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC;IACjD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC;IAE/C,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,GAAG,UAAU,CAAC,EAAE,CAAC;AACjF,CAAC,CAAC;AAdW,QAAA,eAAe,mBAc1B"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decorators for @nest-toolbox/typeorm-audit-log
|
|
3
|
+
*/
|
|
4
|
+
import 'reflect-metadata';
|
|
5
|
+
import type { AuditableOptions, AuditMaskOptions } from './types';
|
|
6
|
+
type Constructor = Function;
|
|
7
|
+
/**
|
|
8
|
+
* Marks an entity class as auditable.
|
|
9
|
+
* All changes to this entity will be automatically logged.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* @Entity()
|
|
14
|
+
* @Auditable()
|
|
15
|
+
* export class User {
|
|
16
|
+
* @PrimaryGeneratedColumn()
|
|
17
|
+
* id: number;
|
|
18
|
+
*
|
|
19
|
+
* @Column()
|
|
20
|
+
* name: string;
|
|
21
|
+
* }
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @example With options
|
|
25
|
+
* ```typescript
|
|
26
|
+
* @Entity()
|
|
27
|
+
* @Auditable({
|
|
28
|
+
* entityName: 'UserAccount',
|
|
29
|
+
* excludeFields: ['lastLoginAt']
|
|
30
|
+
* })
|
|
31
|
+
* export class User {
|
|
32
|
+
* // ...
|
|
33
|
+
* }
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export declare function Auditable(options?: AuditableOptions): ClassDecorator;
|
|
37
|
+
/**
|
|
38
|
+
* Check if an entity class is marked as auditable
|
|
39
|
+
*/
|
|
40
|
+
export declare function isAuditable(target: Constructor): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Get auditable options for an entity class
|
|
43
|
+
*/
|
|
44
|
+
export declare function getAuditableOptions(target: Constructor): AuditableOptions | undefined;
|
|
45
|
+
/**
|
|
46
|
+
* Get the entity name for auditing (custom name or class name)
|
|
47
|
+
*/
|
|
48
|
+
export declare function getAuditEntityName(target: Constructor): string;
|
|
49
|
+
/**
|
|
50
|
+
* Get fields excluded from auditing for an entity
|
|
51
|
+
*/
|
|
52
|
+
export declare function getExcludedFields(target: Constructor): string[];
|
|
53
|
+
/**
|
|
54
|
+
* Marks a property to be excluded from audit logs entirely.
|
|
55
|
+
* Use for sensitive data that should never appear in audit trails.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```typescript
|
|
59
|
+
* @Entity()
|
|
60
|
+
* @Auditable()
|
|
61
|
+
* export class User {
|
|
62
|
+
* @Column()
|
|
63
|
+
* @AuditIgnore()
|
|
64
|
+
* password: string;
|
|
65
|
+
*
|
|
66
|
+
* @Column()
|
|
67
|
+
* @AuditIgnore()
|
|
68
|
+
* refreshToken: string;
|
|
69
|
+
* }
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
export declare function AuditIgnore(): PropertyDecorator;
|
|
73
|
+
/**
|
|
74
|
+
* Get fields marked with @AuditIgnore for an entity
|
|
75
|
+
*/
|
|
76
|
+
export declare function getIgnoredFields(target: Constructor): (string | symbol)[];
|
|
77
|
+
/**
|
|
78
|
+
* Marks a property to be masked in audit logs.
|
|
79
|
+
* The value will be partially hidden (e.g., "jo***@email.com").
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```typescript
|
|
83
|
+
* @Entity()
|
|
84
|
+
* @Auditable()
|
|
85
|
+
* export class User {
|
|
86
|
+
* @Column()
|
|
87
|
+
* @AuditMask()
|
|
88
|
+
* email: string;
|
|
89
|
+
*
|
|
90
|
+
* @Column()
|
|
91
|
+
* @AuditMask({ maskFn: (v) => v ? '****' : null })
|
|
92
|
+
* ssn: string;
|
|
93
|
+
* }
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
export declare function AuditMask(options?: AuditMaskOptions): PropertyDecorator;
|
|
97
|
+
/**
|
|
98
|
+
* Get masked fields and their mask functions for an entity
|
|
99
|
+
*/
|
|
100
|
+
export declare function getMaskedFields(target: Constructor): Record<string | symbol, (value: any) => string>;
|
|
101
|
+
/**
|
|
102
|
+
* Check if a field should be ignored for an entity
|
|
103
|
+
*/
|
|
104
|
+
export declare function isFieldIgnored(target: Constructor, field: string | symbol): boolean;
|
|
105
|
+
/**
|
|
106
|
+
* Get the mask function for a field, if any
|
|
107
|
+
*/
|
|
108
|
+
export declare function getFieldMaskFn(target: Constructor, field: string | symbol): ((value: any) => string) | undefined;
|
|
109
|
+
export {};
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Decorators for @nest-toolbox/typeorm-audit-log
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Auditable = Auditable;
|
|
7
|
+
exports.isAuditable = isAuditable;
|
|
8
|
+
exports.getAuditableOptions = getAuditableOptions;
|
|
9
|
+
exports.getAuditEntityName = getAuditEntityName;
|
|
10
|
+
exports.getExcludedFields = getExcludedFields;
|
|
11
|
+
exports.AuditIgnore = AuditIgnore;
|
|
12
|
+
exports.getIgnoredFields = getIgnoredFields;
|
|
13
|
+
exports.AuditMask = AuditMask;
|
|
14
|
+
exports.getMaskedFields = getMaskedFields;
|
|
15
|
+
exports.isFieldIgnored = isFieldIgnored;
|
|
16
|
+
exports.getFieldMaskFn = getFieldMaskFn;
|
|
17
|
+
require("reflect-metadata");
|
|
18
|
+
const constants_1 = require("./constants");
|
|
19
|
+
/**
|
|
20
|
+
* Marks an entity class as auditable.
|
|
21
|
+
* All changes to this entity will be automatically logged.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* @Entity()
|
|
26
|
+
* @Auditable()
|
|
27
|
+
* export class User {
|
|
28
|
+
* @PrimaryGeneratedColumn()
|
|
29
|
+
* id: number;
|
|
30
|
+
*
|
|
31
|
+
* @Column()
|
|
32
|
+
* name: string;
|
|
33
|
+
* }
|
|
34
|
+
* ```
|
|
35
|
+
*
|
|
36
|
+
* @example With options
|
|
37
|
+
* ```typescript
|
|
38
|
+
* @Entity()
|
|
39
|
+
* @Auditable({
|
|
40
|
+
* entityName: 'UserAccount',
|
|
41
|
+
* excludeFields: ['lastLoginAt']
|
|
42
|
+
* })
|
|
43
|
+
* export class User {
|
|
44
|
+
* // ...
|
|
45
|
+
* }
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
function Auditable(options) {
|
|
49
|
+
return (target) => {
|
|
50
|
+
Reflect.defineMetadata(constants_1.AUDITABLE_KEY, true, target);
|
|
51
|
+
if (options) {
|
|
52
|
+
Reflect.defineMetadata(constants_1.AUDITABLE_OPTIONS_KEY, options, target);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Check if an entity class is marked as auditable
|
|
58
|
+
*/
|
|
59
|
+
function isAuditable(target) {
|
|
60
|
+
return Reflect.getMetadata(constants_1.AUDITABLE_KEY, target) === true;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Get auditable options for an entity class
|
|
64
|
+
*/
|
|
65
|
+
function getAuditableOptions(target) {
|
|
66
|
+
return Reflect.getMetadata(constants_1.AUDITABLE_OPTIONS_KEY, target);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Get the entity name for auditing (custom name or class name)
|
|
70
|
+
*/
|
|
71
|
+
function getAuditEntityName(target) {
|
|
72
|
+
const options = getAuditableOptions(target);
|
|
73
|
+
return (options === null || options === void 0 ? void 0 : options.entityName) || target.name;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Get fields excluded from auditing for an entity
|
|
77
|
+
*/
|
|
78
|
+
function getExcludedFields(target) {
|
|
79
|
+
const options = getAuditableOptions(target);
|
|
80
|
+
return (options === null || options === void 0 ? void 0 : options.excludeFields) || [];
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Marks a property to be excluded from audit logs entirely.
|
|
84
|
+
* Use for sensitive data that should never appear in audit trails.
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```typescript
|
|
88
|
+
* @Entity()
|
|
89
|
+
* @Auditable()
|
|
90
|
+
* export class User {
|
|
91
|
+
* @Column()
|
|
92
|
+
* @AuditIgnore()
|
|
93
|
+
* password: string;
|
|
94
|
+
*
|
|
95
|
+
* @Column()
|
|
96
|
+
* @AuditIgnore()
|
|
97
|
+
* refreshToken: string;
|
|
98
|
+
* }
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
function AuditIgnore() {
|
|
102
|
+
return (target, propertyKey) => {
|
|
103
|
+
const existingIgnored = Reflect.getMetadata(constants_1.AUDIT_IGNORE_KEY, target.constructor) || [];
|
|
104
|
+
Reflect.defineMetadata(constants_1.AUDIT_IGNORE_KEY, [...existingIgnored, propertyKey], target.constructor);
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Get fields marked with @AuditIgnore for an entity
|
|
109
|
+
*/
|
|
110
|
+
function getIgnoredFields(target) {
|
|
111
|
+
return Reflect.getMetadata(constants_1.AUDIT_IGNORE_KEY, target) || [];
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Marks a property to be masked in audit logs.
|
|
115
|
+
* The value will be partially hidden (e.g., "jo***@email.com").
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```typescript
|
|
119
|
+
* @Entity()
|
|
120
|
+
* @Auditable()
|
|
121
|
+
* export class User {
|
|
122
|
+
* @Column()
|
|
123
|
+
* @AuditMask()
|
|
124
|
+
* email: string;
|
|
125
|
+
*
|
|
126
|
+
* @Column()
|
|
127
|
+
* @AuditMask({ maskFn: (v) => v ? '****' : null })
|
|
128
|
+
* ssn: string;
|
|
129
|
+
* }
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
function AuditMask(options) {
|
|
133
|
+
return (target, propertyKey) => {
|
|
134
|
+
const existingMasked = Reflect.getMetadata(constants_1.AUDIT_MASK_KEY, target.constructor) || {};
|
|
135
|
+
const maskFn = (options === null || options === void 0 ? void 0 : options.maskFn) || constants_1.DEFAULT_MASK_FN;
|
|
136
|
+
Reflect.defineMetadata(constants_1.AUDIT_MASK_KEY, Object.assign(Object.assign({}, existingMasked), { [propertyKey]: maskFn }), target.constructor);
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Get masked fields and their mask functions for an entity
|
|
141
|
+
*/
|
|
142
|
+
// biome-ignore lint/suspicious/noExplicitAny: mask functions can return any value
|
|
143
|
+
function getMaskedFields(target) {
|
|
144
|
+
return Reflect.getMetadata(constants_1.AUDIT_MASK_KEY, target) || {};
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Check if a field should be ignored for an entity
|
|
148
|
+
*/
|
|
149
|
+
function isFieldIgnored(target, field) {
|
|
150
|
+
const ignoredFields = getIgnoredFields(target);
|
|
151
|
+
return ignoredFields.includes(field);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Get the mask function for a field, if any
|
|
155
|
+
*/
|
|
156
|
+
// biome-ignore lint/suspicious/noExplicitAny: mask functions can return any value
|
|
157
|
+
function getFieldMaskFn(target, field) {
|
|
158
|
+
const maskedFields = getMaskedFields(target);
|
|
159
|
+
return maskedFields[field];
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=decorators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decorators.js","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @nest-toolbox/typeorm-audit-log
|
|
3
|
+
*
|
|
4
|
+
* Automatic audit logging for TypeORM entities with user attribution and diff tracking.
|
|
5
|
+
*/
|
|
6
|
+
export * from './audit-context';
|
|
7
|
+
export * from './audit-context.middleware';
|
|
8
|
+
export * from './audit-log.entity';
|
|
9
|
+
export * from './audit-log.module';
|
|
10
|
+
export * from './audit-log.service';
|
|
11
|
+
export * from './audit-log.subscriber';
|
|
12
|
+
export * from './constants';
|
|
13
|
+
export * from './decorators';
|
|
14
|
+
export * from './types';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @nest-toolbox/typeorm-audit-log
|
|
4
|
+
*
|
|
5
|
+
* Automatic audit logging for TypeORM entities with user attribution and diff tracking.
|
|
6
|
+
*/
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
19
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
20
|
+
};
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
__exportStar(require("./audit-context"), exports);
|
|
23
|
+
__exportStar(require("./audit-context.middleware"), exports);
|
|
24
|
+
__exportStar(require("./audit-log.entity"), exports);
|
|
25
|
+
__exportStar(require("./audit-log.module"), exports);
|
|
26
|
+
__exportStar(require("./audit-log.service"), exports);
|
|
27
|
+
__exportStar(require("./audit-log.subscriber"), exports);
|
|
28
|
+
__exportStar(require("./constants"), exports);
|
|
29
|
+
__exportStar(require("./decorators"), exports);
|
|
30
|
+
__exportStar(require("./types"), exports);
|
|
31
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;;;;;;;;;;;;;;AAEH,kDAAgC;AAChC,6DAA2C;AAC3C,qDAAmC;AACnC,qDAAmC;AACnC,sDAAoC;AACpC,yDAAuC;AACvC,8CAA4B;AAC5B,+CAA6B;AAC7B,0CAAwB"}
|