@studiosonrai/nestjs-audit-log 1.0.0 → 1.1.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/README.md CHANGED
@@ -1,9 +1,13 @@
1
1
  # @studiosonrai/nestjs-audit-log
2
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.
3
+ Audit logging for NestJS + TypeORM. Mark an entity `@Auditable()` and CREATE / UPDATE /
4
+ DELETE are recorded automatically by a TypeORM subscriber — no per-service code — for
5
+ `repository.save()`, `repository.remove()`, and `repository.softRemove()`. For legacy
6
+ `repository.delete(id)` paths there's a single-line `AuditService.logEntity()` escape
7
+ hatch. The acting user is captured from the request via CLS, so you never thread
8
+ `userId` through your services. The `auditLog` table is created at startup and read/written
9
+ via raw SQL through your existing DataSource, so **no migration is required and you do
10
+ not need to add `AuditLog` to your `entities` array** (Microsoft SQL Server).
7
11
 
8
12
  ## Documentation
9
13
 
@@ -0,0 +1,12 @@
1
+ import { OnModuleInit } from '@nestjs/common';
2
+ import { DataSource } from 'typeorm';
3
+ import { AuditModuleOptions } from './interfaces/audit.interfaces';
4
+ export declare class AuditTableInitializer implements OnModuleInit {
5
+ private readonly dataSource;
6
+ private readonly options;
7
+ private static readonly TABLE;
8
+ private readonly logger;
9
+ constructor(dataSource: DataSource, options: AuditModuleOptions);
10
+ onModuleInit(): Promise<void>;
11
+ private buildCreateTableSql;
12
+ }
@@ -0,0 +1,89 @@
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 AuditTableInitializer_1;
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.AuditTableInitializer = void 0;
17
+ const common_1 = require("@nestjs/common");
18
+ const typeorm_1 = require("@nestjs/typeorm");
19
+ const typeorm_2 = require("typeorm");
20
+ const audit_logger_1 = require("./audit.logger");
21
+ const audit_constants_1 = require("./audit.constants");
22
+ let AuditTableInitializer = class AuditTableInitializer {
23
+ static { AuditTableInitializer_1 = this; }
24
+ dataSource;
25
+ options;
26
+ static TABLE = 'auditLog';
27
+ logger;
28
+ constructor(dataSource, options) {
29
+ this.dataSource = dataSource;
30
+ this.options = options;
31
+ this.logger = (0, audit_logger_1.resolveLogger)(options, AuditTableInitializer_1.name);
32
+ }
33
+ async onModuleInit() {
34
+ if (this.options.autoCreateTable === false) {
35
+ return;
36
+ }
37
+ const driverType = this.dataSource.options.type;
38
+ if (driverType !== 'mssql') {
39
+ this.logger.warn(`Skipping auditLog table creation: this package targets Microsoft SQL Server (got driver "${driverType}"). Create the table manually via a migration.`);
40
+ return;
41
+ }
42
+ if (!this.dataSource.isInitialized) {
43
+ await this.dataSource.initialize();
44
+ }
45
+ const schema = this.options.schema ?? 'dbo';
46
+ const fullName = `[${schema}].[${AuditTableInitializer_1.TABLE}]`;
47
+ try {
48
+ await this.dataSource.query(this.buildCreateTableSql(schema, fullName));
49
+ this.logger.log(`Ensured auditLog table exists at ${fullName}`);
50
+ }
51
+ catch (error) {
52
+ this.logger.error(`Failed to ensure auditLog table at ${fullName}. ` +
53
+ `Set AuditModuleOptions.autoCreateTable: false to manage the schema manually.`, error instanceof Error ? error.stack : String(error));
54
+ throw error;
55
+ }
56
+ }
57
+ buildCreateTableSql(schema, fullName) {
58
+ return `
59
+ IF NOT EXISTS (
60
+ SELECT 1 FROM sys.objects
61
+ WHERE object_id = OBJECT_ID(N'${fullName}') AND type = 'U'
62
+ )
63
+ BEGIN
64
+ CREATE TABLE ${fullName} (
65
+ id INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
66
+ entityType NVARCHAR(255) NOT NULL,
67
+ entityId INT NOT NULL,
68
+ action NVARCHAR(50) NOT NULL DEFAULT 'CREATE',
69
+ changes NVARCHAR(MAX) NULL,
70
+ entityName NVARCHAR(500) NULL,
71
+ changedBy INT NULL,
72
+ changedAt DATETIME2 NOT NULL DEFAULT GETDATE(),
73
+ INDEX IX_${AuditTableInitializer_1.TABLE}_entityType_entityId (entityType, entityId),
74
+ INDEX IX_${AuditTableInitializer_1.TABLE}_changedBy (changedBy),
75
+ INDEX IX_${AuditTableInitializer_1.TABLE}_action (action),
76
+ INDEX IX_${AuditTableInitializer_1.TABLE}_changedAt (changedAt DESC)
77
+ );
78
+ END
79
+ `;
80
+ }
81
+ };
82
+ exports.AuditTableInitializer = AuditTableInitializer;
83
+ exports.AuditTableInitializer = AuditTableInitializer = AuditTableInitializer_1 = __decorate([
84
+ (0, common_1.Injectable)(),
85
+ __param(0, (0, typeorm_1.InjectDataSource)()),
86
+ __param(1, (0, common_1.Inject)(audit_constants_1.AUDIT_MODULE_OPTIONS)),
87
+ __metadata("design:paramtypes", [typeorm_2.DataSource, Object])
88
+ ], AuditTableInitializer);
89
+ //# sourceMappingURL=audit-table.initializer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-table.initializer.js","sourceRoot":"","sources":["../../src/audit-table.initializer.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAKwB;AACxB,6CAAmD;AACnD,qCAAqC;AACrC,iDAA+C;AAC/C,uDAAyD;AAgBlD,IAAM,qBAAqB,GAA3B,MAAM,qBAAqB;;IAKO;IAEpB;IANX,MAAM,CAAU,KAAK,GAAG,UAAU,CAAC;IAC1B,MAAM,CAAgB;IAEvC,YACuC,UAAsB,EAE1C,OAA2B;QAFP,eAAU,GAAV,UAAU,CAAY;QAE1C,YAAO,GAAP,OAAO,CAAoB;QAE5C,IAAI,CAAC,MAAM,GAAG,IAAA,4BAAa,EAAC,OAAO,EAAE,uBAAqB,CAAC,IAAI,CAAC,CAAC;IACnE,CAAC;IAED,KAAK,CAAC,YAAY;QAChB,IAAI,IAAI,CAAC,OAAO,CAAC,eAAe,KAAK,KAAK,EAAE,CAAC;YAC3C,OAAO;QACT,CAAC;QAED,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC;QAChD,IAAI,UAAU,KAAK,OAAO,EAAE,CAAC;YAC3B,IAAI,CAAC,MAAM,CAAC,IAAI,CACd,4FAA4F,UAAU,gDAAgD,CACvJ,CAAC;YACF,OAAO;QACT,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,aAAa,EAAE,CAAC;YACnC,MAAM,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC;QACrC,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,KAAK,CAAC;QAC5C,MAAM,QAAQ,GAAG,IAAI,MAAM,MAAM,uBAAqB,CAAC,KAAK,GAAG,CAAC;QAEhE,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;YACxE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,oCAAoC,QAAQ,EAAE,CAAC,CAAC;QAClE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,sCAAsC,QAAQ,IAAI;gBAChD,8EAA8E,EAChF,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CACrD,CAAC;YACF,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAEO,mBAAmB,CAAC,MAAc,EAAE,QAAgB;QAC1D,OAAO;;;wCAG6B,QAAQ;;;uBAGzB,QAAQ;;;;;;;;;qBASV,uBAAqB,CAAC,KAAK;qBAC3B,uBAAqB,CAAC,KAAK;qBAC3B,uBAAqB,CAAC,KAAK;qBAC3B,uBAAqB,CAAC,KAAK;;;KAG3C,CAAC;IACJ,CAAC;;AApEU,sDAAqB;gCAArB,qBAAqB;IADjC,IAAA,mBAAU,GAAE;IAMR,WAAA,IAAA,0BAAgB,GAAE,CAAA;IAClB,WAAA,IAAA,eAAM,EAAC,sCAAoB,CAAC,CAAA;qCADoB,oBAAU;GALlD,qBAAqB,CAqEjC"}
@@ -0,0 +1,3 @@
1
+ import { LoggerService } from '@nestjs/common';
2
+ import { AuditModuleOptions } from './interfaces/audit.interfaces';
3
+ export declare function resolveLogger(options: AuditModuleOptions, context: string): LoggerService;
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveLogger = resolveLogger;
4
+ class NoopLogger {
5
+ log() {
6
+ }
7
+ error() {
8
+ }
9
+ warn() {
10
+ }
11
+ debug() {
12
+ }
13
+ verbose() {
14
+ }
15
+ fatal() {
16
+ }
17
+ }
18
+ const NOOP_LOGGER = new NoopLogger();
19
+ function resolveLogger(options, context) {
20
+ return options.logger ? options.logger(context) : NOOP_LOGGER;
21
+ }
22
+ //# sourceMappingURL=audit.logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.logger.js","sourceRoot":"","sources":["../../src/audit.logger.ts"],"names":[],"mappings":";;AAoCA,sCAKC;AAhCD,MAAM,UAAU;IACd,GAAG;IAEH,CAAC;IACD,KAAK;IAEL,CAAC;IACD,IAAI;IAEJ,CAAC;IACD,KAAK;IAEL,CAAC;IACD,OAAO;IAEP,CAAC;IACD,KAAK;IAEL,CAAC;CACF;AAED,MAAM,WAAW,GAAkB,IAAI,UAAU,EAAE,CAAC;AAMpD,SAAgB,aAAa,CAC3B,OAA2B,EAC3B,OAAe;IAEf,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;AAChE,CAAC"}
@@ -10,14 +10,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.AuditModule = void 0;
11
11
  const common_1 = require("@nestjs/common");
