@nest-util/nest-crud 2.0.1 → 2.0.3

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.
@@ -0,0 +1,19 @@
1
+ import type { EntityMetadata } from 'typeorm';
2
+ /**
3
+ * Expands modification-field dot paths into every relation prefix required to
4
+ * load the referenced values, so relation fields (e.g. `addresses` or
5
+ * `company.addresses.city`) can be read without the consumer configuring
6
+ * `include`.
7
+ *
8
+ * Non-relation columns yield nothing. Unknown paths are ignored.
9
+ */
10
+ export declare function resolveRelationPaths(metadata: EntityMetadata, fields: readonly string[]): string[];
11
+ /** Checks whether a (root) property name exists on the entity as a column,
12
+ * embedded column, or relation. */
13
+ export declare function isKnownProperty(metadata: EntityMetadata, propertyName: string): boolean;
14
+ /**
15
+ * Normalizes a captured modification value so it is always jsonb-serializable
16
+ * and distinguishable from "not loaded": `undefined` becomes explicit `null`.
17
+ */
18
+ export declare function normalizeCapturedValue(value: unknown): unknown;
19
+ //# sourceMappingURL=relation-path.helper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relation-path.helper.d.ts","sourceRoot":"","sources":["../../../src/lib/helpers/relation-path.helper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,cAAc,EACxB,MAAM,EAAE,SAAS,MAAM,EAAE,GACxB,MAAM,EAAE,CAyBV;AAED;mCACmC;AACnC,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,cAAc,EACxB,YAAY,EAAE,MAAM,GACnB,OAAO,CAST;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE9D"}
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveRelationPaths = resolveRelationPaths;
4
+ exports.isKnownProperty = isKnownProperty;
5
+ exports.normalizeCapturedValue = normalizeCapturedValue;
6
+ /**
7
+ * Expands modification-field dot paths into every relation prefix required to
8
+ * load the referenced values, so relation fields (e.g. `addresses` or
9
+ * `company.addresses.city`) can be read without the consumer configuring
10
+ * `include`.
11
+ *
12
+ * Non-relation columns yield nothing. Unknown paths are ignored.
13
+ */
14
+ function resolveRelationPaths(metadata, fields) {
15
+ const resolved = new Set();
16
+ for (const field of fields) {
17
+ if (!field) {
18
+ continue;
19
+ }
20
+ const segments = field.split('.');
21
+ let relations = metadata.relations ?? [];
22
+ let prefix = [];
23
+ for (const segment of segments) {
24
+ const match = relations.find((relation) => relation.propertyName === segment);
25
+ if (!match) {
26
+ break;
27
+ }
28
+ prefix = [...prefix, match.propertyName];
29
+ resolved.add(prefix.join('.'));
30
+ relations = match.inverseEntityMetadata.relations;
31
+ }
32
+ }
33
+ return [...resolved];
34
+ }
35
+ /** Checks whether a (root) property name exists on the entity as a column,
36
+ * embedded column, or relation. */
37
+ function isKnownProperty(metadata, propertyName) {
38
+ return ((metadata.columns ?? []).some((column) => column.propertyPath === propertyName ||
39
+ column.propertyPath.startsWith(`${propertyName}.`)) ||
40
+ (metadata.relations ?? []).some((relation) => relation.propertyName === propertyName));
41
+ }
42
+ /**
43
+ * Normalizes a captured modification value so it is always jsonb-serializable
44
+ * and distinguishable from "not loaded": `undefined` becomes explicit `null`.
45
+ */
46
+ function normalizeCapturedValue(value) {
47
+ return value === undefined ? null : value;
48
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Produces a deterministic, stable serialization of an arbitrary value so it
3
+ * can be hashed consistently across processes and after jsonb round-trips:
4
+ * - object keys are sorted recursively
5
+ * - Date instances become ISO strings
6
+ * - undefined / null / missing all normalize to null
7
+ * - arrays keep their order
8
+ * - circular references become the string '[Circular]'
9
+ */
10
+ export declare function canonicalJson(value: unknown): string;
11
+ /** SHA-256 hex hash of a value's canonical JSON form. */
12
+ export declare function hashValue(value: unknown): string;
13
+ /** Structural equality used as legacy fallback when no hash is stored. */
14
+ export declare function deepEqual(a: unknown, b: unknown): boolean;
15
+ //# sourceMappingURL=value-hash.helper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"value-hash.helper.d.ts","sourceRoot":"","sources":["../../../src/lib/helpers/value-hash.helper.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CA0BpD;AAED,yDAAyD;AACzD,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEhD;AAED,0EAA0E;AAC1E,wBAAgB,SAAS,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CAEzD"}
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.canonicalJson = canonicalJson;
4
+ exports.hashValue = hashValue;
5
+ exports.deepEqual = deepEqual;
6
+ const crypto_1 = require("crypto");
7
+ /**
8
+ * Produces a deterministic, stable serialization of an arbitrary value so it
9
+ * can be hashed consistently across processes and after jsonb round-trips:
10
+ * - object keys are sorted recursively
11
+ * - Date instances become ISO strings
12
+ * - undefined / null / missing all normalize to null
13
+ * - arrays keep their order
14
+ * - circular references become the string '[Circular]'
15
+ */
16
+ function canonicalJson(value) {
17
+ const seen = new WeakSet();
18
+ const walk = (node) => {
19
+ if (node === undefined || node === null) {
20
+ return null;
21
+ }
22
+ if (node instanceof Date) {
23
+ return Number.isNaN(node.getTime()) ? null : node.toISOString();
24
+ }
25
+ if (typeof node === 'object') {
26
+ if (seen.has(node)) {
27
+ return '[Circular]';
28
+ }
29
+ seen.add(node);
30
+ if (Array.isArray(node)) {
31
+ return node.map((item) => walk(item));
32
+ }
33
+ const out = {};
34
+ for (const key of Object.keys(node).sort()) {
35
+ out[key] = walk(node[key]);
36
+ }
37
+ return out;
38
+ }
39
+ return node;
40
+ };
41
+ return JSON.stringify(walk(value));
42
+ }
43
+ /** SHA-256 hex hash of a value's canonical JSON form. */
44
+ function hashValue(value) {
45
+ return (0, crypto_1.createHash)('sha256').update(canonicalJson(value)).digest('hex');
46
+ }
47
+ /** Structural equality used as legacy fallback when no hash is stored. */
48
+ function deepEqual(a, b) {
49
+ return canonicalJson(a) === canonicalJson(b);
50
+ }
@@ -1,3 +1,4 @@
1
+ import type { ApprovalHooks } from './hooks.interface';
1
2
  /**
2
3
  * Lifecycle of an approval status row.
3
4
  *
@@ -30,6 +31,12 @@ export interface ModificationItem {
30
31
  * '[Circular]').
31
32
  */
32
33
  currentValue?: unknown;
34
+ /**
35
+ * SHA-256 hash of the captured value's canonical JSON form. Stored so the
36
+ * resubmit check can cheaply detect whether the field changed since the
37
+ * request without deep-comparing (possibly large) relation snapshots.
38
+ */
39
+ currentValueHash?: string;
33
40
  /** Value the reviewer wants instead. */
34
41
  wantedValue: unknown;
35
42
  /** Optional human-readable explanation. */
@@ -99,6 +106,40 @@ export interface ApprovalPipelineConfig {
99
106
  * of approval state.
100
107
  */
101
108
  visibleStatuses?: readonly ApprovalStatus[];
109
+ /**
110
+ * Before/after hooks for each approval transition, mirroring the generic
111
+ * `CrudHooks` API. Each hook receives the approval row view and (for
112
+ * `after*`) the previous status.
113
+ */
114
+ hooks?: ApprovalHooks;
115
+ /**
116
+ * Verifies that the requester actually applied the requested changes before
117
+ * allowing a resubmit. For each modification item the live field value is
118
+ * hashed and compared with the hash captured at request time — an identical
119
+ * hash means the field was left untouched.
120
+ */
121
+ resubmitCheck?: ApprovalResubmitCheckConfig;
122
+ }
123
+ export interface ApprovalResubmitCheckConfig {
124
+ /**
125
+ * 'all' (default): every non-ignored modification field must have changed.
126
+ * 'any': at least one must have changed.
127
+ */
128
+ mode?: 'all' | 'any';
129
+ /** Modification fields exempt from the "must have changed" gate. */
130
+ ignoreFields?: readonly string[];
131
+ /**
132
+ * Full override of the built-in comparison. Return false to block the
133
+ * resubmit with CRUD_APPROVAL_RESUBMIT_NOT_SATISFIED.
134
+ */
135
+ customChecker?: (context: {
136
+ modifications: ModificationItem[];
137
+ satisfied: {
138
+ field: string;
139
+ satisfied: boolean;
140
+ }[];
141
+ entity: unknown;
142
+ }) => boolean | Promise<boolean>;
102
143
  }
103
144
  export interface RequestModificationPayload {
104
145
  modifications: ModificationItem[];
@@ -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;;;;;;;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"}
1
+ {"version":3,"file":"approval-pipeline.interface.d.ts","sourceRoot":"","sources":["../../../src/lib/interfaces/approval-pipeline.interface.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,5 @@
1
+ import { ApprovalStatus, ApprovalStatusView, ModificationItem } from './approval-pipeline.interface';
2
+ import { OwnershipUser } from './find-mine.interface';
1
3
  export type CrudHook<TContext = any> = (context: TContext) => Promise<any> | any;
2
4
  export interface CrudHookConfig<TContext = any> {
3
5
  handler: CrudHook<TContext>;
@@ -49,4 +51,31 @@ export interface TransactionConfig {
49
51
  isolationLevel?: 'READ UNCOMMITTED' | 'READ COMMITTED' | 'REPEATABLE READ' | 'SERIALIZABLE';
50
52
  timeout?: number;
51
53
  }
54
+ export interface ApprovalHookContext {
55
+ id: number;
56
+ user?: OwnershipUser;
57
+ approval: ApprovalStatusView;
58
+ }
59
+ export interface AfterApprovalHookContext extends ApprovalHookContext {
60
+ previousStatus: ApprovalStatus;
61
+ }
62
+ export interface RequestModificationApprovalHookContext extends ApprovalHookContext {
63
+ modifications: ModificationItem[];
64
+ note?: string;
65
+ }
66
+ export interface AfterRequestModificationApprovalHookContext extends RequestModificationApprovalHookContext {
67
+ previousStatus: ApprovalStatus;
68
+ }
69
+ export interface ApprovalHooks {
70
+ beforeSubmit?: CrudHookConfig<ApprovalHookContext>;
71
+ afterSubmit?: CrudHookConfig<AfterApprovalHookContext>;
72
+ beforeApprove?: CrudHookConfig<ApprovalHookContext>;
73
+ afterApprove?: CrudHookConfig<AfterApprovalHookContext>;
74
+ beforeReject?: CrudHookConfig<ApprovalHookContext>;
75
+ afterReject?: CrudHookConfig<AfterApprovalHookContext>;
76
+ beforeRequestModification?: CrudHookConfig<RequestModificationApprovalHookContext>;
77
+ afterRequestModification?: CrudHookConfig<AfterRequestModificationApprovalHookContext>;
78
+ beforeResubmit?: CrudHookConfig<ApprovalHookContext>;
79
+ afterResubmit?: CrudHookConfig<AfterApprovalHookContext>;
80
+ }
52
81
  //# sourceMappingURL=hooks.interface.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.interface.d.ts","sourceRoot":"","sources":["../../../src/lib/interfaces/hooks.interface.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,CAAC,QAAQ,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,KAAK,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;AAEjF,MAAM,WAAW,cAAc,CAAC,QAAQ,GAAG,GAAG;IAC5C,OAAO,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC5B,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB,CAAC,OAAO,EAAE,UAAU;IACtD,OAAO,EAAE,UAAU,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB,CAAC,OAAO,EAAE,UAAU;IACrD,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,UAAU,CAAC;CACrB;AAED,MAAM,WAAW,mBAAmB,CAAC,OAAO,EAAE,UAAU;IACtD,OAAO,EAAE,UAAU,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,kBAAkB,CAAC,OAAO,EAAE,UAAU;IACrD,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,UAAU,CAAC;IACpB,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,mBAAmB,CAAC,OAAO;IAC1C,MAAM,EAAE,OAAO,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,mBAAmB,CAAC,OAAO;IAC1C,MAAM,EAAE,OAAO,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,SAAS,CAAC,OAAO,EAAE,UAAU,EAAE,UAAU;IACxD,YAAY,CAAC,EAAE,cAAc,CAAC,mBAAmB,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC;IACxE,WAAW,CAAC,EAAE,cAAc,CAAC,kBAAkB,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC;IACtE,YAAY,CAAC,EAAE,cAAc,CAAC,mBAAmB,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC;IACxE,WAAW,CAAC,EAAE,cAAc,CAAC,kBAAkB,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC;IACtE,YAAY,CAAC,EAAE,cAAc,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAC;IAC5D,WAAW,CAAC,EAAE,cAAc,CAAC,kBAAkB,CAAC,CAAC;IACjD,aAAa,CAAC,EAAE,cAAc,CAAC,oBAAoB,CAAC,CAAC;IACrD,YAAY,CAAC,EAAE,cAAc,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAC;CAC7D;AAED,MAAM,WAAW,iBAAiB;IAChC,cAAc,CAAC,EACX,kBAAkB,GAClB,gBAAgB,GAChB,iBAAiB,GACjB,cAAc,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB"}
1
+ {"version":3,"file":"hooks.interface.d.ts","sourceRoot":"","sources":["../../../src/lib/interfaces/hooks.interface.ts"],"names":[],"mappings":"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"}
@@ -6,7 +6,7 @@ import { CursorPaginationDto } from '../dtos/cursor-pagination.dto';
6
6
  import { FilterDto } from '../dtos/filter.dto';
7
7
  import { CrudEndpoint, CrudInterface, CursorPaginationResult } from '../interfaces/crud.interface';
8
8
  import { CursorStrategy } from '../interfaces/cursor-strategy.interface';
9
- import { CrudHooks, TransactionConfig } from '../interfaces/hooks.interface';
9
+ import { ApprovalHooks, CrudHooks, TransactionConfig } from '../interfaces/hooks.interface';
10
10
  import { FindMineConfig, OwnershipUser } from '../interfaces/find-mine.interface';
11
11
  import { StatusPipelineConfig, StatusTransitionAction, StatusValue } from '../interfaces/status-pipeline.interface';
12
12
  import { ApprovalPipelineConfig, ApprovalStatusView, ApprovalHistoryView, RequestModificationPayload } from '../interfaces/approval-pipeline.interface';
@@ -63,6 +63,7 @@ export declare class NestCrudService<Entity extends ObjectLiteral, CreateDto = P
63
63
  action?: StatusTransitionAction<Entity>;
64
64
  }>;
65
65
  protected readonly approvalPipeline?: ApprovalPipelineConfig;
66
+ protected readonly approvalHooks: ApprovalHooks;
66
67
  constructor(options: CrudServiceOptions<Entity, ResponseDto>);
67
68
  private normalizeStatusTransitions;
68
69
  private resolveRelations;
@@ -132,9 +133,18 @@ export declare class NestCrudService<Entity extends ObjectLiteral, CreateDto = P
132
133
  private sanitizeForJsonb;
133
134
  private loadApprovalStatus;
134
135
  private transitionApproval;
136
+ private fireApprovalBeforeHook;
137
+ private fireApprovalAfterHook;
135
138
  private assertTransitionAllowed;
136
139
  private userHasPermission;
137
140
  private applyApprovalVisibility;
141
+ /**
142
+ * Ensures the requester actually changed the fields covered by the stored
143
+ * modification request before a resubmit is allowed. Each item's live value
144
+ * hash is compared against the hash captured at request time; an identical
145
+ * hash means the field was left untouched.
146
+ */
147
+ private assertResubmitSatisfied;
138
148
  private approvalIdCastExpression;
139
149
  private toApprovalStatusView;
140
150
  private toApprovalHistoryView;
@@ -1 +1 @@
1
- {"version":3,"file":"nest-crud.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/nest-crud.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAE9D,OAAO,EAAe,aAAa,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AACrF,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAE9D,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AACnG,OAAO,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAAkB,SAAS,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAC7F,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAClF,OAAO,EACL,oBAAoB,EAGpB,sBAAsB,EAEtB,WAAW,EACZ,MAAM,yCAAyC,CAAC;AASjD,OAAO,EAEL,sBAAsB,EAEtB,kBAAkB,EAClB,mBAAmB,EAEnB,0BAA0B,EAC3B,MAAM,2CAA2C,CAAC;AAEnD,MAAM,WAAW,kBAAkB,CAAC,MAAM,SAAS,aAAa,EAAE,WAAW,CAC3E,SAAQ,cAAc,CAAC,MAAM,CAAC;IAC9B,UAAU,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;IAC/B,cAAc,CAAC,EAAE,SAAS,CAAC,MAAM,MAAM,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC;IAC3D,iBAAiB,CAAC,EAAE,SAAS,CAAC,MAAM,MAAM,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC;IAC9D,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,SAAS,CAAC,EAAE;QACV,QAAQ,EAAE,MAAM,MAAM,CAAC;QACvB,IAAI,EAAE,UAAU,CAAC,aAAa,CAAC,CAAC;QAChC,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,EAAE,CAAC;IACJ,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,WAAW,GAAG,WAAW,EAAE,CAAC;IAC3E,cAAc,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IAC/B,cAAc,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IAC/B,iBAAiB,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;IAC5C,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,KAAK,CAAC,EAAE,SAAS,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IACpC,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC,cAAc,CAAC,EAAE,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC9C,gBAAgB,CAAC,EAAE,sBAAsB,CAAC;CAC3C;AAED,qBACa,eAAe,CAC1B,MAAM,SAAS,aAAa,EAC5B,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,EAC3B,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,EAC3B,WAAW,GAAG,MAAM,CACpB,YAAW,aAAa,CAAC,SAAS,EAAE,SAAS,EAAE,WAAW,CAAC;IAE3D,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;IAC5C,SAAS,CAAC,QAAQ,CAAC,cAAc,EAAE,SAAS,CAAC,MAAM,MAAM,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC;IAC7E,SAAS,CAAC,QAAQ,CAAC,iBAAiB,EAAE,SAAS,CAAC,MAAM,MAAM,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC;IAChF,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9C,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE;QAC5B,QAAQ,EAAE,MAAM,MAAM,CAAC;QACvB,IAAI,EAAE,UAAU,CAAC,aAAa,CAAC,CAAC;QAChC,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,EAAE,CAAC;IACJ,SAAS,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CACjC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,KACtB,WAAW,GAAG,WAAW,EAAE,CAAC;IACjC,SAAS,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IAClD,SAAS,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IAClD,QAAQ,CAAC,iBAAiB,EAAE,SAAS,YAAY,EAAE,CAAC;IACpD,SAAS,CAAC,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;IAClD,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IACtD,SAAS,CAAC,QAAQ,CAAC,iBAAiB,EAAE,iBAAiB,CAAC;IACxD,SAAS,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,MAAM,CAAC;IACrD,SAAS,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,EAAE,EAAE,kBAAkB,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,KAAK,IAAI,CAAC;IACrG,SAAS,CAAC,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;IAC7C,SAAS,CAAC,QAAQ,CAAC,0BAA0B,EAAE,SAAS,MAAM,EAAE,CAAC;IACjE,SAAS,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,OAAO,CAAC;IACtE,SAAS,CAAC,QAAQ,CAAC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IACjD,SAAS,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,MAAM,CAAC;IAC9C,SAAS,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,WAAW,CAAC;IAC/C,SAAS,CAAC,QAAQ,CAAC,iBAAiB,EAAE,SAAS,WAAW,EAAE,CAAC;IAC7D,SAAS,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,sBAAsB,CAAC,MAAM,CAAC,CAAC;IACvE,SAAS,CAAC,QAAQ,CAAC,iBAAiB,EAAE,GAAG,CACvC,WAAW,EACX;QACE,EAAE,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC;QACrB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,MAAM,CAAC,EAAE,sBAAsB,CAAC,MAAM,CAAC,CAAC;KACzC,CACF,CAAa;IACd,SAAS,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,sBAAsB,CAAC;gBAEjD,OAAO,EAAE,kBAAkB,CAAC,MAAM,EAAE,WAAW,CAAC;IAqC5D,OAAO,CAAC,0BAA0B;YAuDpB,gBAAgB;YAmChB,oBAAoB;YAoBpB,WAAW;IAezB,OAAO,CAAC,oBAAoB;IAoB5B,OAAO,CAAC,iBAAiB;IAuBzB,OAAO,CAAC,YAAY;IAsBpB,OAAO,CAAC,qBAAqB;IAI7B,OAAO,CAAC,sBAAsB;IA8B9B,OAAO,CAAC,kBAAkB;IAwB1B,OAAO,CAAC,mBAAmB;IAQ3B,OAAO,CAAC,uBAAuB;YAWjB,eAAe;IAmB7B,OAAO,CAAC,0BAA0B;IAIlC,OAAO,CAAC,kBAAkB;IA2B1B,OAAO,CAAC,wBAAwB;YAwDlB,oBAAoB;IAuBlC,OAAO,CAAC,+BAA+B;IAQjC,OAAO,CAAC,KAAK,EAAE,aAAa,GAAG,SAAS;;;;;;;;;;;IA4BxC,QAAQ,CACZ,MAAM,EAAE,MAAM,GAAG,MAAM,EACvB,KAAK,EAAE,aAAa,GAAG,SAAS,GAC/B,OAAO,CAAC;QAAE,IAAI,EAAE,WAAW,EAAE,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAkC7C,iBAAiB,CACrB,KAAK,EAAE,mBAAmB,GAAG,SAAS,GACrC,OAAO,CAAC,sBAAsB,CAAC,WAAW,CAAC,CAAC;IA4DzC,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,aAAa;IAqCxC,MAAM,CAAC,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,EAAE,aAAa;IAyD/C,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,EAAE,aAAa;IAI3D,YAAY,CAChB,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,WAAW,EACnB,IAAI,CAAC,EAAE,aAAa,GACnB,OAAO,CAAC,WAAW,CAAC;IAUjB,WAAW,CACf,EAAE,EAAE,MAAM,EACV,IAAI,CAAC,EAAE,aAAa,GACnB,OAAO,CAAC;QAAE,QAAQ,EAAE,kBAAkB,CAAC;QAAC,OAAO,EAAE,mBAAmB,EAAE,CAAA;KAAE,CAAC;IAsBtE,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAI9E,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAI7E,mBAAmB,CACvB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,0BAA0B,EACnC,IAAI,CAAC,EAAE,aAAa,GACnB,OAAO,CAAC,kBAAkB,CAAC;IAUxB,gBAAgB,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAI/E,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAInF,OAAO,CAAC,4BAA4B;IAMpC,OAAO,CAAC,2BAA2B;IAQnC,OAAO,CAAC,qBAAqB;IAI7B,OAAO,CAAC,oBAAoB;YAId,kBAAkB;YA6BlB,wBAAwB;IAUtC;;;OAGG;YACW,sBAAsB;IAgBpC,gEAAgE;IAChE,OAAO,CAAC,gBAAgB;IAexB;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;YAsBV,kBAAkB;YAiBlB,kBAAkB;IAyGhC,OAAO,CAAC,uBAAuB;IAc/B,OAAO,CAAC,iBAAiB;IAQzB,OAAO,CAAC,uBAAuB;IAmB/B,OAAO,CAAC,wBAAwB;IAWhC,OAAO,CAAC,oBAAoB;IAkB5B,OAAO,CAAC,qBAAqB;YAaf,eAAe;IA8CvB,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,aAAa;IAyBvC,aAAa,CAAC,KAAK,EAAE;QACzB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB;;;;;;;;;CA4CF"}
1
+ {"version":3,"file":"nest-crud.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/nest-crud.service.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,8 @@ const nest_error_1 = require("@nest-util/nest-error");
7
7
  const audit_log_entity_1 = require("../entities/audit-log.entity");
8
8
  const filter_helper_1 = require("../helpers/filter.helper");
9
9
  const pagination_helper_1 = require("../helpers/pagination.helper");
10
+ const relation_path_helper_1 = require("../helpers/relation-path.helper");
11
+ const value_hash_helper_1 = require("../helpers/value-hash.helper");
10
12
  const cursor_pagination_helper_1 = require("../helpers/cursor-pagination.helper");
11
13
  const approval_status_entity_1 = require("../entities/approval-status.entity");
12
14
  const modification_request_history_entity_1 = require("../entities/modification-request-history.entity");
@@ -46,6 +48,7 @@ let NestCrudService = class NestCrudService {
46
48
  this.statusTransitions = this.normalizeStatusTransitions(options.statusPipeline.transitions);
47
49
  }
48
50
  this.approvalPipeline = options.approvalPipeline;
51
+ this.approvalHooks = options.approvalPipeline?.hooks ?? {};
49
52
  }
50
53
  normalizeStatusTransitions(transitions) {
51
54
  const result = new Map();
@@ -558,12 +561,15 @@ let NestCrudService = class NestCrudService {
558
561
  * Loads the target entity with its configured `include` relations so that
559
562
  * relation fields can be read as objects when capturing modification values.
560
563
  */
561
- async getEntityWithRelations(id, user) {
564
+ async getEntityWithRelations(id, user, extraRelations) {
562
565
  if (this.enforceOwnershipFor(user)) {
563
566
  return this.findOwnedEntity(id, user);
564
567
  }
565
- const relations = this.include.length
566
- ? this.buildRelationsObject(this.include)
568
+ const relationPaths = [
569
+ ...new Set([...this.include, ...(extraRelations ?? [])]),
570
+ ];
571
+ const relations = relationPaths.length
572
+ ? this.buildRelationsObject(relationPaths)
567
573
  : undefined;
568
574
  return this.repo.findOne({
569
575
  where: { id },
@@ -635,20 +641,28 @@ let NestCrudService = class NestCrudService {
635
641
  throw (0, nest_error_1.keyed)(common_1.HttpStatus.NOT_FOUND, nest_error_1.ErrorKey.CRUD_RESOURCE_NOT_FOUND);
636
642
  }
637
643
  const current = approval.status;
644
+ const previousStatus = current;
638
645
  const now = new Date();
639
646
  const userId = user?.id != null ? String(user.id) : null;
640
647
  const reviewable = [
641
648
  approval_pipeline_interface_1.APPROVAL_STATUS.submitted,
642
649
  approval_pipeline_interface_1.APPROVAL_STATUS.resubmitted,
643
650
  ];
651
+ // Already in a reviewable/terminal state (e.g. the pipeline was
652
+ // configured with initialStatus: 'submitted'): no submit transition is
653
+ // needed, so this is a harmless no-op returning the current status. Hooks
654
+ // are skipped because no transition actually occurs.
655
+ if (action === 'submit' && current !== approval_pipeline_interface_1.APPROVAL_STATUS.draft) {
656
+ return this.toApprovalStatusView(approval);
657
+ }
658
+ const beforeContext = {
659
+ id,
660
+ user,
661
+ approval: this.toApprovalStatusView(approval),
662
+ };
663
+ await this.fireApprovalBeforeHook(action, beforeContext, modifications ?? [], note);
644
664
  switch (action) {
645
665
  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
666
  approval.status = approval_pipeline_interface_1.APPROVAL_STATUS.submitted;
653
667
  approval.requestedBy = userId;
654
668
  break;
@@ -669,14 +683,23 @@ let NestCrudService = class NestCrudService {
669
683
  case 'requestModification': {
670
684
  this.assertTransitionAllowed(action, current, reviewable);
671
685
  approval.status = approval_pipeline_interface_1.APPROVAL_STATUS.modificationRequested;
672
- const entity = await this.getEntityWithRelations(id, user);
673
- const capturedModifications = (modifications ?? []).map((m) => ({
674
- ...m,
675
- currentValue: this.sanitizeForJsonb(m.currentValue !== undefined
686
+ const fields = (modifications ?? []).map((m) => m.field);
687
+ const extraRelations = (0, relation_path_helper_1.resolveRelationPaths)(this.repo.metadata, fields);
688
+ const entity = await this.getEntityWithRelations(id, user, extraRelations);
689
+ const capturedModifications = (modifications ?? []).map((m) => {
690
+ if (!(0, relation_path_helper_1.isKnownProperty)(this.repo.metadata, m.field.split('.')[0])) {
691
+ console.warn(`[NestCrudService] Approval modification field "${m.field}" does not exist on ${this.repo.metadata.tableName}; capturing null`);
692
+ }
693
+ const currentValue = this.sanitizeForJsonb((0, relation_path_helper_1.normalizeCapturedValue)(m.currentValue !== undefined
676
694
  ? m.currentValue
677
- : this.readCurrentValue(entity, m.field)),
678
- wantedValue: this.sanitizeForJsonb(m.wantedValue),
679
- }));
695
+ : this.readCurrentValue(entity, m.field)));
696
+ return {
697
+ ...m,
698
+ currentValue,
699
+ currentValueHash: (0, value_hash_helper_1.hashValue)(currentValue),
700
+ wantedValue: this.sanitizeForJsonb(m.wantedValue),
701
+ };
702
+ });
680
703
  approval.currentModifications = capturedModifications;
681
704
  await this.getHistoryRepository().save(this.getHistoryRepository().create({
682
705
  approvalStatusId: approval.id,
@@ -686,18 +709,65 @@ let NestCrudService = class NestCrudService {
686
709
  }));
687
710
  break;
688
711
  }
689
- case 'resubmit':
712
+ case 'resubmit': {
690
713
  if (current !== approval_pipeline_interface_1.APPROVAL_STATUS.modificationRequested) {
691
714
  throw (0, nest_error_1.keyed)(common_1.HttpStatus.BAD_REQUEST, nest_error_1.ErrorKey.CRUD_APPROVAL_INVALID_TRANSITION, { action: 'resubmit', current: String(current) });
692
715
  }
716
+ await this.assertResubmitSatisfied(approval, id, user);
693
717
  approval.status = approval_pipeline_interface_1.APPROVAL_STATUS.resubmitted;
694
718
  approval.currentModifications = null;
695
719
  approval.resubmittedBy = userId;
696
720
  approval.resubmittedAt = now;
697
721
  break;
722
+ }
698
723
  }
699
724
  const saved = await this.getApprovalRepository().save(approval);
700
- return this.toApprovalStatusView(saved);
725
+ const afterContext = {
726
+ id,
727
+ user,
728
+ approval: this.toApprovalStatusView(saved),
729
+ previousStatus,
730
+ };
731
+ await this.fireApprovalAfterHook(action, afterContext, modifications ?? [], note);
732
+ return afterContext.approval;
733
+ }
734
+ async fireApprovalBeforeHook(action, context, modifications, note) {
735
+ switch (action) {
736
+ case 'submit':
737
+ await this.executeHook(this.approvalHooks.beforeSubmit, context);
738
+ break;
739
+ case 'approve':
740
+ await this.executeHook(this.approvalHooks.beforeApprove, context);
741
+ break;
742
+ case 'reject':
743
+ await this.executeHook(this.approvalHooks.beforeReject, context);
744
+ break;
745
+ case 'resubmit':
746
+ await this.executeHook(this.approvalHooks.beforeResubmit, context);
747
+ break;
748
+ case 'requestModification':
749
+ await this.executeHook(this.approvalHooks.beforeRequestModification, { ...context, modifications, note });
750
+ break;
751
+ }
752
+ }
753
+ async fireApprovalAfterHook(action, context, modifications, note) {
754
+ switch (action) {
755
+ case 'submit':
756
+ await this.executeHook(this.approvalHooks.afterSubmit, context);
757
+ break;
758
+ case 'approve':
759
+ await this.executeHook(this.approvalHooks.afterApprove, context);
760
+ break;
761
+ case 'reject':
762
+ await this.executeHook(this.approvalHooks.afterReject, context);
763
+ break;
764
+ case 'resubmit':
765
+ await this.executeHook(this.approvalHooks.afterResubmit, context);
766
+ break;
767
+ case 'requestModification':
768
+ await this.executeHook(this.approvalHooks.afterRequestModification, { ...context, modifications, note });
769
+ break;
770
+ }
701
771
  }
702
772
  assertTransitionAllowed(action, current, allowedFrom) {
703
773
  if (!allowedFrom.includes(current)) {
@@ -722,6 +792,55 @@ let NestCrudService = class NestCrudService {
722
792
  approvalVisibleStatuses: [...visible],
723
793
  });
724
794
  }
795
+ /**
796
+ * Ensures the requester actually changed the fields covered by the stored
797
+ * modification request before a resubmit is allowed. Each item's live value
798
+ * hash is compared against the hash captured at request time; an identical
799
+ * hash means the field was left untouched.
800
+ */
801
+ async assertResubmitSatisfied(approval, id, user) {
802
+ const checkConfig = this.approvalPipeline?.resubmitCheck;
803
+ const modifications = approval.currentModifications ?? [];
804
+ if (modifications.length === 0) {
805
+ return;
806
+ }
807
+ const fields = modifications.map((m) => m.field);
808
+ const extraRelations = (0, relation_path_helper_1.resolveRelationPaths)(this.repo.metadata, fields);
809
+ const entity = await this.getEntityWithRelations(id, user, extraRelations);
810
+ const ignored = new Set(checkConfig?.ignoreFields ?? []);
811
+ const satisfied = modifications.map((m) => {
812
+ if (ignored.has(m.field)) {
813
+ return { field: m.field, satisfied: true };
814
+ }
815
+ const live = this.readCurrentValue(entity, m.field);
816
+ const satisfiedField = m.currentValueHash !== undefined
817
+ ? (0, value_hash_helper_1.hashValue)(live) !== m.currentValueHash
818
+ : m.currentValue !== undefined
819
+ ? !(0, value_hash_helper_1.deepEqual)(live, m.currentValue)
820
+ : true;
821
+ return { field: m.field, satisfied: satisfiedField };
822
+ });
823
+ let allowed;
824
+ if (checkConfig?.customChecker) {
825
+ allowed = await checkConfig.customChecker({
826
+ modifications,
827
+ satisfied,
828
+ entity,
829
+ });
830
+ }
831
+ else {
832
+ const required = satisfied.filter((s) => s.satisfied);
833
+ allowed =
834
+ checkConfig?.mode === 'any' ? required.length > 0 : required.length === satisfied.length;
835
+ }
836
+ if (!allowed) {
837
+ throw (0, nest_error_1.keyed)(common_1.HttpStatus.BAD_REQUEST, nest_error_1.ErrorKey.CRUD_APPROVAL_RESUBMIT_NOT_SATISFIED, {
838
+ unchangedFields: satisfied
839
+ .filter((s) => !s.satisfied)
840
+ .map((s) => s.field),
841
+ });
842
+ }
843
+ }
725
844
  approvalIdCastExpression() {
726
845
  const type = this.repo.manager.connection.options.type;
727
846
  if (type === 'mysql' || type === 'mariadb' || type === 'aurora-mysql') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nest-util/nest-crud",
3
- "version": "2.0.1",
3
+ "version": "2.0.3",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",