@webpieces/http-server 0.2.12 → 0.2.14
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 +5 -4
- package/src/FilterMatcher.d.ts +7 -5
- package/src/FilterMatcher.js +5 -4
- package/src/FilterMatcher.js.map +1 -1
- package/src/MethodMeta.d.ts +42 -0
- package/src/MethodMeta.js +40 -0
- package/src/MethodMeta.js.map +1 -0
- package/src/RouteBuilderImpl.d.ts +51 -27
- package/src/RouteBuilderImpl.js +96 -36
- package/src/RouteBuilderImpl.js.map +1 -1
- package/src/RouteHandler.d.ts +22 -0
- package/src/RouteHandler.js +20 -0
- package/src/RouteHandler.js.map +1 -0
- package/src/WebpiecesFactory.d.ts +44 -0
- package/src/WebpiecesFactory.js +62 -0
- package/src/WebpiecesFactory.js.map +1 -0
- package/src/WebpiecesServer.d.ts +18 -135
- package/src/WebpiecesServer.js +0 -352
- package/src/WebpiecesServer.js.map +1 -1
- package/src/WebpiecesServerImpl.d.ts +113 -0
- package/src/WebpiecesServerImpl.js +292 -0
- package/src/WebpiecesServerImpl.js.map +1 -0
- package/src/filters/ContextFilter.d.ts +12 -0
- package/src/filters/ContextFilter.js +34 -0
- package/src/filters/ContextFilter.js.map +1 -0
- package/src/filters/JsonFilter.d.ts +62 -0
- package/src/filters/JsonFilter.js +146 -0
- package/src/filters/JsonFilter.js.map +1 -0
- package/src/index.d.ts +6 -1
- package/src/index.js +17 -4
- package/src/index.js.map +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webpieces/http-server",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.14",
|
|
4
4
|
"description": "WebPieces server with filter chain and dependency injection",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -22,8 +22,9 @@
|
|
|
22
22
|
"access": "public"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@webpieces/core-meta": "0.2.
|
|
26
|
-
"@webpieces/
|
|
27
|
-
"@webpieces/http-
|
|
25
|
+
"@webpieces/core-meta": "0.2.14",
|
|
26
|
+
"@webpieces/core-util": "0.2.14",
|
|
27
|
+
"@webpieces/http-routing": "0.2.14",
|
|
28
|
+
"@webpieces/http-filters": "0.2.14"
|
|
28
29
|
}
|
|
29
30
|
}
|
package/src/FilterMatcher.d.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
|
-
import { Filter } from '@webpieces/http-filters';
|
|
1
|
+
import { Filter, WpResponse } from '@webpieces/http-filters';
|
|
2
|
+
import { MethodMeta } from './MethodMeta';
|
|
2
3
|
import { FilterDefinition } from '@webpieces/core-meta';
|
|
4
|
+
/**
|
|
5
|
+
* Type alias for HTTP filters that work with MethodMeta and ResponseWrapper.
|
|
6
|
+
*/
|
|
7
|
+
export type HttpFilter = Filter<MethodMeta, WpResponse<unknown>>;
|
|
3
8
|
/**
|
|
4
9
|
* FilterMatcher - Matches filters to routes based on filepath patterns.
|
|
5
10
|
* Similar to Java SharedMatchUtil.findMatchingFilters().
|
|
@@ -21,10 +26,7 @@ export declare class FilterMatcher {
|
|
|
21
26
|
* @param allFilters - All registered filters with their definitions
|
|
22
27
|
* @returns Array of matching filters, sorted by priority (highest first)
|
|
23
28
|
*/
|
|
24
|
-
static findMatchingFilters(controllerFilepath: string | undefined, allFilters: Array<
|
|
25
|
-
filter: Filter;
|
|
26
|
-
definition: FilterDefinition;
|
|
27
|
-
}>): Filter[];
|
|
29
|
+
static findMatchingFilters(controllerFilepath: string | undefined, allFilters: Array<FilterDefinition>): HttpFilter[];
|
|
28
30
|
/**
|
|
29
31
|
* Normalize a controller filepath for consistent matching.
|
|
30
32
|
* - Converts backslashes to forward slashes (Windows compatibility)
|
package/src/FilterMatcher.js
CHANGED
|
@@ -25,17 +25,18 @@ class FilterMatcher {
|
|
|
25
25
|
*/
|
|
26
26
|
static findMatchingFilters(controllerFilepath, allFilters) {
|
|
27
27
|
const matchingFilters = [];
|
|
28
|
-
for (const
|
|
28
|
+
for (const definition of allFilters) {
|
|
29
29
|
const pattern = definition.filepathPattern;
|
|
30
|
+
const filter = definition.filter;
|
|
30
31
|
// Special case: '*' matches all controllers (global filter)
|
|
31
32
|
if (pattern === '*') {
|
|
32
|
-
matchingFilters.push({ filter, priority:
|
|
33
|
+
matchingFilters.push({ filter, priority: definition.priority });
|
|
33
34
|
continue;
|
|
34
35
|
}
|
|
35
36
|
// If no filepath available, only match wildcard patterns
|
|
36
37
|
if (!controllerFilepath) {
|
|
37
38
|
if (pattern === '**/*') {
|
|
38
|
-
matchingFilters.push({ filter, priority:
|
|
39
|
+
matchingFilters.push({ filter, priority: definition.priority });
|
|
39
40
|
}
|
|
40
41
|
continue;
|
|
41
42
|
}
|
|
@@ -43,7 +44,7 @@ class FilterMatcher {
|
|
|
43
44
|
const normalizedPath = FilterMatcher.normalizeFilepath(controllerFilepath);
|
|
44
45
|
// Match using minimatch
|
|
45
46
|
if ((0, minimatch_1.minimatch)(normalizedPath, pattern)) {
|
|
46
|
-
matchingFilters.push({ filter, priority:
|
|
47
|
+
matchingFilters.push({ filter, priority: definition.priority });
|
|
47
48
|
}
|
|
48
49
|
}
|
|
49
50
|
// Sort by priority (highest first)
|
package/src/FilterMatcher.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FilterMatcher.js","sourceRoot":"","sources":["../../../../../packages/http/http-server/src/FilterMatcher.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"FilterMatcher.js","sourceRoot":"","sources":["../../../../../packages/http/http-server/src/FilterMatcher.ts"],"names":[],"mappings":";;;AAGA,yCAAsC;AAOtC;;;;;;;;;;;;GAYG;AACH,MAAa,aAAa;IACxB;;;;;;OAMG;IACH,MAAM,CAAC,mBAAmB,CACxB,kBAAsC,EACtC,UAAmC;QAEnC,MAAM,eAAe,GAAoD,EAAE,CAAC;QAE5E,KAAK,MAAM,UAAU,IAAI,UAAU,EAAE,CAAC;YACpC,MAAM,OAAO,GAAG,UAAU,CAAC,eAAe,CAAC;YAC3C,MAAM,MAAM,GAAG,UAAU,CAAC,MAAoB,CAAC;YAE/C,4DAA4D;YAC5D,IAAI,OAAO,KAAK,GAAG,EAAE,CAAC;gBACpB,eAAe,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC,QAAQ,EAAE,CAAC,CAAC;gBAChE,SAAS;YACX,CAAC;YAED,yDAAyD;YACzD,IAAI,CAAC,kBAAkB,EAAE,CAAC;gBACxB,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;oBACvB,eAAe,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC,QAAQ,EAAE,CAAC,CAAC;gBAClE,CAAC;gBACD,SAAS;YACX,CAAC;YAED,6CAA6C;YAC7C,MAAM,cAAc,GAAG,aAAa,CAAC,iBAAiB,CAAC,kBAAkB,CAAC,CAAC;YAE3E,wBAAwB;YACxB,IAAI,IAAA,qBAAS,EAAC,cAAc,EAAE,OAAO,CAAC,EAAE,CAAC;gBACvC,eAAe,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC,QAAQ,EAAE,CAAC,CAAC;YAClE,CAAC;QACH,CAAC;QAED,mCAAmC;QACnC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC;QAExD,OAAO,eAAe,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACpD,CAAC;IAED;;;;;;;OAOG;IACH,MAAM,CAAC,iBAAiB,CAAC,QAAgB;QACvC,OAAO,QAAQ;aACZ,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,yCAAyC;aAC7D,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,sBAAsB;IACjD,CAAC;CACF;AA5DD,sCA4DC","sourcesContent":["import { Filter, WpResponse } from '@webpieces/http-filters';\nimport { MethodMeta } from './MethodMeta';\nimport { FilterDefinition } from '@webpieces/core-meta';\nimport { minimatch } from 'minimatch';\n\n/**\n * Type alias for HTTP filters that work with MethodMeta and ResponseWrapper.\n */\nexport type HttpFilter = Filter<MethodMeta, WpResponse<unknown>>;\n\n/**\n * FilterMatcher - Matches filters to routes based on filepath patterns.\n * Similar to Java SharedMatchUtil.findMatchingFilters().\n *\n * Responsibilities:\n * 1. Filter based on filepath glob pattern matching\n * 2. Sort matching filters by priority (higher first)\n *\n * Differences from Java:\n * - Uses glob patterns instead of regex\n * - Only matches filepaths (no URL path or HTTPS filtering yet)\n * - Simpler API focused on one responsibility\n */\nexport class FilterMatcher {\n /**\n * Find filters that match the given controller filepath.\n *\n * @param controllerFilepath - The filepath of the controller source file\n * @param allFilters - All registered filters with their definitions\n * @returns Array of matching filters, sorted by priority (highest first)\n */\n static findMatchingFilters(\n controllerFilepath: string | undefined,\n allFilters: Array<FilterDefinition>\n ): HttpFilter[] {\n const matchingFilters: Array<{ filter: HttpFilter; priority: number }> = [];\n\n for (const definition of allFilters) {\n const pattern = definition.filepathPattern;\n const filter = definition.filter as HttpFilter;\n\n // Special case: '*' matches all controllers (global filter)\n if (pattern === '*') {\n matchingFilters.push({ filter, priority: definition.priority });\n continue;\n }\n\n // If no filepath available, only match wildcard patterns\n if (!controllerFilepath) {\n if (pattern === '**/*') {\n matchingFilters.push({ filter, priority: definition.priority });\n }\n continue;\n }\n\n // Normalize filepath for consistent matching\n const normalizedPath = FilterMatcher.normalizeFilepath(controllerFilepath);\n\n // Match using minimatch\n if (minimatch(normalizedPath, pattern)) {\n matchingFilters.push({ filter, priority: definition.priority });\n }\n }\n\n // Sort by priority (highest first)\n matchingFilters.sort((a, b) => b.priority - a.priority);\n\n return matchingFilters.map((item) => item.filter);\n }\n\n /**\n * Normalize a controller filepath for consistent matching.\n * - Converts backslashes to forward slashes (Windows compatibility)\n * - Removes leading './'\n *\n * @param filepath - Raw filepath\n * @returns Normalized filepath\n */\n static normalizeFilepath(filepath: string): string {\n return filepath\n .replace(/\\\\/g, '/') // Windows backslashes to forward slashes\n .replace(/^\\.\\//, ''); // Remove leading './'\n }\n}\n"]}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { RouteMetadata2, RouteRequest } from '@webpieces/core-meta';
|
|
2
|
+
/**
|
|
3
|
+
* Metadata about the method being invoked.
|
|
4
|
+
* Passed to filters and contains request information.
|
|
5
|
+
*
|
|
6
|
+
* MethodMeta is created by WebpiecesServerImpl when handling a request:
|
|
7
|
+
* - routeMeta: Static route information (httpMethod, path, methodName)
|
|
8
|
+
* - routeRequest: Express Request/Response objects
|
|
9
|
+
* - requestDto: Set by JsonFilter after deserializing the request body
|
|
10
|
+
*/
|
|
11
|
+
export declare class MethodMeta {
|
|
12
|
+
/**
|
|
13
|
+
* Route metadata (httpMethod, path, methodName, parameterTypes)
|
|
14
|
+
*/
|
|
15
|
+
routeMeta: RouteMetadata2;
|
|
16
|
+
/**
|
|
17
|
+
* Express Request and Response objects
|
|
18
|
+
*/
|
|
19
|
+
routeRequest: RouteRequest;
|
|
20
|
+
/**
|
|
21
|
+
* The deserialized request DTO.
|
|
22
|
+
* Set by JsonFilter after deserializing the request body.
|
|
23
|
+
*/
|
|
24
|
+
requestDto?: unknown;
|
|
25
|
+
/**
|
|
26
|
+
* Additional metadata for storing request-scoped data.
|
|
27
|
+
*/
|
|
28
|
+
metadata: Map<string, unknown>;
|
|
29
|
+
constructor(routeMeta: RouteMetadata2, routeRequest: RouteRequest, requestDto?: unknown, metadata?: Map<string, unknown>);
|
|
30
|
+
/**
|
|
31
|
+
* Get the HTTP method (convenience accessor).
|
|
32
|
+
*/
|
|
33
|
+
get httpMethod(): string;
|
|
34
|
+
/**
|
|
35
|
+
* Get the request path (convenience accessor).
|
|
36
|
+
*/
|
|
37
|
+
get path(): string;
|
|
38
|
+
/**
|
|
39
|
+
* Get the method name (convenience accessor).
|
|
40
|
+
*/
|
|
41
|
+
get methodName(): string;
|
|
42
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MethodMeta = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Metadata about the method being invoked.
|
|
6
|
+
* Passed to filters and contains request information.
|
|
7
|
+
*
|
|
8
|
+
* MethodMeta is created by WebpiecesServerImpl when handling a request:
|
|
9
|
+
* - routeMeta: Static route information (httpMethod, path, methodName)
|
|
10
|
+
* - routeRequest: Express Request/Response objects
|
|
11
|
+
* - requestDto: Set by JsonFilter after deserializing the request body
|
|
12
|
+
*/
|
|
13
|
+
class MethodMeta {
|
|
14
|
+
constructor(routeMeta, routeRequest, requestDto, metadata) {
|
|
15
|
+
this.routeMeta = routeMeta;
|
|
16
|
+
this.routeRequest = routeRequest;
|
|
17
|
+
this.requestDto = requestDto;
|
|
18
|
+
this.metadata = metadata ?? new Map();
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Get the HTTP method (convenience accessor).
|
|
22
|
+
*/
|
|
23
|
+
get httpMethod() {
|
|
24
|
+
return this.routeMeta.httpMethod;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Get the request path (convenience accessor).
|
|
28
|
+
*/
|
|
29
|
+
get path() {
|
|
30
|
+
return this.routeMeta.path;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Get the method name (convenience accessor).
|
|
34
|
+
*/
|
|
35
|
+
get methodName() {
|
|
36
|
+
return this.routeMeta.methodName;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
exports.MethodMeta = MethodMeta;
|
|
40
|
+
//# sourceMappingURL=MethodMeta.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MethodMeta.js","sourceRoot":"","sources":["../../../../../packages/http/http-server/src/MethodMeta.ts"],"names":[],"mappings":";;;AAEA;;;;;;;;GAQG;AACH,MAAa,UAAU;IAsBrB,YACE,SAAyB,EACzB,YAA0B,EAC1B,UAAoB,EACpB,QAA+B;QAE/B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;QACjC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,QAAQ,GAAG,QAAQ,IAAI,IAAI,GAAG,EAAE,CAAC;IACxC,CAAC;IAED;;OAEG;IACH,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC;IACnC,CAAC;IAED;;OAEG;IACH,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;IAC7B,CAAC;IAED;;OAEG;IACH,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC;IACnC,CAAC;CACF;AAtDD,gCAsDC","sourcesContent":["import { RouteMetadata2, RouteRequest } from '@webpieces/core-meta';\n\n/**\n * Metadata about the method being invoked.\n * Passed to filters and contains request information.\n *\n * MethodMeta is created by WebpiecesServerImpl when handling a request:\n * - routeMeta: Static route information (httpMethod, path, methodName)\n * - routeRequest: Express Request/Response objects\n * - requestDto: Set by JsonFilter after deserializing the request body\n */\nexport class MethodMeta {\n /**\n * Route metadata (httpMethod, path, methodName, parameterTypes)\n */\n routeMeta: RouteMetadata2;\n\n /**\n * Express Request and Response objects\n */\n routeRequest: RouteRequest;\n\n /**\n * The deserialized request DTO.\n * Set by JsonFilter after deserializing the request body.\n */\n requestDto?: unknown;\n\n /**\n * Additional metadata for storing request-scoped data.\n */\n metadata: Map<string, unknown>;\n\n constructor(\n routeMeta: RouteMetadata2,\n routeRequest: RouteRequest,\n requestDto?: unknown,\n metadata?: Map<string, unknown>\n ) {\n this.routeMeta = routeMeta;\n this.routeRequest = routeRequest;\n this.requestDto = requestDto;\n this.metadata = metadata ?? new Map();\n }\n\n /**\n * Get the HTTP method (convenience accessor).\n */\n get httpMethod(): string {\n return this.routeMeta.httpMethod;\n }\n\n /**\n * Get the request path (convenience accessor).\n */\n get path(): string {\n return this.routeMeta.path;\n }\n\n /**\n * Get the method name (convenience accessor).\n */\n get methodName(): string {\n return this.routeMeta.methodName;\n }\n}\n"]}
|
|
@@ -1,21 +1,32 @@
|
|
|
1
1
|
import { Container } from 'inversify';
|
|
2
|
-
import { RouteBuilder, RouteDefinition, FilterDefinition
|
|
3
|
-
import { Filter } from '@webpieces/http-filters';
|
|
4
|
-
import {
|
|
2
|
+
import { RouteBuilder, RouteDefinition, FilterDefinition } from '@webpieces/core-meta';
|
|
3
|
+
import { Filter, WpResponse } from '@webpieces/http-filters';
|
|
4
|
+
import { RouteHandler } from './RouteHandler';
|
|
5
|
+
import { MethodMeta } from './MethodMeta';
|
|
5
6
|
/**
|
|
6
|
-
*
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
* -
|
|
7
|
+
* Type alias for HTTP filters that work with MethodMeta and ResponseWrapper.
|
|
8
|
+
*/
|
|
9
|
+
export type HttpFilter = Filter<MethodMeta, WpResponse<unknown>>;
|
|
10
|
+
/**
|
|
11
|
+
* FilterWithMeta - Pairs a resolved filter instance with its definition.
|
|
12
|
+
* Stores both the DI-resolved filter and the metadata needed for matching.
|
|
13
|
+
*/
|
|
14
|
+
export declare class FilterWithMeta {
|
|
15
|
+
filter: HttpFilter;
|
|
16
|
+
definition: FilterDefinition;
|
|
17
|
+
constructor(filter: HttpFilter, definition: FilterDefinition);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* RouteHandlerWithMeta - Pairs a route handler with its definition.
|
|
21
|
+
* Stores both the handler (which wraps the DI-resolved controller) and the route metadata.
|
|
11
22
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
23
|
+
* We use unknown for the generic type since we store different TResult types in the same Map.
|
|
24
|
+
* Type safety is maintained through the generic on RouteDefinition at registration time.
|
|
14
25
|
*/
|
|
15
|
-
export declare class
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
constructor(
|
|
26
|
+
export declare class RouteHandlerWithMeta {
|
|
27
|
+
handler: RouteHandler<unknown>;
|
|
28
|
+
definition: RouteDefinition<unknown>;
|
|
29
|
+
constructor(handler: RouteHandler<unknown>, definition: RouteDefinition<unknown>);
|
|
19
30
|
}
|
|
20
31
|
/**
|
|
21
32
|
* RouteBuilderImpl - Concrete implementation of RouteBuilder interface.
|
|
@@ -28,39 +39,52 @@ export declare class RegisteredRoute<TResult = unknown> extends RouteDefinition<
|
|
|
28
39
|
* - Improve traceability and debugging
|
|
29
40
|
* - Make the code easier to understand
|
|
30
41
|
* - Enable better IDE navigation (Cmd+Click on addRoute works!)
|
|
42
|
+
*
|
|
43
|
+
* DI Pattern: This class is registered in webpiecesContainer via @provideSingleton()
|
|
44
|
+
* but needs appContainer to resolve filters/controllers. The container is set via
|
|
45
|
+
* setContainer() after appContainer is created (late binding pattern).
|
|
31
46
|
*/
|
|
32
47
|
export declare class RouteBuilderImpl implements RouteBuilder {
|
|
33
48
|
private routes;
|
|
34
49
|
private filterRegistry;
|
|
35
|
-
private container
|
|
50
|
+
private container?;
|
|
36
51
|
/**
|
|
37
|
-
*
|
|
52
|
+
* Set the DI container used for resolving filters and controllers.
|
|
53
|
+
* Called by WebpiecesCoreServer after appContainer is created.
|
|
38
54
|
*
|
|
39
|
-
* @param
|
|
40
|
-
* @param filterRegistry - Array to store registered filters with their definitions
|
|
41
|
-
* @param container - DI container for resolving filter instances
|
|
55
|
+
* @param container - The application DI container (appContainer)
|
|
42
56
|
*/
|
|
43
|
-
|
|
44
|
-
filter: Filter;
|
|
45
|
-
definition: FilterDefinition;
|
|
46
|
-
}>, container: Container);
|
|
57
|
+
setContainer(container: Container): void;
|
|
47
58
|
/**
|
|
48
59
|
* Register a route with the router.
|
|
49
60
|
*
|
|
61
|
+
* Resolves the controller from DI container ONCE and creates a handler that uses
|
|
62
|
+
* the resolved controller instance. This is more efficient than resolving on every request.
|
|
63
|
+
*
|
|
50
64
|
* The route is stored with a key of "METHOD:path" (e.g., "POST:/search/item").
|
|
51
|
-
* The TResult generic ensures type safety for the route's return type.
|
|
52
65
|
*
|
|
53
|
-
* @param route - Route definition with
|
|
66
|
+
* @param route - Route definition with controller class and method name
|
|
54
67
|
*/
|
|
55
68
|
addRoute<TResult = unknown>(route: RouteDefinition<TResult>): void;
|
|
56
69
|
/**
|
|
57
70
|
* Register a filter with the filter chain.
|
|
58
71
|
*
|
|
59
|
-
*
|
|
72
|
+
* Resolves the filter from DI container and pairs it with the filter definition.
|
|
60
73
|
* The definition includes pattern information used for route-specific filtering.
|
|
61
|
-
* Filters will be matched and executed in priority order (higher priority first).
|
|
62
74
|
*
|
|
63
75
|
* @param filterDef - Filter definition with priority, filter class, and optional filepath pattern
|
|
64
76
|
*/
|
|
65
77
|
addFilter(filterDef: FilterDefinition): void;
|
|
78
|
+
/**
|
|
79
|
+
* Get all registered routes.
|
|
80
|
+
*
|
|
81
|
+
* @returns Map of routes with handlers and definitions, keyed by "METHOD:path"
|
|
82
|
+
*/
|
|
83
|
+
getRoutes(): Map<string, RouteHandlerWithMeta>;
|
|
84
|
+
/**
|
|
85
|
+
* Get all filters sorted by priority (highest priority first).
|
|
86
|
+
*
|
|
87
|
+
* @returns Array of FilterWithMeta sorted by priority
|
|
88
|
+
*/
|
|
89
|
+
getSortedFilters(): Array<FilterWithMeta>;
|
|
66
90
|
}
|
package/src/RouteBuilderImpl.js
CHANGED
|
@@ -1,25 +1,35 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.RouteBuilderImpl = exports.
|
|
4
|
-
const
|
|
3
|
+
exports.RouteBuilderImpl = exports.RouteHandlerWithMeta = exports.FilterWithMeta = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const inversify_1 = require("inversify");
|
|
6
|
+
const http_routing_1 = require("@webpieces/http-routing");
|
|
7
|
+
const RouteHandler_1 = require("./RouteHandler");
|
|
5
8
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
* FilterWithMeta - Pairs a resolved filter instance with its definition.
|
|
10
|
+
* Stores both the DI-resolved filter and the metadata needed for matching.
|
|
11
|
+
*/
|
|
12
|
+
class FilterWithMeta {
|
|
13
|
+
constructor(filter, definition) {
|
|
14
|
+
this.filter = filter;
|
|
15
|
+
this.definition = definition;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
exports.FilterWithMeta = FilterWithMeta;
|
|
19
|
+
/**
|
|
20
|
+
* RouteHandlerWithMeta - Pairs a route handler with its definition.
|
|
21
|
+
* Stores both the handler (which wraps the DI-resolved controller) and the route metadata.
|
|
11
22
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
23
|
+
* We use unknown for the generic type since we store different TResult types in the same Map.
|
|
24
|
+
* Type safety is maintained through the generic on RouteDefinition at registration time.
|
|
14
25
|
*/
|
|
15
|
-
class
|
|
16
|
-
constructor(
|
|
17
|
-
|
|
18
|
-
this.
|
|
19
|
-
this.controllerClass = controllerClass;
|
|
26
|
+
class RouteHandlerWithMeta {
|
|
27
|
+
constructor(handler, definition) {
|
|
28
|
+
this.handler = handler;
|
|
29
|
+
this.definition = definition;
|
|
20
30
|
}
|
|
21
31
|
}
|
|
22
|
-
exports.
|
|
32
|
+
exports.RouteHandlerWithMeta = RouteHandlerWithMeta;
|
|
23
33
|
/**
|
|
24
34
|
* RouteBuilderImpl - Concrete implementation of RouteBuilder interface.
|
|
25
35
|
*
|
|
@@ -31,51 +41,101 @@ exports.RegisteredRoute = RegisteredRoute;
|
|
|
31
41
|
* - Improve traceability and debugging
|
|
32
42
|
* - Make the code easier to understand
|
|
33
43
|
* - Enable better IDE navigation (Cmd+Click on addRoute works!)
|
|
44
|
+
*
|
|
45
|
+
* DI Pattern: This class is registered in webpiecesContainer via @provideSingleton()
|
|
46
|
+
* but needs appContainer to resolve filters/controllers. The container is set via
|
|
47
|
+
* setContainer() after appContainer is created (late binding pattern).
|
|
34
48
|
*/
|
|
35
|
-
class RouteBuilderImpl {
|
|
49
|
+
let RouteBuilderImpl = class RouteBuilderImpl {
|
|
50
|
+
constructor() {
|
|
51
|
+
this.routes = new Map();
|
|
52
|
+
this.filterRegistry = [];
|
|
53
|
+
}
|
|
36
54
|
/**
|
|
37
|
-
*
|
|
55
|
+
* Set the DI container used for resolving filters and controllers.
|
|
56
|
+
* Called by WebpiecesCoreServer after appContainer is created.
|
|
38
57
|
*
|
|
39
|
-
* @param
|
|
40
|
-
* @param filterRegistry - Array to store registered filters with their definitions
|
|
41
|
-
* @param container - DI container for resolving filter instances
|
|
58
|
+
* @param container - The application DI container (appContainer)
|
|
42
59
|
*/
|
|
43
|
-
|
|
44
|
-
this.routes = routes;
|
|
45
|
-
this.filterRegistry = filterRegistry;
|
|
60
|
+
setContainer(container) {
|
|
46
61
|
this.container = container;
|
|
47
62
|
}
|
|
48
63
|
/**
|
|
49
64
|
* Register a route with the router.
|
|
50
65
|
*
|
|
66
|
+
* Resolves the controller from DI container ONCE and creates a handler that uses
|
|
67
|
+
* the resolved controller instance. This is more efficient than resolving on every request.
|
|
68
|
+
*
|
|
51
69
|
* The route is stored with a key of "METHOD:path" (e.g., "POST:/search/item").
|
|
52
|
-
* The TResult generic ensures type safety for the route's return type.
|
|
53
70
|
*
|
|
54
|
-
* @param route - Route definition with
|
|
71
|
+
* @param route - Route definition with controller class and method name
|
|
55
72
|
*/
|
|
56
73
|
addRoute(route) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
74
|
+
if (!this.container) {
|
|
75
|
+
throw new Error('Container not set. Call setContainer() before registering routes.');
|
|
76
|
+
}
|
|
77
|
+
const routeMeta = route.routeMeta;
|
|
78
|
+
const key = `${routeMeta.httpMethod}:${routeMeta.path}`;
|
|
79
|
+
// Resolve controller instance from DI container ONCE (not on every request!)
|
|
80
|
+
const controller = this.container.get(route.controllerClass);
|
|
81
|
+
// Get the controller method
|
|
82
|
+
const method = controller[routeMeta.methodName];
|
|
83
|
+
if (typeof method !== 'function') {
|
|
84
|
+
const controllerName = route.controllerClass.name || 'Unknown';
|
|
85
|
+
throw new Error(`Method ${routeMeta.methodName} not found on controller ${controllerName}`);
|
|
86
|
+
}
|
|
87
|
+
// Create handler that uses the resolved controller instance
|
|
88
|
+
const handler = new class extends RouteHandler_1.RouteHandler {
|
|
89
|
+
async execute(meta) {
|
|
90
|
+
// Invoke the method with requestDto from meta
|
|
91
|
+
// The controller is already resolved - no DI lookup on every request!
|
|
92
|
+
// Pass requestDto as the single argument to the controller method
|
|
93
|
+
const result = await method.call(controller, meta.requestDto);
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
// Store handler with route definition
|
|
98
|
+
const routeWithMeta = new RouteHandlerWithMeta(handler, route);
|
|
99
|
+
this.routes.set(key, routeWithMeta);
|
|
61
100
|
}
|
|
62
101
|
/**
|
|
63
102
|
* Register a filter with the filter chain.
|
|
64
103
|
*
|
|
65
|
-
*
|
|
104
|
+
* Resolves the filter from DI container and pairs it with the filter definition.
|
|
66
105
|
* The definition includes pattern information used for route-specific filtering.
|
|
67
|
-
* Filters will be matched and executed in priority order (higher priority first).
|
|
68
106
|
*
|
|
69
107
|
* @param filterDef - Filter definition with priority, filter class, and optional filepath pattern
|
|
70
108
|
*/
|
|
71
109
|
addFilter(filterDef) {
|
|
110
|
+
if (!this.container) {
|
|
111
|
+
throw new Error('Container not set. Call setContainer() before registering filters.');
|
|
112
|
+
}
|
|
72
113
|
// Resolve filter instance from DI container
|
|
73
114
|
const filter = this.container.get(filterDef.filterClass);
|
|
74
|
-
//
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
this.filterRegistry.push({ filter, definition: filterDef });
|
|
115
|
+
// Store filter with its definition
|
|
116
|
+
const filterWithMeta = new FilterWithMeta(filter, filterDef);
|
|
117
|
+
this.filterRegistry.push(filterWithMeta);
|
|
78
118
|
}
|
|
79
|
-
|
|
119
|
+
/**
|
|
120
|
+
* Get all registered routes.
|
|
121
|
+
*
|
|
122
|
+
* @returns Map of routes with handlers and definitions, keyed by "METHOD:path"
|
|
123
|
+
*/
|
|
124
|
+
getRoutes() {
|
|
125
|
+
return this.routes;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Get all filters sorted by priority (highest priority first).
|
|
129
|
+
*
|
|
130
|
+
* @returns Array of FilterWithMeta sorted by priority
|
|
131
|
+
*/
|
|
132
|
+
getSortedFilters() {
|
|
133
|
+
return [...this.filterRegistry].sort((a, b) => b.definition.priority - a.definition.priority);
|
|
134
|
+
}
|
|
135
|
+
};
|
|
80
136
|
exports.RouteBuilderImpl = RouteBuilderImpl;
|
|
137
|
+
exports.RouteBuilderImpl = RouteBuilderImpl = tslib_1.__decorate([
|
|
138
|
+
(0, http_routing_1.provideSingleton)(),
|
|
139
|
+
(0, inversify_1.injectable)()
|
|
140
|
+
], RouteBuilderImpl);
|
|
81
141
|
//# sourceMappingURL=RouteBuilderImpl.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RouteBuilderImpl.js","sourceRoot":"","sources":["../../../../../packages/http/http-server/src/RouteBuilderImpl.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"RouteBuilderImpl.js","sourceRoot":"","sources":["../../../../../packages/http/http-server/src/RouteBuilderImpl.ts"],"names":[],"mappings":"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","sourcesContent":["import { Container, injectable } from 'inversify';\nimport { RouteBuilder, RouteDefinition, FilterDefinition } from '@webpieces/core-meta';\nimport { Filter, WpResponse } from '@webpieces/http-filters';\nimport { provideSingleton } from '@webpieces/http-routing';\nimport { RouteHandler } from './RouteHandler';\nimport { MethodMeta } from './MethodMeta';\n\n/**\n * Type alias for HTTP filters that work with MethodMeta and ResponseWrapper.\n */\nexport type HttpFilter = Filter<MethodMeta, WpResponse<unknown>>;\n\n/**\n * FilterWithMeta - Pairs a resolved filter instance with its definition.\n * Stores both the DI-resolved filter and the metadata needed for matching.\n */\nexport class FilterWithMeta {\n constructor(\n public filter: HttpFilter,\n public definition: FilterDefinition\n ) {}\n}\n\n/**\n * RouteHandlerWithMeta - Pairs a route handler with its definition.\n * Stores both the handler (which wraps the DI-resolved controller) and the route metadata.\n *\n * We use unknown for the generic type since we store different TResult types in the same Map.\n * Type safety is maintained through the generic on RouteDefinition at registration time.\n */\nexport class RouteHandlerWithMeta {\n constructor(\n public handler: RouteHandler<unknown>,\n public definition: RouteDefinition<unknown>\n ) {}\n}\n\n/**\n * RouteBuilderImpl - Concrete implementation of RouteBuilder interface.\n *\n * Similar to Java WebPieces RouteBuilder, this class is responsible for:\n * 1. Registering routes with their handlers\n * 2. Registering filters with priority\n *\n * This class is explicit (not anonymous) to:\n * - Improve traceability and debugging\n * - Make the code easier to understand\n * - Enable better IDE navigation (Cmd+Click on addRoute works!)\n *\n * DI Pattern: This class is registered in webpiecesContainer via @provideSingleton()\n * but needs appContainer to resolve filters/controllers. The container is set via\n * setContainer() after appContainer is created (late binding pattern).\n */\n@provideSingleton()\n@injectable()\nexport class RouteBuilderImpl implements RouteBuilder {\n private routes: Map<string, RouteHandlerWithMeta> = new Map();\n private filterRegistry: Array<FilterWithMeta> = [];\n private container?: Container;\n\n /**\n * Set the DI container used for resolving filters and controllers.\n * Called by WebpiecesCoreServer after appContainer is created.\n *\n * @param container - The application DI container (appContainer)\n */\n setContainer(container: Container): void {\n this.container = container;\n }\n\n /**\n * Register a route with the router.\n *\n * Resolves the controller from DI container ONCE and creates a handler that uses\n * the resolved controller instance. This is more efficient than resolving on every request.\n *\n * The route is stored with a key of \"METHOD:path\" (e.g., \"POST:/search/item\").\n *\n * @param route - Route definition with controller class and method name\n */\n addRoute<TResult = unknown>(route: RouteDefinition<TResult>): void {\n if (!this.container) {\n throw new Error('Container not set. Call setContainer() before registering routes.');\n }\n\n const routeMeta = route.routeMeta;\n\n const key = `${routeMeta.httpMethod}:${routeMeta.path}`;\n\n // Resolve controller instance from DI container ONCE (not on every request!)\n const controller = this.container.get(route.controllerClass);\n\n // Get the controller method\n const method = (controller as Record<string, unknown>)[routeMeta.methodName];\n if (typeof method !== 'function') {\n const controllerName = (route.controllerClass as { name?: string }).name || 'Unknown';\n throw new Error(\n `Method ${routeMeta.methodName} not found on controller ${controllerName}`\n );\n }\n\n // Create handler that uses the resolved controller instance\n const handler = new class extends RouteHandler<TResult> {\n async execute(meta: MethodMeta): Promise<TResult> {\n // Invoke the method with requestDto from meta\n // The controller is already resolved - no DI lookup on every request!\n // Pass requestDto as the single argument to the controller method\n const result: TResult = await method.call(controller, meta.requestDto);\n return result;\n }\n };\n\n // Store handler with route definition\n const routeWithMeta = new RouteHandlerWithMeta(\n handler as RouteHandler<unknown>,\n route as RouteDefinition<unknown>\n );\n\n this.routes.set(key, routeWithMeta);\n }\n\n /**\n * Register a filter with the filter chain.\n *\n * Resolves the filter from DI container and pairs it with the filter definition.\n * The definition includes pattern information used for route-specific filtering.\n *\n * @param filterDef - Filter definition with priority, filter class, and optional filepath pattern\n */\n addFilter(filterDef: FilterDefinition): void {\n if (!this.container) {\n throw new Error('Container not set. Call setContainer() before registering filters.');\n }\n\n // Resolve filter instance from DI container\n const filter = this.container.get<HttpFilter>(filterDef.filterClass);\n\n // Store filter with its definition\n const filterWithMeta = new FilterWithMeta(filter, filterDef);\n this.filterRegistry.push(filterWithMeta);\n }\n\n /**\n * Get all registered routes.\n *\n * @returns Map of routes with handlers and definitions, keyed by \"METHOD:path\"\n */\n getRoutes(): Map<string, RouteHandlerWithMeta> {\n return this.routes;\n }\n\n /**\n * Get all filters sorted by priority (highest priority first).\n *\n * @returns Array of FilterWithMeta sorted by priority\n */\n getSortedFilters(): Array<FilterWithMeta> {\n return [...this.filterRegistry].sort((a, b) => b.definition.priority - a.definition.priority);\n }\n}\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { MethodMeta } from './MethodMeta';
|
|
2
|
+
/**
|
|
3
|
+
* Handler class for routes.
|
|
4
|
+
* Takes a MethodMeta and returns the controller method result.
|
|
5
|
+
*
|
|
6
|
+
* Generic type parameter TResult represents the return type of the controller method.
|
|
7
|
+
* Example: RouteHandler<SaveResponse> for a method that returns Promise<SaveResponse>
|
|
8
|
+
*
|
|
9
|
+
* Using unknown as default instead of any forces type safety - consumers must
|
|
10
|
+
* handle the result appropriately rather than assuming any type.
|
|
11
|
+
*
|
|
12
|
+
* This is a class instead of a function type to make it easier to trace
|
|
13
|
+
* who is calling what in the debugger/IDE.
|
|
14
|
+
*/
|
|
15
|
+
export declare abstract class RouteHandler<TResult = unknown> {
|
|
16
|
+
/**
|
|
17
|
+
* Execute the route handler.
|
|
18
|
+
* @param meta - The method metadata containing request info and params
|
|
19
|
+
* @returns Promise of the controller method result
|
|
20
|
+
*/
|
|
21
|
+
abstract execute(meta: MethodMeta): Promise<TResult>;
|
|
22
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RouteHandler = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Handler class for routes.
|
|
6
|
+
* Takes a MethodMeta and returns the controller method result.
|
|
7
|
+
*
|
|
8
|
+
* Generic type parameter TResult represents the return type of the controller method.
|
|
9
|
+
* Example: RouteHandler<SaveResponse> for a method that returns Promise<SaveResponse>
|
|
10
|
+
*
|
|
11
|
+
* Using unknown as default instead of any forces type safety - consumers must
|
|
12
|
+
* handle the result appropriately rather than assuming any type.
|
|
13
|
+
*
|
|
14
|
+
* This is a class instead of a function type to make it easier to trace
|
|
15
|
+
* who is calling what in the debugger/IDE.
|
|
16
|
+
*/
|
|
17
|
+
class RouteHandler {
|
|
18
|
+
}
|
|
19
|
+
exports.RouteHandler = RouteHandler;
|
|
20
|
+
//# sourceMappingURL=RouteHandler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RouteHandler.js","sourceRoot":"","sources":["../../../../../packages/http/http-server/src/RouteHandler.ts"],"names":[],"mappings":";;;AAEA;;;;;;;;;;;;GAYG;AACH,MAAsB,YAAY;CAOjC;AAPD,oCAOC","sourcesContent":["import { MethodMeta } from './MethodMeta';\n\n/**\n * Handler class for routes.\n * Takes a MethodMeta and returns the controller method result.\n *\n * Generic type parameter TResult represents the return type of the controller method.\n * Example: RouteHandler<SaveResponse> for a method that returns Promise<SaveResponse>\n *\n * Using unknown as default instead of any forces type safety - consumers must\n * handle the result appropriately rather than assuming any type.\n *\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 RouteHandler<TResult = unknown> {\n /**\n * Execute the route handler.\n * @param meta - The method metadata containing request info and params\n * @returns Promise of the controller method result\n */\n abstract execute(meta: MethodMeta): Promise<TResult>;\n}\n"]}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { WebAppMeta } from '@webpieces/core-meta';
|
|
2
|
+
import { WebpiecesServer } from './WebpiecesServer';
|
|
3
|
+
/**
|
|
4
|
+
* WebpiecesFactory - Factory for creating WebPieces server instances.
|
|
5
|
+
*
|
|
6
|
+
* This factory encapsulates the server creation and initialization logic:
|
|
7
|
+
* 1. Creates the WebPieces DI container
|
|
8
|
+
* 2. Loads the provider module for @provideSingleton decorators
|
|
9
|
+
* 3. Resolves WebpiecesServerImpl from DI
|
|
10
|
+
* 4. Calls initialize() with the container and meta
|
|
11
|
+
* 5. Returns the server as the WebpiecesServer interface
|
|
12
|
+
*
|
|
13
|
+
* The returned WebpiecesServer interface only exposes start() and stop(),
|
|
14
|
+
* hiding the internal initialize() method from consumers.
|
|
15
|
+
*
|
|
16
|
+
* Usage:
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const server = WebpiecesFactory.create(new ProdServerMeta());
|
|
19
|
+
* server.start(8080);
|
|
20
|
+
* // ... later
|
|
21
|
+
* server.stop();
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* This pattern:
|
|
25
|
+
* - Enforces proper initialization order
|
|
26
|
+
* - Hides implementation details from consumers
|
|
27
|
+
* - Makes the API simpler and harder to misuse
|
|
28
|
+
* - Follows the principle of least privilege
|
|
29
|
+
*/
|
|
30
|
+
export declare class WebpiecesFactory {
|
|
31
|
+
/**
|
|
32
|
+
* Create a new WebPieces server instance.
|
|
33
|
+
*
|
|
34
|
+
* This method:
|
|
35
|
+
* 1. Creates the WebPieces framework DI container
|
|
36
|
+
* 2. Loads framework bindings via buildProviderModule()
|
|
37
|
+
* 3. Resolves the server implementation from DI
|
|
38
|
+
* 4. Initializes the server with the container and meta
|
|
39
|
+
*
|
|
40
|
+
* @param meta - User-provided WebAppMeta with DI modules and routes
|
|
41
|
+
* @returns A fully initialized WebpiecesServer ready to start()
|
|
42
|
+
*/
|
|
43
|
+
static create(meta: WebAppMeta): WebpiecesServer;
|
|
44
|
+
}
|