12
12
  const core_1 = require("@nestjs/core");
13
- const typeorm_1 = require("@nestjs/typeorm");
14
13
  const nestjs_cls_1 = require("nestjs-cls");
15
- const audit_log_entity_1 = require("./entities/audit-log.entity");
16
14
  const audit_service_1 = require("./audit.service");
17
15
  const audit_subscriber_1 = require("./audit.subscriber");
18
16
  const audit_context_interceptor_1 = require("./audit-context.interceptor");
17
+ const audit_table_initializer_1 = require("./audit-table.initializer");
19
18
  const audit_constants_1 = require("./audit.constants");
20
19
  const sharedProviders = [
20
+ audit_table_initializer_1.AuditTableInitializer,
21
21
  audit_service_1.AuditService,
22
22
  audit_subscriber_1.AuditSubscriber,
23
23
  { provide: core_1.APP_INTERCEPTOR, useClass: audit_context_interceptor_1.AuditContextInterceptor },
@@ -46,10 +46,7 @@ let AuditModule = AuditModule_1 = class AuditModule {
46
46
  };
47
47
  }
48
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
- ];
49
+ return [nestjs_cls_1.ClsModule.forRoot({ global: true, middleware: { mount: true } })];
53
50
  }
54
51
  static createAsyncProviders(options) {
55
52
  if (options.useExisting || options.useFactory) {
@@ -1 +1 @@
1
- {"version":3,"file":"audit.module.js","sourceRoot":"","sources":["../../src/audit.module.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"audit.module.js","sourceRoot":"","sources":["../../src/audit.module.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,2CAAyE;AACzE,uCAA+C;AAC/C,2CAAuC;AACvC,mDAA+C;AAC/C,yDAAqD;AACrD,2EAAsE;AACtE,uEAAkE;AAClE,uDAAyD;AAOzD,MAAM,eAAe,GAAe;IAClC,+CAAqB;IACrB,4BAAY;IACZ,kCAAe;IACf,EAAE,OAAO,EAAE,sBAAe,EAAE,QAAQ,EAAE,mDAAuB,EAAE;CAChE,CAAC;AAIK,IAAM,WAAW,mBAAjB,MAAM,WAAW;IACtB,MAAM,CAAC,OAAO,CAAC,UAA8B,EAAE;QAC7C,OAAO;YACL,MAAM,EAAE,aAAW;YACnB,OAAO,EAAE,CAAC,GAAG,aAAW,CAAC,WAAW,EAAE,CAAC;YACvC,SAAS,EAAE;gBACT,EAAE,OAAO,EAAE,sCAAoB,EAAE,QAAQ,EAAE,OAAO,EAAE;gBACpD,GAAG,eAAe;aACnB;YACD,OAAO,EAAE,CAAC,4BAAY,EAAE,sCAAoB,CAAC;SAC9C,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,YAAY,CAAC,OAAgC;QAClD,OAAO;YACL,MAAM,EAAE,aAAW;YACnB,OAAO,EAAE,CAAC,GAAG,aAAW,CAAC,WAAW,EAAE,EAAE,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;YACnE,SAAS,EAAE;gBACT,GAAG,aAAW,CAAC,oBAAoB,CAAC,OAAO,CAAC;gBAC5C,GAAG,eAAe;aACnB;YACD,OAAO,EAAE,CAAC,4BAAY,EAAE,sCAAoB,CAAC;SAC9C,CAAC;IACJ,CAAC;IAEO,MAAM,CAAC,WAAW;QACxB,OAAO,CAAC,sBAAS,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;IAC5E,CAAC;IAEO,MAAM,CAAC,oBAAoB,CACjC,OAAgC;QAEhC,IAAI,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;YAC9C,OAAO,CAAC,aAAW,CAAC,0BAA0B,CAAC,OAAO,CAAC,CAAC,CAAC;QAC3D,CAAC;QAED,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACrB,OAAO;gBACL,aAAW,CAAC,0BAA0B,CAAC,OAAO,CAAC;gBAC/C,EAAE,OAAO,EAAE,OAAO,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE;aAC1D,CAAC;QACJ,CAAC;QAED,MAAM,IAAI,KAAK,CACb,+EAA+E,CAChF,CAAC;IACJ,CAAC;IAEO,MAAM,CAAC,0BAA0B,CACvC,OAAgC;QAEhC,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;YACvB,OAAO;gBACL,OAAO,EAAE,sCAAoB;gBAC7B,UAAU,EAAE,OAAO,CAAC,UAAU;gBAC9B,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,EAAE;aAC7B,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,QAAQ,CAAC;QACvD,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CACb,+EAA+E,CAChF,CAAC;QACJ,CAAC;QAED,OAAO;YACL,OAAO,EAAE,sCAAoB;YAC7B,UAAU,EAAE,CAAC,OAAkC,EAAE,EAAE,CACjD,OAAO,CAAC,kBAAkB,EAAE;YAC9B,MAAM,EAAE,CAAC,MAAM,CAAC;SACjB,CAAC;IACJ,CAAC;CACF,CAAA;AAzEY,kCAAW;sBAAX,WAAW;IAFvB,IAAA,eAAM,GAAE;IACR,IAAA,eAAM,EAAC,EAAE,CAAC;GACE,WAAW,CAyEvB"}
@@ -1,4 +1,4 @@
1
- import { Repository } from 'typeorm';
1
+ import { DataSource } from 'typeorm';
2
2
  import { ClsService } from 'nestjs-cls';
3
3
  import { AuditLog, AuditActionType } from './entities/audit-log.entity';
4
4
  import { AuditFilterDto } from './dto/audit-filter.dto';
@@ -6,11 +6,12 @@ import { AuditLogResponseDto } from './dto/audit-log-response.dto';
6
6
  import { PaginatedResultDto } from './dto/paginated-result.dto';
7
7
  import { AuditLogInput, AuditModuleOptions } from './interfaces/audit.interfaces';
8
8
  export declare class AuditService {
9
- private readonly auditRepository;
9
+ private readonly dataSource;
10
10
  private readonly options;
11
11
  private readonly cls?;
12
12
  private readonly logger;
13
- constructor(auditRepository: Repository<AuditLog>, options: AuditModuleOptions, cls?: ClsService | undefined);
13
+ private readonly tableName;
14
+ constructor(dataSource: DataSource, options: AuditModuleOptions, cls?: ClsService | undefined);
14
15
  private currentUserId;
15
16
  private enrichAuditLog;
16
17
  log(input: AuditLogInput): Promise<AuditLog | undefined>;
@@ -18,51 +18,66 @@ const common_1 = require("@nestjs/common");
18
18
  const typeorm_1 = require("@nestjs/typeorm");
19
19
  const typeorm_2 = require("typeorm");
20
20
  const nestjs_cls_1 = require("nestjs-cls");
21
- const audit_log_entity_1 = require("./entities/audit-log.entity");
22
21
  const audit_helper_1 = require("./audit.helper");
23
- const audit_builder_1 = require("./audit.builder");
24
22
  const auditable_decorator_1 = require("./decorators/auditable.decorator");
23
+ const audit_logger_1 = require("./audit.logger");
25
24
  const audit_constants_1 = require("./audit.constants");
25
+ const SELECT_COLUMNS = 'id, entityType, entityId, action, changes, entityName, changedBy, changedAt';
26
26
  let AuditService = AuditService_1 = class AuditService {
27
- auditRepository;
27
+ dataSource;
28
28
  options;
29
29
  cls;
30
- logger = new common_1.Logger(AuditService_1.name);
31
- constructor(auditRepository, options, cls) {
32
- this.auditRepository = auditRepository;
30
+ logger;
31
+ tableName;
32
+ constructor(dataSource, options, cls) {
33
+ this.dataSource = dataSource;
33
34
  this.options = options;
34
35
  this.cls = cls;
36
+ const schema = options.schema ?? 'dbo';
37
+ this.tableName = `[${schema}].[auditLog]`;
38
+ this.logger = (0, audit_logger_1.resolveLogger)(options, AuditService_1.name);
35
39
  }
36
40
  currentUserId() {
37
41
  return this.cls?.get(audit_constants_1.AUDIT_CLS_USER_ID);
38
42
  }
39
- async enrichAuditLog(log) {
43
+ async enrichAuditLog(row) {
40
44
  const response = {
41
- ...log,
45
+ ...row,
42
46
  changedByName: undefined,
43
47
  changedByEmail: undefined,
44
48
  };
45
- if (log.changedBy && this.options.resolveUser) {
49
+ if (row.changedBy && this.options.resolveUser) {
46
50
  try {
47
- const user = await this.options.resolveUser(log.changedBy);
51
+ const user = await this.options.resolveUser(row.changedBy);
48
52
  if (user) {
49
53
  response.changedByName = user.name;
50
54
  response.changedByEmail = user.email;
51
55
  }
52
56
  }
53
57
  catch (error) {
54
- this.logger.error(`Failed to enrich user data for audit log ${log.id}`, String(error));
58
+ this.logger.error(`Failed to enrich user data for audit log ${row.id}`, String(error));
55
59
  }
56
60
  }
57
61
  return response;
58
62
  }
59
63
  async log(input) {
60
64
  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);
65
+ const changedBy = input.changedBy ?? this.currentUserId();
66
+ const changes = input.changes ? JSON.stringify(input.changes) : null;
67
+ const sql = `
68
+ INSERT INTO ${this.tableName} (entityType, entityId, action, changes, entityName, changedBy)
69
+ OUTPUT INSERTED.${SELECT_COLUMNS.split(', ').join(', INSERTED.')}
70
+ VALUES (@0, @1, @2, @3, @4, @5)
71
+ `;
72
+ const rows = await this.dataSource.query(sql, [
73
+ input.entityType,
74
+ input.entityId,
75
+ input.action,
76
+ changes,
77
+ input.entityName ?? null,
78
+ changedBy ?? null,
79
+ ]);
80
+ const saved = rows[0];
66
81
  this.logger.log(`Audit: ${saved.entityType} ${saved.action} id=${saved.entityId} (log #${saved.id})`);
67
82
  return saved;
68
83
  }
@@ -92,11 +107,17 @@ let AuditService = AuditService_1 = class AuditService {
92
107
  }
93
108
  async findByEntity(entityType, entityId) {
94
109
  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)));
110
+ const sql = `
111
+ SELECT ${SELECT_COLUMNS}
112
+ FROM ${this.tableName}
113
+ WHERE entityType = @0 AND entityId = @1
114
+ ORDER BY changedAt DESC, id DESC
115
+ `;
116
+ const rows = await this.dataSource.query(sql, [
117
+ entityType,
118
+ entityId,
119
+ ]);
120
+ return Promise.all(rows.map((row) => this.enrichAuditLog(row)));
100
121
  }
101
122
  catch (error) {
102
123
  this.logger.error(`Error fetching audit logs for ${entityType} ${entityId}`, String(error));
@@ -105,11 +126,14 @@ let AuditService = AuditService_1 = class AuditService {
105
126
  }
106
127
  async findByUser(userId) {
107
128
  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)));
129
+ const sql = `
130
+ SELECT ${SELECT_COLUMNS}
131
+ FROM ${this.tableName}
132
+ WHERE changedBy = @0
133
+ ORDER BY changedAt DESC, id DESC
134
+ `;
135
+ const rows = await this.dataSource.query(sql, [userId]);
136
+ return Promise.all(rows.map((row) => this.enrichAuditLog(row)));
113
137
  }
114
138
  catch (error) {
115
139
  this.logger.error(`Error fetching audit logs for user ${userId}`, String(error));
@@ -118,11 +142,14 @@ let AuditService = AuditService_1 = class AuditService {
118
142
  }
119
143
  async findByAction(action) {
120
144
  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)));
145
+ const sql = `
146
+ SELECT ${SELECT_COLUMNS}
147
+ FROM ${this.tableName}
148
+ WHERE action = @0
149
+ ORDER BY changedAt DESC, id DESC
150
+ `;
151
+ const rows = await this.dataSource.query(sql, [action]);
152
+ return Promise.all(rows.map((row) => this.enrichAuditLog(row)));
126
153
  }
127
154
  catch (error) {
128
155
  this.logger.error(`Error fetching audit logs for action ${action}`, String(error));
@@ -132,34 +159,53 @@ let AuditService = AuditService_1 = class AuditService {
132
159
  async findAll(filterDto) {
133
160
  try {
134
161
  const { page = 0, limit = 10, entityType, entityId, changedBy, action, search, } = filterDto;
135
- const queryBuilder = this.auditRepository.createQueryBuilder('audit');
162
+ const conditions = [];
163
+ const params = [];
136
164
  if (search) {
137
- const searchQuery = `%${search.toLowerCase()}%`;
138
- queryBuilder.andWhere('(LOWER(audit.entityType) LIKE :search OR LOWER(audit.entityName) LIKE :search)', { search: searchQuery });
165
+ const idx = params.length;
166
+ conditions.push(`(LOWER(entityType) LIKE @${idx} OR LOWER(ISNULL(entityName, '')) LIKE @${idx})`);
167
+ params.push(`%${search.toLowerCase()}%`);
139
168
  }
140
169
  if (entityType) {
141
- queryBuilder.andWhere('audit.entityType = :entityType', { entityType });
170
+ conditions.push(`entityType = @${params.length}`);
171
+ params.push(entityType);
142
172
  }
143
173
  if (entityId) {
144
- queryBuilder.andWhere('audit.entityId = :entityId', { entityId });
174
+ conditions.push(`entityId = @${params.length}`);
175
+ params.push(entityId);
145
176
  }
146
177
  if (changedBy) {
147
- queryBuilder.andWhere('audit.changedBy = :changedBy', { changedBy });
178
+ conditions.push(`changedBy = @${params.length}`);
179
+ params.push(changedBy);
148
180
  }
149
181
  if (action) {
150
- queryBuilder.andWhere('audit.action = :action', { action });
182
+ conditions.push(`action = @${params.length}`);
183
+ params.push(action);
151
184
  }
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);
185
+ const where = conditions.length
186
+ ? `WHERE ${conditions.join(' AND ')}`
187
+ : '';
188
+ const countRows = await this.dataSource.query(`SELECT COUNT(*) AS total FROM ${this.tableName} ${where}`, params);
189
+ const total = Number(countRows[0]?.total ?? 0);
190
+ const offset = page * limit;
191
+ const offsetIdx = params.length;
192
+ const limitIdx = params.length + 1;
193
+ const dataSql = `
194
+ SELECT ${SELECT_COLUMNS}
195
+ FROM ${this.tableName}
196
+ ${where}
197
+ ORDER BY changedAt DESC, id DESC
198
+ OFFSET @${offsetIdx} ROWS FETCH NEXT @${limitIdx} ROWS ONLY
199
+ `;
200
+ const rows = await this.dataSource.query(dataSql, [
201
+ ...params,
202
+ offset,
203
+ limit,
204
+ ]);
205
+ const data = await Promise.all(rows.map((row) => this.enrichAuditLog(row)));
206
+ const totalPages = total === 0 ? 0 : Math.ceil(total / limit);
161
207
  return {
162
- data: enrichedLogs,
208
+ data,
163
209
  total,
164
210
  page,
165
211
  limit,
@@ -177,9 +223,9 @@ let AuditService = AuditService_1 = class AuditService {
177
223
  exports.AuditService = AuditService;
178
224
  exports.AuditService = AuditService = AuditService_1 = __decorate([
179
225
  (0, common_1.Injectable)(),
180
- __param(0, (0, typeorm_1.InjectRepository)(audit_log_entity_1.AuditLog)),
226
+ __param(0, (0, typeorm_1.InjectDataSource)()),
181
227
  __param(1, (0, common_1.Inject)(audit_constants_1.AUDIT_MODULE_OPTIONS)),
182
228
  __param(2, (0, common_1.Optional)()),
183
- __metadata("design:paramtypes", [typeorm_2.Repository, Object, nestjs_cls_1.ClsService])
229
+ __metadata("design:paramtypes", [typeorm_2.DataSource, Object, nestjs_cls_1.ClsService])
184
230
  ], AuditService);
185
231
  //# sourceMappingURL=audit.service.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"audit.service.js","sourceRoot":"","sources":["../../src/audit.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"audit.service.js","sourceRoot":"","sources":["../../src/audit.service.ts"],"names":[],"mappings":"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"}
@@ -1,11 +1,16 @@
1
- import { DataSource, EntitySubscriberInterface, InsertEvent, UpdateEvent } from 'typeorm';
1
+ import { DataSource, EntitySubscriberInterface, InsertEvent, RemoveEvent, SoftRemoveEvent, UpdateEvent } from 'typeorm';
2
2
  import { ClsService } from 'nestjs-cls';
3
+ import { AuditModuleOptions } from './interfaces/audit.interfaces';
3
4
  export declare class AuditSubscriber implements EntitySubscriberInterface {
4
5
  private readonly cls;
5
6
  private readonly logger;
6
- constructor(dataSource: DataSource, cls: ClsService);
7
+ private readonly tableName;
8
+ constructor(dataSource: DataSource, options: AuditModuleOptions, cls: ClsService);
7
9
  private currentUserId;
8
10
  afterInsert(event: InsertEvent<object>): Promise<void>;
9
11
  afterUpdate(event: UpdateEvent<object>): Promise<void>;
12
+ afterRemove(event: RemoveEvent<object>): Promise<void>;
13
+ afterSoftRemove(event: SoftRemoveEvent<object>): Promise<void>;
14
+ private handleRemoval;
10
15
  private persist;
11
16
  }
@@ -20,14 +20,18 @@ const typeorm_2 = require("typeorm");
20
20
  const nestjs_cls_1 = require("nestjs-cls");
21
21
  const audit_log_entity_1 = require("./entities/audit-log.entity");
22
22
  const audit_helper_1 = require("./audit.helper");
23
- const audit_builder_1 = require("./audit.builder");
24
23
  const auditable_decorator_1 = require("./decorators/auditable.decorator");
24
+ const audit_logger_1 = require("./audit.logger");
25
25
  const audit_constants_1 = require("./audit.constants");
26
26
  let AuditSubscriber = AuditSubscriber_1 = class AuditSubscriber {
27
27
  cls;
28
- logger = new common_1.Logger(AuditSubscriber_1.name);
29
- constructor(dataSource, cls) {
28
+ logger;
29
+ tableName;
30
+ constructor(dataSource, options, cls) {
30
31
  this.cls = cls;
32
+ const schema = options.schema ?? 'dbo';
33
+ this.tableName = `[${schema}].[auditLog]`;
34
+ this.logger = (0, audit_logger_1.resolveLogger)(options, AuditSubscriber_1.name);
31
35
  dataSource.subscribers.push(this);
32
36
  }
33
37
  currentUserId() {
@@ -43,7 +47,7 @@ let AuditSubscriber = AuditSubscriber_1 = class AuditSubscriber {
43
47
  return;
44
48
  }
45
49
  const record = entity;
46
- await this.persist(event.manager.getRepository(audit_log_entity_1.AuditLog), {
50
+ await this.persist(event.manager, {
47
51
  entityType: auditable.entityType,
48
52
  entityId: record.id,
49
53
  entityName: auditable.nameField
@@ -52,6 +56,7 @@ let AuditSubscriber = AuditSubscriber_1 = class AuditSubscriber {
52
56
  action: audit_log_entity_1.AuditActionType.CREATE,
53
57
  changes: (0, audit_helper_1.extractAuditableFields)(entity, auditable.exclude),
54
58
  });
59
+ this.logger.log(`Recorded CREATE audit for ${auditable.entityType} ${record.id}`);
55
60
  }
56
61
  async afterUpdate(event) {
57
62
  const entity = event.entity;
@@ -71,7 +76,7 @@ let AuditSubscriber = AuditSubscriber_1 = class AuditSubscriber {
71
76
  return;
72
77
  }
73
78
  const record = entity;
74
- await this.persist(event.manager.getRepository(audit_log_entity_1.AuditLog), {
79
+ await this.persist(event.manager, {
75
80
  entityType: auditable.entityType,
76
81
  entityId: record.id,
77
82
  entityName: auditable.nameField
@@ -80,10 +85,50 @@ let AuditSubscriber = AuditSubscriber_1 = class AuditSubscriber {
80
85
  action: audit_log_entity_1.AuditActionType.UPDATE,
81
86
  changes,
82
87
  });
88
+ this.logger.log(`Recorded UPDATE audit for ${auditable.entityType} ${record.id}`);
83
89
  }
84
- async persist(repository, input) {
90
+ async afterRemove(event) {
91
+ await this.handleRemoval(event);
92
+ }
93
+ async afterSoftRemove(event) {
94
+ await this.handleRemoval(event);
95
+ }
96
+ async handleRemoval(event) {
97
+ const source = event.databaseEntity ?? event.entity;
98
+ if (!source || source instanceof audit_log_entity_1.AuditLog) {
99
+ return;
100
+ }
101
+ const auditable = (0, auditable_decorator_1.getAuditableOptions)(source);
102
+ if (!auditable) {
103
+ return;
104
+ }
105
+ const record = source;
106
+ const entityId = event.entityId ?? record.id;
107
+ await this.persist(event.manager, {
108
+ entityType: auditable.entityType,
109
+ entityId,
110
+ entityName: auditable.nameField
111
+ ? record[auditable.nameField]
112
+ : undefined,
113
+ action: audit_log_entity_1.AuditActionType.DELETE,
114
+ changes: (0, audit_helper_1.extractAuditableFields)(source, auditable.exclude),
115
+ });
116
+ this.logger.log(`Recorded DELETE audit for ${auditable.entityType} ${entityId}`);
117
+ }
118
+ async persist(manager, input) {
85
119
  try {
86
- await repository.save((0, audit_builder_1.toAuditLog)({ ...input, changedBy: this.currentUserId() }));
120
+ const sql = `
121
+ INSERT INTO ${this.tableName} (entityType, entityId, action, changes, entityName, changedBy)
122
+ VALUES (@0, @1, @2, @3, @4, @5)
123
+ `;
124
+ await manager.query(sql, [
125
+ input.entityType,
126
+ input.entityId,
127
+ input.action,
128
+ JSON.stringify(input.changes),
129
+ input.entityName ?? null,
130
+ this.currentUserId() ?? null,
131
+ ]);
87
132
  }
88
133
  catch (error) {
89
134
  this.logger.error(`Failed to record ${input.action} audit for ${input.entityType} ${input.entityId}`, String(error));
@@ -94,7 +139,7 @@ exports.AuditSubscriber = AuditSubscriber;
94
139
  exports.AuditSubscriber = AuditSubscriber = AuditSubscriber_1 = __decorate([
95
140
  (0, common_1.Injectable)(),
96
141
  __param(0, (0, typeorm_1.InjectDataSource)()),
97
- __metadata("design:paramtypes", [typeorm_2.DataSource,
98
- nestjs_cls_1.ClsService])
142
+ __param(1, (0, common_1.Inject)(audit_constants_1.AUDIT_MODULE_OPTIONS)),
143
+ __metadata("design:paramtypes", [typeorm_2.DataSource, Object, nestjs_cls_1.ClsService])
99
144
  ], AuditSubscriber);
100
145
  //# sourceMappingURL=audit.subscriber.js.map