@leo-h/create-nodejs-app 1.0.12 → 1.0.14

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
- Object.defineProperty(exports,"__esModule",{value:!0});const name="@leo-h/create-nodejs-app",version="1.0.12",packageManager="pnpm@9.1.1",author="Leonardo Henrique <leonardo0507.business@gmail.com>",description="Create a modern Node.js app with TypeScript using one command.",license="MIT",keywords=["node","node.js","typescript"],bin={"create-nodejs-app":"./dist/index.js"},files=["./dist","./templates"],repository={type:"git",url:"https://github.com/Leo-Henrique/create-nodejs-app"},scripts={prepare:"husky",start:"node ./dist/index.js","start:dev":"tsx ./src/index.ts","start:dev:watch":"tsx watch ./src/index.ts",typecheck:"tsc --noEmit",lint:"eslint . --ext .ts --max-warnings 0 --cache","lint:fix":"pnpm lint --fix",format:"prettier . --write --cache","test:unit":"vitest run","test:unit:watch":"vitest","test:e2e":"vitest run --config ./vitest.config.e2e.mts","test:e2e:watch":"vitest --config ./vitest.config.e2e.mts","test:coverage":"vitest run --coverage.enabled=true",template:"tsx ./scripts/template-cli.ts",prebuild:"rimraf ./dist",build:"unbuild",prepublishOnly:"pnpm build"},dependencies={commander:"12.1.0",picocolors:"1.0.1",prompts:"2.4.2","validate-npm-package-name":"5.0.1",zod:"3.23.8"},devDependencies={"@faker-js/faker":"8.4.1","@types/node":"20.12.12","@types/prompts":"2.4.9","@types/validate-npm-package-name":"4.0.2","@typescript-eslint/eslint-plugin":"7.10.0","@typescript-eslint/parser":"7.10.0","conventional-changelog-conventionalcommits":"8.0.0",eslint:"8.57.0","eslint-config-prettier":"9.1.0","eslint-plugin-vitest":"0.4.0",husky:"9.0.11","lint-staged":"15.2.2","npm-run-all":"4.1.5",prettier:"3.2.5",rimraf:"5.0.7",tsx:"4.10.5",typescript:"5.4.5",unbuild:"2.0.0","vite-tsconfig-paths":"4.3.2",vitest:"1.6.0"},d={name,version,packageManager,author,description,license,keywords,bin,files,repository,scripts,dependencies,devDependencies};exports.author=author;exports.bin=bin;exports.default=d;exports.dependencies=dependencies;exports.description=description;exports.devDependencies=devDependencies;exports.files=files;exports.keywords=keywords;exports.license=license;exports.name=name;exports.packageManager=packageManager;exports.repository=repository;exports.scripts=scripts;exports.version=version;
1
+ Object.defineProperty(exports,"__esModule",{value:!0});const name="@leo-h/create-nodejs-app",version="1.0.14",packageManager="pnpm@9.1.1",author="Leonardo Henrique <leonardo0507.business@gmail.com>",description="Create a modern Node.js app with TypeScript using one command.",license="MIT",keywords=["node","node.js","typescript"],bin={"create-nodejs-app":"./dist/index.js"},files=["./dist","./templates"],repository={type:"git",url:"https://github.com/Leo-Henrique/create-nodejs-app"},scripts={prepare:"husky",start:"node ./dist/index.js","start:dev":"tsx ./src/index.ts","start:dev:watch":"tsx watch ./src/index.ts",typecheck:"tsc --noEmit",lint:"eslint . --ext .ts --max-warnings 0 --cache","lint:fix":"pnpm lint --fix",format:"prettier . --write --cache","test:unit":"vitest run","test:unit:watch":"vitest","test:e2e":"vitest run --config ./vitest.config.e2e.mts","test:e2e:watch":"vitest --config ./vitest.config.e2e.mts","test:coverage":"vitest run --coverage.enabled=true",template:"tsx ./scripts/template-cli.ts",prebuild:"rimraf ./dist",build:"unbuild",prepublishOnly:"pnpm build"},dependencies={commander:"12.1.0",picocolors:"1.0.1",prompts:"2.4.2","validate-npm-package-name":"5.0.1",zod:"3.23.8"},devDependencies={"@faker-js/faker":"8.4.1","@types/node":"20.12.12","@types/prompts":"2.4.9","@types/validate-npm-package-name":"4.0.2","@typescript-eslint/eslint-plugin":"7.10.0","@typescript-eslint/parser":"7.10.0","conventional-changelog-conventionalcommits":"8.0.0",eslint:"8.57.0","eslint-config-prettier":"9.1.0","eslint-plugin-vitest":"0.4.0",husky:"9.0.11","lint-staged":"15.2.2","npm-run-all":"4.1.5",prettier:"3.2.5",rimraf:"5.0.7",tsx:"4.10.5",typescript:"5.4.5",unbuild:"2.0.0","vite-tsconfig-paths":"4.3.2",vitest:"1.6.0"},d={name,version,packageManager,author,description,license,keywords,bin,files,repository,scripts,dependencies,devDependencies};exports.author=author;exports.bin=bin;exports.default=d;exports.dependencies=dependencies;exports.description=description;exports.devDependencies=devDependencies;exports.files=files;exports.keywords=keywords;exports.license=license;exports.name=name;exports.packageManager=packageManager;exports.repository=repository;exports.scripts=scripts;exports.version=version;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leo-h/create-nodejs-app",
3
- "version": "1.0.12",
3
+ "version": "1.0.14",
4
4
  "packageManager": "pnpm@9.1.1",
5
5
  "author": "Leonardo Henrique <leonardo0507.business@gmail.com>",
6
6
  "description": "Create a modern Node.js app with TypeScript using one command.",
