@camcima/nestjs-rfc9457 0.1.0 → 0.3.0

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
@@ -28,6 +28,7 @@ NestJS library for [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457) Problem De
28
28
  - [Async Configuration](#async-configuration)
29
29
  - [Custom Exception Types](#custom-exception-types)
30
30
  - [Validation Integration](#validation-integration)
31
+ - [Swagger / OpenAPI Integration](#swagger--openapi-integration)
31
32
  - [Advanced Usage](#advanced-usage)
32
33
  - [API Reference](#api-reference)
33
34
  - [Example Responses](#example-responses)
@@ -76,9 +77,11 @@ Extension members (arbitrary key-value pairs) are allowed for problem-type-speci
76
77
  - Four `instance` strategies: `'request-uri'`, `'uuid'`, `'none'`, or a custom callback
77
78
  - Optional catch-all mode for non-`HttpException` throwables (produces 500 Problem Details)
78
79
  - Custom `exceptionMapper` callback for full control over any exception
80
+ - Default `error`-level logging of unhandled exceptions when `catchAllExceptions: true` (override via `onUnhandled` callback)
79
81
  - `ProblemDetailsFactory` is injectable — use it directly in GraphQL, microservices, or custom filters
82
+ - Optional `@nestjs/swagger` integration: `ProblemDetailDto` and `ValidationProblemDetailDto` for OpenAPI documentation, plus a `applyProblemDetailResponses()` helper that auto-applies `@ApiResponse` decorators to all controllers under `application/problem+json`
80
83
  - Works with both Express and Fastify adapters
81
- - Zero runtime dependencies; `class-validator` is an optional peer dependency
84
+ - Zero runtime dependencies; `class-validator` and `@nestjs/swagger` are optional peer dependencies
82
85
 
83
86
  ---
84
87
 
@@ -98,12 +101,13 @@ pnpm add @camcima/nestjs-rfc9457
98
101
 
99
102
  ### Peer dependencies
100
103
 
101
- | Package | Version | Required |
102
- | ------------------ | ---------------------- | ------------------------------------ |
103
- | `@nestjs/common` | `^10.0.0 \|\| ^11.0.0` | Yes |
104
- | `@nestjs/core` | `^10.0.0 \|\| ^11.0.0` | Yes |
105
- | `reflect-metadata` | `^0.1.13 \|\| ^0.2.0` | Yes |
106
- | `class-validator` | `^0.14.0` | No (optional, for Tier 2 validation) |
104
+ | Package | Version | Required |
105
+ | ------------------ | --------------------------------- | -------------------------------------- |
106
+ | `@nestjs/common` | `^10.0.0 \|\| ^11.0.0` | Yes |
107
+ | `@nestjs/core` | `^10.0.0 \|\| ^11.0.0` | Yes |
108
+ | `reflect-metadata` | `^0.1.13 \|\| ^0.2.0` | Yes |
109
+ | `class-validator` | `^0.14.0` | No (optional, for Tier 2 validation) |
110
+ | `@nestjs/swagger` | `^7.0.0 \|\| ^8.0.0 \|\| ^11.0.0` | No (optional, for OpenAPI integration) |
107
111
 
108
112
  ---
109
113
 
@@ -257,6 +261,8 @@ When `false` (default), exceptions that are not `HttpException` instances are pa
257
261
  Rfc9457Module.forRoot({ catchAllExceptions: true });
258
262
  ```
259
263
 
264
+ **Observability:** when this branch fires (a non-`HttpException` reaches the filter and no `exceptionMapper` claims it), the library logs the exception at `error` level via NestJS's built-in `Logger` (context `Rfc9457ExceptionFilter`) before sending the generic 500. This keeps unexpected throwables visible in server logs even though the response body is intentionally bland. To redirect or replace this logging, use the [`onUnhandled`](#onunhandled) callback described below.
265
+
260
266
  ### `exceptionMapper`
261
267
 
262
268
  **Type**: `(exception: unknown, request: Rfc9457Request) => ProblemDetail | null`
@@ -281,6 +287,28 @@ Rfc9457Module.forRoot({
281
287
 
282
288
  If the returned `ProblemDetail` omits `status`, the factory falls back to `exception.getStatus()` (if it is an `HttpException`) or `500`.
283
289
 
290
+ ### `onUnhandled`
291
+
292
+ **Type**: `(exception: unknown, request: Rfc9457Request) => void` | **Default**: built-in `Logger.error(...)` (context `Rfc9457ExceptionFilter`)
293
+
294
+ Called when a non-`HttpException` reaches the catch-all branch (i.e. `catchAllExceptions: true` AND the `exceptionMapper` returned `null`). Use this to send unhandled exceptions to a structured sink (Sentry, Datadog, a custom pino child logger) or to suppress the default log entirely.
295
+
296
+ ```typescript
297
+ Rfc9457Module.forRoot({
298
+ catchAllExceptions: true,
299
+ onUnhandled: (exception, request) => {
300
+ // Route to Sentry, Datadog, etc.
301
+ sentry.captureException(exception, {
302
+ tags: { method: request.method, url: request.url },
303
+ });
304
+ },
305
+ });
306
+ ```
307
+
308
+ **The filter still sends the generic 500 Problem Details response after invoking `onUnhandled`.** This callback exists purely for observability — it never changes the HTTP response.
309
+
310
+ When `onUnhandled` is **not** provided, the library calls `Logger.error(...)` with either the exception's `stack` string or a `{ exception }` structured context (for non-`Error` values). The log context is `Rfc9457ExceptionFilter` so it can be filtered or silenced via NestJS's logger configuration.
311
+
284
312
  ### `validationExceptionMapper`
285
313
 
286
314
  **Type**: `(messages: string[], request: Rfc9457Request) => ProblemDetail`
@@ -540,6 +568,156 @@ Nested validation errors are preserved as `children` arrays matching the `class-
540
568
 
541
569
  ---
542
570
 
571
+ ## Swagger / OpenAPI Integration
572
+
573
+ The library ships optional Swagger support under a separate import path so it does not require `@nestjs/swagger` as a mandatory dependency. Install `@nestjs/swagger` as usual if you have not already:
574
+
575
+ ```bash
576
+ npm install @nestjs/swagger
577
+ ```
578
+
579
+ All Swagger-related exports are imported from the `/swagger` subpath:
580
+
581
+ ```typescript
582
+ import {
583
+ ProblemDetailDto,
584
+ ValidationProblemDetailDto,
585
+ ValidationErrorDto,
586
+ applyProblemDetailResponses,
587
+ } from '@camcima/nestjs-rfc9457/swagger';
588
+ ```
589
+
590
+ ### Auto-applying error schemas to all controllers
591
+
592
+ The `applyProblemDetailResponses()` helper uses NestJS's `DiscoveryService` to programmatically attach `@ApiResponse` decorators to every controller in your application. Responses are documented under `application/problem+json` as required by RFC 9457.
593
+
594
+ **Step 1** — Import `DiscoveryModule` in your app module:
595
+
596
+ ```typescript
597
+ import { Module } from '@nestjs/common';
598
+ import { DiscoveryModule } from '@nestjs/core';
599
+ import { Rfc9457Module } from '@camcima/nestjs-rfc9457';
600
+
601
+ @Module({
602
+ imports: [DiscoveryModule, Rfc9457Module.forRoot()],
603
+ })
604
+ export class AppModule {}
605
+ ```
606
+
607
+ **Step 2** — Call the helper inside the lazy document factory passed to `SwaggerModule.setup()`:
608
+
609
+ ```typescript
610
+ import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
611
+ import { applyProblemDetailResponses } from '@camcima/nestjs-rfc9457/swagger';
612
+
613
+ const config = new DocumentBuilder().setTitle('My API').build();
614
+
615
+ SwaggerModule.setup('/api', app, () => {
616
+ applyProblemDetailResponses(app);
617
+ return SwaggerModule.createDocument(app, config);
618
+ });
619
+ ```
620
+
621
+ By default, this documents `400` and `500` responses on every route using `ProblemDetailDto`. The generated OpenAPI spec will show `application/problem+json` as the response media type with the correct schema.
622
+
623
+ ### Options
624
+
625
+ `applyProblemDetailResponses` accepts an optional second argument:
626
+
627
+ ```typescript
628
+ interface ApplyProblemDetailResponsesOptions {
629
+ /** HTTP status codes to document. Default: [400, 500]. */
630
+ statuses?: number[];
631
+
632
+ /**
633
+ * Statuses that use ValidationProblemDetailDto (with the errors array)
634
+ * instead of the base ProblemDetailDto. Default: [].
635
+ */
636
+ validationStatuses?: number[];
637
+ }
638
+ ```
639
+
640
+ #### Documenting additional statuses
641
+
642
+ ```typescript
643
+ applyProblemDetailResponses(app, {
644
+ statuses: [400, 401, 403, 404, 500],
645
+ });
646
+ ```
647
+
648
+ #### Documenting Tier 2 structured validation errors
649
+
650
+ If you use `Rfc9457ValidationException` (Tier 2) for validation, you can tell the helper to use `ValidationProblemDetailDto` for specific statuses. This DTO includes the `errors` array of structured `ValidationErrorDto` objects:
651
+
652
+ ```typescript
653
+ applyProblemDetailResponses(app, {
654
+ statuses: [400, 500],
655
+ validationStatuses: [400],
656
+ });
657
+ ```
658
+
659
+ This documents 400 responses with the `ValidationProblemDetailDto` schema (which includes `errors: ValidationErrorDto[]`) and 500 responses with the base `ProblemDetailDto`.
660
+
661
+ ### Using DTOs manually for per-route documentation
662
+
663
+ For finer control, use the DTO classes directly with `@ApiResponse()` on individual routes:
664
+
665
+ ```typescript
666
+ import { ApiResponse } from '@nestjs/swagger';
667
+ import { ProblemDetailDto, ValidationProblemDetailDto } from '@camcima/nestjs-rfc9457/swagger';
668
+
669
+ @Get(':id')
670
+ @ApiResponse({
671
+ status: 404,
672
+ description: 'Not Found',
673
+ content: {
674
+ 'application/problem+json': {
675
+ schema: { $ref: '#/components/schemas/ProblemDetailDto' },
676
+ },
677
+ },
678
+ })
679
+ findOne(@Param('id') id: string) {
680
+ // ...
681
+ }
682
+ ```
683
+
684
+ Or more concisely using the `type` shorthand (documents as `application/json` instead of `application/problem+json`):
685
+
686
+ ```typescript
687
+ @ApiResponse({ status: 404, type: ProblemDetailDto })
688
+ ```
689
+
690
+ ### Extending DTOs for custom extension members
691
+
692
+ If your API returns extension members (additional fields beyond the five standard RFC 9457 members), extend `ProblemDetailDto` to document them:
693
+
694
+ ```typescript
695
+ import { ApiProperty } from '@nestjs/swagger';
696
+ import { ProblemDetailDto } from '@camcima/nestjs-rfc9457/swagger';
697
+
698
+ export class InsufficientFundsProblemDto extends ProblemDetailDto {
699
+ @ApiProperty({ example: 50 })
700
+ balance!: number;
701
+
702
+ @ApiProperty({ example: 100 })
703
+ required!: number;
704
+ }
705
+ ```
706
+
707
+ ### Available DTOs
708
+
709
+ | DTO | Description |
710
+ | ---------------------------- | ------------------------------------------------------------------------------------ |
711
+ | `ProblemDetailDto` | The five standard RFC 9457 fields (`type`, `title`, `status`, `detail`, `instance`) |
712
+ | `ValidationProblemDetailDto` | Extends `ProblemDetailDto` with `errors: ValidationErrorDto[]` for Tier 2 validation |
713
+ | `ValidationErrorDto` | Structured validation error (`property`, `constraints?`, `children?`) |
714
+
715
+ ### Design note
716
+
717
+ The auto-apply helper uses `ProblemDetailDto` for all statuses by default. This is intentional: a single HTTP status (e.g. 400) can produce different response shapes at runtime — a plain problem detail for non-validation errors, `errors: string[]` for Tier 1 validation, or `errors: ValidationErrorDto[]` for Tier 2 validation. The base DTO is the common denominator that is always correct. Use `validationStatuses` to opt in to the more specific schema when your application uses Tier 2 validation exclusively.
718
+
719
+ ---
720
+
543
721
  ## Advanced Usage
544
722
 
545
723
  ### Using `ProblemDetailsFactory` directly
@@ -624,6 +802,16 @@ export class MySpecialExceptionFilter extends BaseExceptionFilter {
624
802
  | `RFC9457_MODULE_OPTIONS` | Symbol | DI token for the module options |
625
803
  | `PROBLEM_CONTENT_TYPE` | Constant | `'application/problem+json'` |
626
804
 
805
+ **Swagger subpath** (`@camcima/nestjs-rfc9457/swagger`):
806
+
807
+ | Export | Kind | Description |
808
+ | ------------------------------------ | --------- | ------------------------------------------------------------------------------------- |
809
+ | `ProblemDetailDto` | Class | Swagger DTO for the five standard RFC 9457 fields |
810
+ | `ValidationProblemDetailDto` | Class | Extends `ProblemDetailDto` with `errors: ValidationErrorDto[]` |
811
+ | `ValidationErrorDto` | Class | Swagger DTO for a structured validation error (`property`, `constraints`, `children`) |
812
+ | `applyProblemDetailResponses` | Function | Auto-applies `@ApiResponse` decorators to all controllers via `DiscoveryService` |
813
+ | `ApplyProblemDetailResponsesOptions` | Interface | Options for `applyProblemDetailResponses` |
814
+
627
815
  ---
628
816
 
629
817
  ## Example Responses
@@ -767,13 +955,13 @@ Gitleaks must be [installed locally](https://github.com/gitleaks/gitleaks#instal
767
955
 
768
956
  ```bash
769
957
  # Dependency audit (production only)
770
- npm run audit:deps
958
+ pnpm run audit:deps
771
959
 
772
960
  # Secret scanning
773
- npm run audit:secrets
961
+ pnpm run audit:secrets
774
962
 
775
- # Full npm audit (all dependencies)
776
- npm audit
963
+ # Full pnpm audit (all dependencies)
964
+ pnpm audit
777
965
  ```
778
966
 
779
967
  ---
@@ -788,19 +976,19 @@ git clone https://github.com/camcima/nestjs-rfc9457.git
788
976
  cd nestjs-rfc9457
789
977
 
790
978
  # Install dependencies
791
- npm install
979
+ pnpm install
792
980
 
793
981
  # Run unit tests
794
- npm run test:unit
982
+ pnpm run test:unit
795
983
 
796
984
  # Run e2e tests
797
- npm run test:e2e
985
+ pnpm run test:e2e
798
986
 
799
987
  # Run all tests with coverage
800
- npm run test:cov
988
+ pnpm run test:cov
801
989
 
802
990
  # Build
803
- npm run build
991
+ pnpm run build
804
992
  ```
805
993
 
806
994
  This project uses [Conventional Commits](https://www.conventionalcommits.org/) enforced by commitlint, and [Lefthook](https://github.com/evilmartians/lefthook) for pre-commit hooks (lint + format on staged files).
@@ -6,6 +6,7 @@ export declare class Rfc9457ExceptionFilter extends BaseExceptionFilter {
6
6
  private readonly factory;
7
7
  private readonly options;
8
8
  private readonly adapterHost;
9
+ private readonly logger;
9
10
  constructor(factory: ProblemDetailsFactory, options: Rfc9457ModuleOptions, adapterHost: HttpAdapterHost);
10
11
  catch(exception: unknown, host: ArgumentsHost): void;
11
12
  }
@@ -11,18 +11,20 @@ var __metadata = (this && this.__metadata) || function (k, v) {
11
11
  var __param = (this && this.__param) || function (paramIndex, decorator) {
12
12
  return function (target, key) { decorator(target, key, paramIndex); }
13
13
  };
14
+ var Rfc9457ExceptionFilter_1;
14
15
  Object.defineProperty(exports, "__esModule", { value: true });
15
16
  exports.Rfc9457ExceptionFilter = void 0;
16
17
  const common_1 = require("@nestjs/common");
17
18
  const core_1 = require("@nestjs/core");
18
19
  const problem_details_factory_1 = require("./problem-details.factory");
19
20
  const rfc9457_constants_1 = require("./rfc9457.constants");
20
- let Rfc9457ExceptionFilter = class Rfc9457ExceptionFilter extends core_1.BaseExceptionFilter {
21
+ let Rfc9457ExceptionFilter = Rfc9457ExceptionFilter_1 = class Rfc9457ExceptionFilter extends core_1.BaseExceptionFilter {
21
22
  constructor(factory, options, adapterHost) {
22
23
  super(adapterHost.httpAdapter);
23
24
  this.factory = factory;
24
25
  this.options = options;
25
26
  this.adapterHost = adapterHost;
27
+ this.logger = new common_1.Logger(Rfc9457ExceptionFilter_1.name);
26
28
  }
27
29
  catch(exception, host) {
28
30
  if (host.getType() !== 'http') {
@@ -47,6 +49,18 @@ let Rfc9457ExceptionFilter = class Rfc9457ExceptionFilter extends core_1.BaseExc
47
49
  super.catch(exception, host);
48
50
  return;
49
51
  }
52
+ if (!isHttpException) {
53
+ if (this.options.onUnhandled) {
54
+ const ctx = host.switchToHttp();
55
+ this.options.onUnhandled(exception, ctx.getRequest());
56
+ }
57
+ else if (exception instanceof Error) {
58
+ this.logger.error(`Unhandled non-HTTP exception: ${exception.message}`, exception.stack);
59
+ }
60
+ else {
61
+ this.logger.error('Unhandled non-HTTP exception (non-Error value thrown)', exception);
62
+ }
63
+ }
50
64
  const ctx = host.switchToHttp();
51
65
  const request = ctx.getRequest();
52
66
  const response = ctx.getResponse();
@@ -57,7 +71,7 @@ let Rfc9457ExceptionFilter = class Rfc9457ExceptionFilter extends core_1.BaseExc
57
71
  }
58
72
  };
59
73
  exports.Rfc9457ExceptionFilter = Rfc9457ExceptionFilter;
60
- exports.Rfc9457ExceptionFilter = Rfc9457ExceptionFilter = __decorate([
74
+ exports.Rfc9457ExceptionFilter = Rfc9457ExceptionFilter = Rfc9457ExceptionFilter_1 = __decorate([
61
75
  (0, common_1.Catch)(),
62
76
  __param(1, (0, common_1.Inject)(rfc9457_constants_1.RFC9457_MODULE_OPTIONS)),
63
77
  __metadata("design:paramtypes", [problem_details_factory_1.ProblemDetailsFactory, Object, core_1.HttpAdapterHost])
@@ -1 +1 @@
1
- {"version":3,"file":"rfc9457.exception-filter.js","sourceRoot":"","sources":["../src/rfc9457.exception-filter.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAA6E;AAC7E,uCAAoE;AACpE,uEAAkE;AAClE,2DAAmF;AAI5E,IAAM,sBAAsB,GAA5B,MAAM,sBAAuB,SAAQ,0BAAmB;IAC7D,YACmB,OAA8B,EACE,OAA6B,EAC7D,WAA4B;QAE7C,KAAK,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;QAJd,YAAO,GAAP,OAAO,CAAuB;QACE,YAAO,GAAP,OAAO,CAAsB;QAC7D,gBAAW,GAAX,WAAW,CAAiB;IAG/C,CAAC;IAED,KAAK,CAAC,SAAkB,EAAE,IAAmB;QAE3C,IAAI,IAAI,CAAC,OAAO,EAAE,KAAK,MAAM,EAAE,CAAC;YAC9B,KAAK,CAAC,KAAK,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;YAC7B,OAAO;QACT,CAAC;QAED,MAAM,eAAe,GAAG,SAAS,YAAY,sBAAa,CAAC;QAK3D,IAAI,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,CAAC;YACjC,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;YAChC,MAAM,OAAO,GAAG,GAAG,CAAC,UAAU,EAAE,CAAC;YACjC,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YAChE,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,QAAQ,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;gBACnC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;gBACnF,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC;gBACjD,WAAW,CAAC,SAAS,CAAC,QAAQ,EAAE,cAAc,EAAE,wCAAoB,CAAC,CAAC;gBACtE,WAAW,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;gBAC1C,OAAO;YACT,CAAC;QACH,CAAC;QAGD,IAAI,CAAC,eAAe,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,kBAAkB,EAAE,CAAC;YACzD,KAAK,CAAC,KAAK,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;YAC7B,OAAO;QACT,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;QAChC,MAAM,OAAO,GAAG,GAAG,CAAC,UAAU,EAAE,CAAC;QACjC,MAAM,QAAQ,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;QAEnC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;QACvF,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC;QACjD,WAAW,CAAC,SAAS,CAAC,QAAQ,EAAE,cAAc,EAAE,wCAAoB,CAAC,CAAC;QACtE,WAAW,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IAC5C,CAAC;CACF,CAAA;AAlDY,wDAAsB;iCAAtB,sBAAsB;IADlC,IAAA,cAAK,GAAE;IAIH,WAAA,IAAA,eAAM,EAAC,0CAAsB,CAAC,CAAA;qCADL,+CAAqB,UAEjB,sBAAe;GAJpC,sBAAsB,CAkDlC"}
1
+ {"version":3,"file":"rfc9457.exception-filter.js","sourceRoot":"","sources":["../src/rfc9457.exception-filter.ts"],"names":[],"mappings":"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"}
@@ -24,6 +24,7 @@ export interface Rfc9457ModuleOptions {
24
24
  catchAllExceptions?: boolean;
25
25
  exceptionMapper?: (exception: unknown, request: Rfc9457Request) => ProblemDetail | null;
26
26
  validationExceptionMapper?: (messages: string[], request: Rfc9457Request) => ProblemDetail;
27
+ onUnhandled?: (exception: unknown, request: Rfc9457Request) => void;
27
28
  }
28
29
  export interface Rfc9457OptionsFactory {
29
30
  createRfc9457Options(): Promise<Rfc9457ModuleOptions> | Rfc9457ModuleOptions;
@@ -0,0 +1,6 @@
1
+ import { INestApplication } from '@nestjs/common';
2
+ export interface ApplyProblemDetailResponsesOptions {
3
+ statuses?: number[];
4
+ validationStatuses?: number[];
5
+ }
6
+ export declare function applyProblemDetailResponses(app: INestApplication, options?: ApplyProblemDetailResponsesOptions): void;
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.applyProblemDetailResponses = applyProblemDetailResponses;
37
+ const core_1 = require("@nestjs/core");
38
+ const swagger_1 = require("@nestjs/swagger");
39
+ const http = __importStar(require("http"));
40
+ const problem_detail_dto_1 = require("./problem-detail.dto");
41
+ function applyProblemDetailResponses(app, options) {
42
+ const discoveryService = app.get(core_1.DiscoveryService);
43
+ const controllers = discoveryService.getControllers();
44
+ const statuses = options?.statuses ?? [400, 500];
45
+ const validationStatuses = new Set(options?.validationStatuses ?? []);
46
+ for (const controller of controllers) {
47
+ if (!controller.metatype)
48
+ continue;
49
+ (0, swagger_1.ApiExtraModels)(problem_detail_dto_1.ProblemDetailDto, problem_detail_dto_1.ValidationProblemDetailDto)(controller.metatype);
50
+ for (const status of statuses) {
51
+ const dtoClass = validationStatuses.has(status)
52
+ ? problem_detail_dto_1.ValidationProblemDetailDto
53
+ : problem_detail_dto_1.ProblemDetailDto;
54
+ (0, swagger_1.ApiResponse)({
55
+ status,
56
+ description: http.STATUS_CODES[status],
57
+ content: {
58
+ 'application/problem+json': {
59
+ schema: { $ref: (0, swagger_1.getSchemaPath)(dtoClass) },
60
+ },
61
+ },
62
+ })(controller.metatype);
63
+ }
64
+ }
65
+ }
66
+ //# sourceMappingURL=apply-problem-detail-responses.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply-problem-detail-responses.js","sourceRoot":"","sources":["../../src/swagger/apply-problem-detail-responses.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2CA,kEA8BC;AAxED,uCAAgD;AAChD,6CAA6E;AAC7E,2CAA6B;AAC7B,6DAAoF;AAuCpF,SAAgB,2BAA2B,CACzC,GAAqB,EACrB,OAA4C;IAE5C,MAAM,gBAAgB,GAAG,GAAG,CAAC,GAAG,CAAC,uBAAgB,CAAC,CAAC;IACnD,MAAM,WAAW,GAAG,gBAAgB,CAAC,cAAc,EAAE,CAAC;IACtD,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACjD,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC,OAAO,EAAE,kBAAkB,IAAI,EAAE,CAAC,CAAC;IAEtE,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;QACrC,IAAI,CAAC,UAAU,CAAC,QAAQ;YAAE,SAAS;QAEnC,IAAA,wBAAc,EAAC,qCAAgB,EAAE,+CAA0B,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAElF,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;YAC9B,MAAM,QAAQ,GAAG,kBAAkB,CAAC,GAAG,CAAC,MAAM,CAAC;gBAC7C,CAAC,CAAC,+CAA0B;gBAC5B,CAAC,CAAC,qCAAgB,CAAC;YAErB,IAAA,qBAAW,EAAC;gBACV,MAAM;gBACN,WAAW,EAAE,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;gBACtC,OAAO,EAAE;oBACP,0BAA0B,EAAE;wBAC1B,MAAM,EAAE,EAAE,IAAI,EAAE,IAAA,uBAAa,EAAC,QAAQ,CAAC,EAAE;qBAC1C;iBACF;aACF,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { ProblemDetailDto, ValidationErrorDto, ValidationProblemDetailDto, } from './problem-detail.dto';
2
+ export { applyProblemDetailResponses, ApplyProblemDetailResponsesOptions, } from './apply-problem-detail-responses';
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.applyProblemDetailResponses = exports.ValidationProblemDetailDto = exports.ValidationErrorDto = exports.ProblemDetailDto = void 0;
4
+ var problem_detail_dto_1 = require("./problem-detail.dto");
5
+ Object.defineProperty(exports, "ProblemDetailDto", { enumerable: true, get: function () { return problem_detail_dto_1.ProblemDetailDto; } });
6
+ Object.defineProperty(exports, "ValidationErrorDto", { enumerable: true, get: function () { return problem_detail_dto_1.ValidationErrorDto; } });
7
+ Object.defineProperty(exports, "ValidationProblemDetailDto", { enumerable: true, get: function () { return problem_detail_dto_1.ValidationProblemDetailDto; } });
8
+ var apply_problem_detail_responses_1 = require("./apply-problem-detail-responses");
9
+ Object.defineProperty(exports, "applyProblemDetailResponses", { enumerable: true, get: function () { return apply_problem_detail_responses_1.applyProblemDetailResponses; } });
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/swagger/index.ts"],"names":[],"mappings":";;;AAAA,2DAI8B;AAH5B,sHAAA,gBAAgB,OAAA;AAChB,wHAAA,kBAAkB,OAAA;AAClB,gIAAA,0BAA0B,OAAA;AAE5B,mFAG0C;AAFxC,6IAAA,2BAA2B,OAAA"}
@@ -0,0 +1,15 @@
1
+ export declare class ProblemDetailDto {
2
+ type?: string;
3
+ title?: string;
4
+ status: number;
5
+ detail?: string;
6
+ instance?: string;
7
+ }
8
+ export declare class ValidationErrorDto {
9
+ property: string;
10
+ constraints?: Record<string, string>;
11
+ children?: ValidationErrorDto[];
12
+ }
13
+ export declare class ValidationProblemDetailDto extends ProblemDetailDto {
14
+ errors: ValidationErrorDto[];
15
+ }
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
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
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
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
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.ValidationProblemDetailDto = exports.ValidationErrorDto = exports.ProblemDetailDto = void 0;
13
+ const swagger_1 = require("@nestjs/swagger");
14
+ class ProblemDetailDto {
15
+ }
16
+ exports.ProblemDetailDto = ProblemDetailDto;
17
+ __decorate([
18
+ (0, swagger_1.ApiPropertyOptional)({
19
+ description: 'A URI reference that identifies the problem type.',
20
+ example: 'about:blank',
21
+ }),
22
+ __metadata("design:type", String)
23
+ ], ProblemDetailDto.prototype, "type", void 0);
24
+ __decorate([
25
+ (0, swagger_1.ApiPropertyOptional)({
26
+ description: 'A short, human-readable summary of the problem type.',
27
+ example: 'Not Found',
28
+ }),
29
+ __metadata("design:type", String)
30
+ ], ProblemDetailDto.prototype, "title", void 0);
31
+ __decorate([
32
+ (0, swagger_1.ApiProperty)({
33
+ description: 'The HTTP status code generated by the origin server.',
34
+ example: 404,
35
+ }),
36
+ __metadata("design:type", Number)
37
+ ], ProblemDetailDto.prototype, "status", void 0);
38
+ __decorate([
39
+ (0, swagger_1.ApiPropertyOptional)({
40
+ description: 'A human-readable explanation specific to this occurrence.',
41
+ example: 'The requested resource was not found.',
42
+ }),
43
+ __metadata("design:type", String)
44
+ ], ProblemDetailDto.prototype, "detail", void 0);
45
+ __decorate([
46
+ (0, swagger_1.ApiPropertyOptional)({
47
+ description: 'A URI reference that identifies the specific occurrence.',
48
+ }),
49
+ __metadata("design:type", String)
50
+ ], ProblemDetailDto.prototype, "instance", void 0);
51
+ class ValidationErrorDto {
52
+ }
53
+ exports.ValidationErrorDto = ValidationErrorDto;
54
+ __decorate([
55
+ (0, swagger_1.ApiProperty)({
56
+ description: 'The property that failed validation.',
57
+ example: 'email',
58
+ }),
59
+ __metadata("design:type", String)
60
+ ], ValidationErrorDto.prototype, "property", void 0);
61
+ __decorate([
62
+ (0, swagger_1.ApiPropertyOptional)({
63
+ description: 'Constraint name → error message map.',
64
+ example: { isEmail: 'email must be an email' },
65
+ type: 'object',
66
+ additionalProperties: { type: 'string' },
67
+ }),
68
+ __metadata("design:type", Object)
69
+ ], ValidationErrorDto.prototype, "constraints", void 0);
70
+ __decorate([
71
+ (0, swagger_1.ApiPropertyOptional)({
72
+ description: 'Nested validation errors for child properties.',
73
+ type: () => [ValidationErrorDto],
74
+ }),
75
+ __metadata("design:type", Array)
76
+ ], ValidationErrorDto.prototype, "children", void 0);
77
+ class ValidationProblemDetailDto extends ProblemDetailDto {
78
+ }
79
+ exports.ValidationProblemDetailDto = ValidationProblemDetailDto;
80
+ __decorate([
81
+ (0, swagger_1.ApiProperty)({
82
+ description: 'Structured validation errors.',
83
+ type: [ValidationErrorDto],
84
+ }),
85
+ __metadata("design:type", Array)
86
+ ], ValidationProblemDetailDto.prototype, "errors", void 0);
87
+ //# sourceMappingURL=problem-detail.dto.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"problem-detail.dto.js","sourceRoot":"","sources":["../../src/swagger/problem-detail.dto.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,6CAAmE;AASnE,MAAa,gBAAgB;CA6B5B;AA7BD,4CA6BC;AAxBC;IAJC,IAAA,6BAAmB,EAAC;QACnB,WAAW,EAAE,mDAAmD;QAChE,OAAO,EAAE,aAAa;KACvB,CAAC;;8CACY;AAMd;IAJC,IAAA,6BAAmB,EAAC;QACnB,WAAW,EAAE,sDAAsD;QACnE,OAAO,EAAE,WAAW;KACrB,CAAC;;+CACa;AAMf;IAJC,IAAA,qBAAW,EAAC;QACX,WAAW,EAAE,sDAAsD;QACnE,OAAO,EAAE,GAAG;KACb,CAAC;;gDACc;AAMhB;IAJC,IAAA,6BAAmB,EAAC;QACnB,WAAW,EAAE,2DAA2D;QACxE,OAAO,EAAE,uCAAuC;KACjD,CAAC;;gDACc;AAKhB;IAHC,IAAA,6BAAmB,EAAC;QACnB,WAAW,EAAE,0DAA0D;KACxE,CAAC;;kDACgB;AAOpB,MAAa,kBAAkB;CAoB9B;AApBD,gDAoBC;AAfC;IAJC,IAAA,qBAAW,EAAC;QACX,WAAW,EAAE,sCAAsC;QACnD,OAAO,EAAE,OAAO;KACjB,CAAC;;oDACgB;AAQlB;IANC,IAAA,6BAAmB,EAAC;QACnB,WAAW,EAAE,sCAAsC;QACnD,OAAO,EAAE,EAAE,OAAO,EAAE,wBAAwB,EAAE;QAC9C,IAAI,EAAE,QAAQ;QACd,oBAAoB,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;KACzC,CAAC;;uDACmC;AAMrC;IAJC,IAAA,6BAAmB,EAAC;QACnB,WAAW,EAAE,gDAAgD;QAC7D,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,kBAAkB,CAAC;KACjC,CAAC;;oDAC8B;AAclC,MAAa,0BAA2B,SAAQ,gBAAgB;CAM/D;AAND,gEAMC;AADC;IAJC,IAAA,qBAAW,EAAC;QACX,WAAW,EAAE,+BAA+B;QAC5C,IAAI,EAAE,CAAC,kBAAkB,CAAC;KAC3B,CAAC;;0DAC4B"}
package/package.json CHANGED
@@ -1,17 +1,28 @@
1
1
  {
2
2
  "name": "@camcima/nestjs-rfc9457",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "NestJS library for RFC 9457 Problem Details responses",
5
5
  "author": "Carlos Cima",
6
6
  "license": "MIT",
7
7
  "main": "dist/index.js",
8
8
  "types": "dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "default": "./dist/index.js"
13
+ },
14
+ "./swagger": {
15
+ "types": "./dist/swagger/index.d.ts",
16
+ "default": "./dist/swagger/index.js"
17
+ }
18
+ },
9
19
  "files": [
10
20
  "dist"
11
21
  ],
12
22
  "engines": {
13
23
  "node": ">=18"
14
24
  },
25
+ "packageManager": "pnpm@9.15.0",
15
26
  "scripts": {
16
27
  "build": "tsc -p tsconfig.build.json",
17
28
  "lint": "eslint 'src/**/*.ts' 'test/**/*.ts'",
@@ -21,32 +32,37 @@
21
32
  "test:unit": "jest --testPathPattern=test/unit",
22
33
  "test:e2e": "jest --testPathPattern=test/e2e",
23
34
  "test:cov": "jest --coverage",
24
- "prepublishOnly": "npm run build",
35
+ "prepublishOnly": "pnpm run build",
25
36
  "release": "release-it",
26
- "audit:deps": "npm audit --omit=dev",
37
+ "audit:deps": "pnpm audit --prod",
27
38
  "audit:secrets": "gitleaks git --no-banner --redact -v"
28
39
  },
29
40
  "peerDependencies": {
30
41
  "@nestjs/common": "^10.0.0 || ^11.0.0",
31
42
  "@nestjs/core": "^10.0.0 || ^11.0.0",
43
+ "@nestjs/swagger": "^7.0.0 || ^8.0.0 || ^11.0.0",
32
44
  "class-validator": "^0.14.0",
33
45
  "reflect-metadata": "^0.1.13 || ^0.2.0"
34
46
  },
35
47
  "peerDependenciesMeta": {
36
48
  "class-validator": {
37
49
  "optional": true
50
+ },
51
+ "@nestjs/swagger": {
52
+ "optional": true
38
53
  }
39
54
  },
40
55
  "devDependencies": {
41
56
  "@commitlint/cli": "^20.5.0",
42
57
  "@commitlint/config-conventional": "^20.5.0",
43
- "@nestjs/common": "^11.1.18",
44
- "@nestjs/core": "^11.1.18",
45
- "@nestjs/platform-express": "^11.1.18",
46
- "@nestjs/platform-fastify": "^11.1.18",
47
- "@nestjs/testing": "^11.1.18",
58
+ "@nestjs/common": "^11.1.19",
59
+ "@nestjs/core": "^11.1.19",
60
+ "@nestjs/platform-express": "^11.1.19",
61
+ "@nestjs/platform-fastify": "^11.1.19",
62
+ "@nestjs/swagger": "^11.2.7",
63
+ "@nestjs/testing": "^11.1.19",
48
64
  "@types/jest": "^30.0.0",
49
- "@types/node": "^22.19.17",
65
+ "@types/node": "^25.6.0",
50
66
  "@types/supertest": "^7.2.0",
51
67
  "@typescript-eslint/eslint-plugin": "^7.0.0",
52
68
  "@typescript-eslint/parser": "^7.0.0",
@@ -55,10 +71,9 @@
55
71
  "eslint": "^8.0.0",
56
72
  "eslint-config-prettier": "^9.0.0",
57
73
  "eslint-plugin-prettier": "^5.0.0",
58
- "fastify": "^4.0.0",
59
74
  "jest": "^30.3.0",
60
75
  "lefthook": "^1.0.0",
61
- "prettier": "^3.0.0",
76
+ "prettier": "^3.8.3",
62
77
  "reflect-metadata": "^0.2.0",
63
78
  "release-it": "^18.0.0",
64
79
  "rxjs": "^7.0.0",
@@ -67,6 +82,15 @@
67
82
  "ts-node": "^10.9.2",
68
83
  "typescript": "^6.0.2"
69
84
  },
85
+ "pnpm": {
86
+ "overrides": {
87
+ "basic-ftp@<5.3.0": ">=5.3.0",
88
+ "fastify@<5.8.5": ">=5.8.5",
89
+ "lodash@<4.18.0": ">=4.18.0",
90
+ "path-to-regexp@<8.4.0": ">=8.4.0",
91
+ "undici@<6.24.0": ">=6.24.0"
92
+ }
93
+ },
70
94
  "repository": {
71
95
  "type": "git",
72
96
  "url": "git+https://github.com/camcima/nestjs-rfc9457.git"