@nest-util/nest-crud 1.2.2 → 2.0.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.
@@ -1 +1 @@
1
- {"version":3,"file":"nest-crud.controller.d.ts","sourceRoot":"","sources":["../../../src/lib/controllers/nest-crud.controller.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"nest-crud.controller.d.ts","sourceRoot":"","sources":["../../../src/lib/controllers/nest-crud.controller.ts"],"names":[],"mappings":"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"}
@@ -4,6 +4,7 @@ exports.AUTH_PERMISSIONS_METADATA_KEY = void 0;
4
4
  exports.CreateNestedCrudController = CreateNestedCrudController;
5
5
  const tslib_1 = require("tslib");
6
6
  const common_1 = require("@nestjs/common");
7
+ const nest_error_1 = require("@nest-util/nest-error");
7
8
  const swagger_1 = require("@nestjs/swagger");
8
9
  const response_message_decorator_1 = require("../decorators/response-message.decorator");
9
10
  const audit_log_decorator_1 = require("../decorators/audit-log.decorator");
@@ -49,7 +50,7 @@ function CreateNestedCrudController(createDto, updateDto, responseDto, options)
49
50
  }
50
51
  ensureEndpointEnabled(endpoint) {
51
52
  if (this.service.disabledEndpoints?.includes(endpoint)) {
52
- throw new common_1.NotFoundException('Resource not found');
53
+ throw (0, nest_error_1.keyed)(common_1.HttpStatus.NOT_FOUND, nest_error_1.ErrorKey.CRUD_RESOURCE_NOT_FOUND);
53
54
  }
54
55
  }
55
56
  findAll(query) {
@@ -57,7 +58,7 @@ function CreateNestedCrudController(createDto, updateDto, responseDto, options)
57
58
  // Cursor-based pagination: dispatch to cursor endpoint
58
59
  if (query.cursor !== undefined) {
59
60
  if (!this.service.findAllWithCursor) {
60
- throw new common_1.NotFoundException('Resource not found');
61
+ throw (0, nest_error_1.keyed)(common_1.HttpStatus.NOT_FOUND, nest_error_1.ErrorKey.CRUD_RESOURCE_NOT_FOUND);
61
62
  }
62
63
  return this.service.findAllWithCursor(query);
63
64
  }
@@ -66,7 +67,7 @@ function CreateNestedCrudController(createDto, updateDto, responseDto, options)
66
67
  findMine(user, query) {
67
68
  this.ensureEndpointEnabled('findMine');
68
69
  if (!this.service.findMine) {
69
- throw new common_1.NotFoundException('Resource not found');
70
+ throw (0, nest_error_1.keyed)(common_1.HttpStatus.NOT_FOUND, nest_error_1.ErrorKey.CRUD_RESOURCE_NOT_FOUND);
70
71
  }
71
72
  return this.service.findMine(user.id, query);
72
73
  }
@@ -81,45 +82,52 @@ function CreateNestedCrudController(createDto, updateDto, responseDto, options)
81
82
  changeStatus(id, dto, user) {
82
83
  this.ensureEndpointEnabled('changeStatus');
83
84
  if (!this.service.changeStatus) {
84
- throw new common_1.NotFoundException('Resource not found');
85
+ throw (0, nest_error_1.keyed)(common_1.HttpStatus.NOT_FOUND, nest_error_1.ErrorKey.CRUD_RESOURCE_NOT_FOUND);
85
86
  }
86
87
  return this.service.changeStatus(id, dto.status, user);
87
88
  }
88
89
  getApproval(id, user) {
89
90
  this.ensureEndpointEnabled('getApproval');
90
91
  if (!this.service.getApproval) {
91
- throw new common_1.NotFoundException('Resource not found');
92
+ throw (0, nest_error_1.keyed)(common_1.HttpStatus.NOT_FOUND, nest_error_1.ErrorKey.CRUD_RESOURCE_NOT_FOUND);
92
93
  }
93
94
  return this.service.getApproval(id, user);
94
95
  }
95
96
  approveApproval(id, user) {
96
97
  this.ensureEndpointEnabled('approveApproval');
97
98
  if (!this.service.approveApproval) {
98
- throw new common_1.NotFoundException('Resource not found');
99
+ throw (0, nest_error_1.keyed)(common_1.HttpStatus.NOT_FOUND, nest_error_1.ErrorKey.CRUD_RESOURCE_NOT_FOUND);
99
100
  }
100
101
  return this.service.approveApproval(id, user);
101
102
  }
102
103
  rejectApproval(id, user) {
103
104
  this.ensureEndpointEnabled('rejectApproval');
104
105
  if (!this.service.rejectApproval) {
105
- throw new common_1.NotFoundException('Resource not found');
106
+ throw (0, nest_error_1.keyed)(common_1.HttpStatus.NOT_FOUND, nest_error_1.ErrorKey.CRUD_RESOURCE_NOT_FOUND);
106
107
  }
107
108
  return this.service.rejectApproval(id, user);
108
109
  }
109
110
  requestModification(id, dto, user) {
110
111
  this.ensureEndpointEnabled('requestModification');
111
112
  if (!this.service.requestModification) {
112
- throw new common_1.NotFoundException('Resource not found');
113
+ throw (0, nest_error_1.keyed)(common_1.HttpStatus.NOT_FOUND, nest_error_1.ErrorKey.CRUD_RESOURCE_NOT_FOUND);
113
114
  }
114
115
  return this.service.requestModification(id, dto, user);
115
116
  }
116
117
  resubmitApproval(id, user) {
117
118
  this.ensureEndpointEnabled('resubmitApproval');
118
119
  if (!this.service.resubmitApproval) {
119
- throw new common_1.NotFoundException('Resource not found');
120
+ throw (0, nest_error_1.keyed)(common_1.HttpStatus.NOT_FOUND, nest_error_1.ErrorKey.CRUD_RESOURCE_NOT_FOUND);
120
121
  }
121
122
  return this.service.resubmitApproval(id, user);
122
123
  }
124
+ submitApproval(id, user) {
125
+ this.ensureEndpointEnabled('submitApproval');
126
+ if (!this.service.submitApproval) {
127
+ throw (0, nest_error_1.keyed)(common_1.HttpStatus.NOT_FOUND, nest_error_1.ErrorKey.CRUD_RESOURCE_NOT_FOUND);
128
+ }
129
+ return this.service.submitApproval(id, user);
130
+ }
123
131
  remove(id, user) {
124
132
  this.ensureEndpointEnabled('remove');
125
133
  return this.service.remove(id, user);
@@ -127,7 +135,7 @@ function CreateNestedCrudController(createDto, updateDto, responseDto, options)
127
135
  findAuditLogs(query) {
128
136
  this.ensureEndpointEnabled('findAuditLogs');
129
137
  if (!this.service.findAuditLogs) {
130
- throw new common_1.NotFoundException('Resource not found');
138
+ throw (0, nest_error_1.keyed)(common_1.HttpStatus.NOT_FOUND, nest_error_1.ErrorKey.CRUD_RESOURCE_NOT_FOUND);
131
139
  }
132
140
  return this.service.findAuditLogs(query);
133
141
  }
@@ -279,6 +287,17 @@ function CreateNestedCrudController(createDto, updateDto, responseDto, options)
279
287
  tslib_1.__metadata("design:paramtypes", [Number, Object]),
280
288
  tslib_1.__metadata("design:returntype", void 0)
281
289
  ], BaseController.prototype, "resubmitApproval", null);
290
+ tslib_1.__decorate([
291
+ (0, common_1.Post)(':id/approval/submit'),
292
+ (0, response_message_decorator_1.Message)('submitted'),
293
+ (0, audit_log_decorator_1.Audit)({ action: 'SUBMIT' }),
294
+ (0, swagger_1.ApiResponse)({ description: 'The updated approval status' }),
295
+ tslib_1.__param(0, (0, common_1.Param)('id', common_1.ParseIntPipe)),
296
+ tslib_1.__param(1, (0, nest_auth_1.CurrentUser)()),
297
+ tslib_1.__metadata("design:type", Function),
298
+ tslib_1.__metadata("design:paramtypes", [Number, Object]),
299
+ tslib_1.__metadata("design:returntype", void 0)
300
+ ], BaseController.prototype, "submitApproval", null);
282
301
  tslib_1.__decorate([
283
302
  (0, common_1.Delete)(':id'),
284
303
  (0, response_message_decorator_1.Message)('deleted'),
@@ -1 +1 @@
1
- {"version":3,"file":"request-modification.dto.d.ts","sourceRoot":"","sources":["../../../src/lib/dtos/request-modification.dto.ts"],"names":[],"mappings":"AAWA,qBAAa,mBAAmB;IAG9B,KAAK,EAAG,MAAM,CAAC;IAOf,YAAY,CAAC,EAAE,OAAO,CAAC;IAIvB,WAAW,EAAG,OAAO,CAAC;IAKtB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,sBAAsB;IASjC,aAAa,EAAG,mBAAmB,EAAE,CAAC;IAQtC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf"}
1
+ {"version":3,"file":"request-modification.dto.d.ts","sourceRoot":"","sources":["../../../src/lib/dtos/request-modification.dto.ts"],"names":[],"mappings":"AAWA,qBAAa,mBAAmB;IAG9B,KAAK,EAAG,MAAM,CAAC;IAQf,YAAY,CAAC,EAAE,OAAO,CAAC;IAIvB,WAAW,EAAG,OAAO,CAAC;IAKtB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,sBAAsB;IASjC,aAAa,EAAG,mBAAmB,EAAE,CAAC;IAQtC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf"}
@@ -15,7 +15,7 @@ tslib_1.__decorate([
15
15
  ], ModificationItemDto.prototype, "field", void 0);
16
16
  tslib_1.__decorate([
17
17
  (0, swagger_1.ApiProperty)({
18
- description: 'Value currently stored on the record (captured at request time)',
18
+ description: 'Value currently stored on the record. Auto-filled from the live entity when omitted (supports relation objects).',
19
19
  required: false,
20
20
  }),
21
21
  (0, class_validator_1.IsOptional)(),
@@ -1,8 +1,8 @@
1
1
  import type { ModificationItem } from '../interfaces/approval-pipeline.interface';
2
2
  /**
3
- * Tracks the approval lifecycle of a created record. One row per approved-or-
4
- * pending entity, polymorphically referencing the target row via the table
5
- * name (`entity`) and its primary key (`entityId`).
3
+ * Tracks the approval lifecycle of a created record. One row per
4
+ * draft/submitted/approved entity, polymorphically referencing the target row
5
+ * via the table name (`entity`) and its primary key (`entityId`).
6
6
  */
7
7
  export declare class ApprovalStatusEntity {
8
8
  id: number;
@@ -10,7 +10,7 @@ export declare class ApprovalStatusEntity {
10
10
  entity: string;
11
11
  /** Stringified primary key of the target row (works for int and uuid). */
12
12
  entityId: string;
13
- /** pending | approved | rejected | modification_requested | resubmitted */
13
+ /** draft | submitted | approved | rejected | modification_requested | resubmitted */
14
14
  status: string;
15
15
  /** User who submitted the record for approval. */
16
16
  requestedBy?: string | null;
@@ -1 +1 @@
1
- {"version":3,"file":"approval-status.entity.d.ts","sourceRoot":"","sources":["../../../src/lib/entities/approval-status.entity.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2CAA2C,CAAC;AAElF;;;;GAIG;AACH,qBACa,oBAAoB;IAE/B,EAAE,EAAG,MAAM,CAAC;IAEZ,uCAAuC;IAGvC,MAAM,EAAG,MAAM,CAAC;IAEhB,0EAA0E;IAG1E,QAAQ,EAAG,MAAM,CAAC;IAElB,2EAA2E;IAG3E,MAAM,EAAG,MAAM,CAAC;IAEhB,kDAAkD;IAGlD,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAG5B,WAAW,EAAG,IAAI,CAAC;IAEnB,2EAA2E;IAE3E,oBAAoB,CAAC,EAAE,gBAAgB,EAAE,GAAG,IAAI,CAAC;IAEjD,gDAAgD;IAEhD,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAG1B,SAAS,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAExB,2DAA2D;IAE3D,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAG9B,aAAa,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAG5B,SAAS,EAAG,IAAI,CAAC;IAGjB,SAAS,EAAG,IAAI,CAAC;CAClB"}
1
+ {"version":3,"file":"approval-status.entity.d.ts","sourceRoot":"","sources":["../../../src/lib/entities/approval-status.entity.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2CAA2C,CAAC;AAElF;;;;GAIG;AACH,qBACa,oBAAoB;IAE/B,EAAE,EAAG,MAAM,CAAC;IAEZ,uCAAuC;IAGvC,MAAM,EAAG,MAAM,CAAC;IAEhB,0EAA0E;IAG1E,QAAQ,EAAG,MAAM,CAAC;IAElB,qFAAqF;IAGrF,MAAM,EAAG,MAAM,CAAC;IAEhB,kDAAkD;IAGlD,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAG5B,WAAW,EAAG,IAAI,CAAC;IAEnB,2EAA2E;IAE3E,oBAAoB,CAAC,EAAE,gBAAgB,EAAE,GAAG,IAAI,CAAC;IAEjD,gDAAgD;IAEhD,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAG1B,SAAS,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAExB,2DAA2D;IAE3D,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAG9B,aAAa,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAG5B,SAAS,EAAG,IAAI,CAAC;IAGjB,SAAS,EAAG,IAAI,CAAC;CAClB"}
@@ -4,9 +4,9 @@ exports.ApprovalStatusEntity = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const typeorm_1 = require("typeorm");
6
6
  /**
7
- * Tracks the approval lifecycle of a created record. One row per approved-or-
8
- * pending entity, polymorphically referencing the target row via the table
9
- * name (`entity`) and its primary key (`entityId`).
7
+ * Tracks the approval lifecycle of a created record. One row per
8
+ * draft/submitted/approved entity, polymorphically referencing the target row
9
+ * via the table name (`entity`) and its primary key (`entityId`).
10
10
  */
11
11
  let ApprovalStatusEntity = class ApprovalStatusEntity {
12
12
  };
@@ -27,7 +27,7 @@ tslib_1.__decorate([
27
27
  ], ApprovalStatusEntity.prototype, "entityId", void 0);
28
28
  tslib_1.__decorate([
29
29
  (0, typeorm_1.Index)(),
30
- (0, typeorm_1.Column)({ default: 'pending' }),
30
+ (0, typeorm_1.Column)({ default: 'draft' }),
31
31
  tslib_1.__metadata("design:type", String)
32
32
  ], ApprovalStatusEntity.prototype, "status", void 0);
33
33
  tslib_1.__decorate([
@@ -1 +1 @@
1
- {"version":3,"file":"exception-filter.helper.d.ts","sourceRoot":"","sources":["../../../src/lib/helpers/exception-filter.helper.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EAEb,eAAe,EAEhB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAU3C,qBACa,sBAAuB,YAAW,eAAe;IAC5D,KAAK,CAAC,SAAS,EAAE,gBAAgB,EAAE,IAAI,EAAE,aAAa,GAAG,IAAI;CA8B9D"}
1
+ {"version":3,"file":"exception-filter.helper.d.ts","sourceRoot":"","sources":["../../../src/lib/helpers/exception-filter.helper.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EAEb,eAAe,EAEhB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAU3C,qBACa,sBAAuB,YAAW,eAAe;IAC5D,KAAK,CAAC,SAAS,EAAE,gBAAgB,EAAE,IAAI,EAAE,aAAa,GAAG,IAAI;CAwB9D"}
@@ -14,13 +14,9 @@ let TypeOrmExceptionFilter = class TypeOrmExceptionFilter {
14
14
  let message = 'Internal server error';
15
15
  if (isUniqueViolation) {
16
16
  status = common_1.HttpStatus.UNPROCESSABLE_ENTITY;
17
- message = 'Duplicate entry: A record with this value already exists.';
18
- if (driverError.detail) {
19
- message = driverError.detail
20
- .replace('Key ', '')
21
- .replace(/[()]/g, '')
22
- .trim();
23
- }
17
+ // Generic message only the raw driverError.detail (column / constraint /
18
+ // values) is intentionally NOT leaked to the client.
19
+ message = 'A record with this value already exists';
24
20
  }
25
21
  response.status(status).json({
26
22
  status: 'error',
@@ -1,9 +1,13 @@
1
1
  import { NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
2
2
  import { Observable } from 'rxjs';
3
3
  import { Reflector } from '@nestjs/core';
4
+ import { I18nService, LangResolverService } from '@nest-util/nest-error';
4
5
  export declare class ResponseInterceptor implements NestInterceptor {
5
6
  private readonly reflector;
6
- constructor(reflector: Reflector);
7
+ private readonly i18n?;
8
+ private readonly langResolver?;
9
+ constructor(reflector: Reflector, i18n?: I18nService | undefined, langResolver?: LangResolverService | undefined);
7
10
  intercept(context: ExecutionContext, next: CallHandler): Observable<unknown>;
11
+ private localize;
8
12
  }
9
13
  //# sourceMappingURL=response.interceptor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"response.interceptor.d.ts","sourceRoot":"","sources":["../../../src/lib/interceptors/response.interceptor.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,eAAe,EACf,gBAAgB,EAChB,WAAW,EACZ,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAElC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAOzC,qBACa,mBAAoB,YAAW,eAAe;IAC7C,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAAT,SAAS,EAAE,SAAS;IAEjD,SAAS,CAAC,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,WAAW,GAAG,UAAU,CAAC,OAAO,CAAC;CA+B7E"}
1
+ {"version":3,"file":"response.interceptor.d.ts","sourceRoot":"","sources":["../../../src/lib/interceptors/response.interceptor.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,eAAe,EACf,gBAAgB,EAChB,WAAW,EAEZ,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAElC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAOzC,OAAO,EACL,WAAW,EACX,mBAAmB,EAEpB,MAAM,uBAAuB,CAAC;AAE/B,qBACa,mBAAoB,YAAW,eAAe;IAEvD,OAAO,CAAC,QAAQ,CAAC,SAAS;IACd,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC;IACtB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC;gBAFzB,SAAS,EAAE,SAAS,EACR,IAAI,CAAC,EAAE,WAAW,YAAA,EAClB,YAAY,CAAC,EAAE,mBAAmB,YAAA;IAGjE,SAAS,CAAC,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,WAAW,GAAG,UAAU,CAAC,OAAO,CAAC;IA8B5E,OAAO,CAAC,QAAQ;CAwBjB"}
@@ -6,9 +6,12 @@ const common_1 = require("@nestjs/common");
6
6
  const operators_1 = require("rxjs/operators");
7
7
  const core_1 = require("@nestjs/core");
8
8
  const response_message_decorator_1 = require("../decorators/response-message.decorator");
9
+ const nest_error_1 = require("@nest-util/nest-error");
9
10
  let ResponseInterceptor = class ResponseInterceptor {
10
- constructor(reflector) {
11
+ constructor(reflector, i18n, langResolver) {
11
12
  this.reflector = reflector;
13
+ this.i18n = i18n;
14
+ this.langResolver = langResolver;
12
15
  }
13
16
  intercept(context, next) {
14
17
  const handler = context.getHandler();
@@ -20,9 +23,7 @@ let ResponseInterceptor = class ResponseInterceptor {
20
23
  const name = isList
21
24
  ? entityConfig?.plural ?? 'Resources'
22
25
  : entityConfig?.singular ?? 'Resource';
23
- const finalMessage = action
24
- ? `${name} ${action} successfully`
25
- : 'Request successful';
26
+ const finalMessage = this.localize(name, action, context);
26
27
  return {
27
28
  message: finalMessage,
28
29
  data: data?.data ?? data ?? null,
@@ -31,9 +32,24 @@ let ResponseInterceptor = class ResponseInterceptor {
31
32
  };
32
33
  }));
33
34
  }
35
+ localize(name, action, context) {
36
+ if (!this.i18n || !this.langResolver) {
37
+ return action ? `${name} ${action} successfully` : 'Request successful';
38
+ }
39
+ const request = context.switchToHttp().getRequest();
40
+ const lang = this.langResolver.resolve(request ?? { headers: {} });
41
+ const localizedAction = action
42
+ ? this.i18n.translate(action, {}, lang)
43
+ : this.i18n.translate(nest_error_1.ErrorKey.MSG_REQUEST_SUCCESS, {}, lang);
44
+ return this.i18n.translate(nest_error_1.ErrorKey.SUCCESS_FORMAT, { entity: name, action: localizedAction }, lang);
45
+ }
34
46
  };
35
47
  exports.ResponseInterceptor = ResponseInterceptor;
36
48
  exports.ResponseInterceptor = ResponseInterceptor = tslib_1.__decorate([
37
49
  (0, common_1.Injectable)(),
38
- tslib_1.__metadata("design:paramtypes", [core_1.Reflector])
50
+ tslib_1.__param(1, (0, common_1.Optional)()),
51
+ tslib_1.__param(2, (0, common_1.Optional)()),
52
+ tslib_1.__metadata("design:paramtypes", [core_1.Reflector,
53
+ nest_error_1.I18nService,
54
+ nest_error_1.LangResolverService])
39
55
  ], ResponseInterceptor);
@@ -1,15 +1,16 @@
1
1
  /**
2
2
  * Lifecycle of an approval status row.
3
3
  *
4
- * pending ──────────> approved
5
- * │ └───────────> rejected
6
- * └─> modification_requested ──> resubmitted ──> approved / rejected
4
+ * draft ──> submitted ────────> approved
5
+ * │ └────────────> rejected
6
+ * └─> modification_requested ──> resubmitted ──> approved / rejected
7
7
  * │ │
8
8
  * └────────────────────────────────────┘
9
9
  * (modifications may be requested again)
10
10
  */
11
11
  export declare const APPROVAL_STATUS: {
12
- readonly pending: "pending";
12
+ readonly draft: "draft";
13
+ readonly submitted: "submitted";
13
14
  readonly approved: "approved";
14
15
  readonly rejected: "rejected";
15
16
  readonly modificationRequested: "modification_requested";
@@ -17,13 +18,17 @@ export declare const APPROVAL_STATUS: {
17
18
  };
18
19
  export type ApprovalStatus = (typeof APPROVAL_STATUS)[keyof typeof APPROVAL_STATUS];
19
20
  /**
20
- * A single requested modification on a pending record. Each item names the
21
+ * A single requested modification on a record under review. Each item names the
21
22
  * field to change and the value the reviewer wants instead.
22
23
  */
23
24
  export interface ModificationItem {
24
- /** Entity field to modify, e.g. 'title'. */
25
+ /** Entity field to modify, e.g. 'title' or 'category' (a relation). */
25
26
  field: string;
26
- /** Value currently stored on the record (captured at request time). */
27
+ /**
28
+ * Value currently stored on the record. Auto-captured from the live entity
29
+ * when omitted (supports relation objects; circular refs are sanitized to
30
+ * '[Circular]').
31
+ */
27
32
  currentValue?: unknown;
28
33
  /** Value the reviewer wants instead. */
29
34
  wantedValue: unknown;
@@ -54,22 +59,34 @@ export interface ApprovalHistoryView {
54
59
  note?: string | null;
55
60
  }
56
61
  export interface ApprovalPipelinePermissions {
57
- /** Required permission to approve (pending/resubmitted -> approved). */
62
+ /** Required permission to approve (submitted/resubmitted -> approved). */
58
63
  approve?: string;
59
- /** Required permission to reject (pending/resubmitted -> rejected). */
64
+ /** Required permission to reject (submitted/resubmitted -> rejected). */
60
65
  reject?: string;
61
66
  /** Required permission to request modifications. */
62
67
  requestModification?: string;
63
68
  /** Required permission to resubmit after modifications. */
64
69
  resubmit?: string;
70
+ /** Required permission to submit a draft for approval. */
71
+ submit?: string;
65
72
  }
66
73
  export interface ApprovalPipelineConfig {
67
74
  /**
68
- * When true, every created record also gets a pending approval status row
75
+ * When true, every created record also gets a draft approval status row
69
76
  * (created in the same transaction). Defaults to true when the option is
70
77
  * provided.
71
78
  */
72
79
  enabled?: boolean;
80
+ /**
81
+ * Initial status assigned to a record's approval row on create.
82
+ * - 'draft' (default): the record waits in draft until `submitApproval`
83
+ * is called; the `submit` permission applies and `requestedBy` is filled
84
+ * on submit.
85
+ * - 'submitted': the record is created already in the reviewable state
86
+ * (the creating user becomes the requester), so no explicit submit step
87
+ * is needed.
88
+ */
89
+ initialStatus?: 'draft' | 'submitted';
73
90
  /**
74
91
  * Optional permission strings required to perform each action. When unset,
75
92
  * the action is allowed for any authenticated (or anonymous) caller.
@@ -1 +1 @@
1
- {"version":3,"file":"approval-pipeline.interface.d.ts","sourceRoot":"","sources":["../../../src/lib/interfaces/approval-pipeline.interface.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe;;;;;;CAMlB,CAAC;AAEX,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,OAAO,eAAe,CAAC,CAAC;AAEpF;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,uEAAuE;IACvE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,wCAAwC;IACxC,WAAW,EAAE,OAAO,CAAC;IACrB,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,cAAc,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,IAAI,CAAC;IAClB,oBAAoB,CAAC,EAAE,gBAAgB,EAAE,GAAG,IAAI,CAAC;IACjD,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,aAAa,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,gBAAgB,EAAE,CAAC;IAClC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,IAAI,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,2BAA2B;IAC1C,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uEAAuE;IACvE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oDAAoD;IACpD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,sBAAsB;IACrC;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;OAGG;IACH,WAAW,CAAC,EAAE,2BAA2B,CAAC;IAE1C;;;;;OAKG;IACH,eAAe,CAAC,EAAE,SAAS,cAAc,EAAE,CAAC;CAC7C;AAED,MAAM,WAAW,0BAA0B;IACzC,aAAa,EAAE,gBAAgB,EAAE,CAAC;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf"}
1
+ {"version":3,"file":"approval-pipeline.interface.d.ts","sourceRoot":"","sources":["../../../src/lib/interfaces/approval-pipeline.interface.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe;;;;;;;CAOlB,CAAC;AAEX,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,OAAO,eAAe,CAAC,CAAC;AAEpF;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,uEAAuE;IACvE,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,wCAAwC;IACxC,WAAW,EAAE,OAAO,CAAC;IACrB,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,cAAc,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,IAAI,CAAC;IAClB,oBAAoB,CAAC,EAAE,gBAAgB,EAAE,GAAG,IAAI,CAAC;IACjD,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,aAAa,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,gBAAgB,EAAE,CAAC;IAClC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,IAAI,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,2BAA2B;IAC1C,0EAA0E;IAC1E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yEAAyE;IACzE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oDAAoD;IACpD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,sBAAsB;IACrC;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;;;;;;OAQG;IACH,aAAa,CAAC,EAAE,OAAO,GAAG,WAAW,CAAC;IAEtC;;;OAGG;IACH,WAAW,CAAC,EAAE,2BAA2B,CAAC;IAE1C;;;;;OAKG;IACH,eAAe,CAAC,EAAE,SAAS,cAAc,EAAE,CAAC;CAC7C;AAED,MAAM,WAAW,0BAA0B;IACzC,aAAa,EAAE,gBAAgB,EAAE,CAAC;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf"}
@@ -4,15 +4,16 @@ exports.APPROVAL_STATUS = void 0;
4
4
  /**
5
5
  * Lifecycle of an approval status row.
6
6
  *
7
- * pending ──────────> approved
8
- * │ └───────────> rejected
9
- * └─> modification_requested ──> resubmitted ──> approved / rejected
7
+ * draft ──> submitted ────────> approved
8
+ * │ └────────────> rejected
9
+ * └─> modification_requested ──> resubmitted ──> approved / rejected
10
10
  * │ │
11
11
  * └────────────────────────────────────┘
12
12
  * (modifications may be requested again)
13
13
  */
14
14
  exports.APPROVAL_STATUS = {
15
- pending: 'pending',
15
+ draft: 'draft',
16
+ submitted: 'submitted',
16
17
  approved: 'approved',
17
18
  rejected: 'rejected',
18
19
  modificationRequested: 'modification_requested',
@@ -4,7 +4,7 @@ import { CursorPaginationDto } from '../dtos/cursor-pagination.dto';
4
4
  import { OwnershipUser } from './find-mine.interface';
5
5
  import { StatusValue } from './status-pipeline.interface';
6
6
  import { ApprovalHistoryView, ApprovalStatusView, RequestModificationPayload } from './approval-pipeline.interface';
7
- export type CrudEndpoint = 'findAll' | 'findOne' | 'create' | 'update' | 'changeStatus' | 'remove' | 'findAuditLogs' | 'findMine' | 'getApproval' | 'approveApproval' | 'rejectApproval' | 'requestModification' | 'resubmitApproval';
7
+ export type CrudEndpoint = 'findAll' | 'findOne' | 'create' | 'update' | 'changeStatus' | 'remove' | 'findAuditLogs' | 'findMine' | 'getApproval' | 'approveApproval' | 'rejectApproval' | 'requestModification' | 'resubmitApproval' | 'submitApproval';
8
8
  export interface AuditLogQuery {
9
9
  user_id?: string;
10
10
  start_date?: string;
@@ -46,5 +46,6 @@ export interface CrudInterface<CreateDto, UpdateDto, ResponseDto> {
46
46
  rejectApproval?(id: number, user?: OwnershipUser): Promise<ApprovalStatusView>;
47
47
  requestModification?(id: number, dto: RequestModificationPayload, user?: OwnershipUser): Promise<ApprovalStatusView>;
48
48
  resubmitApproval?(id: number, user?: OwnershipUser): Promise<ApprovalStatusView>;
49
+ submitApproval?(id: number, user?: OwnershipUser): Promise<ApprovalStatusView>;
49
50
  }
50
51
  //# sourceMappingURL=crud.interface.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"crud.interface.d.ts","sourceRoot":"","sources":["../../../src/lib/interfaces/crud.interface.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"crud.interface.d.ts","sourceRoot":"","sources":["../../../src/lib/interfaces/crud.interface.ts"],"names":[],"mappings":"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"}
@@ -110,12 +110,26 @@ export declare class NestCrudService<Entity extends ObjectLiteral, CreateDto = P
110
110
  rejectApproval(id: number, user?: OwnershipUser): Promise<ApprovalStatusView>;
111
111
  requestModification(id: number, payload: RequestModificationPayload, user?: OwnershipUser): Promise<ApprovalStatusView>;
112
112
  resubmitApproval(id: number, user?: OwnershipUser): Promise<ApprovalStatusView>;
113
+ submitApproval(id: number, user?: OwnershipUser): Promise<ApprovalStatusView>;
113
114
  private isApprovalPipelineConfigured;
114
115
  private hasApprovalVisibilityFilter;
115
116
  private getApprovalRepository;
116
117
  private getHistoryRepository;
117
118
  private createWithApproval;
118
119
  private resolveEntityForApproval;
120
+ /**
121
+ * Loads the target entity with its configured `include` relations so that
122
+ * relation fields can be read as objects when capturing modification values.
123
+ */
124
+ private getEntityWithRelations;
125
+ /** Reads a (possibly nested, dot-path) field from an entity. */
126
+ private readCurrentValue;
127
+ /**
128
+ * Deep-clones a value so it can be safely stored in a jsonb column. Object
129
+ * graphs with circular references (common for loaded relations) are
130
+ * sanitized: a circular branch is replaced with the string '[Circular]'.
131
+ */
132
+ private sanitizeForJsonb;
119
133
  private loadApprovalStatus;
120
134
  private transitionApproval;
121
135
  private assertTransitionAllowed;
@@ -1 +1 @@
1
- {"version":3,"file":"nest-crud.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/nest-crud.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"nest-crud.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/nest-crud.service.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.NestCrudService = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const common_1 = require("@nestjs/common");
6
+ const nest_error_1 = require("@nest-util/nest-error");
6
7
  const audit_log_entity_1 = require("../entities/audit-log.entity");
7
8
  const filter_helper_1 = require("../helpers/filter.helper");
8
9
  const pagination_helper_1 = require("../helpers/pagination.helper");
@@ -91,7 +92,7 @@ let NestCrudService = class NestCrudService {
91
92
  id,
92
93
  });
93
94
  if (!entity) {
94
- throw new common_1.NotFoundException(`${String(relation.property)} not found`);
95
+ throw (0, nest_error_1.keyed)(common_1.HttpStatus.NOT_FOUND, nest_error_1.ErrorKey.CRUD_RELATION_NOT_FOUND, { property: String(relation.property) });
95
96
  }
96
97
  payload[String(relation.property)] = entity;
97
98
  delete payload[idField];
@@ -238,7 +239,7 @@ let NestCrudService = class NestCrudService {
238
239
  async findOwnedEntity(id, user) {
239
240
  const userId = user?.id;
240
241
  if (userId === undefined || userId === null) {
241
- throw new common_1.ForbiddenException('Authentication required to access this resource');
242
+ throw (0, nest_error_1.keyed)(common_1.HttpStatus.FORBIDDEN, nest_error_1.ErrorKey.AUTH_UNAUTHORIZED);
242
243
  }
243
244
  const qb = this.repo.createQueryBuilder('e');
244
245
  this.applyOwnershipCondition(qb, userId);
@@ -264,9 +265,7 @@ let NestCrudService = class NestCrudService {
264
265
  }
265
266
  if (this.statusCreateAllow.length > 0 &&
266
267
  !this.statusCreateAllow.includes(requested)) {
267
- throw new common_1.BadRequestException(`Invalid initial status '${String(requested)}'. Allowed: ${this.statusCreateAllow
268
- .map(String)
269
- .join(', ') || 'none'}`);
268
+ throw (0, nest_error_1.keyed)(common_1.HttpStatus.BAD_REQUEST, nest_error_1.ErrorKey.CRUD_INVALID_STATUS, { requested: String(requested) });
270
269
  }
271
270
  }
272
271
  validateStatusTransition(existing, payload, user) {
@@ -285,13 +284,13 @@ let NestCrudService = class NestCrudService {
285
284
  }
286
285
  const entry = this.statusTransitions.get(current);
287
286
  if (!entry) {
288
- throw new common_1.BadRequestException(`Invalid status transition: '${String(current)}' -> '${String(requestedValue)}'. Status '${String(current)}' has no allowed transitions`);
287
+ throw (0, nest_error_1.keyed)(common_1.HttpStatus.BAD_REQUEST, nest_error_1.ErrorKey.CRUD_STATUS_TRANSITION_INVALID, { from: String(current), to: String(requestedValue) });
289
288
  }
290
289
  if (!entry.to.has(requestedValue)) {
291
- throw new common_1.BadRequestException(`Invalid status transition: '${String(current)}' -> '${String(requestedValue)}'. Allowed: ${[...entry.to].map(String).join(', ')}`);
290
+ throw (0, nest_error_1.keyed)(common_1.HttpStatus.BAD_REQUEST, nest_error_1.ErrorKey.CRUD_STATUS_TRANSITION_INVALID, { from: String(current), to: String(requestedValue) });
292
291
  }
293
292
  if (entry.permission && !this.canBypassOwnershipForTransition(user, entry.permission)) {
294
- throw new common_1.ForbiddenException(`Missing required permission '${entry.permission}' for status transition`);
293
+ throw (0, nest_error_1.keyed)(common_1.HttpStatus.FORBIDDEN, nest_error_1.ErrorKey.CRUD_STATUS_TRANSITION_FORBIDDEN, { permission: entry.permission });
295
294
  }
296
295
  return {
297
296
  from: current,
@@ -336,7 +335,7 @@ let NestCrudService = class NestCrudService {
336
335
  }
337
336
  async findMine(userId, query) {
338
337
  if (!this.userOwnershipField && !this.findMineQuery) {
339
- throw new common_1.BadRequestException('findMine not configured');
338
+ throw (0, nest_error_1.keyed)(common_1.HttpStatus.BAD_REQUEST, nest_error_1.ErrorKey.CRUD_FIND_MINE_NOT_CONFIGURED);
340
339
  }
341
340
  const qb = this.repo.createQueryBuilder('e');
342
341
  this.applyOwnershipCondition(qb, userId);
@@ -423,7 +422,7 @@ let NestCrudService = class NestCrudService {
423
422
  });
424
423
  }
425
424
  if (!entity) {
426
- throw new common_1.NotFoundException('Resource not found');
425
+ throw (0, nest_error_1.keyed)(common_1.HttpStatus.NOT_FOUND, nest_error_1.ErrorKey.CRUD_RESOURCE_NOT_FOUND);
427
426
  }
428
427
  const result = this.toResponseDto
429
428
  ? this.toResponseDto(entity)
@@ -436,7 +435,7 @@ let NestCrudService = class NestCrudService {
436
435
  this.userOwnershipField &&
437
436
  !this.canBypassOwnership(user)) {
438
437
  if (!user || user.id === undefined || user.id === null) {
439
- throw new common_1.ForbiddenException('Authentication required to access this resource');
438
+ throw (0, nest_error_1.keyed)(common_1.HttpStatus.FORBIDDEN, nest_error_1.ErrorKey.AUTH_UNAUTHORIZED);
440
439
  }
441
440
  const field = String(this.userOwnershipField);
442
441
  const matchingRelation = this.relations.find((r) => String(r.property) === field);
@@ -448,7 +447,7 @@ let NestCrudService = class NestCrudService {
448
447
  if (payloadValue !== undefined && payloadValue !== null) {
449
448
  // Value present — must match the authenticated user
450
449
  if (String(payloadValue) !== String(user.id)) {
451
- throw new common_1.NotFoundException('Resource not found');
450
+ throw (0, nest_error_1.keyed)(common_1.HttpStatus.NOT_FOUND, nest_error_1.ErrorKey.CRUD_RESOURCE_NOT_FOUND);
452
451
  }
453
452
  }
454
453
  else {
@@ -477,18 +476,18 @@ let NestCrudService = class NestCrudService {
477
476
  }
478
477
  async changeStatus(id, status, user) {
479
478
  if (!this.isStatusPipelineConfigured()) {
480
- throw new common_1.NotFoundException('Resource not found');
479
+ throw (0, nest_error_1.keyed)(common_1.HttpStatus.NOT_FOUND, nest_error_1.ErrorKey.CRUD_STATUS_NOT_CONFIGURED);
481
480
  }
482
481
  const payload = { [String(this.statusField)]: status };
483
482
  return this.applyUpdateCore(id, payload, user);
484
483
  }
485
484
  async getApproval(id, user) {
486
485
  if (!this.isApprovalPipelineConfigured()) {
487
- throw new common_1.NotFoundException('Resource not found');
486
+ throw (0, nest_error_1.keyed)(common_1.HttpStatus.NOT_FOUND, nest_error_1.ErrorKey.CRUD_APPROVAL_NOT_CONFIGURED);
488
487
  }
489
488
  const approval = await this.loadApprovalStatus(id, user);
490
489
  if (!approval) {
491
- throw new common_1.NotFoundException('Resource not found');
490
+ throw (0, nest_error_1.keyed)(common_1.HttpStatus.NOT_FOUND, nest_error_1.ErrorKey.CRUD_RESOURCE_NOT_FOUND);
492
491
  }
493
492
  const history = await this.getHistoryRepository().find({
494
493
  where: { approvalStatusId: approval.id },
@@ -511,6 +510,9 @@ let NestCrudService = class NestCrudService {
511
510
  async resubmitApproval(id, user) {
512
511
  return this.transitionApproval(id, 'resubmit', user);
513
512
  }
513
+ async submitApproval(id, user) {
514
+ return this.transitionApproval(id, 'submit', user);
515
+ }
514
516
  isApprovalPipelineConfigured() {
515
517
  return Boolean(this.approvalPipeline && this.approvalPipeline.enabled !== false);
516
518
  }
@@ -532,11 +534,14 @@ let NestCrudService = class NestCrudService {
532
534
  const entityRepo = manager.getRepository(this.repo.target);
533
535
  const saved = await entityRepo.save(resolved);
534
536
  const approvalRepo = manager.getRepository(approval_status_entity_1.ApprovalStatusEntity);
537
+ const initialStatus = this.approvalPipeline?.initialStatus ?? approval_pipeline_interface_1.APPROVAL_STATUS.draft;
535
538
  const approval = approvalRepo.create({
536
539
  entity: this.repo.metadata.tableName,
537
540
  entityId: String(saved.id),
538
- status: approval_pipeline_interface_1.APPROVAL_STATUS.pending,
539
- requestedBy: user?.id != null ? String(user.id) : null,
541
+ status: initialStatus,
542
+ ...(initialStatus === approval_pipeline_interface_1.APPROVAL_STATUS.submitted
543
+ ? { requestedBy: user?.id != null ? String(user.id) : null }
544
+ : {}),
540
545
  });
541
546
  await approvalRepo.save(approval);
542
547
  return saved;
@@ -549,6 +554,63 @@ let NestCrudService = class NestCrudService {
549
554
  }
550
555
  return this.repo.findOneBy({ id });
551
556
  }
557
+ /**
558
+ * Loads the target entity with its configured `include` relations so that
559
+ * relation fields can be read as objects when capturing modification values.
560
+ */
561
+ async getEntityWithRelations(id, user) {
562
+ if (this.enforceOwnershipFor(user)) {
563
+ return this.findOwnedEntity(id, user);
564
+ }
565
+ const relations = this.include.length
566
+ ? this.buildRelationsObject(this.include)
567
+ : undefined;
568
+ return this.repo.findOne({
569
+ where: { id },
570
+ relations: relations,
571
+ });
572
+ }
573
+ /** Reads a (possibly nested, dot-path) field from an entity. */
574
+ readCurrentValue(entity, field) {
575
+ if (!entity || !field) {
576
+ return undefined;
577
+ }
578
+ const parts = field.split('.');
579
+ let current = entity;
580
+ for (const part of parts) {
581
+ if (current == null) {
582
+ return undefined;
583
+ }
584
+ current = current[part];
585
+ }
586
+ return current;
587
+ }
588
+ /**
589
+ * Deep-clones a value so it can be safely stored in a jsonb column. Object
590
+ * graphs with circular references (common for loaded relations) are
591
+ * sanitized: a circular branch is replaced with the string '[Circular]'.
592
+ */
593
+ sanitizeForJsonb(value) {
594
+ const seen = new WeakSet();
595
+ const walk = (node) => {
596
+ if (node === null || typeof node !== 'object') {
597
+ return node;
598
+ }
599
+ if (seen.has(node)) {
600
+ return '[Circular]';
601
+ }
602
+ seen.add(node);
603
+ if (Array.isArray(node)) {
604
+ return node.map((item) => walk(item));
605
+ }
606
+ const out = {};
607
+ for (const key of Object.keys(node)) {
608
+ out[key] = walk(node[key]);
609
+ }
610
+ return out;
611
+ };
612
+ return walk(value);
613
+ }
552
614
  async loadApprovalStatus(id, user) {
553
615
  const entity = await this.resolveEntityForApproval(id, user);
554
616
  if (!entity) {
@@ -562,52 +624,71 @@ let NestCrudService = class NestCrudService {
562
624
  }
563
625
  async transitionApproval(id, action, user, modifications, note) {
564
626
  if (!this.isApprovalPipelineConfigured()) {
565
- throw new common_1.NotFoundException('Resource not found');
627
+ throw (0, nest_error_1.keyed)(common_1.HttpStatus.NOT_FOUND, nest_error_1.ErrorKey.CRUD_APPROVAL_NOT_CONFIGURED);
566
628
  }
567
629
  const permission = this.approvalPipeline?.permissions?.[action];
568
630
  if (permission && !this.userHasPermission(user, permission)) {
569
- throw new common_1.ForbiddenException(`Missing required permission '${permission}' for ${action}`);
631
+ throw (0, nest_error_1.keyed)(common_1.HttpStatus.FORBIDDEN, nest_error_1.ErrorKey.CRUD_APPROVAL_FORBIDDEN, { permission, action });
570
632
  }
571
633
  const approval = await this.loadApprovalStatus(id, user);
572
634
  if (!approval) {
573
- throw new common_1.NotFoundException('Resource not found');
635
+ throw (0, nest_error_1.keyed)(common_1.HttpStatus.NOT_FOUND, nest_error_1.ErrorKey.CRUD_RESOURCE_NOT_FOUND);
574
636
  }
575
637
  const current = approval.status;
576
638
  const now = new Date();
577
639
  const userId = user?.id != null ? String(user.id) : null;
578
- const transitionable = [
579
- approval_pipeline_interface_1.APPROVAL_STATUS.pending,
640
+ const reviewable = [
641
+ approval_pipeline_interface_1.APPROVAL_STATUS.submitted,
580
642
  approval_pipeline_interface_1.APPROVAL_STATUS.resubmitted,
581
643
  ];
582
644
  switch (action) {
645
+ case 'submit':
646
+ // Already in a reviewable/terminal state (e.g. the pipeline was
647
+ // configured with initialStatus: 'submitted'): no submit transition is
648
+ // needed, so this is a harmless no-op returning the current status.
649
+ if (current !== approval_pipeline_interface_1.APPROVAL_STATUS.draft) {
650
+ return this.toApprovalStatusView(approval);
651
+ }
652
+ approval.status = approval_pipeline_interface_1.APPROVAL_STATUS.submitted;
653
+ approval.requestedBy = userId;
654
+ break;
583
655
  case 'approve':
584
- this.assertTransitionAllowed(action, current, transitionable);
656
+ this.assertTransitionAllowed(action, current, reviewable);
585
657
  approval.status = approval_pipeline_interface_1.APPROVAL_STATUS.approved;
586
658
  approval.decidedBy = userId;
587
659
  approval.decidedAt = now;
588
660
  approval.currentModifications = null;
589
661
  break;
590
662
  case 'reject':
591
- this.assertTransitionAllowed(action, current, transitionable);
663
+ this.assertTransitionAllowed(action, current, reviewable);
592
664
  approval.status = approval_pipeline_interface_1.APPROVAL_STATUS.rejected;
593
665
  approval.decidedBy = userId;
594
666
  approval.decidedAt = now;
595
667
  approval.currentModifications = null;
596
668
  break;
597
- case 'requestModification':
598
- this.assertTransitionAllowed(action, current, transitionable);
669
+ case 'requestModification': {
670
+ this.assertTransitionAllowed(action, current, reviewable);
599
671
  approval.status = approval_pipeline_interface_1.APPROVAL_STATUS.modificationRequested;
600
- approval.currentModifications = modifications ?? [];
672
+ const entity = await this.getEntityWithRelations(id, user);
673
+ const capturedModifications = (modifications ?? []).map((m) => ({
674
+ ...m,
675
+ currentValue: this.sanitizeForJsonb(m.currentValue !== undefined
676
+ ? m.currentValue
677
+ : this.readCurrentValue(entity, m.field)),
678
+ wantedValue: this.sanitizeForJsonb(m.wantedValue),
679
+ }));
680
+ approval.currentModifications = capturedModifications;
601
681
  await this.getHistoryRepository().save(this.getHistoryRepository().create({
602
682
  approvalStatusId: approval.id,
603
- modifications: modifications ?? [],
683
+ modifications: capturedModifications,
604
684
  requestedBy: userId,
605
685
  note: note ?? null,
606
686
  }));
607
687
  break;
688
+ }
608
689
  case 'resubmit':
609
690
  if (current !== approval_pipeline_interface_1.APPROVAL_STATUS.modificationRequested) {
610
- throw new common_1.BadRequestException(`Cannot resubmit approval from status '${current}'`);
691
+ throw (0, nest_error_1.keyed)(common_1.HttpStatus.BAD_REQUEST, nest_error_1.ErrorKey.CRUD_APPROVAL_INVALID_TRANSITION, { action: 'resubmit', current: String(current) });
611
692
  }
612
693
  approval.status = approval_pipeline_interface_1.APPROVAL_STATUS.resubmitted;
613
694
  approval.currentModifications = null;
@@ -620,7 +701,7 @@ let NestCrudService = class NestCrudService {
620
701
  }
621
702
  assertTransitionAllowed(action, current, allowedFrom) {
622
703
  if (!allowedFrom.includes(current)) {
623
- throw new common_1.BadRequestException(`Cannot ${action} approval from status '${current}'`);
704
+ throw (0, nest_error_1.keyed)(common_1.HttpStatus.BAD_REQUEST, nest_error_1.ErrorKey.CRUD_APPROVAL_INVALID_TRANSITION, { action, current: String(current) });
624
705
  }
625
706
  }
626
707
  userHasPermission(user, permission) {
@@ -689,7 +770,7 @@ let NestCrudService = class NestCrudService {
689
770
  });
690
771
  }
691
772
  if (!existing) {
692
- throw new common_1.NotFoundException('Resource not found');
773
+ throw (0, nest_error_1.keyed)(common_1.HttpStatus.NOT_FOUND, nest_error_1.ErrorKey.CRUD_RESOURCE_NOT_FOUND);
693
774
  }
694
775
  await this.executeHook(this.hooks.beforeUpdate, { payload, entity: existing, id });
695
776
  const transition = this.validateStatusTransition(existing, payload, user);
@@ -715,7 +796,7 @@ let NestCrudService = class NestCrudService {
715
796
  });
716
797
  }
717
798
  if (!existing) {
718
- throw new common_1.NotFoundException('Resource not found');
799
+ throw (0, nest_error_1.keyed)(common_1.HttpStatus.NOT_FOUND, nest_error_1.ErrorKey.CRUD_RESOURCE_NOT_FOUND);
719
800
  }
720
801
  await this.executeHook(this.hooks.beforeRemove, { entity: existing, id });
721
802
  const result = await this.repo.delete(id);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nest-util/nest-crud",
3
- "version": "1.2.2",
3
+ "version": "2.0.1",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -28,10 +28,12 @@
28
28
  "tslib": "^2.8.1"
29
29
  },
30
30
  "devDependencies": {
31
- "@nest-util/nest-auth": "workspace:*"
31
+ "@nest-util/nest-auth": "workspace:*",
32
+ "@nest-util/nest-error": "workspace:*"
32
33
  },
33
34
  "peerDependencies": {
34
35
  "@nest-util/nest-auth": "workspace:*",
36
+ "@nest-util/nest-error": "workspace:*",
35
37
  "@nestjs/common": "^11.0.0",
36
38
  "@nestjs/core": "^11.0.0",
37
39
  "@nestjs/event-emitter": "^3.0.0",