@zola_do/crud 0.2.15 → 0.2.16

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
@@ -774,6 +774,94 @@ export class OrdersModule {}
774
774
 
775
775
  Requires `@nestjs/microservices` peer dependency.
776
776
 
777
+ ## Advanced features
778
+
779
+ ### Bulk create and bulk delete
780
+
781
+ Enable batch endpoints on `EntityCrudController`:
782
+
783
+ ```typescript
784
+ @EntityCrudController(
785
+ {
786
+ enableBulkCreate: true,
787
+ enableBulkDelete: true,
788
+ bulkCreatePermission: 'products:create',
789
+ bulkDeletePermission: 'products:delete',
790
+ },
791
+ Product,
792
+ )
793
+ export class ProductController extends EntityCrudControllerHost {}
794
+ ```
795
+
796
+ - `POST /products/bulk` — body `{ items: [...] }`
797
+ - `POST /products/bulk-delete` — body `{ ids: string[] }`
798
+ - Disable per operation with `operations.bulkCreate` / `operations.bulkDelete` (`hide` | `block`)
799
+
800
+ ### Create idempotency
801
+
802
+ Register a `CrudIdempotencyStore` and enable on entity options:
803
+
804
+ ```typescript
805
+ import {
806
+ CRUD_IDEMPOTENCY_STORE,
807
+ InMemoryCrudIdempotencyStore,
808
+ } from '@zola_do/crud';
809
+
810
+ @Module({
811
+ providers: [
812
+ {
813
+ provide: CRUD_IDEMPOTENCY_STORE,
814
+ useClass: InMemoryCrudIdempotencyStore, // swap for Redis in production
815
+ },
816
+ ],
817
+ })
818
+ export class AppModule {}
819
+
820
+ @EntityCrudController({ idempotency: { enabled: true, ttlMs: 86_400_000 } }, Order)
821
+ export class OrderController extends EntityCrudControllerHost {}
822
+ ```
823
+
824
+ Clients send `Idempotency-Key` (configurable via `headerName`). Replays return the stored create response.
825
+
826
+ ### Optimistic concurrency
827
+
828
+ ```typescript
829
+ @EntityCrudController({ optimisticConcurrency: true }, Product)
830
+ export class ProductController extends EntityCrudControllerHost {}
831
+ ```
832
+
833
+ Updates require a version field on the entity; conflicts return HTTP 409.
834
+
835
+ ### Cursor pagination (plain query params)
836
+
837
+ CRUD list endpoints accept compact `?q=` (see `@zola_do/collection-query`) **or** plain params:
838
+
839
+ ```
840
+ GET /products?cursor=<token>&limit=20&direction=next
841
+ GET /products?cursor=<token>&limit=20&direction=prev
842
+ ```
843
+
844
+ Response may include cursor metadata alongside `total` / `items` when cursor mode is active.
845
+
846
+ ### `collectionQueryDefaults`
847
+
848
+ Apply default column allowlists for every list on a controller:
849
+
850
+ ```typescript
851
+ @EntityCrudController(
852
+ {
853
+ collectionQueryDefaults: {
854
+ allowedFilterColumns: ['name', 'status', 'createdAt'],
855
+ allowedSortColumns: ['name', 'createdAt'],
856
+ },
857
+ },
858
+ Product,
859
+ )
860
+ export class ProductController extends EntityCrudControllerHost {}
861
+ ```
862
+
863
+ Unset allowlists skip enforcement — set defaults for defense in depth.
864
+
777
865
  ## Troubleshooting
778
866
 
779
867
  ### Q: How do I add custom methods to the CRUD service?
@@ -1,5 +1,10 @@
1
1
  import { ArgumentsHost, ExceptionFilter } from '@nestjs/common';
2
+ export type GlobalExceptionFilterOptions = {
3
+ includePath?: boolean;
4
+ };
2
5
  export declare class GlobalExceptionFilter implements ExceptionFilter {
3
6
  private readonly logger;
7
+ private readonly includePath;
8
+ constructor(options?: GlobalExceptionFilterOptions);
4
9
  catch(exception: any, host: ArgumentsHost): void;
5
10
  }
@@ -5,10 +5,14 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
5
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
6
  return c > 3 && r && Object.defineProperty(target, key, r), r;
7
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
+ };
8
11
  var GlobalExceptionFilter_1;
9
12
  Object.defineProperty(exports, "__esModule", { value: true });
10
13
  exports.GlobalExceptionFilter = void 0;
11
14
  const common_1 = require("@nestjs/common");