@@ -46,6 +46,7 @@ export default defineBuildConfig({
46
46
  entryFileNames: "[name].js",
47
47
  preserveModules: true,
48
48
  strict: false,
49
+ exports: "named",
49
50
  },
50
51
  esbuild: {
51
52
  minifySyntax: true,
@@ -46,6 +46,7 @@ export default defineBuildConfig({
46
46
  entryFileNames: "[name].js",
47
47
  preserveModules: true,
48
48
  strict: false,
49
+ exports: "named",
49
50
  },
50
51
  esbuild: {
51
52
  minifySyntax: true,
@@ -12,9 +12,10 @@
12
12
  "format": "prettier . --write --cache",
13
13
  "test:unit": "vitest run",
14
14
  "test:unit:watch": "vitest",
15
+ "test:unit:coverage": "vitest run --coverage.enabled=true",
15
16
  "test:e2e": "vitest run --config ./vitest.config.e2e.mts",
16
17
  "test:e2e:watch": "vitest --config ./vitest.config.e2e.mts",
17
- "test:coverage": "vitest run --coverage.enabled=true",
18
+ "test:e2e:coverage": "vitest run --config ./vitest.config.e2e.mts --coverage.enabled=true",
18
19
  "prebuild": "rimraf ./dist",
19
20
  "build": "unbuild"
20
21
  },
@@ -39,6 +40,7 @@
39
40
  "@types/supertest": "6.0.2",
40
41
  "@typescript-eslint/eslint-plugin": "7.10.0",
41
42
  "@typescript-eslint/parser": "7.10.0",
43
+ "@vitest/coverage-v8": "1.6.0",
42
44
  "eslint": "8.57.0",
43
45
  "eslint-config-prettier": "9.1.0",
44
46
  "eslint-plugin-vitest": "0.4.0",
@@ -63,6 +63,9 @@ importers:
63
63
  '@typescript-eslint/parser':
64
64
  specifier: 7.10.0
65
65
  version: 7.10.0(eslint@8.57.0)(typescript@5.4.5)
66
+ '@vitest/coverage-v8':
67
+ specifier: 1.6.0
68
+ version: 1.6.0(vitest@1.6.0(@types/node@20.12.12))
66
69
  eslint:
67
70
  specifier: 8.57.0
68
71
  version: 8.57.0
@@ -203,6 +206,9 @@ packages:
203
206
  resolution: {integrity: sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==}
204
207
  engines: {node: '>=6.9.0'}
205
208
 
209
+ '@bcoe/v8-coverage@0.2.3':
210
+ resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
211
+
206
212
  '@esbuild/aix-ppc64@0.19.12':
207
213
  resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==}
208
214
  engines: {node: '>=12'}
@@ -556,6 +562,10 @@ packages:
556
562
  resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
557
563
  engines: {node: '>=12'}
558
564
 
565
+ '@istanbuljs/schema@0.1.3':
566
+ resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==}
567
+ engines: {node: '>=8'}
568
+
559
569
  '@jest/schemas@29.6.3':
560
570
  resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==}
561
571
  engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -855,6 +865,11 @@ packages:
855
865
  '@ungap/structured-clone@1.2.0':
856
866
  resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
857
867
 
868
+ '@vitest/coverage-v8@1.6.0':
869
+ resolution: {integrity: sha512-KvapcbMY/8GYIG0rlwwOKCVNRc0OL20rrhFkg/CHNzncV03TE2XWvO5w9uZYoxNiMEBacAJt3unSOiZ7svePew==}
870
+ peerDependencies:
871
+ vitest: 1.6.0
872
+
858
873
  '@vitest/expect@1.6.0':
859
874
  resolution: {integrity: sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==}
860
875
 
@@ -1591,6 +1606,9 @@ packages:
1591
1606
  hookable@5.5.3:
1592
1607
  resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==}
1593
1608
 
1609
+ html-escaper@2.0.2:
1610
+ resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
1611
+
1594
1612
  http-errors@2.0.0:
1595
1613
  resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
1596
1614
  engines: {node: '>= 0.8'}
@@ -1678,6 +1696,22 @@ packages:
1678
1696
  isexe@2.0.0:
1679
1697
  resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
1680
1698
 
1699
+ istanbul-lib-coverage@3.2.2:
1700
+ resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==}
1701
+ engines: {node: '>=8'}
1702
+
1703
+ istanbul-lib-report@3.0.1:
1704
+ resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==}
1705
+ engines: {node: '>=10'}
1706
+
1707
+ istanbul-lib-source-maps@5.0.6:
1708
+ resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==}
1709
+ engines: {node: '>=10'}
1710
+
1711
+ istanbul-reports@3.1.7:
1712
+ resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==}
1713
+ engines: {node: '>=8'}
1714
+
1681
1715
  jackspeak@3.4.0:
1682
1716
  resolution: {integrity: sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==}
1683
1717
  engines: {node: '>=14'}
@@ -1785,6 +1819,13 @@ packages:
1785
1819
  magic-string@0.30.10:
1786
1820
  resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==}
1787
1821
 
1822
+ magicast@0.3.4:
1823
+ resolution: {integrity: sha512-TyDF/Pn36bBji9rWKHlZe+PZb6Mx5V8IHCSxk7X4aljM4e/vyDvZZYwHewdVaqiA0nb3ghfHU/6AUpDxWoER2Q==}
1824
+
1825
+ make-dir@4.0.0:
1826
+ resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
1827
+ engines: {node: '>=10'}
1828
+
1788
1829
  mdn-data@2.0.28:
1789
1830
  resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==}
1790
1831
 
@@ -2483,6 +2524,10 @@ packages:
2483
2524
  engines: {node: '>=14.0.0'}
2484
2525
  hasBin: true
2485
2526
 
2527
+ test-exclude@6.0.0:
2528
+ resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==}
2529
+ engines: {node: '>=8'}
2530
+
2486
2531
  text-decoding@1.0.0:
2487
2532
  resolution: {integrity: sha512-/0TJD42KDnVwKmDK6jj3xP7E2MG7SHAOG4tyTgyUCRPdHwvkquYNLEQltmdMa3owq3TkddCVcTsoctJI8VQNKA==}
2488
2533
 
@@ -2878,6 +2923,8 @@ snapshots:
2878
2923
  '@babel/helper-validator-identifier': 7.24.7
2879
2924
  to-fast-properties: 2.0.0
2880
2925
 
2926
+ '@bcoe/v8-coverage@0.2.3': {}
2927
+
2881
2928
  '@esbuild/aix-ppc64@0.19.12':
2882
2929
  optional: true
2883
2930
 
@@ -3129,6 +3176,8 @@ snapshots:
3129
3176
  wrap-ansi: 8.1.0
3130
3177
  wrap-ansi-cjs: wrap-ansi@7.0.0
3131
3178
 
3179
+ '@istanbuljs/schema@0.1.3': {}
3180
+
3132
3181
  '@jest/schemas@29.6.3':
