@webpieces/http-filters 0.2.10 → 0.2.11

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webpieces/http-filters",
3
- "version": "0.2.10",
3
+ "version": "0.2.11",
4
4
  "description": "Filter chain infrastructure for cross-cutting concerns",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -21,6 +21,6 @@
21
21
  "access": "public"
22
22
  },
23
23
  "dependencies": {
24
- "@webpieces/core-context": "0.2.10"
24
+ "@webpieces/core-context": "0.2.11"
25
25
  }
26
26
  }
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ContextFilter = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const inversify_1 = require("inversify");
6
+ const http_routing_1 = require("@webpieces/http-routing");
6
7
  const core_context_1 = require("@webpieces/core-context");
7
8
  /**
8
9
  * ContextFilter - Sets up AsyncLocalStorage context for each request.
@@ -17,24 +18,19 @@ let ContextFilter = class ContextFilter {
17
18
  }
18
19
  async filter(meta, next) {
19
20
  // Run the rest of the filter chain within a new context
20
- return core_context_1.Context.run(async () => {
21
+ return core_context_1.RequestContext.run(async () => {
21
22
  // Store request metadata in context for other filters to access
22
- core_context_1.Context.put('METHOD_META', meta);
23
- core_context_1.Context.put('REQUEST_PATH', meta.path);
24
- core_context_1.Context.put('HTTP_METHOD', meta.httpMethod);
25
- try {
26
- return await next.execute();
27
- }
28
- finally {
29
- // Clean up context (AsyncLocalStorage handles this automatically,
30
- // but we can explicitly clear if needed)
31
- core_context_1.Context.clear();
32
- }
23
+ core_context_1.RequestContext.put('METHOD_META', meta);
24
+ core_context_1.RequestContext.put('REQUEST_PATH', meta.path);
25
+ core_context_1.RequestContext.put('HTTP_METHOD', meta.httpMethod);
26
+ return await next.execute();
27
+ //RequestContext is auto cleared when done.
33
28
  });
34
29
  }
35
30
  };
36
31
  exports.ContextFilter = ContextFilter;
37
32
  exports.ContextFilter = ContextFilter = tslib_1.__decorate([
33
+ (0, http_routing_1.provideSingleton)(),
38
34
  (0, inversify_1.injectable)()
39
35
  ], ContextFilter);
40
36
  //# sourceMappingURL=ContextFilter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ContextFilter.js","sourceRoot":"","sources":["../../../../../../packages/http/http-filters/src/filters/ContextFilter.ts"],"names":[],"mappings":";;;;AAAA,yCAAuC;AACvC,0DAAkD;AAGlD;;;;;;GAMG;AAEI,IAAM,aAAa,GAAnB,MAAM,aAAa;IAAnB;QACL,aAAQ,GAAG,GAAG,CAAC;IAmBjB,CAAC;IAjBC,KAAK,CAAC,MAAM,CAAC,IAAgB,EAAE,IAAgB;QAC7C,wDAAwD;QACxD,OAAO,sBAAO,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE;YAC5B,gEAAgE;YAChE,sBAAO,CAAC,GAAG,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;YACjC,sBAAO,CAAC,GAAG,CAAC,cAAc,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;YACvC,sBAAO,CAAC,GAAG,CAAC,aAAa,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;YAE5C,IAAI,CAAC;gBACH,OAAO,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;YAC9B,CAAC;oBAAS,CAAC;gBACT,kEAAkE;gBAClE,yCAAyC;gBACzC,sBAAO,CAAC,KAAK,EAAE,CAAC;YAClB,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;CACF,CAAA;AApBY,sCAAa;wBAAb,aAAa;IADzB,IAAA,sBAAU,GAAE;GACA,aAAa,CAoBzB","sourcesContent":["import { injectable } from 'inversify';\nimport { Context } from '@webpieces/core-context';\nimport { Filter, MethodMeta, Action, NextFilter } from '../Filter';\n\n/**\n * ContextFilter - Sets up AsyncLocalStorage context for each request.\n * Priority: 140 (executes first)\n *\n * This filter ensures that all subsequent filters and the controller\n * execute within a context that can store request-scoped data.\n */\n@injectable()\nexport class ContextFilter implements Filter {\n priority = 140;\n\n async filter(meta: MethodMeta, next: NextFilter): Promise<Action> {\n // Run the rest of the filter chain within a new context\n return Context.run(async () => {\n // Store request metadata in context for other filters to access\n Context.put('METHOD_META', meta);\n Context.put('REQUEST_PATH', meta.path);\n Context.put('HTTP_METHOD', meta.httpMethod);\n\n try {\n return await next.execute();\n } finally {\n // Clean up context (AsyncLocalStorage handles this automatically,\n // but we can explicitly clear if needed)\n Context.clear();\n }\n });\n }\n}\n"]}
1
+ {"version":3,"file":"ContextFilter.js","sourceRoot":"","sources":["../../../../../../packages/http/http-filters/src/filters/ContextFilter.ts"],"names":[],"mappings":";;;;AAAA,yCAAuC;AACvC,0DAA2D;AAC3D,0DAAyD;AAGzD;;;;;;GAMG;AAGI,IAAM,aAAa,GAAnB,MAAM,aAAa;IAAnB;QACL,aAAQ,GAAG,GAAG,CAAC;IAcjB,CAAC;IAZC,KAAK,CAAC,MAAM,CAAC,IAAgB,EAAE,IAAgB;QAC7C,wDAAwD;QACxD,OAAO,6BAAc,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE;YACnC,gEAAgE;YAChE,6BAAc,CAAC,GAAG,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;YACxC,6BAAc,CAAC,GAAG,CAAC,cAAc,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;YAC9C,6BAAc,CAAC,GAAG,CAAC,aAAa,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;YAEjD,OAAO,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;YAC5B,2CAA2C;QAC/C,CAAC,CAAC,CAAC;IACL,CAAC;CACF,CAAA;AAfY,sCAAa;wBAAb,aAAa;IAFzB,IAAA,+BAAgB,GAAE;IAClB,IAAA,sBAAU,GAAE;GACA,aAAa,CAezB","sourcesContent":["import { injectable } from 'inversify';\nimport { provideSingleton } from '@webpieces/http-routing';\nimport { RequestContext } from '@webpieces/core-context';\nimport { Filter, MethodMeta, Action, NextFilter } from '../Filter';\n\n/**\n * ContextFilter - Sets up AsyncLocalStorage context for each request.\n * Priority: 140 (executes first)\n *\n * This filter ensures that all subsequent filters and the controller\n * execute within a context that can store request-scoped data.\n */\n@provideSingleton()\n@injectable()\nexport class ContextFilter implements Filter {\n priority = 140;\n\n async filter(meta: MethodMeta, next: NextFilter): Promise<Action> {\n // Run the rest of the filter chain within a new context\n return RequestContext.run(async () => {\n // Store request metadata in context for other filters to access\n RequestContext.put('METHOD_META', meta);\n RequestContext.put('REQUEST_PATH', meta.path);\n RequestContext.put('HTTP_METHOD', meta.httpMethod);\n\n return await next.execute();\n //RequestContext is auto cleared when done.\n });\n }\n}\n"]}
@@ -1,6 +1,22 @@
1
1
  import { Filter, MethodMeta, Action, NextFilter } from '../Filter';
2
+ /**
3
+ * DI tokens for http-filters.
4
+ */
5
+ export declare const FILTER_TYPES: {
6
+ JsonFilterConfig: symbol;
7
+ };
2
8
  /**
3
9
  * Configuration for JsonFilter.
10
+ * Register this in your DI container to customize JsonFilter behavior.
11
+ *
12
+ * Example:
13
+ * ```typescript
14
+ * export const MyModule = new ContainerModule((bind) => {
15
+ * bind(FILTER_TYPES.JsonFilterConfig).toConstantValue(
16
+ * new JsonFilterConfig(true, true) // validation enabled, logging enabled
17
+ * );
18
+ * });
19
+ * ```
4
20
  */
5
21
  export declare class JsonFilterConfig {
6
22
  /**
@@ -27,11 +43,16 @@ export declare class JsonFilterConfig {
27
43
  * 3. Execute next filter/controller
28
44
  * 4. Serialize response to JSON
29
45
  * 5. Handle errors and translate to JSON error responses
46
+ *
47
+ * Configuration:
48
+ * JsonFilter uses constructor injection to receive JsonFilterConfig.
49
+ * The default config has validation enabled and logging disabled.
50
+ * To customize, bind JsonFilterConfig in your DI module.
30
51
  */
31
52
  export declare class JsonFilter implements Filter {
32
53
  private config;
33
54
  priority: number;
34
- constructor(config?: JsonFilterConfig);
55
+ constructor(config: JsonFilterConfig);
35
56
  filter(meta: MethodMeta, next: NextFilter): Promise<Action>;
36
57
  /**
37
58
  * Process the request: deserialize and validate.
@@ -1,20 +1,41 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.HttpException = exports.ValidationException = exports.JsonFilter = exports.JsonFilterConfig = void 0;
3
+ exports.HttpException = exports.ValidationException = exports.JsonFilter = exports.JsonFilterConfig = exports.FILTER_TYPES = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const inversify_1 = require("inversify");
6
+ const http_routing_1 = require("@webpieces/http-routing");
6
7
  const class_validator_1 = require("class-validator");
7
8
  const Filter_1 = require("../Filter");
9
+ /**
10
+ * DI tokens for http-filters.
11
+ */
12
+ exports.FILTER_TYPES = {
13
+ JsonFilterConfig: Symbol.for('JsonFilterConfig'),
14
+ };
8
15
  /**
9
16
  * Configuration for JsonFilter.
17
+ * Register this in your DI container to customize JsonFilter behavior.
18
+ *
19
+ * Example:
20
+ * ```typescript
21
+ * export const MyModule = new ContainerModule((bind) => {
22
+ * bind(FILTER_TYPES.JsonFilterConfig).toConstantValue(
23
+ * new JsonFilterConfig(true, true) // validation enabled, logging enabled
24
+ * );
25
+ * });
26
+ * ```
10
27
  */
11
- class JsonFilterConfig {
28
+ let JsonFilterConfig = class JsonFilterConfig {
12
29
  constructor(validationEnabled = true, loggingEnabled = false) {
13
30
  this.validationEnabled = validationEnabled;
14
31
  this.loggingEnabled = loggingEnabled;
15
32
  }
16
- }
33
+ };
17
34
  exports.JsonFilterConfig = JsonFilterConfig;
35
+ exports.JsonFilterConfig = JsonFilterConfig = tslib_1.__decorate([
36
+ (0, inversify_1.injectable)(),
37
+ tslib_1.__metadata("design:paramtypes", [Boolean, Boolean])
38
+ ], JsonFilterConfig);
18
39
  /**
19
40
  * JsonFilter - Handles JSON deserialization and serialization.
20
41
  * Priority: 60
@@ -27,12 +48,17 @@ exports.JsonFilterConfig = JsonFilterConfig;
27
48
  * 3. Execute next filter/controller
28
49
  * 4. Serialize response to JSON
29
50
  * 5. Handle errors and translate to JSON error responses
51
+ *
52
+ * Configuration:
53
+ * JsonFilter uses constructor injection to receive JsonFilterConfig.
54
+ * The default config has validation enabled and logging disabled.
55
+ * To customize, bind JsonFilterConfig in your DI module.
30
56
  */
31
57
  let JsonFilter = class JsonFilter {
32
- constructor(config = new JsonFilterConfig()) {
58
+ constructor(config) {
33
59
  this.config = config;
34
60
  this.priority = 60;
35
- // Config is now a class with defaults already set in constructor
61
+ // Config is injected from DI container
36
62
  }
37
63
  async filter(meta, next) {
38
64
  try {
@@ -144,8 +170,9 @@ let JsonFilter = class JsonFilter {
144
170
  };
145
171
  exports.JsonFilter = JsonFilter;
146
172
  exports.JsonFilter = JsonFilter = tslib_1.__decorate([
173
+ (0, http_routing_1.provideSingleton)(),
147
174
  (0, inversify_1.injectable)(),
148
- tslib_1.__param(0, (0, inversify_1.unmanaged)()),
175
+ tslib_1.__param(0, (0, inversify_1.inject)(exports.FILTER_TYPES.JsonFilterConfig)),
149
176
  tslib_1.__metadata("design:paramtypes", [JsonFilterConfig])
150
177
  ], JsonFilter);
151
178
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"JsonFilter.js","sourceRoot":"","sources":["../../../../../../packages/http/http-filters/src/filters/JsonFilter.ts"],"names":[],"mappings":"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","sourcesContent":["import { injectable, unmanaged } from 'inversify';\nimport { plainToInstance } from 'class-transformer';\nimport { validate, ValidationError } from 'class-validator';\nimport { Filter, MethodMeta, Action, NextFilter, jsonAction, errorAction } from '../Filter';\nimport { Context } from '@webpieces/core-context';\n\n/**\n * Configuration for JsonFilter.\n */\nexport class JsonFilterConfig {\n /**\n * Whether to enable validation using class-validator.\n * Default: true\n */\n validationEnabled: boolean;\n\n /**\n * Whether to log requests and responses.\n * Default: false\n */\n loggingEnabled: boolean;\n\n constructor(\n validationEnabled: boolean = true,\n loggingEnabled: boolean = false\n ) {\n this.validationEnabled = validationEnabled;\n this.loggingEnabled = loggingEnabled;\n }\n}\n\n/**\n * JsonFilter - Handles JSON deserialization and serialization.\n * Priority: 60\n *\n * Similar to Java WebPieces JacksonCatchAllFilter.\n *\n * Responsibilities:\n * 1. Deserialize request body to DTO (if request has body)\n * 2. Validate DTO using class-validator (if enabled)\n * 3. Execute next filter/controller\n * 4. Serialize response to JSON\n * 5. Handle errors and translate to JSON error responses\n */\n@injectable()\nexport class JsonFilter implements Filter {\n priority = 60;\n\n constructor(@unmanaged() private config: JsonFilterConfig = new JsonFilterConfig()) {\n // Config is now a class with defaults already set in constructor\n }\n\n async filter(meta: MethodMeta, next: NextFilter): Promise<Action> {\n try {\n // Deserialize and validate request if there's a body\n await this.processRequest(meta);\n\n if (this.config.loggingEnabled) {\n this.logRequest(meta);\n }\n\n // Execute next filter/controller\n const action = await next.execute();\n\n if (this.config.loggingEnabled) {\n this.logResponse(action);\n }\n\n // Ensure response is JSON\n if (action.type !== 'json' && action.type !== 'error') {\n return jsonAction(action.data);\n }\n\n return action;\n } catch (error) {\n // Translate error to JSON response\n return this.handleError(error, meta);\n }\n }\n\n /**\n * Process the request: deserialize and validate.\n */\n private async processRequest(meta: MethodMeta): Promise<void> {\n // If there's request data and a parameter type, deserialize it\n if (meta.request?.body && meta.params.length === 0) {\n const body = meta.request.body;\n\n // For now, we'll just pass the body as-is\n // In a real implementation, we'd use the parameter type from decorators\n // to properly deserialize and validate\n\n // If we have type information, we can do proper transformation\n // For this MVP, we'll store the body in params[0]\n meta.params[0] = body;\n\n // If validation is enabled and we have a class instance, validate it\n if (this.config.validationEnabled && body.constructor !== Object) {\n await this.validateDto(body);\n }\n }\n }\n\n /**\n * Validate a DTO using class-validator.\n */\n private async validateDto(dto: any): Promise<void> {\n const errors = await validate(dto);\n\n if (errors.length > 0) {\n const messages = this.formatValidationErrors(errors);\n throw new ValidationException(messages);\n }\n }\n\n /**\n * Format validation errors into a readable format.\n */\n private formatValidationErrors(errors: ValidationError[]): string[] {\n const messages: string[] = [];\n\n for (const error of errors) {\n if (error.constraints) {\n const constraints = Object.values(error.constraints);\n messages.push(...constraints);\n }\n\n if (error.children && error.children.length > 0) {\n const childMessages = this.formatValidationErrors(error.children);\n messages.push(...childMessages);\n }\n }\n\n return messages;\n }\n\n /**\n * Handle errors and translate to JSON error responses.\n */\n private handleError(error: any, meta: MethodMeta): Action {\n if (error instanceof ValidationException) {\n return errorAction(\n {\n error: 'Validation failed',\n violations: error.violations,\n } as any,\n 400\n );\n }\n\n if (error instanceof HttpException) {\n return errorAction(\n {\n error: error.message,\n code: error.statusCode,\n } as any,\n error.statusCode\n );\n }\n\n // Log unexpected errors\n console.error('Unexpected error in filter chain:', error);\n\n return errorAction(\n 'Internal server error',\n 500\n );\n }\n\n /**\n * Log the incoming request.\n */\n private logRequest(meta: MethodMeta): void {\n console.log(`[JsonFilter] ${meta.httpMethod} ${meta.path}`);\n if (meta.params.length > 0) {\n console.log('[JsonFilter] Request body:', JSON.stringify(meta.params[0], null, 2));\n }\n }\n\n /**\n * Log the outgoing response.\n */\n private logResponse(action: Action): void {\n console.log(`[JsonFilter] Response: ${action.statusCode}`);\n if (action.data) {\n console.log('[JsonFilter] Response body:', JSON.stringify(action.data, null, 2));\n }\n }\n}\n\n/**\n * Exception thrown when validation fails.\n */\nexport class ValidationException extends Error {\n constructor(public violations: string[]) {\n super('Validation failed');\n this.name = 'ValidationException';\n }\n}\n\n/**\n * HTTP exception with status code.\n */\nexport class HttpException extends Error {\n constructor(message: string, public statusCode: number) {\n super(message);\n this.name = 'HttpException';\n }\n}\n"]}
1
+ {"version":3,"file":"JsonFilter.js","sourceRoot":"","sources":["../../../../../../packages/http/http-filters/src/filters/JsonFilter.ts"],"names":[],"mappings":"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","sourcesContent":["import { injectable, inject } from 'inversify';\nimport { provideSingleton } from '@webpieces/http-routing';\nimport { plainToInstance } from 'class-transformer';\nimport { validate, ValidationError } from 'class-validator';\nimport { Filter, MethodMeta, Action, NextFilter, jsonAction, errorAction } from '../Filter';\nimport { RequestContext } from '@webpieces/core-context';\n\n/**\n * DI tokens for http-filters.\n */\nexport const FILTER_TYPES = {\n JsonFilterConfig: Symbol.for('JsonFilterConfig'),\n};\n\n/**\n * Configuration for JsonFilter.\n * Register this in your DI container to customize JsonFilter behavior.\n *\n * Example:\n * ```typescript\n * export const MyModule = new ContainerModule((bind) => {\n * bind(FILTER_TYPES.JsonFilterConfig).toConstantValue(\n * new JsonFilterConfig(true, true) // validation enabled, logging enabled\n * );\n * });\n * ```\n */\n@injectable()\nexport class JsonFilterConfig {\n /**\n * Whether to enable validation using class-validator.\n * Default: true\n */\n validationEnabled: boolean;\n\n /**\n * Whether to log requests and responses.\n * Default: false\n */\n loggingEnabled: boolean;\n\n constructor(\n validationEnabled: boolean = true,\n loggingEnabled: boolean = false\n ) {\n this.validationEnabled = validationEnabled;\n this.loggingEnabled = loggingEnabled;\n }\n}\n\n/**\n * JsonFilter - Handles JSON deserialization and serialization.\n * Priority: 60\n *\n * Similar to Java WebPieces JacksonCatchAllFilter.\n *\n * Responsibilities:\n * 1. Deserialize request body to DTO (if request has body)\n * 2. Validate DTO using class-validator (if enabled)\n * 3. Execute next filter/controller\n * 4. Serialize response to JSON\n * 5. Handle errors and translate to JSON error responses\n *\n * Configuration:\n * JsonFilter uses constructor injection to receive JsonFilterConfig.\n * The default config has validation enabled and logging disabled.\n * To customize, bind JsonFilterConfig in your DI module.\n */\n@provideSingleton()\n@injectable()\nexport class JsonFilter implements Filter {\n priority = 60;\n\n constructor(@inject(FILTER_TYPES.JsonFilterConfig) private config: JsonFilterConfig) {\n // Config is injected from DI container\n }\n\n async filter(meta: MethodMeta, next: NextFilter): Promise<Action> {\n try {\n // Deserialize and validate request if there's a body\n await this.processRequest(meta);\n\n if (this.config.loggingEnabled) {\n this.logRequest(meta);\n }\n\n // Execute next filter/controller\n const action = await next.execute();\n\n if (this.config.loggingEnabled) {\n this.logResponse(action);\n }\n\n // Ensure response is JSON\n if (action.type !== 'json' && action.type !== 'error') {\n return jsonAction(action.data);\n }\n\n return action;\n } catch (error) {\n // Translate error to JSON response\n return this.handleError(error, meta);\n }\n }\n\n /**\n * Process the request: deserialize and validate.\n */\n private async processRequest(meta: MethodMeta): Promise<void> {\n // If there's request data and a parameter type, deserialize it\n if (meta.request?.body && meta.params.length === 0) {\n const body = meta.request.body;\n\n // For now, we'll just pass the body as-is\n // In a real implementation, we'd use the parameter type from decorators\n // to properly deserialize and validate\n\n // If we have type information, we can do proper transformation\n // For this MVP, we'll store the body in params[0]\n meta.params[0] = body;\n\n // If validation is enabled and we have a class instance, validate it\n if (this.config.validationEnabled && body.constructor !== Object) {\n await this.validateDto(body);\n }\n }\n }\n\n /**\n * Validate a DTO using class-validator.\n */\n private async validateDto(dto: any): Promise<void> {\n const errors = await validate(dto);\n\n if (errors.length > 0) {\n const messages = this.formatValidationErrors(errors);\n throw new ValidationException(messages);\n }\n }\n\n /**\n * Format validation errors into a readable format.\n */\n private formatValidationErrors(errors: ValidationError[]): string[] {\n const messages: string[] = [];\n\n for (const error of errors) {\n if (error.constraints) {\n const constraints = Object.values(error.constraints);\n messages.push(...constraints);\n }\n\n if (error.children && error.children.length > 0) {\n const childMessages = this.formatValidationErrors(error.children);\n messages.push(...childMessages);\n }\n }\n\n return messages;\n }\n\n /**\n * Handle errors and translate to JSON error responses.\n */\n private handleError(error: any, meta: MethodMeta): Action {\n if (error instanceof ValidationException) {\n return errorAction(\n {\n error: 'Validation failed',\n violations: error.violations,\n } as any,\n 400\n );\n }\n\n if (error instanceof HttpException) {\n return errorAction(\n {\n error: error.message,\n code: error.statusCode,\n } as any,\n error.statusCode\n );\n }\n\n // Log unexpected errors\n console.error('Unexpected error in filter chain:', error);\n\n return errorAction(\n 'Internal server error',\n 500\n );\n }\n\n /**\n * Log the incoming request.\n */\n private logRequest(meta: MethodMeta): void {\n console.log(`[JsonFilter] ${meta.httpMethod} ${meta.path}`);\n if (meta.params.length > 0) {\n console.log('[JsonFilter] Request body:', JSON.stringify(meta.params[0], null, 2));\n }\n }\n\n /**\n * Log the outgoing response.\n */\n private logResponse(action: Action): void {\n console.log(`[JsonFilter] Response: ${action.statusCode}`);\n if (action.data) {\n console.log('[JsonFilter] Response body:', JSON.stringify(action.data, null, 2));\n }\n }\n}\n\n/**\n * Exception thrown when validation fails.\n */\nexport class ValidationException extends Error {\n constructor(public violations: string[]) {\n super('Validation failed');\n this.name = 'ValidationException';\n }\n}\n\n/**\n * HTTP exception with status code.\n */\nexport class HttpException extends Error {\n constructor(message: string, public statusCode: number) {\n super(message);\n this.name = 'HttpException';\n }\n}\n"]}
package/src/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export { Filter, MethodMeta, Action, NextFilter, jsonAction, errorAction, } from './Filter';
2
2
  export { FilterChain } from './FilterChain';
3
3
  export { ContextFilter } from './filters/ContextFilter';
4
- export { JsonFilter, JsonFilterConfig, ValidationException, HttpException, } from './filters/JsonFilter';
4
+ export { JsonFilter, JsonFilterConfig, FILTER_TYPES, ValidationException, HttpException, } from './filters/JsonFilter';
package/src/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.HttpException = exports.ValidationException = exports.JsonFilterConfig = exports.JsonFilter = exports.ContextFilter = exports.FilterChain = exports.errorAction = exports.jsonAction = exports.NextFilter = exports.Action = exports.MethodMeta = void 0;
3
+ exports.HttpException = exports.ValidationException = exports.FILTER_TYPES = exports.JsonFilterConfig = exports.JsonFilter = exports.ContextFilter = exports.FilterChain = exports.errorAction = exports.jsonAction = exports.NextFilter = exports.Action = exports.MethodMeta = void 0;
4
4
  var Filter_1 = require("./Filter");
5
5
  Object.defineProperty(exports, "MethodMeta", { enumerable: true, get: function () { return Filter_1.MethodMeta; } });
6
6
  Object.defineProperty(exports, "Action", { enumerable: true, get: function () { return Filter_1.Action; } });
@@ -14,6 +14,7 @@ Object.defineProperty(exports, "ContextFilter", { enumerable: true, get: functio
14
14
  var JsonFilter_1 = require("./filters/JsonFilter");
15
15
  Object.defineProperty(exports, "JsonFilter", { enumerable: true, get: function () { return JsonFilter_1.JsonFilter; } });
16
16
  Object.defineProperty(exports, "JsonFilterConfig", { enumerable: true, get: function () { return JsonFilter_1.JsonFilterConfig; } });
17
+ Object.defineProperty(exports, "FILTER_TYPES", { enumerable: true, get: function () { return JsonFilter_1.FILTER_TYPES; } });
17
18
  Object.defineProperty(exports, "ValidationException", { enumerable: true, get: function () { return JsonFilter_1.ValidationException; } });
18
19
  Object.defineProperty(exports, "HttpException", { enumerable: true, get: function () { return JsonFilter_1.HttpException; } });
19
20
  //# sourceMappingURL=index.js.map
package/src/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/http/http-filters/src/index.ts"],"names":[],"mappings":";;;AAAA,mCAOkB;AALhB,oGAAA,UAAU,OAAA;AACV,gGAAA,MAAM,OAAA;AACN,oGAAA,UAAU,OAAA;AACV,oGAAA,UAAU,OAAA;AACV,qGAAA,WAAW,OAAA;AAGb,6CAA4C;AAAnC,0GAAA,WAAW,OAAA;AAEpB,yDAAwD;AAA/C,8GAAA,aAAa,OAAA;AACtB,mDAK8B;AAJ5B,wGAAA,UAAU,OAAA;AACV,8GAAA,gBAAgB,OAAA;AAChB,iHAAA,mBAAmB,OAAA;AACnB,2GAAA,aAAa,OAAA","sourcesContent":["export {\n Filter,\n MethodMeta,\n Action,\n NextFilter,\n jsonAction,\n errorAction,\n} from './Filter';\n\nexport { FilterChain } from './FilterChain';\n\nexport { ContextFilter } from './filters/ContextFilter';\nexport {\n JsonFilter,\n JsonFilterConfig,\n ValidationException,\n HttpException,\n} from './filters/JsonFilter';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/http/http-filters/src/index.ts"],"names":[],"mappings":";;;AAAA,mCAOkB;AALhB,oGAAA,UAAU,OAAA;AACV,gGAAA,MAAM,OAAA;AACN,oGAAA,UAAU,OAAA;AACV,oGAAA,UAAU,OAAA;AACV,qGAAA,WAAW,OAAA;AAGb,6CAA4C;AAAnC,0GAAA,WAAW,OAAA;AAEpB,yDAAwD;AAA/C,8GAAA,aAAa,OAAA;AACtB,mDAM8B;AAL5B,wGAAA,UAAU,OAAA;AACV,8GAAA,gBAAgB,OAAA;AAChB,0GAAA,YAAY,OAAA;AACZ,iHAAA,mBAAmB,OAAA;AACnB,2GAAA,aAAa,OAAA","sourcesContent":["export {\n Filter,\n MethodMeta,\n Action,\n NextFilter,\n jsonAction,\n errorAction,\n} from './Filter';\n\nexport { FilterChain } from './FilterChain';\n\nexport { ContextFilter } from './filters/ContextFilter';\nexport {\n JsonFilter,\n JsonFilterConfig,\n FILTER_TYPES,\n ValidationException,\n HttpException,\n} from './filters/JsonFilter';\n"]}