{"_id":"@ballistix.digital/exception-mapper","_rev":"8-04159eff831638256fa0ad803cafb96f","name":"@ballistix.digital/exception-mapper","dist-tags":{"latest":"0.6.0"},"versions":{"0.0.1":{"name":"@ballistix.digital/exception-mapper","version":"0.0.1","license":"MIT","_id":"@ballistix.digital/exception-mapper@0.0.1","maintainers":[{"name":"brecht-p7s-ballistix","email":"brecht.pallemans@ballistix.digital"},{"name":"maartenraes","email":"maarten@ballistix.digital"},{"name":"jmostaer","email":"jens@ballistix.digital"},{"name":"aaron-ballistix","email":"aaron@ballistix.digital"},{"name":"aude-ballistix","email":"aude@ballistix.digital"}],"homepage":"https://github.com/layeredprints/exception-mapper#readme","bugs":{"url":"https://github.com/layeredprints/exception-mapper/issues"},"dist":{"shasum":"724d6bbea7ae24a1a70dc180bd3c827b466d8a49","tarball":"https://registry.npmjs.org/@ballistix.digital/exception-mapper/-/exception-mapper-0.0.1.tgz","fileCount":5,"integrity":"sha512-aQWnq+FJwVA4Otes2X9OXpnqeFITqPsj0f2Fo/KdC15TPgFMccC7JC2NWxznDh60TQfS4PuKuMg3P7kiPf/fYg==","signatures":[{"sig":"MEYCIQCGFozxSWBANTfoXAyFl5Z/t+b7PTjvZLiQM3NSWDR8FwIhALjqBv/X2uQ9q2iyrm0skyxXIRx6UJTvSn44pbSNgK+V","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1507},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=22.12"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"scripts":{"build":"rm -rf dist && tsc -p tsconfig.build.json"},"_npmUser":{"name":"jmostaer","email":"jens@ballistix.digital"},"repository":{"url":"git+https://github.com/layeredprints/exception-mapper.git","type":"git","directory":"exception-mapper"},"_npmVersion":"11.12.1","description":"A NestJS module that maps any thrown value to a coded BaseException and to the ExceptionDto envelope, for HTTP filters and task processors.","directories":{},"_nodeVersion":"24.15.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typeorm":">=0.3.0 <2.0.0","@nestjs/common":"^11","class-validator":"^0.15.1","reflect-metadata":"^0.2.2","@ballistix.digital/exception-types":"^0.1.0"},"_npmOperationalInternal":{"tmp":"tmp/exception-mapper_0.0.1_1788805349080_0.9749543470058317","host":"s3://npm-registry-packages-npm-production"}},"0.1.0":{"name":"@ballistix.digital/exception-mapper","version":"0.1.0","license":"MIT","_id":"@ballistix.digital/exception-mapper@0.1.0","maintainers":[{"name":"brecht-p7s-ballistix","email":"brecht.pallemans@ballistix.digital"},{"name":"maartenraes","email":"maarten@ballistix.digital"},{"name":"jmostaer","email":"jens@ballistix.digital"},{"name":"aaron-ballistix","email":"aaron@ballistix.digital"},{"name":"aude-ballistix","email":"aude@ballistix.digital"}],"homepage":"https://github.com/layeredprints/exception-mapper#readme","bugs":{"url":"https://github.com/layeredprints/exception-mapper/issues"},"dist":{"shasum":"e5eb3198e94295666bdc7179c755f02a88257c19","tarball":"https://registry.npmjs.org/@ballistix.digital/exception-mapper/-/exception-mapper-0.1.0.tgz","fileCount":24,"integrity":"sha512-NL/N7KNPc5LTkNg91i+BDMkWB/2rSnk3dp4gR62Xyqflb5lpA8sKE7wEHHlNtNxNxbgnp8djs9zvwOfuG3X3Jg==","signatures":[{"sig":"MEYCIQDHf4brlArdihd85ycf+h1DdOocciupq//ccCrNh/rYlgIhAIgxc+78wKqd0Pq9MPVh9CpVJy76yTsLByrcz04iVAR9","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":32649},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=22.12"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"54a1ba001162c206e4df1fe3d8e96bb45674c78b","scripts":{"build":"rm -rf dist && tsc -p tsconfig.build.json"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:af5ec201-ba60-4437-bb26-5ad568f270de"}},"repository":{"url":"git+https://github.com/layeredprints/exception-mapper.git","type":"git","directory":"exception-mapper"},"_npmVersion":"12.0.2","description":"A NestJS module that maps any thrown value to a coded BaseException and to the ExceptionDto envelope, for HTTP filters and task processors.","directories":{},"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typeorm":">=0.3.0 <2.0.0","@nestjs/common":"^11","class-validator":"^0.15.1","reflect-metadata":"^0.2.2","@ballistix.digital/exception-types":"^0.1.0"},"_npmOperationalInternal":{"tmp":"tmp/exception-mapper_0.1.0_1788867731615_0.10402214217837202","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@ballistix.digital/exception-mapper","version":"0.2.0","license":"MIT","_id":"@ballistix.digital/exception-mapper@0.2.0","maintainers":[{"name":"brecht-p7s-ballistix","email":"brecht.pallemans@ballistix.digital"},{"name":"maartenraes","email":"maarten@ballistix.digital"},{"name":"jmostaer","email":"jens@ballistix.digital"},{"name":"aaron-ballistix","email":"aaron@ballistix.digital"},{"name":"aude-ballistix","email":"aude@ballistix.digital"}],"homepage":"https://github.com/layeredprints/exception-mapper#readme","bugs":{"url":"https://github.com/layeredprints/exception-mapper/issues"},"dist":{"shasum":"177f8fb8c83cfba801d664285e6187123fd06679","tarball":"https://registry.npmjs.org/@ballistix.digital/exception-mapper/-/exception-mapper-0.2.0.tgz","fileCount":23,"integrity":"sha512-+FJusQ8rTZxwQKSWcqQz9uTU3JsMdPmct3R7PBR6W/7tYBryZrjH6CW60bODgRal5cy3JPbHoZe3c1jSqceaeA==","signatures":[{"sig":"MEYCIQDTflboNM1d6Oq7LcC8GyKNaSEDcc3o5ffTMN55ARY2xgIhANR7+Vx46xSczOBVVkVo37GOZQL01+qTlGr768DLnC0a","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":31538},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=22.12"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"12d60510477763278b990ed7968578749aeabbcb","scripts":{"build":"rm -rf dist && tsc -p tsconfig.build.json"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:af5ec201-ba60-4437-bb26-5ad568f270de"}},"repository":{"url":"git+https://github.com/layeredprints/exception-mapper.git","type":"git","directory":"exception-mapper"},"_npmVersion":"12.0.2","description":"A NestJS module that maps any thrown value to a coded BaseException and to the ExceptionDto envelope, for HTTP filters and task processors.","directories":{},"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typeorm":">=0.3.0 <2.0.0","@nestjs/common":"^11 || ^12","class-validator":"^0.15.1","reflect-metadata":"^0.2.2","@ballistix.digital/exception-types":"^0.2.0"},"_npmOperationalInternal":{"tmp":"tmp/exception-mapper_0.2.0_1789398100699_0.09700439127504268","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@ballistix.digital/exception-mapper","version":"0.3.0","license":"MIT","_id":"@ballistix.digital/exception-mapper@0.3.0","maintainers":[{"name":"brecht-p7s-ballistix","email":"brecht.pallemans@ballistix.digital"},{"name":"maartenraes","email":"maarten@ballistix.digital"},{"name":"jmostaer","email":"jens@ballistix.digital"},{"name":"aaron-ballistix","email":"aaron@ballistix.digital"},{"name":"aude-ballistix","email":"aude@ballistix.digital"}],"homepage":"https://github.com/layeredprints/exception-mapper#readme","bugs":{"url":"https://github.com/layeredprints/exception-mapper/issues"},"dist":{"shasum":"68a404a867ee5d7734184a9f31e3c8d177ccd98d","tarball":"https://registry.npmjs.org/@ballistix.digital/exception-mapper/-/exception-mapper-0.3.0.tgz","fileCount":23,"integrity":"sha512-FMiNNTrhgnbk4O9rN7E5bLBz6V18EsybS6p8sdq53uLrPOjfwLYAdyhH2jVd5KZmPax1RvGz3ZlhaAflw9E98Q==","signatures":[{"sig":"MEYCIQCoc6fhSOCVr45UEG5NUy3iGhQZHHiJs8dYPJWozd8PTwIhALIYpzI6V3YsQRh3EWA5t1X+PoARrl6V5e1d6Sisl3Xo","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIFeUHnVLzvfGccDCVR5lJKTrSVOMD7Ugk7o/RpbscTr6AiEArFr6KEnhm1sQmWJCLJ1rx6yguwIuAmPWYIDe8FqkDT4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":31538},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=22.12"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"2ca3e9359611b193082bc8c632fa66444e42a369","scripts":{"build":"rm -rf dist && tsc -p tsconfig.build.json"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:af5ec201-ba60-4437-bb26-5ad568f270de"}},"repository":{"url":"git+https://github.com/layeredprints/exception-mapper.git","type":"git","directory":"exception-mapper"},"_npmVersion":"12.0.2","description":"A NestJS module that maps any thrown value to a coded BaseException and to the ExceptionDto envelope, for HTTP filters and task processors.","directories":{},"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typeorm":">=0.3.0 <2.0.0","@nestjs/common":"^11 || ^12","class-validator":"^0.15.1","reflect-metadata":"^0.2.2","@ballistix.digital/exception-types":"^0.3.0"},"_npmOperationalInternal":{"tmp":"tmp/exception-mapper_0.3.0_1789481799152_0.7833229124238712","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@ballistix.digital/exception-mapper","version":"0.4.0","license":"MIT","_id":"@ballistix.digital/exception-mapper@0.4.0","maintainers":[{"name":"brecht-p7s-ballistix","email":"brecht.pallemans@ballistix.digital"},{"name":"maartenraes","email":"maarten@ballistix.digital"},{"name":"jmostaer","email":"jens@ballistix.digital"},{"name":"aaron-ballistix","email":"aaron@ballistix.digital"},{"name":"aude-ballistix","email":"aude@ballistix.digital"}],"homepage":"https://github.com/layeredprints/exception-mapper#readme","bugs":{"url":"https://github.com/layeredprints/exception-mapper/issues"},"dist":{"shasum":"886ca9456e68c294aed63fd4b1d0d73436fd0302","tarball":"https://registry.npmjs.org/@ballistix.digital/exception-mapper/-/exception-mapper-0.4.0.tgz","fileCount":23,"integrity":"sha512-QNY/nhi1sk8P691hNF55rTm2NXl6xGZVERjlaWvMZXh0VxPIvbnJ8k0u/UOfX+lXvbwzUYtBmBlWYGnwik6zLw==","signatures":[{"sig":"MEYCIQCtcytO11R+55jhLJV2f8QcTQej6r6qKdXqvvOd4Re/9AIhAK6m/p1RRzCi9jDzjnUrjFLVjomEPa6ssLD2O2YLG5K9","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIHgtVTxpaiPm7vJXelmhc+FvQCfyCKkDQEGzS21VIi4CAiAsF2FkWsJ8ZfSByQzgnHEUob+F59NgnEnrHow2h2xd5g==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":37712},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=22.12"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"e73d228e0a98d6914a8b86d7e1e80d62491b01d1","scripts":{"build":"rm -rf dist && tsc -p tsconfig.build.json"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:af5ec201-ba60-4437-bb26-5ad568f270de"}},"repository":{"url":"git+https://github.com/layeredprints/exception-mapper.git","type":"git","directory":"exception-mapper"},"_npmVersion":"12.0.2","description":"A NestJS module that maps any thrown value to a coded BaseException and to the ExceptionDto envelope, for HTTP filters and task processors.","directories":{},"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typeorm":">=0.3.0 <2.0.0","@nestjs/common":"^11 || ^12","class-validator":"^0.15.1","reflect-metadata":"^0.2.2","@ballistix.digital/exception-types":"^0.4.0"},"_npmOperationalInternal":{"tmp":"tmp/exception-mapper_0.4.0_1789576958280_0.29507189936738776","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"@ballistix.digital/exception-mapper","version":"0.5.0","license":"MIT","_id":"@ballistix.digital/exception-mapper@0.5.0","maintainers":[{"name":"brecht-p7s-ballistix","email":"brecht.pallemans@ballistix.digital"},{"name":"maartenraes","email":"maarten@ballistix.digital"},{"name":"jmostaer","email":"jens@ballistix.digital"},{"name":"aaron-ballistix","email":"aaron@ballistix.digital"},{"name":"aude-ballistix","email":"aude@ballistix.digital"}],"homepage":"https://github.com/layeredprints/exception-mapper#readme","bugs":{"url":"https://github.com/layeredprints/exception-mapper/issues"},"dist":{"shasum":"caeb511313e34c2100f4bd6314ee06866de33c53","tarball":"https://registry.npmjs.org/@ballistix.digital/exception-mapper/-/exception-mapper-0.5.0.tgz","fileCount":23,"integrity":"sha512-FNJfBMQSwMniVaO4Co/b7WjOVjGsjfVaNiAizXn56SiGomB+OHFpMpTSaTI55SLQWyaQmSH0f23of6SglBrvWQ==","signatures":[{"sig":"MEYCIQCiLWvklThm8KnNIFNj6+GFSZSF+PCZz5BHN+nTY5n7QAIhAM+uIf2yb46XhmDkWfUe5DuFWsAU4fI+dUwqmJ+DzxP8","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIHtxR+WEaNgvEzUArRNs3qhdcGBYaliT39AniCzz15d5AiEA2C8rIRxsc8YVeHoYnHTGTTV9e+LXynF9nuret7fgAVE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":37712},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=22.12"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"27d58b7076ff1393fd508eb733e5f7beeba7c3a3","scripts":{"build":"rm -rf dist && tsc -p tsconfig.build.json"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:af5ec201-ba60-4437-bb26-5ad568f270de"}},"repository":{"url":"git+https://github.com/layeredprints/exception-mapper.git","type":"git","directory":"exception-mapper"},"_npmVersion":"12.0.2","description":"A NestJS module that maps any thrown value to a coded BaseException and to the ExceptionDto envelope, for HTTP filters and task processors.","directories":{},"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typeorm":">=0.3.0 <2.0.0","@nestjs/common":"^11 || ^12","class-validator":"^0.15.1","reflect-metadata":"^0.2.2","@ballistix.digital/exception-types":"^0.5.0"},"_npmOperationalInternal":{"tmp":"tmp/exception-mapper_0.5.0_1789632608888_0.32739748120050316","host":"s3://npm-registry-packages-npm-production"}},"0.6.0":{"name":"@ballistix.digital/exception-mapper","version":"0.6.0","license":"MIT","_id":"@ballistix.digital/exception-mapper@0.6.0","maintainers":[{"name":"brecht-p7s-ballistix","email":"brecht.pallemans@ballistix.digital"},{"name":"maartenraes","email":"maarten@ballistix.digital"},{"name":"jmostaer","email":"jens@ballistix.digital"},{"name":"aaron-ballistix","email":"aaron@ballistix.digital"},{"name":"aude-ballistix","email":"aude@ballistix.digital"}],"homepage":"https://github.com/layeredprints/exception-mapper#readme","bugs":{"url":"https://github.com/layeredprints/exception-mapper/issues"},"dist":{"shasum":"f0aecc11ca5db382675be82efff5f6e5f14a76e6","tarball":"https://registry.npmjs.org/@ballistix.digital/exception-mapper/-/exception-mapper-0.6.0.tgz","fileCount":23,"integrity":"sha512-S+uvcW77By1c7tPwcvXUruqMOJ5XO+B038N6+eanhFIo9xbGgzFI/04rUx5SSUtppGjrfGblqI2lYSwgZPv2qQ==","signatures":[{"sig":"MEUCIAG5U45K4ZFvM7wKzVhaarGepSO5dmN4KkwPuDckg3/PAiEA6rNFrZ1dTVsf1S/ZipmKLYZj8V67wPKuASyZsUnr0X4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQCVhGXi49Pfs7VgPke3QukOlG6O07JgYXWc8d912+LpDQIhAP59HTQ66G7wMNpGbo2AFNSWHk3jP4SiL9gySAtL8dEN","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":37712},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=22.12"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"859d0d393a7be6e8711a492174daa468c7f3c2e3","scripts":{"build":"rm -rf dist && tsc -p tsconfig.build.json"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:af5ec201-ba60-4437-bb26-5ad568f270de"}},"repository":{"url":"git+https://github.com/layeredprints/exception-mapper.git","type":"git","directory":"exception-mapper"},"_npmVersion":"12.1.0","description":"A NestJS module that maps any thrown value to a coded BaseException and to the ExceptionDto envelope, for HTTP filters and task processors.","directories":{},"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"typeorm":">=0.3.0 <2.0.0","@nestjs/common":"^11 || ^12","class-validator":"^0.15.1","reflect-metadata":"^0.2.2","@ballistix.digital/exception-types":"^0.6.0"},"_npmOperationalInternal":{"tmp":"tmp/exception-mapper_0.6.0_1790241215962_0.9151317996259789","host":"s3://npm-registry-packages-npm-production"}}},"time":{"created":"2026-09-07T18:22:28.931Z","modified":"2026-10-01T12:25:26.206Z","0.0.1":"2026-09-07T18:22:29.219Z","0.1.0":"2026-09-08T11:42:11.729Z","0.2.0":"2026-09-14T15:01:40.830Z","0.3.0":"2026-09-15T14:16:39.224Z","0.4.0":"2026-09-16T16:42:38.372Z","0.5.0":"2026-09-17T08:10:09.035Z","0.6.0":"2026-09-24T09:13:36.057Z"},"bugs":{"url":"https://github.com/layeredprints/exception-mapper/issues"},"license":"MIT","homepage":"https://github.com/layeredprints/exception-mapper#readme","repository":{"url":"git+https://github.com/layeredprints/exception-mapper.git","type":"git","directory":"exception-mapper"},"description":"A NestJS module that maps any thrown value to a coded BaseException and to the ExceptionDto envelope, for HTTP filters and task processors.","maintainers":[{"email":"brecht.pallemans@ballistix.digital","name":"brecht-p7s-ballistix"},{"email":"maarten@ballistix.digital","name":"maartenraes"},{"email":"jens@ballistix.digital","name":"jmostaer"},{"email":"aaron@ballistix.digital","name":"aaron-ballistix"},{"email":"aude@ballistix.digital","name":"aude-ballistix"},{"email":"lukas@ballistix.digital","name":"lukaskindt"}],"readme":"# @ballistix.digital/exception-mapper\n\nA NestJS module that maps any thrown value to a coded `BaseException` and to\nthe `ExceptionDto` envelope, for HTTP filters and task processors. A **mapper**\nturns one kind of thrown value into an exception, and the **registry** holds\nthe mappers in order. The exception classes, the codes and the envelope live\nin [`@ballistix.digital/exception-types`](../exception-types/README.md).\n\nThis file is the consumer guide. The pages that describe how the package is\nbuilt live in the [Ballistix wiki](https://github.com/layeredprints/ballistix-okf-wiki/blob/main/general/libraries/exception-mapper/).\n\n## Install\n\n```bash\nnpm install @ballistix.digital/exception-mapper @ballistix.digital/exception-types\n```\n\nThe package needs Node 22.12 or later. Install these peer dependencies in the\napplication.\n\n| Peer | Range |\n| --- | --- |\n| `@ballistix.digital/exception-types` | the release each published manifest pins |\n| `@nestjs/common` | `^11` |\n| `class-validator` | `^0.15.1` |\n| `typeorm` | `>=0.3.0 <2.0.0` |\n| `reflect-metadata` | `^0.2.2` |\n\nThe application throws the exception classes of the types package, and this\npackage maps to the same classes. A publish of `exception-mapper` pins the\n`exception-types` version of the same build.\n\n## Register the module\n\nRegister the module once, at the root of the application. It is global, so a\nservice in any feature module injects `ExceptionMapperRegistry` without an\nimport.\n\n```ts\nimport { Module } from '@nestjs/common';\nimport { ExceptionModule } from '@ballistix.digital/exception-mapper';\n\n@Module({\n\timports: [ExceptionModule.forRoot()],\n})\nexport class AppModule {}\n```\n\n`forRootAsync` takes the options from a factory, so a `ConfigService` can\ndecide them:\n\n```ts\nimport { Module } from '@nestjs/common';\nimport { ConfigModule, ConfigService } from '@nestjs/config';\nimport { ExceptionModule } from '@ballistix.digital/exception-mapper';\n\n@Module({\n\timports: [\n\t\tExceptionModule.forRootAsync({\n\t\t\timports: [ConfigModule],\n\t\t\tinject: [ConfigService],\n\t\t\tuseFactory: (config: ConfigService) => ({\n\t\t\t\texposeErrorDetails: config.get('EXPOSE_ERROR_DETAILS') === 'true',\n\t\t\t}),\n\t\t}),\n\t],\n})\nexport class AppModule {}\n```\n\nThe raw driver message of a `QueryFailedError` can carry SQL text and\nconstraint names. With `exposeErrorDetails` on, the database mapper adds that\nmessage as a second entry of `errors`, and the `title` stays the generic\nmessage. CAUTION: If an untrusted client reads the response, keep\n`exposeErrorDetails` off. The option is off by default.\n\n## From a thrown value to the envelope\n\nThe registry asks each mapper in one order, and the first match wins.\n\n```mermaid\nflowchart TD\n    thrown[\"a thrown value\"] --> base{\"BaseExceptionMapper<br/>supports?\"}\n    base -- yes --> same[\"the same BaseException\"]\n    base -- no --> validation{\"ValidationExceptionMapper<br/>supports?\"}\n    validation -- yes --> failed[\"ValidationFailedException<br/>400\"]\n    validation -- no --> database{\"DatabaseExceptionMapper<br/>supports?\"}\n    database -- yes --> dbError[\"DatabaseErrorException<br/>400 for SQLSTATE class 22, 23, P0<br/>500 for the rest\"]\n    database -- no --> generic[\"GenericExceptionMapper<br/>GenericErrorException<br/>the status of the value, else 500\"]\n    same --> dtoMapper[\"ExceptionDtoMapper\"]\n    failed --> dtoMapper\n    dbError --> dtoMapper\n    generic --> dtoMapper\n    dtoMapper --> envelope[\"the ExceptionDto envelope\"]\n    envelope --> retry{\"status >= 500?\"}\n    retry -- yes --> again[\"a task processor repeats the attempt\"]\n    retry -- no --> stop[\"a task processor fails the task\"]\n```\n\nLook at the last branch: the status the mappers give is also the retry rule a\ntask processor reads.\n\nThe database mapper reads the first two characters of the Postgres SQLSTATE,\nits class. Class 22 is a data exception, such as a malformed uuid. Class 23 is\nan integrity constraint violation, such as a unique or foreign key breach.\nClass P0 is a `RAISE EXCEPTION` from PL/pgSQL. All three mean the statement\nitself was wrong, which is the fault of the request, so they give 400. A\ndeadlock or a connection failure gives 500.\n\n`ValidationExceptionMapper` matches the `ValidationException` that\n`convertAndValidate` throws, and gives one detail for each field and rule that\nfailed. The `args` of a detail come from the decorator's explicit `context`\nwhen it sets one, else from the rule's own constraint values, read from the\nclass-validator metadata of the validated class. So `@Max(24)` on `months`\ngives `{ inputField: 'months', rule: 'MAX', args: { max: 24 } }` with no\nchange to the DTO.\n\n| Rule | args |\n| --- | --- |\n| `min`, `max`, `minLength`, `maxLength`, `arrayMinSize`, `arrayMaxSize`, `minDate`, `maxDate` | `{ min }` or `{ max }` |\n| `isLength`, `isByteLength` | `{ min, max }` |\n| `matches` | `{ pattern, modifiers }`, the source and flags of the RegExp |\n| `isIn`, `isNotIn`, `isEnum` | `{ values }` |\n| `isDivisibleBy` | `{ divisor }` |\n| `contains`, `notContains` | `{ seed }` |\n| `equals`, `notEquals` | `{ comparison }` |\n| any other rule with constraint values | `{ constraints: [...] }`, positional |\n| a rule without constraint values (`isString`, `isNotEmpty`) | no `args` |\n\nThe values are JSON-safe: a RegExp becomes its source and flags, a Date its\nISO string, and a function or class object is left out. An error without a\n`target` keeps the contexts only. `GenericExceptionMapper` is the fallback the registry uses when no mapper in\nthe list supports the value, so `map()` never returns `undefined`.\n\n## Write your HTTP filter\n\nThe package ships no `@Catch()` filter. Write one in the application:\n\n```ts\nimport { ArgumentsHost, Catch, ExceptionFilter } from '@nestjs/common';\nimport { ExceptionMapperRegistry } from '@ballistix.digital/exception-mapper';\nimport { Response } from 'express';\n\n@Catch()\nexport class HttpExceptionFilter implements ExceptionFilter {\n\tconstructor(private readonly registry: ExceptionMapperRegistry) {}\n\n\tpublic catch(exception: unknown, host: ArgumentsHost): void {\n\t\tconst response = host.switchToHttp().getResponse<Response>();\n\t\tconst envelope = this.registry.toExceptionDto(exception);\n\n\t\tresponse.status(envelope.status).json(envelope);\n\t}\n}\n```\n\nThe filter stays in the application, so a breakpoint on the raw thrown value\nsits in application code. What the filter logs, and what request context it\nadds, is the decision of the application. See\n[ADR 0002](https://github.com/layeredprints/ballistix-okf-wiki/blob/main/general/libraries/exception-mapper/decisions/0002-filter-stays-in-the-app.md).\n\nRegister it as the global filter:\n\n```ts\nimport { APP_FILTER } from '@nestjs/core';\n\n@Module({\n\timports: [ExceptionModule.forRoot()],\n\tproviders: [{ provide: APP_FILTER, useClass: HttpExceptionFilter }],\n})\nexport class AppModule {}\n```\n\n## Use it in a task processor\n\nA task processor has no response to write. It stores the envelope on the row,\nand the status decides whether another attempt can succeed:\n\n```ts\n@Injectable()\nexport class ReportTaskProcessor {\n\tconstructor(\n\t\tprivate readonly registry: ExceptionMapperRegistry,\n\t\tprivate readonly repository: Repository<ReportTask>,\n\t) {}\n\n\tpublic async run(task: ReportTask): Promise<void> {\n\t\ttry {\n\t\t\tawait this.build(task);\n\t\t} catch (error) {\n\t\t\tconst envelope = this.registry.toExceptionDto(error);\n\n\t\t\t// A 5xx is a server fault, so the attempt can be repeated. A 4xx is the\n\t\t\t// input's fault and repeats with the same result.\n\t\t\ttask.processingError = envelope;\n\t\t\ttask.status = envelope.status >= 500 ? TaskStatus.PENDING : TaskStatus.FAILED;\n\n\t\t\tawait this.repository.save(task);\n\t\t}\n\t}\n}\n```\n\nThe retry rule belongs to the application. This package only says which status\nthe thrown value earns.\n\n## Test with the registry\n\nThe registry is a plain class. A unit test builds it by hand, with no NestJS\nbootstrap:\n\n```ts\nconst registry = new ExceptionMapperRegistry(\n\tnew BaseExceptionMapper(),\n\tnew ValidationExceptionMapper(),\n\tnew DatabaseExceptionMapper({ exposeErrorDetails: false }),\n\tnew GenericExceptionMapper(),\n\tnew ExceptionDtoMapper(),\n);\n\nexpect(registry.toExceptionDto(new Error('boom'))).toMatchObject({\n\tcode: ExceptionCodeEnum.GENERIC_ERROR,\n\tstatus: 500,\n});\n```\n\n`DatabaseExceptionMapper` is the only mapper with a constructor argument. Pass\n`{}` when the test does not care about the driver message.\n\n## API reference\n\nEverything below comes from the package root.\n\n| Export | What it does |\n| --- | --- |\n| `ExceptionModule.forRoot(options?)` | Registers the module with options that are already known |\n| `ExceptionModule.forRootAsync(options)` | The same, with `imports`, `inject` and a `useFactory` |\n| `ExceptionModuleOptions` | `{ exposeErrorDetails?: boolean }` |\n| `ExceptionModuleAsyncOptions` | `{ imports?, inject?, useFactory }` |\n| `EXCEPTION_MODULE_OPTIONS` | The injection token of the resolved options |\n| `ExceptionMapperRegistry` | Holds the mappers in order. `map(error)` gives the exception, `toExceptionDto(error)` gives the envelope |\n| `ExceptionDtoMapper` | `map(exception)` turns one `BaseException` into the envelope |\n| `ExceptionMapper<TError>` | The interface a mapper implements: `supports(error)` and `map(error)` |\n| `BaseExceptionMapper` | Maps a `BaseException` to itself |\n| `ValidationExceptionMapper` | Maps a `ValidationException` to `ValidationFailedException` |\n| `DatabaseExceptionMapper` | Maps a TypeORM `QueryFailedError` to `DatabaseErrorException` |\n| `GenericExceptionMapper` | Maps anything else to `GenericErrorException` |\n\n## Guarantees\n\n- `toExceptionDto()` never throws. A detail that fails its own validation\n  travels raw into the envelope instead of replacing the error the caller\n  handles.\n- First match wins. The order of the mappers is a constructor argument, not a\n  search.\n- The generic mapper is the fallback for a value no mapper in the list\n  supports, so `map()` always returns a `BaseException`.\n- A validation rule with no `ValidationRuleEnum` member becomes `UNKNOWN`, so\n  a new class-validator rule cannot break the mapping.\n- The same thrown value gives the same envelope on every path. An HTTP\n  response and a stored task error read alike.\n- The package ships no filter, no logger and no HTTP dependency.\n","readmeFilename":"README.md"}