3133
3182
  dependencies:
3134
3183
  '@sinclair/typebox': 0.27.8
@@ -3416,6 +3465,25 @@ snapshots:
3416
3465
 
3417
3466
  '@ungap/structured-clone@1.2.0': {}
3418
3467
 
3468
+ '@vitest/coverage-v8@1.6.0(vitest@1.6.0(@types/node@20.12.12))':
3469
+ dependencies:
3470
+ '@ampproject/remapping': 2.3.0
3471
+ '@bcoe/v8-coverage': 0.2.3
3472
+ debug: 4.3.5
3473
+ istanbul-lib-coverage: 3.2.2
3474
+ istanbul-lib-report: 3.0.1
3475
+ istanbul-lib-source-maps: 5.0.6
3476
+ istanbul-reports: 3.1.7
3477
+ magic-string: 0.30.10
3478
+ magicast: 0.3.4
3479
+ picocolors: 1.0.1
3480
+ std-env: 3.7.0
3481
+ strip-literal: 2.1.0
3482
+ test-exclude: 6.0.0
3483
+ vitest: 1.6.0(@types/node@20.12.12)
3484
+ transitivePeerDependencies:
3485
+ - supports-color
3486
+
3419
3487
  '@vitest/expect@1.6.0':
3420
3488
  dependencies:
3421
3489
  '@vitest/spy': 1.6.0
@@ -4263,6 +4331,8 @@ snapshots:
4263
4331
 
4264
4332
  hookable@5.5.3: {}
4265
4333
 
4334
+ html-escaper@2.0.2: {}
4335
+
4266
4336
  http-errors@2.0.0:
4267
4337
  dependencies:
4268
4338
  depd: 2.0.0
@@ -4331,6 +4401,27 @@ snapshots:
4331
4401
 
4332
4402
  isexe@2.0.0: {}
4333
4403
 
4404
+ istanbul-lib-coverage@3.2.2: {}
4405
+
4406
+ istanbul-lib-report@3.0.1:
4407
+ dependencies:
4408
+ istanbul-lib-coverage: 3.2.2
4409
+ make-dir: 4.0.0
4410
+ supports-color: 7.2.0
4411
+
4412
+ istanbul-lib-source-maps@5.0.6:
4413
+ dependencies:
4414
+ '@jridgewell/trace-mapping': 0.3.25
4415
+ debug: 4.3.5
4416
+ istanbul-lib-coverage: 3.2.2
4417
+ transitivePeerDependencies:
4418
+ - supports-color
4419
+
4420
+ istanbul-reports@3.1.7:
4421
+ dependencies:
4422
+ html-escaper: 2.0.2
4423
+ istanbul-lib-report: 3.0.1
4424
+
4334
4425
  jackspeak@3.4.0:
4335
4426
  dependencies:
4336
4427
  '@isaacs/cliui': 8.0.2
@@ -4455,6 +4546,16 @@ snapshots:
4455
4546
  dependencies:
4456
4547
  '@jridgewell/sourcemap-codec': 1.4.15
4457
4548
 
4549
+ magicast@0.3.4:
4550
+ dependencies:
4551
+ '@babel/parser': 7.24.7
4552
+ '@babel/types': 7.24.7
4553
+ source-map-js: 1.2.0
4554
+
4555
+ make-dir@4.0.0:
4556
+ dependencies:
4557
+ semver: 7.6.2
4558
+
4458
4559
  mdn-data@2.0.28: {}
4459
4560
 
4460
4561
  mdn-data@2.0.30: {}
@@ -5108,6 +5209,12 @@ snapshots:
5108
5209
  csso: 5.0.5
5109
5210
  picocolors: 1.0.1
5110
5211
 
5212
+ test-exclude@6.0.0:
5213
+ dependencies:
5214
+ '@istanbuljs/schema': 0.1.3
5215
+ glob: 7.2.3
5216
+ minimatch: 3.1.2
5217
+
5111
5218
  text-decoding@1.0.0: {}
5112
5219
 
5113
5220
  text-table@0.2.0: {}
@@ -12,13 +12,13 @@
12
12
  "format": "prettier . --write --cache",
13
13
  "test:unit": "vitest run",
14
14
  "test:unit:watch": "vitest",
15
+ "test:unit:coverage": "vitest run --coverage.enabled=true",
15
16
  "test:e2e": "vitest run --config ./vitest.config.e2e.mts",
16
17
  "test:e2e:watch": "vitest --config ./vitest.config.e2e.mts",
17
- "test:coverage": "vitest run --coverage.enabled=true",
18
+ "test:e2e:coverage": "vitest run --config ./vitest.config.e2e.mts --coverage.enabled=true",
18
19
  "build": "nest build"
19
20
  },
20
21
  "dependencies": {
21
- "@anatine/zod-nestjs": "2.0.9",
22
22
  "@anatine/zod-openapi": "2.2.6",
23
23
  "@fastify/static": "7.0.4",
24
24
  "@nestjs/common": "10.3.10",
@@ -30,6 +30,7 @@
30
30
  "fastify-multer": "2.0.3",
31
31
  "mime-types": "2.1.35",
32
32
  "pretty-bytes": "5.6.0",
33
+ "rxjs": "7.8.1",
33
34
  "zod": "3.23.8"
34
35
  },
