@webpieces/http-filters 0.2.9 → 0.2.10
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 +2 -2
- package/src/Filter.d.ts +4 -2
- package/src/Filter.js +34 -13
- package/src/Filter.js.map +1 -1
- package/src/filters/JsonFilter.d.ts +4 -3
- package/src/filters/JsonFilter.js +14 -8
- package/src/filters/JsonFilter.js.map +1 -1
- package/src/index.js +4 -1
- package/src/index.js.map +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webpieces/http-filters",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.10",
|
|
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.
|
|
24
|
+
"@webpieces/core-context": "0.2.10"
|
|
25
25
|
}
|
|
26
26
|
}
|
package/src/Filter.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Metadata about the method being invoked.
|
|
3
3
|
* Passed to filters and contains request information.
|
|
4
4
|
*/
|
|
5
|
-
export
|
|
5
|
+
export declare class MethodMeta {
|
|
6
6
|
/**
|
|
7
7
|
* The HTTP method (GET, POST, etc.)
|
|
8
8
|
*/
|
|
@@ -32,16 +32,18 @@ export interface MethodMeta {
|
|
|
32
32
|
* Additional metadata
|
|
33
33
|
*/
|
|
34
34
|
metadata?: Map<string, any>;
|
|
35
|
+
constructor(httpMethod: string, path: string, methodName: string, params: any[], request?: any, response?: any, metadata?: Map<string, any>);
|
|
35
36
|
}
|
|
36
37
|
/**
|
|
37
38
|
* Action returned by filters and controllers.
|
|
38
39
|
* Can represent different types of responses.
|
|
39
40
|
*/
|
|
40
|
-
export
|
|
41
|
+
export declare class Action {
|
|
41
42
|
type: 'json' | 'html' | 'redirect' | 'error';
|
|
42
43
|
data?: any;
|
|
43
44
|
statusCode?: number;
|
|
44
45
|
headers?: Record<string, string>;
|
|
46
|
+
constructor(type: 'json' | 'html' | 'redirect' | 'error', data?: any, statusCode?: number, headers?: Record<string, string>);
|
|
45
47
|
}
|
|
46
48
|
/**
|
|
47
49
|
* Next filter class.
|
package/src/Filter.js
CHANGED
|
@@ -1,8 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.NextFilter = void 0;
|
|
3
|
+
exports.NextFilter = exports.Action = exports.MethodMeta = void 0;
|
|
4
4
|
exports.jsonAction = jsonAction;
|
|
5
5
|
exports.errorAction = errorAction;
|
|
6
|
+
/**
|
|
7
|
+
* Metadata about the method being invoked.
|
|
8
|
+
* Passed to filters and contains request information.
|
|
9
|
+
*/
|
|
10
|
+
class MethodMeta {
|
|
11
|
+
constructor(httpMethod, path, methodName, params, request, response, metadata) {
|
|
12
|
+
this.httpMethod = httpMethod;
|
|
13
|
+
this.path = path;
|
|
14
|
+
this.methodName = methodName;
|
|
15
|
+
this.params = params;
|
|
16
|
+
this.request = request;
|
|
17
|
+
this.response = response;
|
|
18
|
+
this.metadata = metadata;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
exports.MethodMeta = MethodMeta;
|
|
22
|
+
/**
|
|
23
|
+
* Action returned by filters and controllers.
|
|
24
|
+
* Can represent different types of responses.
|
|
25
|
+
*/
|
|
26
|
+
class Action {
|
|
27
|
+
constructor(type, data, statusCode, headers) {
|
|
28
|
+
this.type = type;
|
|
29
|
+
this.data = data;
|
|
30
|
+
this.statusCode = statusCode;
|
|
31
|
+
this.headers = headers;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
exports.Action = Action;
|
|
6
35
|
/**
|
|
7
36
|
* Next filter class.
|
|
8
37
|
* This is a class instead of a function type to make it easier to trace
|
|
@@ -15,22 +44,14 @@ exports.NextFilter = NextFilter;
|
|
|
15
44
|
* Helper to create a JSON action response.
|
|
16
45
|
*/
|
|
17
46
|
function jsonAction(data, statusCode = 200) {
|
|
18
|
-
return
|
|
19
|
-
type: 'json',
|
|
20
|
-
data,
|
|
21
|
-
statusCode,
|
|
22
|
-
};
|
|
47
|
+
return new Action('json', data, statusCode);
|
|
23
48
|
}
|
|
24
49
|
/**
|
|
25
50
|
* Helper to create an error action response.
|
|
26
51
|
*/
|
|
27
52
|
function errorAction(error, statusCode = 500) {
|
|
28
|
-
return {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
error: typeof error === 'string' ? error : error.message,
|
|
32
|
-
},
|
|
33
|
-
statusCode,
|
|
34
|
-
};
|
|
53
|
+
return new Action('error', {
|
|
54
|
+
error: typeof error === 'string' ? error : error.message,
|
|
55
|
+
}, statusCode);
|
|
35
56
|
}
|
|
36
57
|
//# sourceMappingURL=Filter.js.map
|
package/src/Filter.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Filter.js","sourceRoot":"","sources":["../../../../../packages/http/http-filters/src/Filter.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"Filter.js","sourceRoot":"","sources":["../../../../../packages/http/http-filters/src/Filter.ts"],"names":[],"mappings":";;;AAkJA,gCAEC;AAKD,kCAWC;AApKD;;;GAGG;AACH,MAAa,UAAU;IAqCrB,YACE,UAAkB,EAClB,IAAY,EACZ,UAAkB,EAClB,MAAa,EACb,OAAa,EACb,QAAc,EACd,QAA2B;QAE3B,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;CACF;AAtDD,gCAsDC;AAED;;;GAGG;AACH,MAAa,MAAM;IAMjB,YACE,IAA4C,EAC5C,IAAU,EACV,UAAmB,EACnB,OAAgC;QAEhC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;CACF;AAjBD,wBAiBC;AAED;;;;GAIG;AACH,MAAsB,UAAU;CAM/B;AAND,gCAMC;AAiDD;;GAEG;AACH,SAAgB,UAAU,CAAC,IAAS,EAAE,aAAqB,GAAG;IAC5D,OAAO,IAAI,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;AAC9C,CAAC;AAED;;GAEG;AACH,SAAgB,WAAW,CACzB,KAAqB,EACrB,aAAqB,GAAG;IAExB,OAAO,IAAI,MAAM,CACf,OAAO,EACP;QACE,KAAK,EAAE,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO;KACzD,EACD,UAAU,CACX,CAAC;AACJ,CAAC","sourcesContent":["/**\n * Metadata about the method being invoked.\n * Passed to filters and contains request information.\n */\nexport class MethodMeta {\n /**\n * The HTTP method (GET, POST, etc.)\n */\n httpMethod: string;\n\n /**\n * The request path\n */\n path: string;\n\n /**\n * The method name being invoked on the controller\n */\n methodName: string;\n\n /**\n * Parameters to pass to the controller method.\n * Filters can modify this array (e.g., JsonFilter deserializes request body into params[0])\n */\n params: any[];\n\n /**\n * The original request object (if applicable)\n */\n request?: any;\n\n /**\n * The response object (if applicable)\n */\n response?: any;\n\n /**\n * Additional metadata\n */\n metadata?: Map<string, any>;\n\n constructor(\n httpMethod: string,\n path: string,\n methodName: string,\n params: any[],\n request?: any,\n response?: any,\n metadata?: Map<string, any>\n ) {\n this.httpMethod = httpMethod;\n this.path = path;\n this.methodName = methodName;\n this.params = params;\n this.request = request;\n this.response = response;\n this.metadata = metadata;\n }\n}\n\n/**\n * Action returned by filters and controllers.\n * Can represent different types of responses.\n */\nexport class Action {\n type: 'json' | 'html' | 'redirect' | 'error';\n data?: any;\n statusCode?: number;\n headers?: Record<string, string>;\n\n constructor(\n type: 'json' | 'html' | 'redirect' | 'error',\n data?: any,\n statusCode?: number,\n headers?: Record<string, string>\n ) {\n this.type = type;\n this.data = data;\n this.statusCode = statusCode;\n this.headers = headers;\n }\n}\n\n/**\n * Next filter class.\n * This is a class instead of a function type to make it easier to trace\n * who is calling what in the debugger/IDE.\n */\nexport abstract class NextFilter {\n /**\n * Execute the next filter in the chain.\n * @returns Promise of the action\n */\n abstract execute(): Promise<Action>;\n}\n\n/**\n * Filter interface.\n * Similar to Java WebPieces RouteFilter.\n *\n * Filters are executed in priority order (higher priority first)\n * and can wrap the execution of subsequent filters and the controller.\n *\n * Example:\n * ```typescript\n * @injectable()\n * export class LoggingFilter implements Filter {\n * priority = 100;\n *\n * async filter(meta: MethodMeta, next: NextFilter): Promise<Action> {\n * console.log(`Request: ${meta.httpMethod} ${meta.path}`);\n * const action = await next.execute();\n * console.log(`Response: ${action.statusCode}`);\n * return action;\n * }\n * }\n * ```\n */\nexport interface Filter {\n /**\n * Priority of this filter.\n * Higher numbers execute first.\n * Typical values:\n * - 140: Context setup\n * - 120: Request attributes\n * - 90: Metrics\n * - 80: Logging\n * - 60: JSON serialization\n * - 40: Transactions\n * - 0: Controller\n */\n priority: number;\n\n /**\n * Filter method that wraps the next filter/controller.\n *\n * @param meta - Metadata about the method being invoked\n * @param next - NextFilter instance to invoke the next filter in the chain\n * @returns Promise of the action to return\n */\n filter(meta: MethodMeta, next: NextFilter): Promise<Action>;\n}\n\n/**\n * Helper to create a JSON action response.\n */\nexport function jsonAction(data: any, statusCode: number = 200): Action {\n return new Action('json', data, statusCode);\n}\n\n/**\n * Helper to create an error action response.\n */\nexport function errorAction(\n error: Error | string,\n statusCode: number = 500\n): Action {\n return new Action(\n 'error',\n {\n error: typeof error === 'string' ? error : error.message,\n },\n statusCode\n );\n}\n"]}
|
|
@@ -2,17 +2,18 @@ import { Filter, MethodMeta, Action, NextFilter } from '../Filter';
|
|
|
2
2
|
/**
|
|
3
3
|
* Configuration for JsonFilter.
|
|
4
4
|
*/
|
|
5
|
-
export
|
|
5
|
+
export declare class JsonFilterConfig {
|
|
6
6
|
/**
|
|
7
7
|
* Whether to enable validation using class-validator.
|
|
8
8
|
* Default: true
|
|
9
9
|
*/
|
|
10
|
-
validationEnabled
|
|
10
|
+
validationEnabled: boolean;
|
|
11
11
|
/**
|
|
12
12
|
* Whether to log requests and responses.
|
|
13
13
|
* Default: false
|
|
14
14
|
*/
|
|
15
|
-
loggingEnabled
|
|
15
|
+
loggingEnabled: boolean;
|
|
16
|
+
constructor(validationEnabled?: boolean, loggingEnabled?: boolean);
|
|
16
17
|
}
|
|
17
18
|
/**
|
|
18
19
|
* JsonFilter - Handles JSON deserialization and serialization.
|
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.HttpException = exports.ValidationException = exports.JsonFilter = void 0;
|
|
3
|
+
exports.HttpException = exports.ValidationException = exports.JsonFilter = exports.JsonFilterConfig = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const inversify_1 = require("inversify");
|
|
6
6
|
const class_validator_1 = require("class-validator");
|
|
7
7
|
const Filter_1 = require("../Filter");
|
|
8
|
+
/**
|
|
9
|
+
* Configuration for JsonFilter.
|
|
10
|
+
*/
|
|
11
|
+
class JsonFilterConfig {
|
|
12
|
+
constructor(validationEnabled = true, loggingEnabled = false) {
|
|
13
|
+
this.validationEnabled = validationEnabled;
|
|
14
|
+
this.loggingEnabled = loggingEnabled;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
exports.JsonFilterConfig = JsonFilterConfig;
|
|
8
18
|
/**
|
|
9
19
|
* JsonFilter - Handles JSON deserialization and serialization.
|
|
10
20
|
* Priority: 60
|
|
@@ -19,14 +29,10 @@ const Filter_1 = require("../Filter");
|
|
|
19
29
|
* 5. Handle errors and translate to JSON error responses
|
|
20
30
|
*/
|
|
21
31
|
let JsonFilter = class JsonFilter {
|
|
22
|
-
constructor(config =
|
|
32
|
+
constructor(config = new JsonFilterConfig()) {
|
|
23
33
|
this.config = config;
|
|
24
34
|
this.priority = 60;
|
|
25
|
-
|
|
26
|
-
validationEnabled: true,
|
|
27
|
-
loggingEnabled: false,
|
|
28
|
-
...config,
|
|
29
|
-
};
|
|
35
|
+
// Config is now a class with defaults already set in constructor
|
|
30
36
|
}
|
|
31
37
|
async filter(meta, next) {
|
|
32
38
|
try {
|
|
@@ -140,7 +146,7 @@ exports.JsonFilter = JsonFilter;
|
|
|
140
146
|
exports.JsonFilter = JsonFilter = tslib_1.__decorate([
|
|
141
147
|
(0, inversify_1.injectable)(),
|
|
142
148
|
tslib_1.__param(0, (0, inversify_1.unmanaged)()),
|
|
143
|
-
tslib_1.__metadata("design:paramtypes", [
|
|
149
|
+
tslib_1.__metadata("design:paramtypes", [JsonFilterConfig])
|
|
144
150
|
], JsonFilter);
|
|
145
151
|
/**
|
|
146
152
|
* Exception thrown when validation fails.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JsonFilter.js","sourceRoot":"","sources":["../../../../../../packages/http/http-filters/src/filters/JsonFilter.ts"],"names":[],"mappings":";;;;AAAA,yCAAkD;AAElD,qDAA4D;AAC5D,sCAA4F;
|
|
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"]}
|
package/src/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.HttpException = exports.ValidationException = exports.JsonFilter = exports.ContextFilter = exports.FilterChain = exports.errorAction = exports.jsonAction = exports.NextFilter = void 0;
|
|
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;
|
|
4
4
|
var Filter_1 = require("./Filter");
|
|
5
|
+
Object.defineProperty(exports, "MethodMeta", { enumerable: true, get: function () { return Filter_1.MethodMeta; } });
|
|
6
|
+
Object.defineProperty(exports, "Action", { enumerable: true, get: function () { return Filter_1.Action; } });
|
|
5
7
|
Object.defineProperty(exports, "NextFilter", { enumerable: true, get: function () { return Filter_1.NextFilter; } });
|
|
6
8
|
Object.defineProperty(exports, "jsonAction", { enumerable: true, get: function () { return Filter_1.jsonAction; } });
|
|
7
9
|
Object.defineProperty(exports, "errorAction", { enumerable: true, get: function () { return Filter_1.errorAction; } });
|
|
@@ -11,6 +13,7 @@ var ContextFilter_1 = require("./filters/ContextFilter");
|
|
|
11
13
|
Object.defineProperty(exports, "ContextFilter", { enumerable: true, get: function () { return ContextFilter_1.ContextFilter; } });
|
|
12
14
|
var JsonFilter_1 = require("./filters/JsonFilter");
|
|
13
15
|
Object.defineProperty(exports, "JsonFilter", { enumerable: true, get: function () { return JsonFilter_1.JsonFilter; } });
|
|
16
|
+
Object.defineProperty(exports, "JsonFilterConfig", { enumerable: true, get: function () { return JsonFilter_1.JsonFilterConfig; } });
|
|
14
17
|
Object.defineProperty(exports, "ValidationException", { enumerable: true, get: function () { return JsonFilter_1.ValidationException; } });
|
|
15
18
|
Object.defineProperty(exports, "HttpException", { enumerable: true, get: function () { return JsonFilter_1.HttpException; } });
|
|
16
19
|
//# 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;
|
|
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"]}
|