@studiosonrai/nestjs-audit-log 1.0.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 (45) hide show
  1. package/README.md +86 -0
  2. package/dist/src/audit-context.interceptor.d.ts +10 -0
  3. package/dist/src/audit-context.interceptor.js +48 -0
  4. package/dist/src/audit-context.interceptor.js.map +1 -0
  5. package/dist/src/audit.builder.d.ts +3 -0
  6. package/dist/src/audit.builder.js +15 -0
  7. package/dist/src/audit.builder.js.map +1 -0
  8. package/dist/src/audit.constants.d.ts +3 -0
  9. package/dist/src/audit.constants.js +7 -0
  10. package/dist/src/audit.constants.js.map +1 -0
  11. package/dist/src/audit.helper.d.ts +5 -0
  12. package/dist/src/audit.helper.js +41 -0
  13. package/dist/src/audit.helper.js.map +1 -0
  14. package/dist/src/audit.module.d.ts +9 -0
  15. package/dist/src/audit.module.js +90 -0
  16. package/dist/src/audit.module.js.map +1 -0
  17. package/dist/src/audit.service.d.ts +22 -0
  18. package/dist/src/audit.service.js +185 -0
  19. package/dist/src/audit.service.js.map +1 -0
  20. package/dist/src/audit.subscriber.d.ts +11 -0
  21. package/dist/src/audit.subscriber.js +100 -0
  22. package/dist/src/audit.subscriber.js.map +1 -0
  23. package/dist/src/decorators/auditable.decorator.d.ts +3 -0
  24. package/dist/src/decorators/auditable.decorator.js +22 -0
  25. package/dist/src/decorators/auditable.decorator.js.map +1 -0
  26. package/dist/src/dto/audit-filter.dto.d.ts +10 -0
  27. package/dist/src/dto/audit-filter.dto.js +101 -0
  28. package/dist/src/dto/audit-filter.dto.js.map +1 -0
  29. package/dist/src/dto/audit-log-response.dto.d.ts +13 -0
  30. package/dist/src/dto/audit-log-response.dto.js +91 -0
  31. package/dist/src/dto/audit-log-response.dto.js.map +1 -0
  32. package/dist/src/dto/paginated-result.dto.d.ts +9 -0
  33. package/dist/src/dto/paginated-result.dto.js +52 -0
  34. package/dist/src/dto/paginated-result.dto.js.map +1 -0
  35. package/dist/src/entities/audit-log.entity.d.ts +15 -0
  36. package/dist/src/entities/audit-log.entity.js +101 -0
  37. package/dist/src/entities/audit-log.entity.js.map +1 -0
  38. package/dist/src/index.d.ts +13 -0
  39. package/dist/src/index.js +30 -0
  40. package/dist/src/index.js.map +1 -0
  41. package/dist/src/interfaces/audit.interfaces.d.ts +34 -0
  42. package/dist/src/interfaces/audit.interfaces.js +3 -0
  43. package/dist/src/interfaces/audit.interfaces.js.map +1 -0
  44. package/dist/tsconfig.tsbuildinfo +1 -0
  45. package/package.json +56 -0