35
36
  "devDependencies": {
@@ -44,6 +45,7 @@
44
45
  "@types/supertest": "6.0.2",
45
46
  "@typescript-eslint/eslint-plugin": "7.10.0",
46
47
  "@typescript-eslint/parser": "7.10.0",
48
+ "@vitest/coverage-v8": "1.6.0",
47
49
  "eslint": "8.57.0",
48
50
  "eslint-config-prettier": "9.1.0",
49
51
  "eslint-plugin-vitest": "0.4.0",
@@ -8,9 +8,6 @@ importers:
8
8
 
9
9
  .:
10
10
  dependencies:
11
- '@anatine/zod-nestjs':
12
- specifier: 2.0.9
13
- version: 2.0.9(@anatine/zod-openapi@2.2.6(openapi3-ts@4.3.3)(zod@3.23.8))(@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/swagger@7.4.0(@fastify/static@7.0.4)(@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.10(@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.10)(reflect-metadata@0.2.2)(rxjs@7.8.1))(reflect-metadata@0.2.2))(openapi3-ts@4.3.3)(zod@3.23.8)
14
11
  '@anatine/zod-openapi':
15
12
  specifier: 2.2.6
16
13
  version: 2.2.6(openapi3-ts@4.3.3)(zod@3.23.8)
@@ -44,6 +41,9 @@ importers:
44
41
  pretty-bytes:
45
42
  specifier: 5.6.0
46
43
  version: 5.6.0
44
+ rxjs:
45
+ specifier: 7.8.1
46
+ version: 7.8.1
47
47
  zod:
48
48
  specifier: 3.23.8
49
49
  version: 3.23.8
@@ -81,6 +81,9 @@ importers:
81
81
  '@typescript-eslint/parser':
82
82
  specifier: 7.10.0
83
83
  version: 7.10.0(eslint@8.57.0)(typescript@5.4.5)
84
+ '@vitest/coverage-v8':
85
+ specifier: 1.6.0
86
+ version: 1.6.0(vitest@1.6.0(@types/node@20.12.12)(terser@5.31.3))
84
87
  eslint:
85
88
  specifier: 8.57.0
86
89
  version: 8.57.0
@@ -117,14 +120,9 @@ importers:
117
120
 
118
121
  packages:
119
122
 
120
- '@anatine/zod-nestjs@2.0.9':
121
- resolution: {integrity: sha512-XEK+7wMXAxc4tOkzOpH/vav1MVZrVYeOwKpXmn7aFiTUoB08G1FzAP7rDQ90ZrIFOGSoC0hpJA9izPQxBRAIDg==}
122
- peerDependencies:
123
- '@anatine/zod-openapi': ^2.0.1
124
- '@nestjs/common': ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0
125
- '@nestjs/swagger': ^6.0.0 || ^7.0.0
126
- openapi3-ts: ^4.1.2
127
- zod: ^3.20.0
123
+ '@ampproject/remapping@2.3.0':
124
+ resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
125
+ engines: {node: '>=6.0.0'}
128
126
 
129
127
  '@anatine/zod-openapi@2.2.6':
130
128
  resolution: {integrity: sha512-Z5sr2Nq2xifEpPbPdUcvyl776LY652oR3VHMV++WFSmRrRL8RDP2XTkbuGn+vgfVNOD7UrndYwCWnxaiw7IZog==}
@@ -154,6 +152,10 @@ packages:
154
152
  resolution: {integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==}
155
153
  engines: {node: '>=6.9.0'}
156
154
 
155
+ '@babel/helper-string-parser@7.24.8':
156
+ resolution: {integrity: sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==}
157
+ engines: {node: '>=6.9.0'}
158
+
157
159
  '@babel/helper-validator-identifier@7.24.7':
158
160
  resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==}
159
161
  engines: {node: '>=6.9.0'}
@@ -162,6 +164,18 @@ packages:
162
164
  resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==}
163
165
  engines: {node: '>=6.9.0'}
164
166
 
167
+ '@babel/parser@7.25.4':
168
+ resolution: {integrity: sha512-nq+eWrOgdtu3jG5Os4TQP3x3cLA8hR8TvJNjD8vnPa20WGycimcparWnLK4jJhElTK6SDyuJo1weMKO/5LpmLA==}
169
+ engines: {node: '>=6.0.0'}
170
+ hasBin: true
171
+
172
+ '@babel/types@7.25.4':
173
+ resolution: {integrity: sha512-zQ1ijeeCXVEh+aNL0RlmkPkG8HUiDcU2pzQQFjtbntgAczRASFzj4H+6+bV+dy1ntKR14I/DypeuRG1uma98iQ==}
174
+ engines: {node: '>=6.9.0'}
175
+
176
+ '@bcoe/v8-coverage@0.2.3':
177
+ resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
178
+
165
179
  '@colors/colors@1.5.0':
166
180
  resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==}
167
181
  engines: {node: '>=0.1.90'}
@@ -378,6 +392,10 @@ packages:
378
392
  resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
379
393
  engines: {node: '>=12'}
380
394
 
395
+ '@istanbuljs/schema@0.1.3':
396
+ resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==}
397
+ engines: {node: '>=8'}
398
+
381
399
  '@jest/schemas@29.6.3':
382
400
  resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==}
383
401
  engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -872,6 +890,11 @@ packages:
872
890
  '@ungap/structured-clone@1.2.0':
873
891
  resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
874
892
 
893
+ '@vitest/coverage-v8@1.6.0':
894
+ resolution: {integrity: sha512-KvapcbMY/8GYIG0rlwwOKCVNRc0OL20rrhFkg/CHNzncV03TE2XWvO5w9uZYoxNiMEBacAJt3unSOiZ7svePew==}
895
+ peerDependencies:
896
+ vitest: 1.6.0
897
+
875
898
  '@vitest/expect@1.6.0':
876
899
  resolution: {integrity: sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==}
877
900
 
@@ -1823,6 +1846,9 @@ packages:
1823
1846
  resolution: {integrity: sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==}
1824
1847
  engines: {node: '>=8'}
1825
1848
 
1849
+ html-escaper@2.0.2:
1850
+ resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
1851
+
1826
1852
  http-cache-semantics@4.1.1:
1827
1853
  resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==}
1828
1854
 
@@ -1950,6 +1976,22 @@ packages:
1950
1976
  isexe@2.0.0:
1951
1977
  resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
1952
1978
 
1979
+ istanbul-lib-coverage@3.2.2:
1980
+ resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==}
1981
+ engines: {node: '>=8'}
1982
+
1983
+ istanbul-lib-report@3.0.1:
1984
+ resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==}
1985
+ engines: {node: '>=10'}
1986
+
1987
+ istanbul-lib-source-maps@5.0.6:
1988
+ resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==}
1989
+ engines: {node: '>=10'}
1990
+
1991
+ istanbul-reports@3.1.7:
1992
+ resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==}
1993
+ engines: {node: '>=8'}
1994
+
1953
1995
  iterare@1.2.1:
1954
1996
  resolution: {integrity: sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==}
1955
1997
  engines: {node: '>=6'}
@@ -2079,6 +2121,13 @@ packages:
2079
2121
  resolution: {integrity: sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==}
2080
2122
  engines: {node: '>=12'}
2081
2123
 
