nestjs-api-forge 1.0.1

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.
Files changed (54) hide show
  1. package/README.md +221 -0
  2. package/dist/api-forge.module.d.ts +11 -0
  3. package/dist/api-forge.module.js +70 -0
  4. package/dist/api-forge.module.js.map +1 -0
  5. package/dist/decorators/api-response.decorator.d.ts +6 -0
  6. package/dist/decorators/api-response.decorator.js +19 -0
  7. package/dist/decorators/api-response.decorator.js.map +1 -0
  8. package/dist/decorators/index.d.ts +1 -0
  9. package/dist/decorators/index.js +18 -0
  10. package/dist/decorators/index.js.map +1 -0
  11. package/dist/dto/api-response.dto.d.ts +7 -0
  12. package/dist/dto/api-response.dto.js +37 -0
  13. package/dist/dto/api-response.dto.js.map +1 -0
  14. package/dist/dto/index.d.ts +1 -0
  15. package/dist/dto/index.js +18 -0
  16. package/dist/dto/index.js.map +1 -0
  17. package/dist/exceptions/api.exception.d.ts +34 -0
  18. package/dist/exceptions/api.exception.js +67 -0
  19. package/dist/exceptions/api.exception.js.map +1 -0
  20. package/dist/exceptions/index.d.ts +2 -0
  21. package/dist/exceptions/index.js +19 -0
  22. package/dist/exceptions/index.js.map +1 -0
  23. package/dist/exceptions/validation.exception.d.ts +6 -0
  24. package/dist/exceptions/validation.exception.js +19 -0
  25. package/dist/exceptions/validation.exception.js.map +1 -0
  26. package/dist/filters/global-exception.filter.d.ts +12 -0
  27. package/dist/filters/global-exception.filter.js +93 -0
  28. package/dist/filters/global-exception.filter.js.map +1 -0
  29. package/dist/filters/index.d.ts +1 -0
  30. package/dist/filters/index.js +18 -0
  31. package/dist/filters/index.js.map +1 -0
  32. package/dist/index.d.ts +8 -0
  33. package/dist/index.js +25 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/interceptors/index.d.ts +1 -0
  36. package/dist/interceptors/index.js +18 -0
  37. package/dist/interceptors/index.js.map +1 -0
  38. package/dist/interceptors/response.interceptor.d.ts +11 -0
  39. package/dist/interceptors/response.interceptor.js +52 -0
  40. package/dist/interceptors/response.interceptor.js.map +1 -0
  41. package/dist/interfaces/api-response.interface.d.ts +36 -0
  42. package/dist/interfaces/api-response.interface.js +3 -0
  43. package/dist/interfaces/api-response.interface.js.map +1 -0
  44. package/dist/interfaces/index.d.ts +1 -0
  45. package/dist/interfaces/index.js +18 -0
  46. package/dist/interfaces/index.js.map +1 -0
  47. package/dist/tsconfig.build.tsbuildinfo +1 -0
  48. package/dist/utils/error-code.util.d.ts +3 -0
  49. package/dist/utils/error-code.util.js +37 -0
  50. package/dist/utils/error-code.util.js.map +1 -0
  51. package/dist/utils/index.d.ts +1 -0
  52. package/dist/utils/index.js +18 -0
  53. package/dist/utils/index.js.map +1 -0
  54. package/package.json +52 -0