package/README.md ADDED
@@ -0,0 +1,86 @@
1
+ # @studiosonrai/nestjs-audit-log
2
+
3
+ Audit logging for NestJS + TypeORM. Mark an entity `@Auditable()` and CREATE/UPDATE
4
+ are recorded automatically by a TypeORM subscriber — no per-service code. DELETE is a
5
+ single explicit call. The acting user is captured from the request via CLS, so you never
6
+ thread `userId` through your services.
7
+
8
+ ## Documentation
9
+
10
+ - [Setup & Usage](docs/setup.md) — prerequisites, install, configuration, and day-to-day use.
11
+ - [How It Works](docs/internals.md) — architecture, core logic, and design decisions.
12
+ - [Migration Guide](docs/migration.md) — move an existing hand-rolled audit module onto this package.
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install @studiosonrai/nestjs-audit-log
18
+ # peers (already present in most NestJS apps):
19
+ npm install @nestjs/typeorm @nestjs/swagger typeorm class-validator class-transformer
20
+ ```
21
+
22
+ ## Setup
23
+
24
+ ```typescript
25
+ import { AuditModule } from '@studiosonrai/nestjs-audit-log';
26
+ import { AuditLog } from '@studiosonrai/nestjs-audit-log';
27
+
28
+ @Module({
29
+ imports: [
30
+ AuditModule.forRootAsync({
31
+ inject: [getRepositoryToken(User)],
32
+ useFactory: (userRepo: Repository<User>) => ({
33
+ // read-time enrichment of `changedBy` -> name/email (optional)
34
+ resolveUser: async (id) => {
35
+ const u = await userRepo.findOneBy({ id });
36
+ return u && { name: `${u.firstName} ${u.lastName ?? ''}`.trim(), email: u.email };
37
+ },
38
+ // how to read the acting user id from the request (default: req.user?.id)
39
+ getUserId: (req) => (req as { user?: { id?: number } }).user?.id,
40
+ }),
41
+ }),
42
+ ],
43
+ })
44
+ export class AppModule {}
45
+ ```
46
+
47
+ Register the `AuditLog` entity with your DataSource (e.g. `autoLoadEntities: true`, or add
48
+ `AuditLog` to your `entities` array / migrations) so the `auditLog` table exists.
49
+
50
+ > The module mounts `nestjs-cls` middleware globally to carry the request user into the
51
+ > TypeORM subscriber. If your app already configures `nestjs-cls`, import `AuditModule` only
52
+ > once and avoid registering a second `ClsModule.forRoot`.
53
+
54
+ ## Automatic capture
55
+
56
+ ```typescript
57
+ import { Auditable } from '@studiosonrai/nestjs-audit-log';
58
+
59
+ @Auditable({ nameField: 'fullName' }) // entityType defaults to the class name
60
+ @Entity()
61
+ export class Contact { /* ... */ }
62
+ ```
63
+
64
+ - `entityType?` — logical type stored in the log (default: class name)
65
+ - `nameField?` — property used as the human-readable name
66
+ - `exclude?: string[]` — extra fields to omit from the diff (beyond `id/createdAt/updatedAt`)
67
+
68
+ CREATE and UPDATE are now logged automatically whenever the entity is inserted or saved
69
+ (loaded-then-`save()`), inside the same transaction as the operation.
70
+
71
+ ## DELETE and manual logging
72
+
73
+ `repository.delete(id)` does not fire TypeORM remove subscribers, so record deletes explicitly:
74
+
75
+ ```typescript
76
+ await this.auditService.logEntity(contact, AuditActionType.DELETE);
77
+ await this.contactRepository.delete(id);
78
+ ```
79
+
80
+ For full control use `auditService.log({ entityType, entityId, action, changes, entityName })`.
81
+ `changedBy` is filled from CLS when omitted.
82
+
83
+ ## Querying
84
+
85
+ `AuditService` exposes `findAll(filter)` (paginated), `findByEntity`, `findByUser`, `findByAction`.
86
+ Mount your own controller with your app's guards — the package ships no routes.
@@ -0,0 +1,10 @@
1
+ import { CallHandler, ExecutionContext, NestInterceptor } from '@nestjs/common';
2
+ import { Observable } from 'rxjs';
3
+ import { ClsService } from 'nestjs-cls';
4
+ import { AuditModuleOptions } from './interfaces/audit.interfaces';
5
+ export declare class AuditContextInterceptor implements NestInterceptor {
6
+ private readonly options;
7
+ private readonly cls;
8
+ constructor(options: AuditModuleOptions, cls: ClsService);
9
+ intercept(context: ExecutionContext, next: CallHandler): Observable<unknown>;
10
+ }
@@ -0,0 +1,48 @@
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
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.AuditContextInterceptor = void 0;
16
+ const common_1 = require("@nestjs/common");
17
+ const nestjs_cls_1 = require("nestjs-cls");
18
+ const audit_constants_1 = require("./audit.constants");
19
+ function defaultGetUserId(request) {
20
+ const user = request?.user;
21
+ return user?.id;
22
+ }
23
+ let AuditContextInterceptor = class AuditContextInterceptor {
24
+ options;
25
+ cls;
26
+ constructor(options, cls) {
27
+ this.options = options;
28
+ this.cls = cls;
29
+ }
30
+ intercept(context, next) {
31
+ if (context.getType() === 'http' && this.cls.isActive()) {
32
+ const request = context.switchToHttp().getRequest();
33
+ const extractor = this.options.getUserId ?? defaultGetUserId;
34
+ const userId = extractor(request);
35
+ if (userId !== undefined) {
36
+ this.cls.set(audit_constants_1.AUDIT_CLS_USER_ID, userId);
37
+ }
38
+ }
39
+ return next.handle();
40
+ }
41
+ };
42
+ exports.AuditContextInterceptor = AuditContextInterceptor;
43
+ exports.AuditContextInterceptor = AuditContextInterceptor = __decorate([
44
+ (0, common_1.Injectable)(),
45
+ __param(0, (0, common_1.Inject)(audit_constants_1.AUDIT_MODULE_OPTIONS)),
46
+ __metadata("design:paramtypes", [Object, nestjs_cls_1.ClsService])
47
+ ], AuditContextInterceptor);
48
+ //# sourceMappingURL=audit-context.interceptor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-context.interceptor.js","sourceRoot":"","sources":["../../src/audit-context.interceptor.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAMwB;AAExB,2CAAwC;AACxC,uDAA4E;AAG5E,SAAS,gBAAgB,CAAC,OAAgB;IACxC,MAAM,IAAI,GAAI,OAAkD,EAAE,IAAI,CAAC;IACvE,OAAO,IAAI,EAAE,EAAE,CAAC;AAClB,CAAC;AAQM,IAAM,uBAAuB,GAA7B,MAAM,uBAAuB;IAGf;IACA;IAHnB,YAEmB,OAA2B,EAC3B,GAAe;QADf,YAAO,GAAP,OAAO,CAAoB;QAC3B,QAAG,GAAH,GAAG,CAAY;IAC/B,CAAC;IAEJ,SAAS,CAAC,OAAyB,EAAE,IAAiB;QACpD,IAAI,OAAO,CAAC,OAAO,EAAE,KAAK,MAAM,IAAI,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC;YACxD,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAW,CAAC;YAC7D,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,IAAI,gBAAgB,CAAC;YAC7D,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;YAClC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;gBACzB,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,mCAAiB,EAAE,MAAM,CAAC,CAAC;YAC1C,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC;IACvB,CAAC;CACF,CAAA;AAlBY,0DAAuB;kCAAvB,uBAAuB;IADnC,IAAA,mBAAU,GAAE;IAGR,WAAA,IAAA,eAAM,EAAC,sCAAoB,CAAC,CAAA;6CAEP,uBAAU;GAJvB,uBAAuB,CAkBnC"}
@@ -0,0 +1,3 @@
1
+ import { AuditLog } from './entities/audit-log.entity';
2
+ import { AuditLogInput } from './interfaces/audit.interfaces';
3
+ export declare function toAuditLog(input: AuditLogInput): AuditLog;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toAuditLog = toAuditLog;
4
+ const audit_log_entity_1 = require("./entities/audit-log.entity");
5
+ function toAuditLog(input) {
6
+ const auditLog = new audit_log_entity_1.AuditLog();
7
+ auditLog.entityType = input.entityType;
8
+ auditLog.entityId = input.entityId;
9
+ auditLog.entityName = input.entityName;
10
+ auditLog.action = input.action;
11
+ auditLog.changedBy = input.changedBy;
12
+ auditLog.changes = input.changes ? JSON.stringify(input.changes) : undefined;
13
+ return auditLog;
14
+ }
15
+ //# sourceMappingURL=audit.builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.builder.js","sourceRoot":"","sources":["../../src/audit.builder.ts"],"names":[],"mappings":";;AAIA,gCASC;AAbD,kEAAuD;AAIvD,SAAgB,UAAU,CAAC,KAAoB;IAC7C,MAAM,QAAQ,GAAG,IAAI,2BAAQ,EAAE,CAAC;IAChC,QAAQ,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;IACvC,QAAQ,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;IACnC,QAAQ,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;IACvC,QAAQ,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;IAC/B,QAAQ,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC;IACrC,QAAQ,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC7E,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare const AUDIT_MODULE_OPTIONS = "AUDIT_MODULE_OPTIONS";
2
+ export declare const AUDITABLE_METADATA = "audit:auditable";
3
+ export declare const AUDIT_CLS_USER_ID = "audit:userId";
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AUDIT_CLS_USER_ID = exports.AUDITABLE_METADATA = exports.AUDIT_MODULE_OPTIONS = void 0;
4
+ exports.AUDIT_MODULE_OPTIONS = 'AUDIT_MODULE_OPTIONS';
5
+ exports.AUDITABLE_METADATA = 'audit:auditable';
6
+ exports.AUDIT_CLS_USER_ID = 'audit:userId';
7
+ //# sourceMappingURL=audit.constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.constants.js","sourceRoot":"","sources":["../../src/audit.constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,oBAAoB,GAAG,sBAAsB,CAAC;AAG9C,QAAA,kBAAkB,GAAG,iBAAiB,CAAC;AAGvC,QAAA,iBAAiB,GAAG,cAAc,CAAC"}
@@ -0,0 +1,5 @@
1
+ export declare function calculateChanges(oldData: Record<string, unknown> | undefined, newData: Record<string, unknown>): Record<string, {
2
+ old?: unknown;
3
+ new: unknown;
4
+ }>;
5
+ export declare function extractAuditableFields(entity: Record<string, unknown> | object, fieldsToExclude?: string[]): Record<string, unknown>;
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.calculateChanges = calculateChanges;
4
+ exports.extractAuditableFields = extractAuditableFields;
5
+ function calculateChanges(oldData, newData) {
6
+ const changes = {};
7
+ if (!oldData) {
8
+ for (const [key, value] of Object.entries(newData)) {
9
+ changes[key] = { new: value };
10
+ }
11
+ return changes;
12
+ }
13
+ for (const [key, newValue] of Object.entries(newData)) {
14
+ const oldValue = oldData[key];
15
+ if (JSON.stringify(oldValue) !== JSON.stringify(newValue)) {
16
+ changes[key] = { old: oldValue, new: newValue };
17
+ }
18
+ }
19
+ for (const [key, oldValue] of Object.entries(oldData)) {
20
+ if (!(key in newData)) {
21
+ changes[key] = { old: oldValue, new: undefined };
22
+ }
23
+ }
24
+ return changes;
25
+ }
26
+ function extractAuditableFields(entity, fieldsToExclude = []) {
27
+ const defaultExcludedFields = [
28
+ 'createdAt',
29
+ 'updatedAt',
30
+ 'id',
31
+ ...fieldsToExclude,
32
+ ];
33
+ const result = {};
34
+ for (const [key, value] of Object.entries(entity)) {
35
+ if (!defaultExcludedFields.includes(key)) {
36
+ result[key] = value;
37
+ }
38
+ }
39
+ return result;
40
+ }
41
+ //# sourceMappingURL=audit.helper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.helper.js","sourceRoot":"","sources":["../../src/audit.helper.ts"],"names":[],"mappings":";;AAIA,4CA+BC;AAMD,wDAoBC;AAzDD,SAAgB,gBAAgB,CAC9B,OAA4C,EAC5C,OAAgC;IAEhC,MAAM,OAAO,GAAoD,EAAE,CAAC;IAEpE,IAAI,CAAC,OAAO,EAAE,CAAC;QAEb,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;YACnD,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;QAChC,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAGD,KAAK,MAAM,CAAC,GAAG,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACtD,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAE9B,IAAI,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1D,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC;QAClD,CAAC;IACH,CAAC;IAGD,KAAK,MAAM,CAAC,GAAG,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACtD,IAAI,CAAC,CAAC,GAAG,IAAI,OAAO,CAAC,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC;QACnD,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAMD,SAAgB,sBAAsB,CACpC,MAAwC,EACxC,kBAA4B,EAAE;IAE9B,MAAM,qBAAqB,GAAG;QAC5B,WAAW;QACX,WAAW;QACX,IAAI;QACJ,GAAG,eAAe;KACnB,CAAC;IAEF,MAAM,MAAM,GAA4B,EAAE,CAAC;IAE3C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,IAAI,CAAC,qBAAqB,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACzC,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACtB,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { DynamicModule } from '@nestjs/common';
2
+ import { AuditModuleAsyncOptions, AuditModuleOptions } from './interfaces/audit.interfaces';
3
+ export declare class AuditModule {
4
+ static forRoot(options?: AuditModuleOptions): DynamicModule;
5
+ static forRootAsync(options: AuditModuleAsyncOptions): DynamicModule;
6
+ private static baseImports;
7
+ private static createAsyncProviders;
8
+ private static createAsyncOptionsProvider;
9
+ }
@@ -0,0 +1,90 @@
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
+ var AuditModule_1;
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.AuditModule = void 0;
11
+ const common_1 = require("@nestjs/common");
12
+ const core_1 = require("@nestjs/core");
13
+ const typeorm_1 = require("@nestjs/typeorm");
14
+ const nestjs_cls_1 = require("nestjs-cls");
15
+ const audit_log_entity_1 = require("./entities/audit-log.entity");
16
+ const audit_service_1 = require("./audit.service");
17
+ const audit_subscriber_1 = require("./audit.subscriber");
18
+ const audit_context_interceptor_1 = require("./audit-context.interceptor");
19
+ const audit_constants_1 = require("./audit.constants");
20
+ const sharedProviders = [
21
+ audit_service_1.AuditService,
22
+ audit_subscriber_1.AuditSubscriber,
23
+ { provide: core_1.APP_INTERCEPTOR, useClass: audit_context_interceptor_1.AuditContextInterceptor },
24
+ ];
25
+ let AuditModule = AuditModule_1 = class AuditModule {
26
+ static forRoot(options = {}) {
27
+ return {
28
+ module: AuditModule_1,
29
+ imports: [...AuditModule_1.baseImports()],
30
+ providers: [
31
+ { provide: audit_constants_1.AUDIT_MODULE_OPTIONS, useValue: options },
32
+ ...sharedProviders,
33
+ ],
34
+ exports: [audit_service_1.AuditService, audit_constants_1.AUDIT_MODULE_OPTIONS],
35
+ };
36
+ }
37
+ static forRootAsync(options) {
38
+ return {
39
+ module: AuditModule_1,
40
+ imports: [...AuditModule_1.baseImports(), ...(options.imports ?? [])],
41
+ providers: [
42
+ ...AuditModule_1.createAsyncProviders(options),
43
+ ...sharedProviders,
44
+ ],
45
+ exports: [audit_service_1.AuditService, audit_constants_1.AUDIT_MODULE_OPTIONS],
46
+ };
47
+ }
48
+ static baseImports() {
49
+ return [
50
+ nestjs_cls_1.ClsModule.forRoot({ global: true, guard: { mount: true } }),
51
+ typeorm_1.TypeOrmModule.forFeature([audit_log_entity_1.AuditLog]),
52
+ ];
53
+ }
54
+ static createAsyncProviders(options) {
55
+ if (options.useExisting || options.useFactory) {
56
+ return [AuditModule_1.createAsyncOptionsProvider(options)];
57
+ }
58
+ if (options.useClass) {
59
+ return [
60
+ AuditModule_1.createAsyncOptionsProvider(options),
61
+ { provide: options.useClass, useClass: options.useClass },
62
+ ];
63
+ }
64
+ throw new Error('Invalid AuditModuleAsyncOptions: provide useExisting, useClass, or useFactory');
65
+ }
66
+ static createAsyncOptionsProvider(options) {
67
+ if (options.useFactory) {
68
+ return {
69
+ provide: audit_constants_1.AUDIT_MODULE_OPTIONS,
70
+ useFactory: options.useFactory,
71
+ inject: options.inject ?? [],
72
+ };
73
+ }
74
+ const inject = options.useExisting ?? options.useClass;
75
+ if (!inject) {
76
+ throw new Error('Invalid AuditModuleAsyncOptions: provide useExisting, useClass, or useFactory');
77
+ }
78
+ return {
79
+ provide: audit_constants_1.AUDIT_MODULE_OPTIONS,
80
+ useFactory: (factory) => factory.createAuditOptions(),
81
+ inject: [inject],
82
+ };
83
+ }
84
+ };
85
+ exports.AuditModule = AuditModule;
86
+ exports.AuditModule = AuditModule = AuditModule_1 = __decorate([
87
+ (0, common_1.Global)(),
88
+ (0, common_1.Module)({})
89
+ ], AuditModule);
90
+ //# sourceMappingURL=audit.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.module.js","sourceRoot":"","sources":["../../src/audit.module.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import { Repository } from 'typeorm';
2
+ import { ClsService } from 'nestjs-cls';
3
+ import { AuditLog, AuditActionType } from './entities/audit-log.entity';
4
+ import { AuditFilterDto } from './dto/audit-filter.dto';
5
+ import { AuditLogResponseDto } from './dto/audit-log-response.dto';
6
+ import { PaginatedResultDto } from './dto/paginated-result.dto';
7
+ import { AuditLogInput, AuditModuleOptions } from './interfaces/audit.interfaces';
8
+ export declare class AuditService {
9
+ private readonly auditRepository;
10
+ private readonly options;
11
+ private readonly cls?;
12
+ private readonly logger;
13
+ constructor(auditRepository: Repository<AuditLog>, options: AuditModuleOptions, cls?: ClsService | undefined);
14
+ private currentUserId;
15
+ private enrichAuditLog;
16
+ log(input: AuditLogInput): Promise<AuditLog | undefined>;
17
+ logEntity(entity: object, action: AuditActionType, changedBy?: number): Promise<AuditLog | undefined>;
18
+ findByEntity(entityType: string, entityId: number): Promise<AuditLogResponseDto[]>;
19
+ findByUser(userId: number): Promise<AuditLogResponseDto[]>;
20
+ findByAction(action: AuditActionType): Promise<AuditLogResponseDto[]>;
21
+ findAll(filterDto: AuditFilterDto): Promise<PaginatedResultDto<AuditLogResponseDto>>;
22
+ }
@@ -0,0 +1,185 @@
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
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ var AuditService_1;
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.AuditService = void 0;
17
+ const common_1 = require("@nestjs/common");
18
+ const typeorm_1 = require("@nestjs/typeorm");
19
+ const typeorm_2 = require("typeorm");
20
+ const nestjs_cls_1 = require("nestjs-cls");
21
+ const audit_log_entity_1 = require("./entities/audit-log.entity");
22
+ const audit_helper_1 = require("./audit.helper");
23
+ const audit_builder_1 = require("./audit.builder");
24
+ const auditable_decorator_1 = require("./decorators/auditable.decorator");
25
+ const audit_constants_1 = require("./audit.constants");
26
+ let AuditService = AuditService_1 = class AuditService {
27
+ auditRepository;
28
+ options;
29
+ cls;
30
+ logger = new common_1.Logger(AuditService_1.name);
31
+ constructor(auditRepository, options, cls) {
32
+ this.auditRepository = auditRepository;
33
+ this.options = options;
34
+ this.cls = cls;
35
+ }
36
+ currentUserId() {
37
+ return this.cls?.get(audit_constants_1.AUDIT_CLS_USER_ID);
38
+ }
39
+ async enrichAuditLog(log) {
40
+ const response = {
41
+ ...log,
42
+ changedByName: undefined,
43
+ changedByEmail: undefined,
44
+ };
45
+ if (log.changedBy && this.options.resolveUser) {
46
+ try {
47
+ const user = await this.options.resolveUser(log.changedBy);
48
+ if (user) {
49
+ response.changedByName = user.name;
50
+ response.changedByEmail = user.email;
51
+ }
52
+ }
53
+ catch (error) {
54
+ this.logger.error(`Failed to enrich user data for audit log ${log.id}`, String(error));
55
+ }
56
+ }
57
+ return response;
58
+ }
59
+ async log(input) {
60
+ try {
61
+ const auditLog = (0, audit_builder_1.toAuditLog)({
62
+ ...input,
63
+ changedBy: input.changedBy ?? this.currentUserId(),
64
+ });
65
+ const saved = await this.auditRepository.save(auditLog);
66
+ this.logger.log(`Audit: ${saved.entityType} ${saved.action} id=${saved.entityId} (log #${saved.id})`);
67
+ return saved;
68
+ }
69
+ catch (error) {
70
+ this.logger.error('Error recording audit log', String(error));
71
+ return undefined;
72
+ }
73
+ }
74
+ async logEntity(entity, action, changedBy) {
75
+ const auditable = (0, auditable_decorator_1.getAuditableOptions)(entity);
76
+ if (!auditable) {
77
+ this.logger.warn(`logEntity called for a non-@Auditable entity: ${entity?.constructor?.name}`);
78
+ return undefined;
79
+ }
80
+ const record = entity;
81
+ const entityName = auditable.nameField
82
+ ? record[auditable.nameField]
83
+ : undefined;
84
+ return this.log({
85
+ entityType: auditable.entityType,
86
+ entityId: record.id,
87
+ entityName,
88
+ action,
89
+ changes: (0, audit_helper_1.extractAuditableFields)(entity, auditable.exclude),
90
+ changedBy,
91
+ });
92
+ }
93
+ async findByEntity(entityType, entityId) {
94
+ try {
95
+ const logs = await this.auditRepository.find({
96
+ where: { entityType, entityId },
97
+ order: { changedAt: 'DESC' },
98
+ });
99
+ return Promise.all(logs.map((log) => this.enrichAuditLog(log)));
100
+ }
101
+ catch (error) {
102
+ this.logger.error(`Error fetching audit logs for ${entityType} ${entityId}`, String(error));
103
+ throw new common_1.InternalServerErrorException('Failed to fetch audit logs');
104
+ }
105
+ }
106
+ async findByUser(userId) {
107
+ try {
108
+ const logs = await this.auditRepository.find({
109
+ where: { changedBy: userId },
110
+ order: { changedAt: 'DESC' },
111
+ });
112
+ return Promise.all(logs.map((log) => this.enrichAuditLog(log)));
113
+ }
114
+ catch (error) {
115
+ this.logger.error(`Error fetching audit logs for user ${userId}`, String(error));
116
+ throw new common_1.InternalServerErrorException('Failed to fetch audit logs');
117
+ }
118
+ }
119
+ async findByAction(action) {
120
+ try {
121
+ const logs = await this.auditRepository.find({
122
+ where: { action },
123
+ order: { changedAt: 'DESC' },
124
+ });
125
+ return Promise.all(logs.map((log) => this.enrichAuditLog(log)));
126
+ }
127
+ catch (error) {
128
+ this.logger.error(`Error fetching audit logs for action ${action}`, String(error));
129
+ throw new common_1.InternalServerErrorException('Failed to fetch audit logs');
130
+ }
131
+ }
132
+ async findAll(filterDto) {
133
+ try {
134
+ const { page = 0, limit = 10, entityType, entityId, changedBy, action, search, } = filterDto;
135
+ const queryBuilder = this.auditRepository.createQueryBuilder('audit');
136
+ if (search) {
137
+ const searchQuery = `%${search.toLowerCase()}%`;
138
+ queryBuilder.andWhere('(LOWER(audit.entityType) LIKE :search OR LOWER(audit.entityName) LIKE :search)', { search: searchQuery });
139
+ }
140
+ if (entityType) {
141
+ queryBuilder.andWhere('audit.entityType = :entityType', { entityType });
142
+ }
143
+ if (entityId) {
144
+ queryBuilder.andWhere('audit.entityId = :entityId', { entityId });
145
+ }
146
+ if (changedBy) {
147
+ queryBuilder.andWhere('audit.changedBy = :changedBy', { changedBy });
148
+ }
149
+ if (action) {
150
+ queryBuilder.andWhere('audit.action = :action', { action });
151
+ }
152
+ const total = await queryBuilder.getCount();
153
+ const logs = await queryBuilder
154
+ .orderBy('audit.changedAt', 'DESC')
155
+ .addOrderBy('audit.id', 'DESC')
156
+ .skip(page * limit)
157
+ .take(limit)
158
+ .getMany();
159
+ const enrichedLogs = await Promise.all(logs.map((log) => this.enrichAuditLog(log)));
160
+ const totalPages = Math.ceil(total / limit);
161
+ return {
162
+ data: enrichedLogs,
163
+ total,
164
+ page,
165
+ limit,
166
+ totalPages,
167
+ hasNextPage: page < totalPages - 1,
168
+ hasPreviousPage: page > 0,
169
+ };
170
+ }
171
+ catch (error) {
172
+ this.logger.error('Error fetching audit logs', String(error));
173
+ throw new common_1.InternalServerErrorException('Failed to fetch audit logs');
174
+ }
175
+ }
176
+ };
177
+ exports.AuditService = AuditService;
178
+ exports.AuditService = AuditService = AuditService_1 = __decorate([
179
+ (0, common_1.Injectable)(),
180
+ __param(0, (0, typeorm_1.InjectRepository)(audit_log_entity_1.AuditLog)),
181
+ __param(1, (0, common_1.Inject)(audit_constants_1.AUDIT_MODULE_OPTIONS)),
182
+ __param(2, (0, common_1.Optional)()),
183
+ __metadata("design:paramtypes", [typeorm_2.Repository, Object, nestjs_cls_1.ClsService])
184
+ ], AuditService);
185
+ //# sourceMappingURL=audit.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.service.js","sourceRoot":"","sources":["../../src/audit.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { DataSource, EntitySubscriberInterface, InsertEvent, UpdateEvent } from 'typeorm';
2
+ import { ClsService } from 'nestjs-cls';
3
+ export declare class AuditSubscriber implements EntitySubscriberInterface {
4
+ private readonly cls;
5
+ private readonly logger;
6
+ constructor(dataSource: DataSource, cls: ClsService);
7
+ private currentUserId;
8
+ afterInsert(event: InsertEvent<object>): Promise<void>;
9
+ afterUpdate(event: UpdateEvent<object>): Promise<void>;
10
+ private persist;
11
+ }