2124
+ magicast@0.3.4:
2125
+ resolution: {integrity: sha512-TyDF/Pn36bBji9rWKHlZe+PZb6Mx5V8IHCSxk7X4aljM4e/vyDvZZYwHewdVaqiA0nb3ghfHU/6AUpDxWoER2Q==}
2126
+
2127
+ make-dir@4.0.0:
2128
+ resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
2129
+ engines: {node: '>=10'}
2130
+
2082
2131
  media-typer@0.3.0:
2083
2132
  resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
2084
2133
  engines: {node: '>= 0.6'}
@@ -2863,6 +2912,10 @@ packages:
2863
2912
  engines: {node: '>=10'}
2864
2913
  hasBin: true
2865
2914
 
2915
+ test-exclude@6.0.0:
2916
+ resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==}
2917
+ engines: {node: '>=8'}
2918
+
2866
2919
  text-decoding@1.0.0:
2867
2920
  resolution: {integrity: sha512-/0TJD42KDnVwKmDK6jj3xP7E2MG7SHAOG4tyTgyUCRPdHwvkquYNLEQltmdMa3owq3TkddCVcTsoctJI8VQNKA==}
2868
2921
 
@@ -2890,6 +2943,10 @@ packages:
2890
2943
  resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==}
2891
2944
  engines: {node: '>=0.6.0'}
2892
2945
 
2946
+ to-fast-properties@2.0.0:
2947
+ resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
2948
+ engines: {node: '>=4'}
2949
+
2893
2950
  to-regex-range@5.0.1:
2894
2951
  resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
2895
2952
  engines: {node: '>=8.0'}
@@ -3185,14 +3242,10 @@ packages:
3185
3242
 
3186
3243
  snapshots:
3187
3244
 
3188
- '@anatine/zod-nestjs@2.0.9(@anatine/zod-openapi@2.2.6(openapi3-ts@4.3.3)(zod@3.23.8))(@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/swagger@7.4.0(@fastify/static@7.0.4)(@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.10(@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.10)(reflect-metadata@0.2.2)(rxjs@7.8.1))(reflect-metadata@0.2.2))(openapi3-ts@4.3.3)(zod@3.23.8)':
3245
+ '@ampproject/remapping@2.3.0':
3189
3246
  dependencies:
3190
- '@anatine/zod-openapi': 2.2.6(openapi3-ts@4.3.3)(zod@3.23.8)
3191
- '@nestjs/common': 10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1)
3192
- '@nestjs/swagger': 7.4.0(@fastify/static@7.0.4)(@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.10(@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.10)(reflect-metadata@0.2.2)(rxjs@7.8.1))(reflect-metadata@0.2.2)
3193
- openapi3-ts: 4.3.3
3194
- ts-deepmerge: 6.2.1
3195
- zod: 3.23.8
3247
+ '@jridgewell/gen-mapping': 0.3.5
3248
+ '@jridgewell/trace-mapping': 0.3.25
3196
3249
 
3197
3250
  '@anatine/zod-openapi@2.2.6(openapi3-ts@4.3.3)(zod@3.23.8)':
3198
3251
  dependencies:
@@ -3237,6 +3290,8 @@ snapshots:
3237
3290
  '@babel/highlight': 7.24.7
3238
3291
  picocolors: 1.0.1
3239
3292
 
3293
+ '@babel/helper-string-parser@7.24.8': {}
3294
+
3240
3295
  '@babel/helper-validator-identifier@7.24.7': {}
3241
3296
 
3242
3297
  '@babel/highlight@7.24.7':
@@ -3246,6 +3301,18 @@ snapshots:
3246
3301
  js-tokens: 4.0.0
3247
3302
  picocolors: 1.0.1
3248
3303
 
3304
+ '@babel/parser@7.25.4':
3305
+ dependencies:
3306
+ '@babel/types': 7.25.4
3307
+
3308
+ '@babel/types@7.25.4':
3309
+ dependencies:
3310
+ '@babel/helper-string-parser': 7.24.8
3311
+ '@babel/helper-validator-identifier': 7.24.7
3312
+ to-fast-properties: 2.0.0
3313
+
3314
+ '@bcoe/v8-coverage@0.2.3': {}
3315
+
3249
3316
  '@colors/colors@1.5.0':
3250
3317
  optional: true
3251
3318
 
@@ -3420,6 +3487,8 @@ snapshots:
3420
3487
  wrap-ansi: 8.1.0
3421
3488
  wrap-ansi-cjs: wrap-ansi@7.0.0
3422
3489
 
3490
+ '@istanbuljs/schema@0.1.3': {}
3491
+
3423
3492
  '@jest/schemas@29.6.3':
3424
3493
  dependencies:
3425
3494
  '@sinclair/typebox': 0.27.8
@@ -3926,6 +3995,25 @@ snapshots:
3926
3995
 
3927
3996
  '@ungap/structured-clone@1.2.0': {}
3928
3997
 
3998
+ '@vitest/coverage-v8@1.6.0(vitest@1.6.0(@types/node@20.12.12)(terser@5.31.3))':
3999
+ dependencies:
4000
+ '@ampproject/remapping': 2.3.0
4001
+ '@bcoe/v8-coverage': 0.2.3
4002
+ debug: 4.3.5
4003
+ istanbul-lib-coverage: 3.2.2
4004
+ istanbul-lib-report: 3.0.1
4005
+ istanbul-lib-source-maps: 5.0.6
4006
+ istanbul-reports: 3.1.7
4007
+ magic-string: 0.30.10
4008
+ magicast: 0.3.4
4009
+ picocolors: 1.0.1
4010
+ std-env: 3.7.0
4011
+ strip-literal: 2.1.0
4012
+ test-exclude: 6.0.0
4013
+ vitest: 1.6.0(@types/node@20.12.12)(terser@5.31.3)
4014
+ transitivePeerDependencies:
4015
+ - supports-color
4016
+
3929
4017
  '@vitest/expect@1.6.0':
3930
4018
  dependencies:
3931
4019
  '@vitest/spy': 1.6.0
@@ -5057,6 +5145,8 @@ snapshots:
5057
5145
 
5058
5146
  hexoid@1.0.0: {}
5059
5147
 
5148
+ html-escaper@2.0.2: {}
5149
+
5060
5150
  http-cache-semantics@4.1.1: {}
5061
5151
 
5062
5152
  http-errors@2.0.0:
@@ -5179,6 +5269,27 @@ snapshots:
5179
5269
 
5180
5270
  isexe@2.0.0: {}