package/README.md ADDED
@@ -0,0 +1,221 @@
1
+ # nestjs-api-forge
2
+
3
+ Standardized API response formatting, structured error handling, and exception filters for [NestJS](https://nestjs.com/) applications.
4
+
5
+ ## Features
6
+
7
+ - **Uniform success response** envelope wrapping all handler return values
8
+ - **Structured error responses** with `code`, `message`, and optional `details` array
9
+ - **Global exception filter** that handles `HttpException`, `ValidationPipe` errors, and unexpected exceptions
10
+ - **Built-in typed exceptions** (`NotFoundException`, `UnauthorizedException`, `ValidationException`, etc.)
11
+ - **`@ForgeMessage`** decorator to override per-route success messages
12
+ - **`@ForgeRawResponse`** decorator to opt a route out of wrapping
13
+ - **`ApiForgeModule.forRoot()`** for one-line global registration
14
+ - **`ApiForgeModule.forRootAsync()`** for config-service-driven options
15
+
16
+ ---
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ npm install nestjs-api-forge
22
+ ```
23
+
24
+ ---
25
+
26
+ ## Quick Start
27
+
28
+ ### 1. Register globally (`app.module.ts`)
29
+
30
+ ```typescript
31
+ import { Module } from '@nestjs/common';
32
+ import { ApiForgeModule } from 'nestjs-api-forge';
33
+
34
+ @Module({
35
+ imports: [
36
+ ApiForgeModule.forRoot({
37
+ version: '1.0',
38
+ defaultSuccessMessage: 'OK',
39
+ includePath: true,
40
+ includeTimestamp: true,
41
+ }),
42
+ ],
43
+ })
44
+ export class AppModule {}
45
+ ```
46
+
47
+ Every route in your application will now return a standardized response automatically.
48
+
49
+ ---
50
+
51
+ ## Response Formats
52
+
53
+ ### Success
54
+
55
+ ```json
56
+ {
57
+ "success": true,
58
+ "statusCode": 200,
59
+ "message": "Request successful",
60
+ "data": { "id": 1, "name": "Alice" },
61
+ "meta": {
62
+ "timestamp": "2026-05-02T10:00:00.000Z",
63
+ "path": "/api/users/1",
64
+ "version": "1.0"
65
+ }
66
+ }
67
+ ```
68
+
69
+ ### Error
70
+
71
+ ```json
72
+ {
73
+ "success": false,
74
+ "statusCode": 404,
75
+ "message": "User not found",
76
+ "error": {
77
+ "code": "NOT_FOUND"
78
+ },
79
+ "meta": {
80
+ "timestamp": "2026-05-02T10:00:00.000Z",
81
+ "path": "/api/users/99",
82
+ "version": "1.0"
83
+ }
84
+ }
85
+ ```
86
+
87
+ ### Validation Error (from `ValidationPipe`)
88
+
89
+ ```json
90
+ {
91
+ "success": false,
92
+ "statusCode": 400,
93
+ "message": "Validation failed",
94
+ "error": {
95
+ "code": "VALIDATION_ERROR",
96
+ "details": [
97
+ { "field": "email", "message": "must be an email" },
98
+ { "field": "password", "message": "must be longer than 8 characters" }
99
+ ]
100
+ },
101
+ "meta": {
102
+ "timestamp": "2026-05-02T10:00:00.000Z",
103
+ "path": "/api/auth/register"
104
+ }
105
+ }
106
+ ```
107
+
108
+ ---
109
+
110
+ ## API Reference
111
+
112
+ ### `ApiForgeModule.forRoot(options?)`
113
+
114
+ | Option | Type | Default | Description |
115
+ |---|---|---|---|
116
+ | `includePath` | `boolean` | `true` | Include request path in `meta` |
117
+ | `includeTimestamp` | `boolean` | `true` | Include ISO timestamp in `meta` |
118
+ | `version` | `string` | `undefined` | API version string added to `meta` |
119
+ | `defaultSuccessMessage` | `string` | `'Request successful'` | Default success message |
120
+
121
+ ### Decorators
122
+
123
+ | Decorator | Scope | Description |
124
+ |---|---|---|
125
+ | `@ApiForge(options?)` | Controller / Method | Apply filter + interceptor to a single controller or method |
126
+ | `@ForgeMessage(msg)` | Controller / Method | Override the success message for that route |
127
+ | `@ForgeRawResponse()` | Controller / Method | Skip response wrapping; return handler value as-is |
128
+
129
+ ### Built-in Exceptions
130
+
131
+ All exceptions extend `ApiException` which extends NestJS's `HttpException`.
132
+
133
+ | Class | Status | Code |
134
+ |---|---|---|
135
+ | `BadRequestException` | 400 | `BAD_REQUEST` |
136
+ | `UnauthorizedException` | 401 | `UNAUTHORIZED` |
137
+ | `ForbiddenException` | 403 | `FORBIDDEN` |
138
+ | `NotFoundException` | 404 | `NOT_FOUND` |
139
+ | `ConflictException` | 409 | `CONFLICT` |
140
+ | `UnprocessableEntityException` | 422 | `UNPROCESSABLE_ENTITY` |
141
+ | `TooManyRequestsException` | 429 | `TOO_MANY_REQUESTS` |
142
+ | `InternalServerException` | 500 | `INTERNAL_SERVER_ERROR` |
143
+ | `ServiceUnavailableException` | 503 | `SERVICE_UNAVAILABLE` |
144
+ | `ValidationException` | 400 | `VALIDATION_ERROR` |
145
+
146
+ ### `ApiResponseDto` (manual usage)
147
+
148
+ ```typescript
149
+ import { ApiResponseDto } from 'nestjs-api-forge';
150
+
151
+ ApiResponseDto.success(data, 'User fetched', 200, { path: '/users/1' });
152
+ ApiResponseDto.created(data, 'User created');
153
+ ApiResponseDto.noContent('Deleted');
154
+ ApiResponseDto.error('Not found', 404, { code: 'NOT_FOUND' });
155
+ ```
156
+
157
+ ---
158
+
159
+ ## Usage Examples
160
+
161
+ ### Controller with custom message
162
+
163
+ ```typescript
164
+ import { Controller, Get, Param } from '@nestjs/common';
165
+ import { ForgeMessage, NotFoundException } from 'nestjs-api-forge';
166
+
167
+ @Controller('users')
168
+ export class UsersController {
169
+ @Get(':id')
170
+ @ForgeMessage('User fetched successfully')
171
+ findOne(@Param('id') id: string) {
172
+ const user = this.usersService.findById(+id);
173
+ if (!user) throw new NotFoundException('User');
174
+ return user;
175
+ }
176
+ }
177
+ ```
178
+
179
+ ### Skip wrapping for a specific route
180
+
181
+ ```typescript
182
+ @Get('health')
183
+ @ForgeRawResponse()
184
+ healthCheck() {
185
+ return { status: 'ok' };
186
+ }
187
+ ```
188
+
189
+ ### Async module registration (with ConfigService)
190
+
191
+ ```typescript
192
+ ApiForgeModule.forRootAsync({
193
+ imports: [ConfigModule],
194
+ inject: [ConfigService],
195
+ useFactory: (config: ConfigService) => ({
196
+ version: config.get('API_VERSION'),
197
+ defaultSuccessMessage: config.get('DEFAULT_SUCCESS_MSG'),
198
+ }),
199
+ })
200
+ ```
201
+
202
+ ### Use with `ValidationPipe`
203
+
204
+ ```typescript
205
+ // main.ts
206
+ app.useGlobalPipes(
207
+ new ValidationPipe({
208
+ whitelist: true,
209
+ forbidNonWhitelisted: true,
210
+ transform: true,
211
+ }),
212
+ );
213
+ ```
214
+
215
+ The exception filter automatically parses `ValidationPipe` error arrays and formats them into `error.details`.
216
+
217
+ ---
218
+
219
+ ## License
220
+
221
+ MIT
@@ -0,0 +1,11 @@
1
+ import { DynamicModule } from '@nestjs/common';
2
+ import { ForgeOptions } from './interfaces/api-response.interface';
3
+ export declare const FORGE_OPTIONS = "FORGE_OPTIONS";
4
+ export declare class ApiForgeModule {
5
+ static forRoot(options?: ForgeOptions): DynamicModule;
6
+ static forRootAsync(asyncOptions: {
7
+ useFactory: (...args: any[]) => ForgeOptions | Promise<ForgeOptions>;
8
+ inject?: any[];
9
+ imports?: any[];
10
+ }): DynamicModule;
11
+ }
@@ -0,0 +1,70 @@
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 ApiForgeModule_1;
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.ApiForgeModule = exports.FORGE_OPTIONS = void 0;
11
+ const common_1 = require("@nestjs/common");
12
+ const core_1 = require("@nestjs/core");
13
+ const global_exception_filter_1 = require("./filters/global-exception.filter");
14
+ const response_interceptor_1 = require("./interceptors/response.interceptor");
15
+ exports.FORGE_OPTIONS = 'FORGE_OPTIONS';
16
+ let ApiForgeModule = ApiForgeModule_1 = class ApiForgeModule {
17
+ static forRoot(options = {}) {
18
+ const optionsProvider = {
19
+ provide: exports.FORGE_OPTIONS,
20
+ useValue: options,
21
+ };
22
+ const exceptionFilterProvider = {
23
+ provide: core_1.APP_FILTER,
24
+ useFactory: () => new global_exception_filter_1.ForgeExceptionFilter(options),
25
+ };
26
+ const responseInterceptorProvider = {
27
+ provide: core_1.APP_INTERCEPTOR,
28
+ useFactory: (reflector) => new response_interceptor_1.ForgeResponseInterceptor(reflector, options),
29
+ inject: [core_1.Reflector],
30
+ };
31
+ return {
32
+ module: ApiForgeModule_1,
33
+ providers: [
34
+ optionsProvider,
35
+ exceptionFilterProvider,
36
+ responseInterceptorProvider,
37
+ ],
38
+ exports: [exports.FORGE_OPTIONS],
39
+ };
40
+ }
41
+ static forRootAsync(asyncOptions) {
42
+ const exceptionFilterProvider = {
43
+ provide: core_1.APP_FILTER,
44
+ useFactory: async (...args) => {
45
+ const options = await asyncOptions.useFactory(...args);
46
+ return new global_exception_filter_1.ForgeExceptionFilter(options);
47
+ },
48
+ inject: asyncOptions.inject ?? [],
49
+ };
50
+ const responseInterceptorProvider = {
51
+ provide: core_1.APP_INTERCEPTOR,
52
+ useFactory: async (reflector, ...args) => {
53
+ const options = await asyncOptions.useFactory(...args);
54
+ return new response_interceptor_1.ForgeResponseInterceptor(reflector, options);
55
+ },
56
+ inject: [core_1.Reflector, ...(asyncOptions.inject ?? [])],
57
+ };
58
+ return {
59
+ module: ApiForgeModule_1,
60
+ imports: asyncOptions.imports ?? [],
61
+ providers: [exceptionFilterProvider, responseInterceptorProvider],
62
+ };
63
+ }
64
+ };
65
+ exports.ApiForgeModule = ApiForgeModule;
66
+ exports.ApiForgeModule = ApiForgeModule = ApiForgeModule_1 = __decorate([
67
+ (0, common_1.Global)(),
68
+ (0, common_1.Module)({})
69
+ ], ApiForgeModule);
70
+ //# sourceMappingURL=api-forge.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-forge.module.js","sourceRoot":"","sources":["../src/api-forge.module.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,2CAAyE;AACzE,uCAAsE;AACtE,+EAAyE;AACzE,8EAA+E;AAGlE,QAAA,aAAa,GAAG,eAAe,CAAC;AAItC,IAAM,cAAc,sBAApB,MAAM,cAAc;IAKzB,MAAM,CAAC,OAAO,CAAC,UAAwB,EAAE;QACvC,MAAM,eAAe,GAAa;YAChC,OAAO,EAAE,qBAAa;YACtB,QAAQ,EAAE,OAAO;SAClB,CAAC;QAEF,MAAM,uBAAuB,GAAa;YACxC,OAAO,EAAE,iBAAU;YACnB,UAAU,EAAE,GAAG,EAAE,CAAC,IAAI,8CAAoB,CAAC,OAAO,CAAC;SACpD,CAAC;QAEF,MAAM,2BAA2B,GAAa;YAC5C,OAAO,EAAE,sBAAe;YACxB,UAAU,EAAE,CAAC,SAAoB,EAAE,EAAE,CACnC,IAAI,+CAAwB,CAAC,SAAS,EAAE,OAAO,CAAC;YAClD,MAAM,EAAE,CAAC,gBAAS,CAAC;SACpB,CAAC;QAEF,OAAO;YACL,MAAM,EAAE,gBAAc;YACtB,SAAS,EAAE;gBACT,eAAe;gBACf,uBAAuB;gBACvB,2BAA2B;aAC5B;YACD,OAAO,EAAE,CAAC,qBAAa,CAAC;SACzB,CAAC;IACJ,CAAC;IAKD,MAAM,CAAC,YAAY,CAAC,YAInB;QACC,MAAM,uBAAuB,GAAa;YACxC,OAAO,EAAE,iBAAU;YACnB,UAAU,EAAE,KAAK,EAAE,GAAG,IAAW,EAAE,EAAE;gBACnC,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC,CAAC;gBACvD,OAAO,IAAI,8CAAoB,CAAC,OAAO,CAAC,CAAC;YAC3C,CAAC;YACD,MAAM,EAAE,YAAY,CAAC,MAAM,IAAI,EAAE;SAClC,CAAC;QAEF,MAAM,2BAA2B,GAAa;YAC5C,OAAO,EAAE,sBAAe;YACxB,UAAU,EAAE,KAAK,EAAE,SAAoB,EAAE,GAAG,IAAW,EAAE,EAAE;gBACzD,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC,CAAC;gBACvD,OAAO,IAAI,+CAAwB,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YAC1D,CAAC;YACD,MAAM,EAAE,CAAC,gBAAS,EAAE,GAAG,CAAC,YAAY,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;SACpD,CAAC;QAEF,OAAO;YACL,MAAM,EAAE,gBAAc;YACtB,OAAO,EAAE,YAAY,CAAC,OAAO,IAAI,EAAE;YACnC,SAAS,EAAE,CAAC,uBAAuB,EAAE,2BAA2B,CAAC;SAClE,CAAC;IACJ,CAAC;CACF,CAAA;AAlEY,wCAAc;yBAAd,cAAc;IAF1B,IAAA,eAAM,GAAE;IACR,IAAA,eAAM,EAAC,EAAE,CAAC;GACE,cAAc,CAkE1B"}
@@ -0,0 +1,6 @@
1
+ import { ForgeOptions } from '../interfaces/api-response.interface';
2
+ export declare const FORGE_MESSAGE_KEY = "forge:response_message";
3
+ export declare const FORGE_RAW_RESPONSE_KEY = "forge:raw_response";
4
+ export declare const ForgeMessage: (message: string) => import("@nestjs/common").CustomDecorator<string>;
5
+ export declare const ForgeRawResponse: () => import("@nestjs/common").CustomDecorator<string>;
6
+ export declare function ApiForge(options?: ForgeOptions): <TFunction extends Function, Y>(target: TFunction | object, propertyKey?: string | symbol, descriptor?: TypedPropertyDescriptor<Y>) => void;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ForgeRawResponse = exports.ForgeMessage = exports.FORGE_RAW_RESPONSE_KEY = exports.FORGE_MESSAGE_KEY = void 0;
4
+ exports.ApiForge = ApiForge;
5
+ const common_1 = require("@nestjs/common");
6
+ const core_1 = require("@nestjs/core");
7
+ const response_interceptor_1 = require("../interceptors/response.interceptor");
8
+ const global_exception_filter_1 = require("../filters/global-exception.filter");
9
+ exports.FORGE_MESSAGE_KEY = 'forge:response_message';
10
+ exports.FORGE_RAW_RESPONSE_KEY = 'forge:raw_response';
11
+ const ForgeMessage = (message) => (0, common_1.SetMetadata)(exports.FORGE_MESSAGE_KEY, message);
12
+ exports.ForgeMessage = ForgeMessage;
13
+ const ForgeRawResponse = () => (0, common_1.SetMetadata)(exports.FORGE_RAW_RESPONSE_KEY, true);
14
+ exports.ForgeRawResponse = ForgeRawResponse;
15
+ function ApiForge(options = {}) {
16
+ const reflector = new core_1.Reflector();
17
+ return (0, common_1.applyDecorators)((0, common_1.UseInterceptors)(new response_interceptor_1.ForgeResponseInterceptor(reflector, options)), (0, common_1.UseFilters)(new global_exception_filter_1.ForgeExceptionFilter(options)));
18
+ }
19
+ //# sourceMappingURL=api-response.decorator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-response.decorator.js","sourceRoot":"","sources":["../../src/decorators/api-response.decorator.ts"],"names":[],"mappings":";;;AAoBA,4BAMC;AA1BD,2CAA2F;AAC3F,uCAAyC;AACzC,+EAAgF;AAChF,gFAA0E;AAG7D,QAAA,iBAAiB,GAAG,wBAAwB,CAAC;AAC7C,QAAA,sBAAsB,GAAG,oBAAoB,CAAC;AAGpD,MAAM,YAAY,GAAG,CAAC,OAAe,EAAE,EAAE,CAC9C,IAAA,oBAAW,EAAC,yBAAiB,EAAE,OAAO,CAAC,CAAC;AAD7B,QAAA,YAAY,gBACiB;AAGnC,MAAM,gBAAgB,GAAG,GAAG,EAAE,CAAC,IAAA,oBAAW,EAAC,8BAAsB,EAAE,IAAI,CAAC,CAAC;AAAnE,QAAA,gBAAgB,oBAAmD;AAMhF,SAAgB,QAAQ,CAAC,UAAwB,EAAE;IACjD,MAAM,SAAS,GAAG,IAAI,gBAAS,EAAE,CAAC;IAClC,OAAO,IAAA,wBAAe,EACpB,IAAA,wBAAe,EAAC,IAAI,+CAAwB,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,EACjE,IAAA,mBAAU,EAAC,IAAI,8CAAoB,CAAC,OAAO,CAAC,CAAC,CAC9C,CAAC;AACJ,CAAC"}
@@ -0,0 +1 @@
1
+ export * from './api-response.decorator';
@@ -0,0 +1,18 @@
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./api-response.decorator"), exports);
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/decorators/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2DAAyC"}
@@ -0,0 +1,7 @@
1
+ import { ApiErrorPayload, ApiMeta, ApiSuccessResponse, ApiErrorResponse } from '../interfaces/api-response.interface';
2
+ export declare class ApiResponseDto {
3
+ static success<T>(data: T, message?: string, statusCode?: number, meta?: Partial<ApiMeta>): ApiSuccessResponse<T>;
4
+ static created<T>(data: T, message?: string, meta?: Partial<ApiMeta>): ApiSuccessResponse<T>;
5
+ static noContent(message?: string, meta?: Partial<ApiMeta>): ApiSuccessResponse<null>;
6
+ static error(message: string, statusCode: number, error: ApiErrorPayload, meta?: Partial<ApiMeta>): ApiErrorResponse;
7
+ }
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ApiResponseDto = void 0;
4
+ class ApiResponseDto {
5
+ static success(data, message = 'Request successful', statusCode = 200, meta = {}) {
6
+ return {
7
+ success: true,
8
+ statusCode,
9
+ message,
10
+ data,
11
+ meta: {
12
+ timestamp: new Date().toISOString(),
13
+ ...meta,
14
+ },
15
+ };
16
+ }
17
+ static created(data, message = 'Resource created successfully', meta = {}) {
18
+ return ApiResponseDto.success(data, message, 201, meta);
19
+ }
20
+ static noContent(message = 'No content', meta = {}) {
21
+ return ApiResponseDto.success(null, message, 204, meta);
22
+ }
23
+ static error(message, statusCode, error, meta = {}) {
24
+ return {
25
+ success: false,
26
+ statusCode,
27
+ message,
28
+ error,
29
+ meta: {
30
+ timestamp: new Date().toISOString(),
31
+ ...meta,
32
+ },
33
+ };
34
+ }
35
+ }
36
+ exports.ApiResponseDto = ApiResponseDto;
37
+ //# sourceMappingURL=api-response.dto.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-response.dto.js","sourceRoot":"","sources":["../../src/dto/api-response.dto.ts"],"names":[],"mappings":";;;AAOA,MAAa,cAAc;IACzB,MAAM,CAAC,OAAO,CACZ,IAAO,EACP,OAAO,GAAG,oBAAoB,EAC9B,UAAU,GAAG,GAAG,EAChB,OAAyB,EAAE;QAE3B,OAAO;YACL,OAAO,EAAE,IAAI;YACb,UAAU;YACV,OAAO;YACP,IAAI;YACJ,IAAI,EAAE;gBACJ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBACnC,GAAG,IAAI;aACR;SACF,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,OAAO,CACZ,IAAO,EACP,OAAO,GAAG,+BAA+B,EACzC,OAAyB,EAAE;QAE3B,OAAO,cAAc,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;IAC1D,CAAC;IAED,MAAM,CAAC,SAAS,CACd,OAAO,GAAG,YAAY,EACtB,OAAyB,EAAE;QAE3B,OAAO,cAAc,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;IAC1D,CAAC;IAED,MAAM,CAAC,KAAK,CACV,OAAe,EACf,UAAkB,EAClB,KAAsB,EACtB,OAAyB,EAAE;QAE3B,OAAO;YACL,OAAO,EAAE,KAAK;YACd,UAAU;YACV,OAAO;YACP,KAAK;YACL,IAAI,EAAE;gBACJ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBACnC,GAAG,IAAI;aACR;SACF,CAAC;IACJ,CAAC;CACF;AAnDD,wCAmDC"}
@@ -0,0 +1 @@
1
+ export * from './api-response.dto';
@@ -0,0 +1,18 @@
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./api-response.dto"), exports);
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/dto/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,qDAAmC"}
@@ -0,0 +1,34 @@
1
+ import { HttpException, HttpStatus } from '@nestjs/common';
2
+ import { ApiErrorDetail } from '../interfaces/api-response.interface';
3
+ export declare class ApiException extends HttpException {
4
+ readonly code: string;
5
+ readonly details?: ApiErrorDetail[] | undefined;
6
+ constructor(message: string, statusCode: HttpStatus, code: string, details?: ApiErrorDetail[] | undefined);
7
+ }
8
+ export declare class BadRequestException extends ApiException {
9
+ constructor(message?: string, details?: ApiErrorDetail[]);
10
+ }
11
+ export declare class UnauthorizedException extends ApiException {
12
+ constructor(message?: string);
13
+ }
14
+ export declare class ForbiddenException extends ApiException {
15
+ constructor(message?: string);
16
+ }
17
+ export declare class NotFoundException extends ApiException {
18
+ constructor(resource?: string);
19
+ }
20
+ export declare class ConflictException extends ApiException {
21
+ constructor(message?: string);
22
+ }
23
+ export declare class UnprocessableEntityException extends ApiException {
24
+ constructor(message?: string, details?: ApiErrorDetail[]);
25
+ }
26
+ export declare class TooManyRequestsException extends ApiException {
27
+ constructor(message?: string);
28
+ }
29
+ export declare class InternalServerException extends ApiException {
30
+ constructor(message?: string);
31
+ }
32
+ export declare class ServiceUnavailableException extends ApiException {
33
+ constructor(message?: string);
34
+ }
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ServiceUnavailableException = exports.InternalServerException = exports.TooManyRequestsException = exports.UnprocessableEntityException = exports.ConflictException = exports.NotFoundException = exports.ForbiddenException = exports.UnauthorizedException = exports.BadRequestException = exports.ApiException = void 0;
4
+ const common_1 = require("@nestjs/common");
5
+ class ApiException extends common_1.HttpException {
6
+ constructor(message, statusCode, code, details) {
7
+ super({ message, code, details }, statusCode);
8
+ this.code = code;
9
+ this.details = details;
10
+ }
11
+ }
12
+ exports.ApiException = ApiException;
13
+ class BadRequestException extends ApiException {
14
+ constructor(message = 'Bad request', details) {
15
+ super(message, common_1.HttpStatus.BAD_REQUEST, 'BAD_REQUEST', details);
16
+ }
17
+ }
18
+ exports.BadRequestException = BadRequestException;
19
+ class UnauthorizedException extends ApiException {
20
+ constructor(message = 'Unauthorized') {
21
+ super(message, common_1.HttpStatus.UNAUTHORIZED, 'UNAUTHORIZED');
22
+ }
23
+ }
24
+ exports.UnauthorizedException = UnauthorizedException;
25
+ class ForbiddenException extends ApiException {
26
+ constructor(message = 'Forbidden resource') {
27
+ super(message, common_1.HttpStatus.FORBIDDEN, 'FORBIDDEN');
28
+ }
29
+ }
30
+ exports.ForbiddenException = ForbiddenException;
31
+ class NotFoundException extends ApiException {
32
+ constructor(resource = 'Resource') {
33
+ super(`${resource} not found`, common_1.HttpStatus.NOT_FOUND, 'NOT_FOUND');
34
+ }
35
+ }
36
+ exports.NotFoundException = NotFoundException;
37
+ class ConflictException extends ApiException {
38
+ constructor(message = 'Resource already exists') {
39
+ super(message, common_1.HttpStatus.CONFLICT, 'CONFLICT');
40
+ }
41
+ }
42
+ exports.ConflictException = ConflictException;
43
+ class UnprocessableEntityException extends ApiException {
44
+ constructor(message = 'Unprocessable entity', details) {
45
+ super(message, common_1.HttpStatus.UNPROCESSABLE_ENTITY, 'UNPROCESSABLE_ENTITY', details);
46
+ }
47
+ }
48
+ exports.UnprocessableEntityException = UnprocessableEntityException;
49
+ class TooManyRequestsException extends ApiException {
50
+ constructor(message = 'Too many requests') {
51
+ super(message, common_1.HttpStatus.TOO_MANY_REQUESTS, 'TOO_MANY_REQUESTS');
52
+ }
53
+ }
54
+ exports.TooManyRequestsException = TooManyRequestsException;
55
+ class InternalServerException extends ApiException {
56
+ constructor(message = 'Internal server error') {
57
+ super(message, common_1.HttpStatus.INTERNAL_SERVER_ERROR, 'INTERNAL_SERVER_ERROR');
58
+ }
59
+ }
60
+ exports.InternalServerException = InternalServerException;
61
+ class ServiceUnavailableException extends ApiException {
62
+ constructor(message = 'Service unavailable') {
63
+ super(message, common_1.HttpStatus.SERVICE_UNAVAILABLE, 'SERVICE_UNAVAILABLE');
64
+ }
65
+ }
66
+ exports.ServiceUnavailableException = ServiceUnavailableException;
67
+ //# sourceMappingURL=api.exception.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.exception.js","sourceRoot":"","sources":["../../src/exceptions/api.exception.ts"],"names":[],"mappings":";;;AAAA,2CAA2D;AAG3D,MAAa,YAAa,SAAQ,sBAAa;IAC7C,YACE,OAAe,EACf,UAAsB,EACN,IAAY,EACZ,OAA0B;QAE1C,KAAK,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,UAAU,CAAC,CAAC;QAH9B,SAAI,GAAJ,IAAI,CAAQ;QACZ,YAAO,GAAP,OAAO,CAAmB;IAG5C,CAAC;CACF;AATD,oCASC;AAED,MAAa,mBAAoB,SAAQ,YAAY;IACnD,YAAY,OAAO,GAAG,aAAa,EAAE,OAA0B;QAC7D,KAAK,CAAC,OAAO,EAAE,mBAAU,CAAC,WAAW,EAAE,aAAa,EAAE,OAAO,CAAC,CAAC;IACjE,CAAC;CACF;AAJD,kDAIC;AAED,MAAa,qBAAsB,SAAQ,YAAY;IACrD,YAAY,OAAO,GAAG,cAAc;QAClC,KAAK,CAAC,OAAO,EAAE,mBAAU,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;IAC1D,CAAC;CACF;AAJD,sDAIC;AAED,MAAa,kBAAmB,SAAQ,YAAY;IAClD,YAAY,OAAO,GAAG,oBAAoB;QACxC,KAAK,CAAC,OAAO,EAAE,mBAAU,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;IACpD,CAAC;CACF;AAJD,gDAIC;AAED,MAAa,iBAAkB,SAAQ,YAAY;IACjD,YAAY,QAAQ,GAAG,UAAU;QAC/B,KAAK,CAAC,GAAG,QAAQ,YAAY,EAAE,mBAAU,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;IACpE,CAAC;CACF;AAJD,8CAIC;AAED,MAAa,iBAAkB,SAAQ,YAAY;IACjD,YAAY,OAAO,GAAG,yBAAyB;QAC7C,KAAK,CAAC,OAAO,EAAE,mBAAU,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IAClD,CAAC;CACF;AAJD,8CAIC;AAED,MAAa,4BAA6B,SAAQ,YAAY;IAC5D,YAAY,OAAO,GAAG,sBAAsB,EAAE,OAA0B;QACtE,KAAK,CACH,OAAO,EACP,mBAAU,CAAC,oBAAoB,EAC/B,sBAAsB,EACtB,OAAO,CACR,CAAC;IACJ,CAAC;CACF;AATD,oEASC;AAED,MAAa,wBAAyB,SAAQ,YAAY;IACxD,YAAY,OAAO,GAAG,mBAAmB;QACvC,KAAK,CAAC,OAAO,EAAE,mBAAU,CAAC,iBAAiB,EAAE,mBAAmB,CAAC,CAAC;IACpE,CAAC;CACF;AAJD,4DAIC;AAED,MAAa,uBAAwB,SAAQ,YAAY;IACvD,YAAY,OAAO,GAAG,uBAAuB;QAC3C,KAAK,CAAC,OAAO,EAAE,mBAAU,CAAC,qBAAqB,EAAE,uBAAuB,CAAC,CAAC;IAC5E,CAAC;CACF;AAJD,0DAIC;AAED,MAAa,2BAA4B,SAAQ,YAAY;IAC3D,YAAY,OAAO,GAAG,qBAAqB;QACzC,KAAK,CAAC,OAAO,EAAE,mBAAU,CAAC,mBAAmB,EAAE,qBAAqB,CAAC,CAAC;IACxE,CAAC;CACF;AAJD,kEAIC"}
@@ -0,0 +1,2 @@
1
+ export * from './api.exception';
2
+ export * from './validation.exception';
@@ -0,0 +1,19 @@
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./api.exception"), exports);
18
+ __exportStar(require("./validation.exception"), exports);
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/exceptions/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,kDAAgC;AAChC,yDAAuC"}
@@ -0,0 +1,6 @@
1
+ import { ApiException } from './api.exception';
2
+ import { ApiErrorDetail } from '../interfaces/api-response.interface';
3
+ export declare class ValidationException extends ApiException {
4
+ constructor(details: ApiErrorDetail[]);
5
+ static fromConstraints(constraints: Record<string, Record<string, string>>): ValidationException;
6
+ }
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ValidationException = void 0;
4
+ const common_1 = require("@nestjs/common");
5
+ const api_exception_1 = require("./api.exception");
6
+ class ValidationException extends api_exception_1.ApiException {
7
+ constructor(details) {
8
+ super('Validation failed', common_1.HttpStatus.BAD_REQUEST, 'VALIDATION_ERROR', details);
9
+ }
10
+ static fromConstraints(constraints) {
11
+ const details = Object.entries(constraints).map(([field, messages]) => ({
12
+ field,
13
+ message: Object.values(messages).join(', '),
14
+ }));
15
+ return new ValidationException(details);
16
+ }
17
+ }
18
+ exports.ValidationException = ValidationException;
19
+ //# sourceMappingURL=validation.exception.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.exception.js","sourceRoot":"","sources":["../../src/exceptions/validation.exception.ts"],"names":[],"mappings":";;;AAAA,2CAA4C;AAC5C,mDAA+C;AAG/C,MAAa,mBAAoB,SAAQ,4BAAY;IACnD,YAAY,OAAyB;QACnC,KAAK,CAAC,mBAAmB,EAAE,mBAAU,CAAC,WAAW,EAAE,kBAAkB,EAAE,OAAO,CAAC,CAAC;IAClF,CAAC;IAED,MAAM,CAAC,eAAe,CACpB,WAAmD;QAEnD,MAAM,OAAO,GAAqB,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,GAAG,CAC/D,CAAC,CAAC,KAAK,EAAE,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC;YACtB,KAAK;YACL,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;SAC5C,CAAC,CACH,CAAC;QACF,OAAO,IAAI,mBAAmB,CAAC,OAAO,CAAC,CAAC;IAC1C,CAAC;CACF;AAhBD,kDAgBC"}
@@ -0,0 +1,12 @@
1
+ import { ArgumentsHost, ExceptionFilter } from '@nestjs/common';
2
+ import { ForgeOptions } from '../interfaces/api-response.interface';
3
+ export declare class ForgeExceptionFilter implements ExceptionFilter {
4
+ private readonly options;
5
+ private readonly logger;
6
+ constructor(options?: ForgeOptions);
7
+ catch(exception: unknown, host: ArgumentsHost): void;
8
+ private buildMeta;
9
+ private buildErrorResponse;
10
+ private extractHttpExceptionMessage;
11
+ private extractValidationDetails;
12
+ }