15
+ const get_client_ip_helper_1 = require("../utils/get-client-ip.helper");
12
16
  function normalizeHttpExceptionMessage(exception) {
13
17
  const res = exception.getResponse();
14
18
  if (typeof res === 'string') {
@@ -26,11 +30,12 @@ function normalizeHttpExceptionMessage(exception) {
26
30
  return exception.message;
27
31
  }
28
32
  let GlobalExceptionFilter = GlobalExceptionFilter_1 = class GlobalExceptionFilter {
29
- constructor() {
33
+ constructor(options = {}) {
30
34
  this.logger = new common_1.Logger(GlobalExceptionFilter_1.name);
35
+ this.includePath = options.includePath !== false;
31
36
  }
32
37
  catch(exception, host) {
33
- var _a, _b, _c, _d, _e;
38
+ var _a, _b, _c;
34
39
  const ctx = host.switchToHttp();
35
40
  const response = ctx.getResponse();
36
41
  const request = ctx.getRequest();
@@ -42,6 +47,9 @@ let GlobalExceptionFilter = GlobalExceptionFilter_1 = class GlobalExceptionFilte
42
47
  let message;
43
48
  if (isHttp) {
44
49
  message = normalizeHttpExceptionMessage(exception);
50
+ if (isProd && status >= common_1.HttpStatus.INTERNAL_SERVER_ERROR) {
51
+ message = 'Internal server error';
52
+ }
45
53
  }
46
54
  else {
47
55
  const err = exception;
@@ -52,17 +60,20 @@ let GlobalExceptionFilter = GlobalExceptionFilter_1 = class GlobalExceptionFilte
52
60
  const responseData = {
53
61
  statusCode: status,
54
62
  message,
55
- path: request.url,
56
63
  timestamp: new Date().toISOString(),
57
64
  };
65
+ if (this.includePath) {
66
+ responseData.path = request.url;
67
+ }
58
68
  const err = exception instanceof Error ? exception : undefined;
59
- this.logger.error(Object.assign(Object.assign({}, responseData), { exceptionMessage: err === null || err === void 0 ? void 0 : err.message, stack: err === null || err === void 0 ? void 0 : err.stack, name: err === null || err === void 0 ? void 0 : err.name, remoteAddress: (_b = (_a = request.socket) === null || _a === void 0 ? void 0 : _a.remoteAddress) !== null && _b !== void 0 ? _b : (_c = request.connection) === null || _c === void 0 ? void 0 : _c.remoteAddress, ip: request.ip, ips: request.ips, forward: (_d = request.headers['x-forwarded-for']) !== null && _d !== void 0 ? _d : '', real: (_e = request.headers['x-Real-IP']) !== null && _e !== void 0 ? _e : '' }));
69
+ this.logger.error(Object.assign(Object.assign({}, responseData), { exceptionMessage: err === null || err === void 0 ? void 0 : err.message, stack: err === null || err === void 0 ? void 0 : err.stack, name: err === null || err === void 0 ? void 0 : err.name, clientIp: (0, get_client_ip_helper_1.getClientIp)(request), remoteAddress: (_b = (_a = request.socket) === null || _a === void 0 ? void 0 : _a.remoteAddress) !== null && _b !== void 0 ? _b : (_c = request.connection) === null || _c === void 0 ? void 0 : _c.remoteAddress }));
60
70
  response.status(status).json(responseData);
61
71
  return;
62
72
  }
63
73
  };
64
74
  exports.GlobalExceptionFilter = GlobalExceptionFilter;
65
75
  exports.GlobalExceptionFilter = GlobalExceptionFilter = GlobalExceptionFilter_1 = __decorate([
66
- (0, common_1.Catch)()
76
+ (0, common_1.Catch)(),
77
+ __metadata("design:paramtypes", [Object])
67
78
  ], GlobalExceptionFilter);
68
79
  //# sourceMappingURL=global-exception.filter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"global-exception.filter.js","sourceRoot":"","sources":["../../../src/shared/exceptions/global-exception.filter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"global-exception.filter.js","sourceRoot":"","sources":["../../../src/shared/exceptions/global-exception.filter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ export type ClientIpRequest = {
2
+ ip?: string;
3
+ ips?: string[];
4
+ headers?: Record<string, string | string[] | undefined>;
5
+ socket?: {
6
+ remoteAddress?: string;
7
+ };
8
+ connection?: {
9
+ remoteAddress?: string;
10
+ };
11
+ };
12
+ export declare function getClientIp(req: ClientIpRequest): string;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getClientIp = getClientIp;
4
+ function getClientIp(req) {
5
+ var _a, _b, _c, _d, _e, _f, _g, _h;
6
+ if ((_a = req.ips) === null || _a === void 0 ? void 0 : _a.length) {
7
+ return req.ips[0];
8
+ }
9
+ if (req.ip) {
10
+ return req.ip;
11
+ }
12
+ const xff = (_b = req.headers) === null || _b === void 0 ? void 0 : _b['x-forwarded-for'];
13
+ if (xff) {
14
+ const raw = Array.isArray(xff) ? xff[0] : xff;
15
+ const first = (_c = raw.split(',')[0]) === null || _c === void 0 ? void 0 : _c.trim();
16
+ if (first) {
17
+ return first;
18
+ }
19
+ }
20
+ const realIp = (_d = req.headers) === null || _d === void 0 ? void 0 : _d['x-real-ip'];
21
+ if (realIp) {
22
+ return Array.isArray(realIp) ? realIp[0] : realIp;
23
+ }
24
+ return ((_h = (_f = (_e = req.socket) === null || _e === void 0 ? void 0 : _e.remoteAddress) !== null && _f !== void 0 ? _f : (_g = req.connection) === null || _g === void 0 ? void 0 : _g.remoteAddress) !== null && _h !== void 0 ? _h : 'unknown');
25
+ }
26
+ //# sourceMappingURL=get-client-ip.helper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-client-ip.helper.js","sourceRoot":"","sources":["../../../src/shared/utils/get-client-ip.helper.ts"],"names":[],"mappings":";;AAaA,kCA4BC;AA5BD,SAAgB,WAAW,CAAC,GAAoB;;IAC9C,IAAI,MAAA,GAAG,CAAC,GAAG,0CAAE,MAAM,EAAE,CAAC;QACpB,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IAED,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC;QACX,OAAO,GAAG,CAAC,EAAE,CAAC;IAChB,CAAC;IAED,MAAM,GAAG,GAAG,MAAA,GAAG,CAAC,OAAO,0CAAG,iBAAiB,CAAC,CAAC;IAC7C,IAAI,GAAG,EAAE,CAAC;QACR,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;QAC9C,MAAM,KAAK,GAAG,MAAA,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,0CAAE,IAAI,EAAE,CAAC;QACxC,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,MAAA,GAAG,CAAC,OAAO,0CAAG,WAAW,CAAC,CAAC;IAC1C,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IACpD,CAAC;IAED,OAAO,CACL,MAAA,MAAA,MAAA,GAAG,CAAC,MAAM,0CAAE,aAAa,mCACzB,MAAA,GAAG,CAAC,UAAU,0CAAE,aAAa,mCAC7B,SAAS,CACV,CAAC;AACJ,CAAC"}
@@ -4,5 +4,6 @@ export * from './crud-hooks.helper';
4
4
  export * from './cursor-query.helper';
5
5
  export * from './collection-query-merge';
6
6
  export * from './in-memory-idempotency.store';
7
+ export * from './redis-idempotency.store';
7
8
  export * from './transactional-repository.helper';
8
9
  export * from './crud-transaction.decorators';
@@ -20,6 +20,7 @@ __exportStar(require("./crud-hooks.helper"), exports);
20
20
  __exportStar(require("./cursor-query.helper"), exports);
21
21
  __exportStar(require("./collection-query-merge"), exports);
22
22
  __exportStar(require("./in-memory-idempotency.store"), exports);
23
+ __exportStar(require("./redis-idempotency.store"), exports);
23
24
  __exportStar(require("./transactional-repository.helper"), exports);
24
25
  __exportStar(require("./crud-transaction.decorators"), exports);
25
26
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/shared/utils/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,wDAAsC;AACtC,iDAA+B;AAC/B,sDAAoC;AACpC,wDAAsC;AACtC,2DAAyC;AACzC,gEAA8C;AAC9C,oEAAkD;AAClD,gEAA8C"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/shared/utils/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,wDAAsC;AACtC,iDAA+B;AAC/B,sDAAoC;AACpC,wDAAsC;AACtC,2DAAyC;AACzC,gEAA8C;AAC9C,4DAA0C;AAC1C,oEAAkD;AAClD,gEAA8C"}
@@ -0,0 +1,12 @@
1
+ import type { CrudIdempotencyStore } from '../types/crud-idempotency-store.interface';
2
+ export type RedisIdempotencyClient = {
3
+ get(key: string): Promise<string | null>;
4
+ set(key: string, value: string, mode: 'PX', ttlMs: number): Promise<unknown>;
5
+ };
6
+ export declare class RedisCrudIdempotencyStore implements CrudIdempotencyStore {
7
+ private readonly redis;
8
+ private readonly keyPrefix;
9
+ constructor(redis: RedisIdempotencyClient, keyPrefix?: string);
10
+ get(key: string): Promise<any | undefined>;
11
+ set(key: string, body: any, ttlMs?: number): Promise<void>;
12
+ }
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RedisCrudIdempotencyStore = void 0;
4
+ class RedisCrudIdempotencyStore {
5
+ constructor(redis, keyPrefix = 'crud:idempotency:') {
6
+ this.redis = redis;
7
+ this.keyPrefix = keyPrefix;
8
+ }
9
+ async get(key) {
10
+ const raw = await this.redis.get(`${this.keyPrefix}${key}`);
11
+ if (!raw) {
12
+ return undefined;
13
+ }
14
+ try {
15
+ return JSON.parse(raw);
16
+ }
17
+ catch (_a) {
18
+ return undefined;
19
+ }
20
+ }
21
+ async set(key, body, ttlMs) {
22
+ const ttl = ttlMs && ttlMs > 0 ? ttlMs : 86400000;
23
+ await this.redis.set(`${this.keyPrefix}${key}`, JSON.stringify(body), 'PX', ttl);
24
+ }
25
+ }
26
+ exports.RedisCrudIdempotencyStore = RedisCrudIdempotencyStore;
27
+ //# sourceMappingURL=redis-idempotency.store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redis-idempotency.store.js","sourceRoot":"","sources":["../../../src/shared/utils/redis-idempotency.store.ts"],"names":[],"mappings":";;;AAWA,MAAa,yBAAyB;IACpC,YACmB,KAA6B,EAC7B,YAAY,mBAAmB;QAD/B,UAAK,GAAL,KAAK,CAAwB;QAC7B,cAAS,GAAT,SAAS,CAAsB;IAC/C,CAAC;IAEJ,KAAK,CAAC,GAAG,CAAC,GAAW;QACnB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,SAAS,GAAG,GAAG,EAAE,CAAC,CAAC;QAC5D,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACzB,CAAC;QAAC,WAAM,CAAC;YACP,OAAO,SAAS,CAAC;QACnB,CAAC;IACH,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW,EAAE,IAAS,EAAE,KAAc;QAC9C,MAAM,GAAG,GAAG,KAAK,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAU,CAAC;QACpD,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAClB,GAAG,IAAI,CAAC,SAAS,GAAG,GAAG,EAAE,EACzB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EACpB,IAAI,EACJ,GAAG,CACJ,CAAC;IACJ,CAAC;CACF;AA3BD,8DA2BC"}
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.validateDto = validateDto;
4
+ const common_1 = require("@nestjs/common");
4
5
  const class_transformer_1 = require("class-transformer");
5
6
  const class_validator_1 = require("class-validator");
6
7
  async function validateDto(dto, itemData) {
@@ -8,7 +9,7 @@ async function validateDto(dto, itemData) {
8
9
  const errors = (0, class_validator_1.validateSync)(instance);
9
10
  const errorMessages = errors.flatMap((e) => Object.values(e.constraints));
10
11
  if (errorMessages.length > 0) {
11
- throw errorMessages;
12
+ throw new common_1.BadRequestException({ errors: errorMessages });
12
13
  }
13
14
  }
14
15
  //# sourceMappingURL=validate-dto.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"validate-dto.js","sourceRoot":"","sources":["../../../src/shared/utils/validate-dto.ts"],"names":[],"mappings":";;AAGA,kCAOC;AAVD,yDAAoD;AACpD,qDAA+C;AAExC,KAAK,UAAU,WAAW,CAAC,GAAQ,EAAE,QAAa;IACvD,MAAM,QAAQ,GAAG,IAAA,mCAAe,EAAC,GAAG,EAAE,QAAQ,CAAQ,CAAC;IACvD,MAAM,MAAM,GAAG,IAAA,8BAAY,EAAC,QAAQ,CAAC,CAAC;IACtC,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;IAC1E,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,MAAM,aAAa,CAAC;IACtB,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"validate-dto.js","sourceRoot":"","sources":["../../../src/shared/utils/validate-dto.ts"],"names":[],"mappings":";;AAIA,kCAOC;AAXD,2CAAqD;AACrD,yDAAoD;AACpD,qDAA+C;AAExC,KAAK,UAAU,WAAW,CAAC,GAAQ,EAAE,QAAa;IACvD,MAAM,QAAQ,GAAG,IAAA,mCAAe,EAAC,GAAG,EAAE,QAAQ,CAAQ,CAAC;IACvD,MAAM,MAAM,GAAG,IAAA,8BAAY,EAAC,QAAQ,CAAC,CAAC;IACtC,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;IAC1E,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,4BAAmB,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;IAC3D,CAAC;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zola_do/crud",
3
- "version": "0.2.15",
3
+ "version": "0.2.16",
4
4
  "description": "Generic CRUD controllers and services for NestJS",
5
5
  "author": "zolaDO",
6
6
  "license": "ISC",
@@ -78,8 +78,8 @@
78
78
  }
79
79
  },
80
80
  "dependencies": {
81
- "@zola_do/collection-query": "^0.2.7",
82
- "@zola_do/authorization": "^0.2.7"
81
+ "@zola_do/collection-query": "^0.2.15",
82
+ "@zola_do/authorization": "^0.2.15"
83
83
  },
84
84
  "devDependencies": {
85
85
  "rimraf": "^6.1.3",