5181
5271
 
5272
+ istanbul-lib-coverage@3.2.2: {}
5273
+
5274
+ istanbul-lib-report@3.0.1:
5275
+ dependencies:
5276
+ istanbul-lib-coverage: 3.2.2
5277
+ make-dir: 4.0.0
5278
+ supports-color: 7.2.0
5279
+
5280
+ istanbul-lib-source-maps@5.0.6:
5281
+ dependencies:
5282
+ '@jridgewell/trace-mapping': 0.3.25
5283
+ debug: 4.3.5
5284
+ istanbul-lib-coverage: 3.2.2
5285
+ transitivePeerDependencies:
5286
+ - supports-color
5287
+
5288
+ istanbul-reports@3.1.7:
5289
+ dependencies:
5290
+ html-escaper: 2.0.2
5291
+ istanbul-lib-report: 3.0.1
5292
+
5182
5293
  iterare@1.2.1: {}
5183
5294
 
5184
5295
  jackspeak@3.4.3:
@@ -5321,6 +5432,16 @@ snapshots:
5321
5432
  dependencies:
5322
5433
  '@jridgewell/sourcemap-codec': 1.5.0
5323
5434
 
5435
+ magicast@0.3.4:
5436
+ dependencies:
5437
+ '@babel/parser': 7.25.4
5438
+ '@babel/types': 7.25.4
5439
+ source-map-js: 1.2.0
5440
+
5441
+ make-dir@4.0.0:
5442
+ dependencies:
5443
+ semver: 7.6.3
5444
+
5324
5445
  media-typer@0.3.0: {}
5325
5446
 
5326
5447
  memfs@3.5.3:
@@ -6070,6 +6191,12 @@ snapshots:
6070
6191
  commander: 2.20.3
6071
6192
  source-map-support: 0.5.21
6072
6193
 
6194
+ test-exclude@6.0.0:
6195
+ dependencies:
6196
+ '@istanbuljs/schema': 0.1.3
6197
+ glob: 7.2.3
6198
+ minimatch: 3.1.2
6199
+
6073
6200
  text-decoding@1.0.0: {}
6074
6201
 
6075
6202
  text-table@0.2.0: {}
@@ -6090,6 +6217,8 @@ snapshots:
6090
6217
  dependencies:
6091
6218
  os-tmpdir: 1.0.2
6092
6219
 
6220
+ to-fast-properties@2.0.0: {}
6221
+
6093
6222
  to-regex-range@5.0.1:
6094
6223
  dependencies:
6095
6224
  is-number: 7.0.0
@@ -0,0 +1,12 @@
1
+ import { DomainError } from "./domain-error";
2
+
3
+ export class ValidationError extends DomainError {
4
+ public error = "ValidationError" as const;
5
+ public debug: object | null;
6
+
7
+ constructor(debug?: object) {
8
+ super("Os dados recebidos são inválidos.");
9
+
10
+ this.debug = debug ?? null;
11
+ }
12
+ }
@@ -0,0 +1,31 @@
1
+ import {
2
+ ArgumentsHost,
3
+ Catch,
4
+ ExceptionFilter,
5
+ HttpException,
6
+ } from "@nestjs/common";
7
+ import { FastifyReply } from "fastify";
8
+ import { InternalServerError } from "../internal-server.error";
9
+
10
+ @Catch()
11
+ export class AllExceptionFilter implements ExceptionFilter {
12
+ catch(exception: unknown, host: ArgumentsHost): void {
13
+ const ctx = host.switchToHttp();
14
+ const response = ctx.getResponse<FastifyReply>();
15
+
16
+ const debug =
17
+ exception && typeof exception === "object" && "message" in exception
18
+ ? exception.message
19
+ : null;
20
+
21
+ let httpException: HttpException = new InternalServerError(debug);
22
+
23
+ if (exception instanceof HttpException) httpException = exception;
24
+
25
+ console.error(exception);
26
+
27
+ response
28
+ .status(httpException.getStatus())
29
+ .send(httpException.getResponse());
30
+ }
31
+ }
@@ -0,0 +1,39 @@
1
+ import { DomainError } from "@/core/errors/domain-error";
2
+ import { ValidationError } from "@/core/errors/validation.error";
3
+ import { ErrorPresenter } from "@/infra/presenters/error.presenter";
4
+ import {
5
+ ArgumentsHost,
6
+ BadRequestException,
7
+ Catch,
8
+ ExceptionFilter,
9
+ HttpException,
10
+ } from "@nestjs/common";
11
+ import { FastifyReply } from "fastify";
12
+ import { InternalServerError } from "../internal-server.error";
13
+
14
+ @Catch(DomainError)
15
+ export class DomainExceptionFilter implements ExceptionFilter {
16
+ catch(exception: DomainError, host: ArgumentsHost): void {
17
+ const ctx = host.switchToHttp();
18
+ const response = ctx.getResponse<FastifyReply>();
19
+
20
+ let httpException: HttpException;
21
+
22
+ switch (exception.constructor) {
23
+ case ValidationError:
24
+ httpException = new BadRequestException(
25
+ ErrorPresenter.toHttp(400, exception),
26
+ );
27
+ break;
28
+
29
+ default:
30
+ httpException = new InternalServerError(exception.message);
31
+ }
32
+
33
+ console.error(exception);
34
+
35
+ response
36
+ .status(httpException.getStatus())
37
+ .send(httpException.getResponse());
38
+ }
39
+ }
@@ -0,0 +1,15 @@
1
+ import { ErrorPresenter } from "@/infra/presenters/error.presenter";
2
+ import { HttpException } from "@nestjs/common";
3
+
4
+ export class InternalServerError extends HttpException {
5
+ constructor(debug: unknown) {
6
+ const statusCode = 500;
7
+ const presenter = ErrorPresenter.toHttp(statusCode, {
8
+ error: "InternalServerError",
9
+ message: "Desculpe, um erro inesperado ocorreu.",
10
+ debug,
11
+ });
12
+
13
+ super(presenter, statusCode);
14
+ }
15
+ }
@@ -2,20 +2,20 @@ import { Module } from "@nestjs/common";
2
2
  import { APP_FILTER } from "@nestjs/core";
3
3
  import { HelloMultipartController } from "./controllers/hello/hello-multipart.controller";
4
4
  import { HelloController } from "./controllers/hello/hello.controller";
5
+ import { AllExceptionFilter } from "./errors/filters/all-exception.filter";
6
+ import { DomainExceptionFilter } from "./errors/filters/domain-exception.filter";
5
7
  import { FastifyMulterEventModule } from "./events/fastify-multer.event.module";
6
- import { DomainExceptionFilter } from "./filters/domain-exception.filter";
7
- import { HttpExceptionFilter } from "./filters/http-exception.filter";
8
8
 
9
9
  @Module({
10
10
  imports: [FastifyMulterEventModule],
11
11
  providers: [
12
12
  {
13
13
  provide: APP_FILTER,
14
- useClass: DomainExceptionFilter,
14
+ useClass: AllExceptionFilter,
15
15
  },
16
16
  {
17
17
  provide: APP_FILTER,
18
- useClass: HttpExceptionFilter,
18
+ useClass: DomainExceptionFilter,
19
19
  },
20
20
  ],
21
21
  controllers: [HelloController, HelloMultipartController],
@@ -15,9 +15,11 @@ import multer, {
15
15
  memoryStorage,
16
16
  } from "fastify-multer";
17
17
  import { File, FileFilter, StorageEngine } from "fastify-multer/lib/interfaces";
18
+ import { unlink } from "fs/promises";
18
19
  import { extension } from "mime-types";
19
20
  import { extname } from "path";
20
21
  import prettyBytes from "pretty-bytes";
22
+ import { finalize } from "rxjs";
21
23
  import { ZodObject, ZodRawShape, z } from "zod";
22
24
  import { UploadValidationError } from "../errors/upload-validation.error";
23
25
  import { zodSchemaToSwaggerSchema } from "./zod-schema-pipe";
@@ -108,6 +110,12 @@ type UploadInterceptorOptions = Storage & {
108
110
  * Infinity
109
111
  */
110
112
  maxNonFileFieldSize?: number;
113
+ /**
114
+ * Removes all uploaded files after handler execution.
115
+ *
116
+ * @default true
117
+ */
118
+ removeFilesAfterHandlerExecution?: boolean;
111
119
  };
112
120
 
113
121
  /**
@@ -123,6 +131,7 @@ export function UploadInterceptor(options: UploadInterceptorOptions) {
123
131
  maxFileSize,
124
132
  nonFileFieldsZodSchema,
125
133
  maxNonFileFieldSize,
134
+ removeFilesAfterHandlerExecution,
126
135
  ...restOptions
127
136
  } = {
128
137
  destination: "./tmp",
@@ -132,6 +141,7 @@ export function UploadInterceptor(options: UploadInterceptorOptions) {
132
141
  maxFileSize: 50,
133
142
  nonFileFieldsZodSchema: z.object({}),
134
143
  maxNonFileFieldSize: 1,
144
+ removeFilesAfterHandlerExecution: true,
135
145
  ...options,
136
146
  };
137
147
  const nonFileFieldsSwaggerSchema = zodSchemaToSwaggerSchema(
@@ -211,24 +221,28 @@ export function UploadInterceptor(options: UploadInterceptorOptions) {
211
221
  };
212
222
 
213
223
  const megabytesToBytes = (mb: number) => mb * 1000 * 1000;
224
+ const interceptors: NestInterceptor[] = [
225
+ new ExecuteUploadInterceptor({
226
+ multerInstance: multer({
227
+ storage: getMulterStorage(),
228
+ fileFilter: setMulterFileFilter,
229
+ limits: {
230
+ files: maxFileCount,
231
+ fileSize: megabytesToBytes(maxFileSize),
232
+ fields: Infinity,
233
+ fieldSize: megabytesToBytes(maxNonFileFieldSize),
234
+ },
235
+ }),
236
+ fieldName,
237
+ required,
238
+ }),
239
+ ];
240
+
241
+ if (removeFilesAfterHandlerExecution)
242
+ interceptors.push(new RemoveUploadsInterceptor());
214
243
 
215
244
  return applyDecorators(
216
- UseInterceptors(
217
- new ExecuteUploadInterceptor({
218
- multerInstance: multer({
219
- storage: getMulterStorage(),
220
- fileFilter: setMulterFileFilter,
221
- limits: {
222
- files: maxFileCount,
223
- fileSize: megabytesToBytes(maxFileSize),
224
- fields: Object.keys(nonFileFieldsZodSchema.shape).length,
225
- fieldSize: megabytesToBytes(maxNonFileFieldSize),
226
- },
227
- }),
228
- fieldName,
229
- required,
230
- }),
231
- ),
245
+ UseInterceptors(...interceptors),
232
246
  ApiConsumes("multipart/form-data"),
233
247
  ApiBody({
234
248
  schema: {
@@ -366,3 +380,26 @@ export class ExecuteUploadInterceptor implements NestInterceptor {
366
380
  return next.handle();
367
381
  }
368
382
  }
383
+
384
+ export class RemoveUploadsInterceptor implements NestInterceptor {
385
+ intercept(context: ExecutionContext, next: CallHandler) {
386
+ const ctx = context.switchToHttp();
387
+ const request = ctx.getRequest<FastifyRequestWithFile>();
388
+
389
+ return next.handle().pipe(
390
+ finalize(async () => {
391
+ const { file, files } = request;
392
+
393
+ if (file && file.path) await unlink(file.path);
394
+
395
+ if (files) {
396
+ await Promise.all(
397
+ files.map(async file => {
398
+ if (file.path) return unlink(file.path);
399
+ }),
400
+ );
401
+ }
402
+ }),
403
+ );
404
+ }
405
+ }
@@ -1,5 +1,4 @@
1
- import { createZodDto } from "@anatine/zod-nestjs";
2
- import { extendApi, generateSchema } from "@anatine/zod-openapi";
1
+ import { generateSchema } from "@anatine/zod-openapi";
3
2
  import { UsePipes, applyDecorators } from "@nestjs/common";
4
3
  import { ZodType } from "zod";
5
4
  import {
@@ -15,10 +14,6 @@ export function zodSchemaToSwaggerSchema(schema: ZodType) {
15
14
  return generateSchema(schema, false, "3.0") as SchemaObject;
16
15
  }
17
16
 
18
- export function zodSchemaToNestDto(schema: ZodType) {
19
- return class Dto extends createZodDto(extendApi(schema)) {};
20
- }
21
-
22
17
  interface ZodSchemaPipeParams extends ZodValidationPipeSchemas {
23
18
  isMultipart?: boolean;
24
19
  response?: ZodType | Record<number, ZodType>;
@@ -38,17 +33,35 @@ export function ZodSchemaPipe({
38
33
  const apiDecorators: NestSwaggerDecorator[] = [];
39
34
 
40
35
  if (routeParams) {
41
- apiDecorators.push(
42
- ApiParam({ type: zodSchemaToNestDto(routeParams), name: "" }),
43
- );
36
+ const routeParamsSchema = zodSchemaToSwaggerSchema(routeParams);
37
+
38
+ for (const paramName in routeParams.shape) {
39
+ apiDecorators.push(
40
+ ApiParam({
41
+ name: paramName,
42
+ schema: zodSchemaToSwaggerSchema(routeParams.shape[paramName]),
43
+ required: routeParamsSchema.required?.includes(paramName) ?? false,
44
+ }),
45
+ );
46
+ }
44
47
  }
45
48
 
46
49
  if (queryParams) {
47
- apiDecorators.push(ApiQuery({ type: zodSchemaToNestDto(queryParams) }));
50
+ const queryParamsSchema = zodSchemaToSwaggerSchema(queryParams);
51
+
52
+ for (const paramName in queryParams.shape) {
53
+ apiDecorators.push(
54
+ ApiQuery({
55
+ name: paramName,
56
+ schema: zodSchemaToSwaggerSchema(queryParams.shape[paramName]),
57
+ required: queryParamsSchema.required?.includes(paramName) ?? false,
58
+ }),
59
+ );
60
+ }
48
61
  }
49
62
 
50
63
  if (body && !isMultipart) {
51
- apiDecorators.push(ApiBody({ type: zodSchemaToNestDto(body) }));
64
+ apiDecorators.push(ApiBody({ schema: zodSchemaToSwaggerSchema(body) }));
52
65
  }
53
66
 
54
67
  if (response) {
@@ -1,10 +1,10 @@
1
- import { ValidationError } from "@/core/errors/errors";
1
+ import { ValidationError } from "@/core/errors/validation.error";
2
2
  import { ArgumentMetadata, PipeTransform } from "@nestjs/common";
3
- import { ZodError, ZodType } from "zod";
3
+ import { ZodError, ZodObject, ZodRawShape, ZodType } from "zod";
4
4
 
5
5
  export interface ZodValidationPipeSchemas {
6
- routeParams?: ZodType;
7
- queryParams?: ZodType;
6
+ routeParams?: ZodObject<ZodRawShape>;
7
+ queryParams?: ZodObject<ZodRawShape>;
8
8
  body?: ZodType;
9
9
  }
10
10
 
@@ -1,4 +1,5 @@
1
1
  import { DomainError } from "@/core/errors/domain-error";
2
+ import { env } from "../env";
2
3
 
3
4
  type CustomError = Pick<DomainError, "error" | "message" | "debug">;
4
5
 
@@ -8,7 +9,7 @@ export class ErrorPresenter {
8
9
  error: error.error,
9
10
  message: error.message,
10
11
  statusCode,
11
- debug: error.debug,
12
+ debug: env.NODE_ENV !== "production" ? error.debug : null,
12
13
  };
13
14
  }
14
15
  }
@@ -1,9 +0,0 @@
1
- import { DomainError } from "./domain-error";
2
-
3
- export class ValidationError extends DomainError {
4
- public error = "ValidationError";
5
-
6
- constructor(public debug: object | null = null) {
7
- super("Os dados enviados são inválidos.");
8
- }
9
- }
@@ -1,53 +0,0 @@
1
- import { DomainError } from "@/core/errors/domain-error";
2
- import { ValidationError } from "@/core/errors/errors";
3
- import { env } from "@/infra/env";
4
- import { ErrorPresenter } from "@/infra/presenters/error.presenter";
5
- import {
6
- ArgumentsHost,
7
- BadRequestException,
8
- Catch,
9
- ExceptionFilter,
10
- HttpException,
11
- HttpStatus,
12
- InternalServerErrorException,
13
- } from "@nestjs/common";
14
- import { FastifyReply } from "fastify";
15
-
16
- @Catch(DomainError)
17
- export class DomainExceptionFilter implements ExceptionFilter {
18
- catch(exception: DomainError, host: ArgumentsHost): void {
19
- const ctx = host.switchToHttp();
20
- const response = ctx.getResponse<FastifyReply>();
21
-
22
- let httpException: HttpException;
23
-
24
- switch (exception.constructor) {
25
- case ValidationError:
26
- httpException = new BadRequestException(
27
- ErrorPresenter.toHttp(HttpStatus.BAD_REQUEST, exception),
28
- );
29
- break;
30
-
31
- default:
32
- httpException = new InternalServerErrorException(
33
- ErrorPresenter.toHttp(HttpStatus.INTERNAL_SERVER_ERROR, {
34
- error: "InternalServerError",
35
- message: "Desculpe, um erro inesperado ocorreu.",
36
- debug: exception.message,
37
- }),
38
- );
39
- break;
40
- }
41
-
42
- const httpResponse = httpException.getResponse();
43
-
44
- if (
45
- env.NODE_ENV === "production" &&
46
- typeof httpResponse === "object" &&
47
- "debug" in httpResponse
48
- )
49
- delete httpResponse.debug;
50
-
51
- response.status(httpException.getStatus()).send(httpResponse);
52
- }
53
- }
@@ -1,26 +0,0 @@
1
- import { env } from "@/infra/env";
2
- import {
3
- ArgumentsHost,
4
- Catch,
5
- ExceptionFilter,
6
- HttpException,
7
- } from "@nestjs/common";
8
- import { FastifyReply } from "fastify";
9
-
10
- @Catch(HttpException)
11
- export class HttpExceptionFilter implements ExceptionFilter {
12
- catch(httpException: HttpException, host: ArgumentsHost): void {
13
- const ctx = host.switchToHttp();
14
- const response = ctx.getResponse<FastifyReply>();
15
- const httpResponse = httpException.getResponse();
16
-
17
- if (
18
- env.NODE_ENV === "production" &&
19
- typeof httpResponse === "object" &&
20
- "debug" in httpResponse
21
- )
22
- delete httpResponse.debug;
23
-
24
- response.status(httpException.getStatus()).send(httpResponse);
25
- }
26
- }