@webpieces/http-routing 0.3.262 → 0.3.271

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-routing",
3
- "version": "0.3.262",
3
+ "version": "0.3.271",
4
4
  "description": "Decorator-based routing with auto-wiring for WebPieces",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -21,9 +21,9 @@
21
21
  "access": "public"
22
22
  },
23
23
  "dependencies": {
24
- "@webpieces/http-api": "0.3.262",
25
- "@webpieces/http-filters": "0.3.262",
26
- "@webpieces/wp-logging": "0.3.262",
24
+ "@webpieces/core-context": "0.3.271",
25
+ "@webpieces/core-util": "0.3.271",
26
+ "@webpieces/http-filters": "0.3.271",
27
27
  "inversify": "7.10.4",
28
28
  "minimatch": "10.0.1"
29
29
  }
@@ -1,5 +1,5 @@
1
1
  import { Routes, RouteBuilder } from './WebAppMeta';
2
- import { AuthMeta } from '@webpieces/http-api';
2
+ import { AuthMeta } from '@webpieces/core-util';
3
3
  import 'reflect-metadata';
4
4
  /**
5
5
  * Type representing a class constructor (abstract or concrete).
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ApiRoutingFactory = void 0;
4
4
  const WebAppMeta_1 = require("./WebAppMeta");
5
- const http_api_1 = require("@webpieces/http-api");
5
+ const core_util_1 = require("@webpieces/core-util");
6
6
  require("reflect-metadata");
7
7
  const decorators_1 = require("./decorators");
8
8
  /**
@@ -34,7 +34,7 @@ class ApiRoutingFactory {
34
34
  this.apiMetaClass = apiMetaClass;
35
35
  this.controllerClass = controllerClass;
36
36
  // Validate that apiMetaClass is marked with @ApiPath
37
- if (!(0, http_api_1.isApiPath)(apiMetaClass)) {
37
+ if (!(0, core_util_1.isApiPath)(apiMetaClass)) {
38
38
  const className = apiMetaClass.name || 'Unknown';
39
39
  throw new Error(`Class ${className} must be decorated with @ApiPath()`);
40
40
  }
@@ -56,8 +56,8 @@ class ApiRoutingFactory {
56
56
  * Validates controller methods and auth decorators in single loop.
57
57
  */
58
58
  configure(routeBuilder) {
59
- const basePath = (0, http_api_1.getApiPath)(this.apiMetaClass);
60
- const endpoints = (0, http_api_1.getEndpoints)(this.apiMetaClass) || {};
59
+ const basePath = (0, core_util_1.getApiPath)(this.apiMetaClass);
60
+ const endpoints = (0, core_util_1.getEndpoints)(this.apiMetaClass) || {};
61
61
  const controllerFilepath = this.getControllerFilepath();
62
62
  const apiName = this.apiMetaClass.name || 'Unknown';
63
63
  const controllerName = this.controllerClass.name || 'Unknown';
@@ -67,13 +67,13 @@ class ApiRoutingFactory {
67
67
  throw new Error(`Controller ${controllerName} must implement method ${methodName} from API ${apiName}`);
68
68
  }
69
69
  // Validate auth decorator exists (class-level or method-level)
70
- const authMeta = (0, http_api_1.getAuthMeta)(this.apiMetaClass, methodName);
70
+ const authMeta = (0, core_util_1.getAuthMeta)(this.apiMetaClass, methodName);
71
71
  if (!authMeta) {
72
72
  throw new Error(`Endpoint '${methodName}' in ${apiName} has no @Authentication decorator. ` +
73
73
  `Add @Authentication(new AuthenticationConfig(...)) to the class or method.`);
74
74
  }
75
75
  const fullPath = basePath + endpointPath;
76
- const routeMeta = new http_api_1.RouteMetadata('POST', fullPath, methodName, controllerName, authMeta);
76
+ const routeMeta = new core_util_1.RouteMetadata('POST', fullPath, methodName, controllerName, authMeta);
77
77
  routeBuilder.addRoute(new WebAppMeta_1.RouteDefinition(routeMeta, this.controllerClass, controllerFilepath));
78
78
  }
79
79
  }
@@ -95,7 +95,7 @@ class ApiRoutingFactory {
95
95
  * Get auth metadata for a specific method, falling back to class-level.
96
96
  */
97
97
  getAuthMetaForMethod(methodName) {
98
- return (0, http_api_1.getAuthMeta)(this.apiMetaClass, methodName);
98
+ return (0, core_util_1.getAuthMeta)(this.apiMetaClass, methodName);
99
99
  }
100
100
  /**
101
101
  * Get the API interface class.
@@ -1 +1 @@
1
- {"version":3,"file":"ApiRoutingFactory.js","sourceRoot":"","sources":["../../../../../packages/http/http-routing/src/ApiRoutingFactory.ts"],"names":[],"mappings":"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","sourcesContent":["import { Routes, RouteBuilder, RouteDefinition } from './WebAppMeta';\nimport { isApiPath, getApiPath, getEndpoints, getAuthMeta, RouteMetadata, AuthMeta } from '@webpieces/http-api';\nimport 'reflect-metadata';\nimport { ROUTING_METADATA_KEYS } from './decorators';\n\n/**\n * Type representing a class constructor (abstract or concrete).\n */\n// webpieces-disable no-any-unknown -- generic type alias requires unconstrained default\nexport type ClassType<T = unknown> = Function & { prototype: T };\n\n/**\n * ApiRoutingFactory - Automatically wire API interfaces to controllers.\n * Reads @ApiPath/@Endpoint decorators from an API prototype class and\n * registers POST routes for each endpoint.\n *\n * Replaces the old RESTApiRoutes class.\n *\n * Usage:\n * ```typescript\n * // In your ServerMeta:\n * getRoutes(): Routes[] {\n * return [\n * new ApiRoutingFactory(SaveApi, SaveController),\n * ];\n * }\n * ```\n */\n// webpieces-disable no-any-unknown -- generic class requires unconstrained default type params\nexport class ApiRoutingFactory<TApi = unknown, TController extends TApi = TApi> implements Routes {\n private apiMetaClass: ClassType<TApi>;\n private controllerClass: ClassType<TController>;\n\n /**\n * @param apiMetaClass - The API prototype class with @ApiPath/@Endpoint decorators\n * @param controllerClass - The controller class that implements the API\n */\n constructor(apiMetaClass: ClassType<TApi>, controllerClass: ClassType<TController>) {\n this.apiMetaClass = apiMetaClass;\n this.controllerClass = controllerClass;\n\n // Validate that apiMetaClass is marked with @ApiPath\n if (!isApiPath(apiMetaClass)) {\n const className = apiMetaClass.name || 'Unknown';\n throw new Error(`Class ${className} must be decorated with @ApiPath()`);\n }\n\n // Validate that controllerClass actually extends apiMetaClass.\n // TypeScript's structural typing won't catch a missing `extends` here, so we check\n // the runtime prototype chain. Without this, a controller can silently drift from\n // the API contract (wrong method names, wrong signatures) and only fail later as a\n // confusing routing or method-not-found error.\n const apiName = apiMetaClass.name || 'Unknown';\n const controllerName = controllerClass.name || 'Unknown';\n if (!(apiMetaClass.prototype as object).isPrototypeOf(controllerClass.prototype as object)) {\n throw new Error(\n `Controller ${controllerName} must extend ${apiName}. ` +\n `Change the class declaration to: ` +\n `'export class ${controllerName} extends ${apiName} { ... }'`,\n );\n }\n\n }\n\n /**\n * Configure routes by reading @ApiPath + @Endpoint metadata.\n * Validates controller methods and auth decorators in single loop.\n */\n configure(routeBuilder: RouteBuilder): void {\n const basePath = getApiPath(this.apiMetaClass)!;\n const endpoints = getEndpoints(this.apiMetaClass) || {};\n const controllerFilepath = this.getControllerFilepath();\n const apiName = this.apiMetaClass.name || 'Unknown';\n const controllerName = this.controllerClass.name || 'Unknown';\n\n for (const [methodName, endpointPath] of Object.entries(endpoints)) {\n // Validate controller implements this method\n if (typeof this.controllerClass.prototype[methodName] !== 'function') {\n throw new Error(\n `Controller ${controllerName} must implement method ${methodName} from API ${apiName}`,\n );\n }\n\n // Validate auth decorator exists (class-level or method-level)\n const authMeta = getAuthMeta(this.apiMetaClass, methodName);\n if (!authMeta) {\n throw new Error(\n `Endpoint '${methodName}' in ${apiName} has no @Authentication decorator. ` +\n `Add @Authentication(new AuthenticationConfig(...)) to the class or method.`,\n );\n }\n\n const fullPath = basePath + endpointPath;\n const routeMeta = new RouteMetadata(\n 'POST',\n fullPath,\n methodName,\n controllerName,\n authMeta,\n );\n\n routeBuilder.addRoute(new RouteDefinition(routeMeta, this.controllerClass, controllerFilepath));\n }\n }\n\n /**\n * Get the filepath of the controller source file.\n * Uses a heuristic based on the controller class name.\n */\n private getControllerFilepath(): string | undefined {\n // Check for explicit @SourceFile decorator metadata\n const filepath = Reflect.getMetadata(\n ROUTING_METADATA_KEYS.SOURCE_FILEPATH,\n this.controllerClass,\n );\n if (filepath) {\n return filepath;\n }\n\n // Fallback to class name pattern\n const className = this.controllerClass.name;\n return className ? `**/${className}.ts` : undefined;\n }\n\n /**\n * Get auth metadata for a specific method, falling back to class-level.\n */\n getAuthMetaForMethod(methodName: string): AuthMeta | undefined {\n return getAuthMeta(this.apiMetaClass, methodName);\n }\n\n /**\n * Get the API interface class.\n */\n getApiClass(): ClassType<TApi> {\n return this.apiMetaClass;\n }\n\n /**\n * Get the controller class.\n */\n getControllerClass(): ClassType<TController> {\n return this.controllerClass;\n }\n}\n"]}
1
+ {"version":3,"file":"ApiRoutingFactory.js","sourceRoot":"","sources":["../../../../../packages/http/http-routing/src/ApiRoutingFactory.ts"],"names":[],"mappings":"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","sourcesContent":["import { Routes, RouteBuilder, RouteDefinition } from './WebAppMeta';\nimport { isApiPath, getApiPath, getEndpoints, getAuthMeta, RouteMetadata, AuthMeta } from '@webpieces/core-util';\nimport 'reflect-metadata';\nimport { ROUTING_METADATA_KEYS } from './decorators';\n\n/**\n * Type representing a class constructor (abstract or concrete).\n */\n// webpieces-disable no-any-unknown -- generic type alias requires unconstrained default\nexport type ClassType<T = unknown> = Function & { prototype: T };\n\n/**\n * ApiRoutingFactory - Automatically wire API interfaces to controllers.\n * Reads @ApiPath/@Endpoint decorators from an API prototype class and\n * registers POST routes for each endpoint.\n *\n * Replaces the old RESTApiRoutes class.\n *\n * Usage:\n * ```typescript\n * // In your ServerMeta:\n * getRoutes(): Routes[] {\n * return [\n * new ApiRoutingFactory(SaveApi, SaveController),\n * ];\n * }\n * ```\n */\n// webpieces-disable no-any-unknown -- generic class requires unconstrained default type params\nexport class ApiRoutingFactory<TApi = unknown, TController extends TApi = TApi> implements Routes {\n private apiMetaClass: ClassType<TApi>;\n private controllerClass: ClassType<TController>;\n\n /**\n * @param apiMetaClass - The API prototype class with @ApiPath/@Endpoint decorators\n * @param controllerClass - The controller class that implements the API\n */\n constructor(apiMetaClass: ClassType<TApi>, controllerClass: ClassType<TController>) {\n this.apiMetaClass = apiMetaClass;\n this.controllerClass = controllerClass;\n\n // Validate that apiMetaClass is marked with @ApiPath\n if (!isApiPath(apiMetaClass)) {\n const className = apiMetaClass.name || 'Unknown';\n throw new Error(`Class ${className} must be decorated with @ApiPath()`);\n }\n\n // Validate that controllerClass actually extends apiMetaClass.\n // TypeScript's structural typing won't catch a missing `extends` here, so we check\n // the runtime prototype chain. Without this, a controller can silently drift from\n // the API contract (wrong method names, wrong signatures) and only fail later as a\n // confusing routing or method-not-found error.\n const apiName = apiMetaClass.name || 'Unknown';\n const controllerName = controllerClass.name || 'Unknown';\n if (!(apiMetaClass.prototype as object).isPrototypeOf(controllerClass.prototype as object)) {\n throw new Error(\n `Controller ${controllerName} must extend ${apiName}. ` +\n `Change the class declaration to: ` +\n `'export class ${controllerName} extends ${apiName} { ... }'`,\n );\n }\n\n }\n\n /**\n * Configure routes by reading @ApiPath + @Endpoint metadata.\n * Validates controller methods and auth decorators in single loop.\n */\n configure(routeBuilder: RouteBuilder): void {\n const basePath = getApiPath(this.apiMetaClass)!;\n const endpoints = getEndpoints(this.apiMetaClass) || {};\n const controllerFilepath = this.getControllerFilepath();\n const apiName = this.apiMetaClass.name || 'Unknown';\n const controllerName = this.controllerClass.name || 'Unknown';\n\n for (const [methodName, endpointPath] of Object.entries(endpoints)) {\n // Validate controller implements this method\n if (typeof this.controllerClass.prototype[methodName] !== 'function') {\n throw new Error(\n `Controller ${controllerName} must implement method ${methodName} from API ${apiName}`,\n );\n }\n\n // Validate auth decorator exists (class-level or method-level)\n const authMeta = getAuthMeta(this.apiMetaClass, methodName);\n if (!authMeta) {\n throw new Error(\n `Endpoint '${methodName}' in ${apiName} has no @Authentication decorator. ` +\n `Add @Authentication(new AuthenticationConfig(...)) to the class or method.`,\n );\n }\n\n const fullPath = basePath + endpointPath;\n const routeMeta = new RouteMetadata(\n 'POST',\n fullPath,\n methodName,\n controllerName,\n authMeta,\n );\n\n routeBuilder.addRoute(new RouteDefinition(routeMeta, this.controllerClass, controllerFilepath));\n }\n }\n\n /**\n * Get the filepath of the controller source file.\n * Uses a heuristic based on the controller class name.\n */\n private getControllerFilepath(): string | undefined {\n // Check for explicit @SourceFile decorator metadata\n const filepath = Reflect.getMetadata(\n ROUTING_METADATA_KEYS.SOURCE_FILEPATH,\n this.controllerClass,\n );\n if (filepath) {\n return filepath;\n }\n\n // Fallback to class name pattern\n const className = this.controllerClass.name;\n return className ? `**/${className}.ts` : undefined;\n }\n\n /**\n * Get auth metadata for a specific method, falling back to class-level.\n */\n getAuthMetaForMethod(methodName: string): AuthMeta | undefined {\n return getAuthMeta(this.apiMetaClass, methodName);\n }\n\n /**\n * Get the API interface class.\n */\n getApiClass(): ClassType<TApi> {\n return this.apiMetaClass;\n }\n\n /**\n * Get the controller class.\n */\n getControllerClass(): ClassType<TController> {\n return this.controllerClass;\n }\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { Filter, WpResponse } from '@webpieces/http-filters';
2
- import { MethodMeta } from './MethodMeta';
2
+ import { MethodMeta } from '@webpieces/http-filters';
3
3
  import { FilterDefinition } from './WebAppMeta';
4
4
  /**
5
5
  * Type alias for HTTP filters that work with MethodMeta and ResponseWrapper.
@@ -1 +1 @@
1
- {"version":3,"file":"FilterMatcher.js","sourceRoot":"","sources":["../../../../../packages/http/http-routing/src/FilterMatcher.ts"],"names":[],"mappings":";;;AAGA,yCAAsC;AAOtC;;;;;;;;;;;;GAYG;AACH,MAAa,aAAa;IACtB;;;;;;OAMG;IACH,MAAM,CAAC,mBAAmB,CACtB,kBAAsC,EACtC,UAAmC;QAEnC,MAAM,eAAe,GAAoD,EAAE,CAAC;QAE5E,KAAK,MAAM,UAAU,IAAI,UAAU,EAAE,CAAC;YAClC,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;gBAClB,eAAe,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC,QAAQ,EAAE,CAAC,CAAC;gBAChE,SAAS;YACb,CAAC;YAED,yDAAyD;YACzD,IAAI,CAAC,kBAAkB,EAAE,CAAC;gBACtB,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;oBACrB,eAAe,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC,QAAQ,EAAE,CAAC,CAAC;gBACpE,CAAC;gBACD,SAAS;YACb,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;gBACrC,eAAe,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC,QAAQ,EAAE,CAAC,CAAC;YACpE,CAAC;QACL,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;IACtD,CAAC;IAED;;;;;;;OAOG;IACH,MAAM,CAAC,iBAAiB,CAAC,QAAgB;QACrC,OAAO,QAAQ;aACV,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,yCAAyC;aAC7D,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,sBAAsB;IACrD,CAAC;CACJ;AA5DD,sCA4DC","sourcesContent":["import { Filter, WpResponse } from '@webpieces/http-filters';\nimport { MethodMeta } from './MethodMeta';\nimport { FilterDefinition } from './WebAppMeta';\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"]}
1
+ {"version":3,"file":"FilterMatcher.js","sourceRoot":"","sources":["../../../../../packages/http/http-routing/src/FilterMatcher.ts"],"names":[],"mappings":";;;AAGA,yCAAsC;AAOtC;;;;;;;;;;;;GAYG;AACH,MAAa,aAAa;IACtB;;;;;;OAMG;IACH,MAAM,CAAC,mBAAmB,CACtB,kBAAsC,EACtC,UAAmC;QAEnC,MAAM,eAAe,GAAoD,EAAE,CAAC;QAE5E,KAAK,MAAM,UAAU,IAAI,UAAU,EAAE,CAAC;YAClC,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;gBAClB,eAAe,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC,QAAQ,EAAE,CAAC,CAAC;gBAChE,SAAS;YACb,CAAC;YAED,yDAAyD;YACzD,IAAI,CAAC,kBAAkB,EAAE,CAAC;gBACtB,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;oBACrB,eAAe,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC,QAAQ,EAAE,CAAC,CAAC;gBACpE,CAAC;gBACD,SAAS;YACb,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;gBACrC,eAAe,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC,QAAQ,EAAE,CAAC,CAAC;YACpE,CAAC;QACL,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;IACtD,CAAC;IAED;;;;;;;OAOG;IACH,MAAM,CAAC,iBAAiB,CAAC,QAAgB;QACrC,OAAO,QAAQ;aACV,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,yCAAyC;aAC7D,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,sBAAsB;IACrD,CAAC;CACJ;AA5DD,sCA4DC","sourcesContent":["import { Filter, WpResponse } from '@webpieces/http-filters';\nimport { MethodMeta } from '@webpieces/http-filters';\nimport { FilterDefinition } from './WebAppMeta';\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"]}
@@ -2,8 +2,8 @@ import { Container } from 'inversify';
2
2
  import { Request, Response, NextFunction } from 'express';
3
3
  import { RouteBuilder, RouteDefinition, FilterDefinition } from './WebAppMeta';
4
4
  import { RouteHandler } from './RouteHandler';
5
- import { MethodMeta } from './MethodMeta';
6
- import { RouteMetadata } from '@webpieces/http-api';
5
+ import { MethodMeta } from '@webpieces/http-filters';
6
+ import { RouteMetadata } from '@webpieces/core-util';
7
7
  import { WpResponse, Service } from '@webpieces/http-filters';
8
8
  import { HttpFilter } from './FilterMatcher';
9
9
  /**
@@ -3,11 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RouteBuilderImpl = exports.RouteHandlerWithMeta = exports.RouteHandlerImpl = exports.FilterWithMeta = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const inversify_1 = require("inversify");
6
- const decorators_1 = require("./decorators");
6
+ const core_context_1 = require("@webpieces/core-context");
7
7
  const http_filters_1 = require("@webpieces/http-filters");
8
8
  const FilterMatcher_1 = require("./FilterMatcher");
9
- const wp_logging_1 = require("@webpieces/wp-logging");
10
- const log = wp_logging_1.LogManager.getLogger('RouteBuilder');
9
+ const core_util_1 = require("@webpieces/core-util");
10
+ const log = core_util_1.LogManager.getLogger('RouteBuilder');
11
11
  /**
12
12
  * FilterWithMeta - Pairs a resolved filter instance with its definition.
13
13
  * Stores both the DI-resolved filter and the metadata needed for matching.
@@ -272,7 +272,7 @@ let RouteBuilderImpl = class RouteBuilderImpl {
272
272
  };
273
273
  exports.RouteBuilderImpl = RouteBuilderImpl;
274
274
  exports.RouteBuilderImpl = RouteBuilderImpl = tslib_1.__decorate([
275
- (0, decorators_1.provideSingleton)(),
275
+ (0, core_context_1.provideSingleton)(),
276
276
  (0, inversify_1.injectable)()
277
277
  ], RouteBuilderImpl);
278
278
  //# sourceMappingURL=RouteBuilderImpl.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"RouteBuilderImpl.js","sourceRoot":"","sources":["../../../../../packages/http/http-routing/src/RouteBuilderImpl.ts"],"names":[],"mappings":"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","sourcesContent":["import { Container, injectable } from 'inversify';\nimport { Request, Response, NextFunction } from 'express';\nimport { RouteBuilder, RouteDefinition, FilterDefinition } from './WebAppMeta';\nimport { provideSingleton } from './decorators';\nimport { RouteHandler } from './RouteHandler';\nimport { MethodMeta } from './MethodMeta';\nimport { RouteMetadata } from '@webpieces/http-api';\nimport { WpResponse, Service } from '@webpieces/http-filters';\nimport { FilterMatcher, HttpFilter } from './FilterMatcher';\nimport { LogManager } from '@webpieces/wp-logging';\n\nconst log = LogManager.getLogger('RouteBuilder');\n\n/**\n * Express route handler function type.\n * Used by wrapExpress to create handlers that Express can call.\n */\nexport type ExpressRouteHandler = (\n req: Request,\n res: Response,\n next: NextFunction,\n) => Promise<void>;\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 * RouteHandlerImpl - Concrete implementation of RouteHandler.\n * Wraps a resolved controller and method to invoke on each request.\n */\nexport class RouteHandlerImpl<TResult> implements RouteHandler<TResult> {\n constructor(\n private controller: Record<string, unknown>,\n private method: (this: unknown, requestDto?: unknown) => Promise<TResult>,\n ) {}\n\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 const result: TResult = await this.method.call(this.controller, meta.requestDto);\n return result;\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 invokeControllerHandler: RouteHandler<unknown>,\n public definition: RouteDefinition,\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: RouteHandlerWithMeta[] = [];\n private filterRegistry: Array<FilterWithMeta> = [];\n private container?: Container;\n\n /**\n * Map for O(1) route lookup by method:path.\n * Used by both addRoute() and createRouteInvoker() for fast route access.\n */\n private routeMap: Map<string, RouteHandlerWithMeta> = new Map();\n\n /**\n * Create route key for consistent lookup.\n * Key format: \"${METHOD}:${path}\" (e.g., \"POST:/search/item\")\n */\n private createRouteKey(method: string, path: string): string {\n return `${method.toUpperCase()}:${path}`;\n }\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 * Uses createRouteHandlerWithMeta() to create the handler, then stores it\n * in both the routes array and the routeMap for O(1) lookup.\n *\n * @param route - Route definition with controller class and method name\n */\n addRoute(route: RouteDefinition): void {\n const routeWithMeta = this.createRouteHandlerWithMeta(route);\n this.routes.push(routeWithMeta);\n\n // Also add to map for O(1) lookup by method:path\n const key = this.createRouteKey(\n route.routeMeta.httpMethod,\n route.routeMeta.path\n );\n this.routeMap.set(key, routeWithMeta);\n }\n\n /**\n * Create RouteHandlerWithMeta from a RouteDefinition.\n *\n * Resolves controller from DI container ONCE and creates a handler that\n * invokes the controller method with the request DTO.\n *\n * This method is used by:\n * - addRoute() for production route registration\n * - createRouteInvoker() for test clients (via createApiClient)\n *\n * @param route - Route definition with controller class and method name\n * @returns RouteHandlerWithMeta containing the handler and route definition\n */\n private createRouteHandlerWithMeta<TResult = unknown>(\n route: RouteDefinition,\n ): RouteHandlerWithMeta {\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 // Resolve controller instance from DI container ONCE (not on every request!)\n const controller = this.container.get(route.controllerClass) as Record<string, unknown>;\n\n // Get the controller method\n const method = controller[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 const handler = new RouteHandlerImpl<TResult>(\n controller,\n method as (this: unknown, requestDto?: unknown) => Promise<TResult>\n );\n\n // Return handler with route definition\n return new RouteHandlerWithMeta(\n handler as RouteHandler<unknown>,\n route,\n );\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(): 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(\n (a, b) => b.definition.priority - a.definition.priority,\n );\n }\n\n /**\n * Cached filter definitions for lazy route setup.\n */\n private cachedFilterDefinitions?: FilterDefinition[];\n\n /**\n * Get filter definitions, computing once and caching.\n */\n private getFilterDefinitions(): FilterDefinition[] {\n if (!this.cachedFilterDefinitions) {\n const sortedFilters = this.getSortedFilters();\n this.cachedFilterDefinitions = sortedFilters.map((fwm) => {\n const def = fwm.definition;\n def.filter = fwm.filter;\n return def;\n });\n }\n return this.cachedFilterDefinitions;\n }\n\n /**\n * Setup a single route by creating its filter chain.\n * This is called lazily by createHandler() and getRouteService().\n *\n * Creates a Service that wraps the filter chain and controller invocation.\n * The service is DTO-only and has no Express dependency.\n *\n * @param key - Route key in format \"METHOD:path\"\n * @param routeWithMeta - Route handler with metadata\n * @returns The service for this route\n */\n public createRouteHandler(\n routeWithMeta: RouteHandlerWithMeta,\n ): Service<MethodMeta, WpResponse<unknown>> {\n const route = routeWithMeta.definition;\n const routeMeta = route.routeMeta;\n\n log.info(`[RouteBuilder] Setting up route: ${routeMeta.httpMethod} ${routeMeta.path}`);\n\n // Get cached filter definitions\n const filterDefinitions = this.getFilterDefinitions();\n\n // Find matching filters for this route\n const matchingFilters = FilterMatcher.findMatchingFilters(\n route.controllerFilepath,\n filterDefinitions,\n );\n\n // Create service that wraps the controller execution\n const controllerService: Service<MethodMeta, WpResponse<unknown>> = {\n invoke: async (meta: MethodMeta): Promise<WpResponse<unknown>> => {\n const result = await routeWithMeta.invokeControllerHandler.execute(meta);\n // A void endpoint (e.g. a @PubSub cloud-task handler returning Promise<void>)\n // yields undefined; coerce to {} so the response is a non-null JSON body\n // (downstream LogApiCall/serialization require one), mirroring `result ?? {}`.\n return new WpResponse(result ?? {});\n },\n };\n\n if (matchingFilters.length === 0) {\n throw new Error(\"No filters found for route. Check filter definitions as you must have at least ContextFilter\");\n }\n\n // Chain filters: highest priority (first in array) should run first (be outermost)\n // Build from innermost (lowest priority) to outermost (highest priority)\n // Start with controller, then wrap with filters in reverse priority order\n let service: Service<MethodMeta, WpResponse<unknown>> = controllerService;\n for (let i = matchingFilters.length - 1; i >= 0; i--) {\n service = matchingFilters[i].chainService(service);\n }\n\n return service;\n }\n\n /**\n * Create an invoker function for a route (for testing via createApiClient).\n * Uses routeMap for O(1) lookup, sets up the filter chain ONCE,\n * and returns a Service that can be called multiple times without\n * recreating the filter chain.\n *\n * This method is called by WebpiecesServer.createApiClient() during proxy setup.\n * The returned Service is stored as the proxy method and invoked on each call.\n *\n * @param method - HTTP method (GET, POST, etc.)\n * @param path - URL path\n * @returns A Service that invokes the route\n */\n createRouteInvoker(method: string, path: string): Service<MethodMeta, WpResponse<unknown>> {\n // Use routeMap for O(1) lookup (not linear search!)\n const key = this.createRouteKey(method, path);\n const routeWithMeta = this.routeMap.get(key);\n\n if (!routeWithMeta) {\n throw new Error(`Route not found: ${method} ${path}`);\n }\n\n // Setup filter chain ONCE (not on every invocation!)\n return this.createRouteHandler(routeWithMeta);\n }\n\n /**\n * Look up the RouteMetadata (incl. authMeta) for a registered route by method+path.\n * Used to build a MethodMeta for an in-process dispatch (e.g. a delivered cloud\n * task) so the filter chain sees the same routeMeta production HTTP would.\n *\n * @returns the route's RouteMetadata, or undefined if no route is registered.\n */\n getRouteMeta(method: string, path: string): RouteMetadata | undefined {\n const key = this.createRouteKey(method, path);\n return this.routeMap.get(key)?.definition.routeMeta;\n }\n}\n"]}
1
+ {"version":3,"file":"RouteBuilderImpl.js","sourceRoot":"","sources":["../../../../../packages/http/http-routing/src/RouteBuilderImpl.ts"],"names":[],"mappings":"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","sourcesContent":["import { Container, injectable } from 'inversify';\nimport { Request, Response, NextFunction } from 'express';\nimport { RouteBuilder, RouteDefinition, FilterDefinition } from './WebAppMeta';\nimport { provideSingleton } from '@webpieces/core-context';\nimport { RouteHandler } from './RouteHandler';\nimport { MethodMeta } from '@webpieces/http-filters';\nimport { RouteMetadata } from '@webpieces/core-util';\nimport { WpResponse, Service } from '@webpieces/http-filters';\nimport { FilterMatcher, HttpFilter } from './FilterMatcher';\nimport { LogManager } from '@webpieces/core-util';\n\nconst log = LogManager.getLogger('RouteBuilder');\n\n/**\n * Express route handler function type.\n * Used by wrapExpress to create handlers that Express can call.\n */\nexport type ExpressRouteHandler = (\n req: Request,\n res: Response,\n next: NextFunction,\n) => Promise<void>;\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 * RouteHandlerImpl - Concrete implementation of RouteHandler.\n * Wraps a resolved controller and method to invoke on each request.\n */\nexport class RouteHandlerImpl<TResult> implements RouteHandler<TResult> {\n constructor(\n private controller: Record<string, unknown>,\n private method: (this: unknown, requestDto?: unknown) => Promise<TResult>,\n ) {}\n\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 const result: TResult = await this.method.call(this.controller, meta.requestDto);\n return result;\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 invokeControllerHandler: RouteHandler<unknown>,\n public definition: RouteDefinition,\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: RouteHandlerWithMeta[] = [];\n private filterRegistry: Array<FilterWithMeta> = [];\n private container?: Container;\n\n /**\n * Map for O(1) route lookup by method:path.\n * Used by both addRoute() and createRouteInvoker() for fast route access.\n */\n private routeMap: Map<string, RouteHandlerWithMeta> = new Map();\n\n /**\n * Create route key for consistent lookup.\n * Key format: \"${METHOD}:${path}\" (e.g., \"POST:/search/item\")\n */\n private createRouteKey(method: string, path: string): string {\n return `${method.toUpperCase()}:${path}`;\n }\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 * Uses createRouteHandlerWithMeta() to create the handler, then stores it\n * in both the routes array and the routeMap for O(1) lookup.\n *\n * @param route - Route definition with controller class and method name\n */\n addRoute(route: RouteDefinition): void {\n const routeWithMeta = this.createRouteHandlerWithMeta(route);\n this.routes.push(routeWithMeta);\n\n // Also add to map for O(1) lookup by method:path\n const key = this.createRouteKey(\n route.routeMeta.httpMethod,\n route.routeMeta.path\n );\n this.routeMap.set(key, routeWithMeta);\n }\n\n /**\n * Create RouteHandlerWithMeta from a RouteDefinition.\n *\n * Resolves controller from DI container ONCE and creates a handler that\n * invokes the controller method with the request DTO.\n *\n * This method is used by:\n * - addRoute() for production route registration\n * - createRouteInvoker() for test clients (via createApiClient)\n *\n * @param route - Route definition with controller class and method name\n * @returns RouteHandlerWithMeta containing the handler and route definition\n */\n private createRouteHandlerWithMeta<TResult = unknown>(\n route: RouteDefinition,\n ): RouteHandlerWithMeta {\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 // Resolve controller instance from DI container ONCE (not on every request!)\n const controller = this.container.get(route.controllerClass) as Record<string, unknown>;\n\n // Get the controller method\n const method = controller[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 const handler = new RouteHandlerImpl<TResult>(\n controller,\n method as (this: unknown, requestDto?: unknown) => Promise<TResult>\n );\n\n // Return handler with route definition\n return new RouteHandlerWithMeta(\n handler as RouteHandler<unknown>,\n route,\n );\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(): 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(\n (a, b) => b.definition.priority - a.definition.priority,\n );\n }\n\n /**\n * Cached filter definitions for lazy route setup.\n */\n private cachedFilterDefinitions?: FilterDefinition[];\n\n /**\n * Get filter definitions, computing once and caching.\n */\n private getFilterDefinitions(): FilterDefinition[] {\n if (!this.cachedFilterDefinitions) {\n const sortedFilters = this.getSortedFilters();\n this.cachedFilterDefinitions = sortedFilters.map((fwm) => {\n const def = fwm.definition;\n def.filter = fwm.filter;\n return def;\n });\n }\n return this.cachedFilterDefinitions;\n }\n\n /**\n * Setup a single route by creating its filter chain.\n * This is called lazily by createHandler() and getRouteService().\n *\n * Creates a Service that wraps the filter chain and controller invocation.\n * The service is DTO-only and has no Express dependency.\n *\n * @param key - Route key in format \"METHOD:path\"\n * @param routeWithMeta - Route handler with metadata\n * @returns The service for this route\n */\n public createRouteHandler(\n routeWithMeta: RouteHandlerWithMeta,\n ): Service<MethodMeta, WpResponse<unknown>> {\n const route = routeWithMeta.definition;\n const routeMeta = route.routeMeta;\n\n log.info(`[RouteBuilder] Setting up route: ${routeMeta.httpMethod} ${routeMeta.path}`);\n\n // Get cached filter definitions\n const filterDefinitions = this.getFilterDefinitions();\n\n // Find matching filters for this route\n const matchingFilters = FilterMatcher.findMatchingFilters(\n route.controllerFilepath,\n filterDefinitions,\n );\n\n // Create service that wraps the controller execution\n const controllerService: Service<MethodMeta, WpResponse<unknown>> = {\n invoke: async (meta: MethodMeta): Promise<WpResponse<unknown>> => {\n const result = await routeWithMeta.invokeControllerHandler.execute(meta);\n // A void endpoint (e.g. a @PubSub cloud-task handler returning Promise<void>)\n // yields undefined; coerce to {} so the response is a non-null JSON body\n // (downstream LogApiCall/serialization require one), mirroring `result ?? {}`.\n return new WpResponse(result ?? {});\n },\n };\n\n if (matchingFilters.length === 0) {\n throw new Error(\"No filters found for route. Check filter definitions as you must have at least ContextFilter\");\n }\n\n // Chain filters: highest priority (first in array) should run first (be outermost)\n // Build from innermost (lowest priority) to outermost (highest priority)\n // Start with controller, then wrap with filters in reverse priority order\n let service: Service<MethodMeta, WpResponse<unknown>> = controllerService;\n for (let i = matchingFilters.length - 1; i >= 0; i--) {\n service = matchingFilters[i].chainService(service);\n }\n\n return service;\n }\n\n /**\n * Create an invoker function for a route (for testing via createApiClient).\n * Uses routeMap for O(1) lookup, sets up the filter chain ONCE,\n * and returns a Service that can be called multiple times without\n * recreating the filter chain.\n *\n * This method is called by WebpiecesServer.createApiClient() during proxy setup.\n * The returned Service is stored as the proxy method and invoked on each call.\n *\n * @param method - HTTP method (GET, POST, etc.)\n * @param path - URL path\n * @returns A Service that invokes the route\n */\n createRouteInvoker(method: string, path: string): Service<MethodMeta, WpResponse<unknown>> {\n // Use routeMap for O(1) lookup (not linear search!)\n const key = this.createRouteKey(method, path);\n const routeWithMeta = this.routeMap.get(key);\n\n if (!routeWithMeta) {\n throw new Error(`Route not found: ${method} ${path}`);\n }\n\n // Setup filter chain ONCE (not on every invocation!)\n return this.createRouteHandler(routeWithMeta);\n }\n\n /**\n * Look up the RouteMetadata (incl. authMeta) for a registered route by method+path.\n * Used to build a MethodMeta for an in-process dispatch (e.g. a delivered cloud\n * task) so the filter chain sees the same routeMeta production HTTP would.\n *\n * @returns the route's RouteMetadata, or undefined if no route is registered.\n */\n getRouteMeta(method: string, path: string): RouteMetadata | undefined {\n const key = this.createRouteKey(method, path);\n return this.routeMap.get(key)?.definition.routeMeta;\n }\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { MethodMeta } from './MethodMeta';
1
+ import { MethodMeta } from '@webpieces/http-filters';
2
2
  /**
3
3
  * Handler class for routes.
4
4
  * Takes a MethodMeta and returns the controller method result.
@@ -1 +1 @@
1
- {"version":3,"file":"RouteHandler.js","sourceRoot":"","sources":["../../../../../packages/http/http-routing/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"]}
1
+ {"version":3,"file":"RouteHandler.js","sourceRoot":"","sources":["../../../../../packages/http/http-routing/src/RouteHandler.ts"],"names":[],"mappings":";;;AAEA;;;;;;;;;;;;GAYG;AACH,MAAsB,YAAY;CAOjC;AAPD,oCAOC","sourcesContent":["import { MethodMeta } from '@webpieces/http-filters';\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"]}
@@ -1,5 +1,5 @@
1
1
  import { ContainerModule } from 'inversify';
2
- import { RouteMetadata } from "@webpieces/http-api";
2
+ import { RouteMetadata } from "@webpieces/core-util";
3
3
  /**
4
4
  * Represents a route configuration that can be registered with the router.
5
5
  * Similar to Java WebPieces Routes interface.
@@ -1 +1 @@
1
- {"version":3,"file":"WebAppMeta.js","sourceRoot":"","sources":["../../../../../packages/http/http-routing/src/WebAppMeta.ts"],"names":[],"mappings":";;;AAuBA;;;;;GAKG;AACH,MAAa,eAAe;IAEb;IACA;IACA;IAHX,YACW,SAAwB,EACxB,eAAoB,EACpB,kBAA2B;QAF3B,cAAS,GAAT,SAAS,CAAe;QACxB,oBAAe,GAAf,eAAe,CAAK;QACpB,uBAAkB,GAAlB,kBAAkB,CAAS;IACnC,CAAC;CACP;AAND,0CAMC;AAED;;;;;;;;;GASG;AACH,MAAa,gBAAgB;IACzB,QAAQ,CAAS;IACjB,WAAW,CAAM;IACjB,MAAM,CAAO,CAAC,+DAA+D;IAE7E;;;OAGG;IACH,eAAe,CAAS;IAExB,YAAY,QAAgB,EAAE,WAAgB,EAAE,eAAuB;QACnE,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,eAAe,GAAG,eAAe,CAAC;QACvC,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC,4BAA4B;IACzD,CAAC;CACJ;AAjBD,4CAiBC;AAuBD;;GAEG;AACU,QAAA,iBAAiB,GAAG,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC","sourcesContent":["import { ContainerModule } from 'inversify';\nimport {RouteMetadata} from \"@webpieces/http-api\";\n\n/**\n * Represents a route configuration that can be registered with the router.\n * Similar to Java WebPieces Routes interface.\n */\nexport interface Routes {\n /**\n * Configure routes using the provided RouteBuilder.\n */\n configure(routeBuilder: RouteBuilder): void;\n}\n\n/**\n * Builder for registering routes.\n * Will be implemented in http-server package.\n */\nexport interface RouteBuilder {\n addRoute(route: RouteDefinition): void;\n addFilter(filter: FilterDefinition): void;\n}\n\n/**\n * Definition of a single route.\n *\n * Generic type parameter TResult represents the return type of the route handler.\n * This provides type safety for the entire request/response cycle.\n */\nexport class RouteDefinition {\n constructor(\n public routeMeta: RouteMetadata,\n public controllerClass: any,\n public controllerFilepath?: string,\n ) {}\n}\n\n/**\n * Definition of a filter with priority.\n *\n * Use filepathPattern to scope filters to specific controllers:\n * - 'src/controllers/admin/**' + '/*.ts' - All admin controllers\n * - '**' + '/admin/**' - Any file in admin directories\n * - '**' + '/UserController.ts' - Specific controller file\n *\n * If filepathPattern is not specified, the filter matches all controllers.\n */\nexport class FilterDefinition {\n priority: number;\n filterClass: any;\n filter?: any; // Filter instance (set by RouteBuilder when resolving from DI)\n\n /**\n * Glob pattern to match controller file paths.\n * If not specified, defaults to matching all controllers.\n */\n filepathPattern: string;\n\n constructor(priority: number, filterClass: any, filepathPattern: string) {\n this.priority = priority;\n this.filterClass = filterClass;\n this.filepathPattern = filepathPattern;\n this.filter = undefined; // Set later by RouteBuilder\n }\n}\n\n\n/**\n * Main application metadata interface.\n * Similar to Java WebPieces WebAppMeta.\n *\n * This is the entry point that WebpiecesServer calls to configure your application.\n */\nexport interface WebAppMeta {\n /**\n * Returns the list of Inversify container modules for dependency injection.\n * Similar to getGuiceModules() in Java.\n */\n getDIModules(): ContainerModule[];\n\n /**\n * Returns the list of route configurations.\n * Similar to getRouteModules() in Java.\n */\n getRoutes(): Routes[];\n}\n\n/**\n * DI token for WebAppMeta injection.\n */\nexport const WEBAPP_META_TOKEN = Symbol.for('WebAppMeta');\n"]}
1
+ {"version":3,"file":"WebAppMeta.js","sourceRoot":"","sources":["../../../../../packages/http/http-routing/src/WebAppMeta.ts"],"names":[],"mappings":";;;AAuBA;;;;;GAKG;AACH,MAAa,eAAe;IAEb;IACA;IACA;IAHX,YACW,SAAwB,EACxB,eAAoB,EACpB,kBAA2B;QAF3B,cAAS,GAAT,SAAS,CAAe;QACxB,oBAAe,GAAf,eAAe,CAAK;QACpB,uBAAkB,GAAlB,kBAAkB,CAAS;IACnC,CAAC;CACP;AAND,0CAMC;AAED;;;;;;;;;GASG;AACH,MAAa,gBAAgB;IACzB,QAAQ,CAAS;IACjB,WAAW,CAAM;IACjB,MAAM,CAAO,CAAC,+DAA+D;IAE7E;;;OAGG;IACH,eAAe,CAAS;IAExB,YAAY,QAAgB,EAAE,WAAgB,EAAE,eAAuB;QACnE,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,eAAe,GAAG,eAAe,CAAC;QACvC,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC,4BAA4B;IACzD,CAAC;CACJ;AAjBD,4CAiBC;AAuBD;;GAEG;AACU,QAAA,iBAAiB,GAAG,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC","sourcesContent":["import { ContainerModule } from 'inversify';\nimport {RouteMetadata} from \"@webpieces/core-util\";\n\n/**\n * Represents a route configuration that can be registered with the router.\n * Similar to Java WebPieces Routes interface.\n */\nexport interface Routes {\n /**\n * Configure routes using the provided RouteBuilder.\n */\n configure(routeBuilder: RouteBuilder): void;\n}\n\n/**\n * Builder for registering routes.\n * Will be implemented in http-server package.\n */\nexport interface RouteBuilder {\n addRoute(route: RouteDefinition): void;\n addFilter(filter: FilterDefinition): void;\n}\n\n/**\n * Definition of a single route.\n *\n * Generic type parameter TResult represents the return type of the route handler.\n * This provides type safety for the entire request/response cycle.\n */\nexport class RouteDefinition {\n constructor(\n public routeMeta: RouteMetadata,\n public controllerClass: any,\n public controllerFilepath?: string,\n ) {}\n}\n\n/**\n * Definition of a filter with priority.\n *\n * Use filepathPattern to scope filters to specific controllers:\n * - 'src/controllers/admin/**' + '/*.ts' - All admin controllers\n * - '**' + '/admin/**' - Any file in admin directories\n * - '**' + '/UserController.ts' - Specific controller file\n *\n * If filepathPattern is not specified, the filter matches all controllers.\n */\nexport class FilterDefinition {\n priority: number;\n filterClass: any;\n filter?: any; // Filter instance (set by RouteBuilder when resolving from DI)\n\n /**\n * Glob pattern to match controller file paths.\n * If not specified, defaults to matching all controllers.\n */\n filepathPattern: string;\n\n constructor(priority: number, filterClass: any, filepathPattern: string) {\n this.priority = priority;\n this.filterClass = filterClass;\n this.filepathPattern = filepathPattern;\n this.filter = undefined; // Set later by RouteBuilder\n }\n}\n\n\n/**\n * Main application metadata interface.\n * Similar to Java WebPieces WebAppMeta.\n *\n * This is the entry point that WebpiecesServer calls to configure your application.\n */\nexport interface WebAppMeta {\n /**\n * Returns the list of Inversify container modules for dependency injection.\n * Similar to getGuiceModules() in Java.\n */\n getDIModules(): ContainerModule[];\n\n /**\n * Returns the list of route configurations.\n * Similar to getRouteModules() in Java.\n */\n getRoutes(): Routes[];\n}\n\n/**\n * DI token for WebAppMeta injection.\n */\nexport const WEBAPP_META_TOKEN = Symbol.for('WebAppMeta');\n"]}
@@ -1,80 +1,41 @@
1
1
  import 'reflect-metadata';
2
- import type { ServiceIdentifier } from 'inversify';
3
2
  /**
4
3
  * Metadata keys for server-side routing.
5
4
  * These are specific to the routing package (server-side only).
6
5
  */
7
6
  export declare const ROUTING_METADATA_KEYS: {
8
- CONTROLLER: string;
9
- NOT_CONTROLLER: string;
10
- API_IMPLEMENTATION: string;
7
+ DOCUMENT_DESIGN: string;
11
8
  SOURCE_FILEPATH: string;
12
9
  };
13
10
  /**
14
- * @Controller decorator — marks a controller (server-side only).
11
+ * @DocumentDesign decorator — marks a class as a DI-design ROOT: the top-of-DAG class whose
12
+ * dependency-injection tree the design-doc generator walks and renders into that project's
13
+ * `design.json` / `design.md` / `design.html`.
15
14
  *
16
- * Usage:
17
- * ```typescript
18
- * @Controller()
19
- * export class SaveController {
20
- * // ...
21
- * }
22
- * ```
23
- */
24
- export declare function Controller(): ClassDecorator;
25
- /**
26
- * Helper function to check if a class is a controller.
27
- * Server-side only.
28
- */
29
- export declare function isController(controllerClass: any): boolean;
30
- /**
31
- * @NotController decorator — explicitly marks a class that implements/extends an `*Api` contract
32
- * as deliberately NOT a controller (e.g. a simulator, an in-process client, a test double).
15
+ * It is the single marker for every kind of design root — server controllers (the class an
16
+ * `ApiRoutingFactory(Api, Controller)` binds) and library implementation classes (the top class a
17
+ * `role:designed-lib` project exports and binds in its `ContainerModule`). A `role:designed-lib`
18
+ * project is REQUIRED to have at least one `@DocumentDesign` class otherwise the DI-graph
19
+ * generator has no root and fails.
33
20
  *
34
- * The `enforce-controller-naming` rule requires every class whose heritage ends in `*Api` to declare
35
- * its intent: either `@Controller` (then it must be named `{Something}Controller` and live in a
36
- * `{something}-controller.ts` file) OR `@NotController` (then it is exempt from those naming rules).
37
- * This is a pure marker it registers no route and only records intent for the lint rule.
21
+ * This is a pure marker read STATICALLY by the DI-graph analyzer (by decorator name); nothing reads
22
+ * its runtime metadata. Routing does NOT depend on it routes are wired explicitly by
23
+ * `ApiRoutingFactory(Api, Controller)`, which reads `@ApiPath`/`@Endpoint` off the API class and
24
+ * `@SourceFile` off the controller. The metadata below exists only for symmetry/debuggability.
38
25
  *
39
26
  * Usage:
40
27
  * ```typescript
41
- * @NotController()
42
- * export class Server2Simulator { ... }
43
- * ```
44
- */
45
- export declare function NotController(): ClassDecorator;
46
- /**
47
- * Helper function to check if a class is explicitly marked as NOT a controller.
48
- * Server-side only.
49
- */
50
- export declare function isNotController(controllerClass: object): boolean;
51
- /**
52
- * @ApiImplementation decorator — marks the top-of-DAG implementation class in a LIBRARY
53
- * (a `role:designed-lib` project) whose DI design should be generated.
54
- *
55
- * It is the library-side analog of `@Controller`: where a server's design roots on its
56
- * `@Controller` classes, a designed-lib's design roots on its `@ApiImplementation` classes.
57
- * A `role:designed-lib` project is REQUIRED to have at least one such class — otherwise the
58
- * DI-graph generator has no root and fails.
59
- *
60
- * Put it on the top implementation class a library exports and binds in its `ContainerModule`
61
- * (e.g. the class an app injects to drive the library). Like `@Controller`, this is a pure
62
- * marker read by the static DI-graph analyzer (by decorator name); it registers nothing at
63
- * runtime on its own.
64
- *
65
- * Usage:
66
- * ```typescript
67
- * @ApiImplementation()
28
+ * @DocumentDesign()
68
29
  * @injectable()
69
- * export class AgentHandler { ... }
30
+ * export class SaveController extends SaveApi { ... }
70
31
  * ```
71
32
  */
72
- export declare function ApiImplementation(): ClassDecorator;
33
+ export declare function DocumentDesign(): ClassDecorator;
73
34
  /**
74
- * Helper function to check if a class is marked as an API implementation (designed-lib root).
35
+ * Helper function to check if a class is marked as a DI-design root.
75
36
  * Server/library side only.
76
37
  */
77
- export declare function isApiImplementation(implClass: object): boolean;
38
+ export declare function isDocumentDesign(designClass: object): boolean;
78
39
  /**
79
40
  * SourceFile decorator to explicitly set the source filepath for a controller.
80
41
  * This is used by filter matching to determine which filters apply to the controller.
@@ -83,54 +44,9 @@ export declare function isApiImplementation(implClass: object): boolean;
83
44
  *
84
45
  * Usage:
85
46
  * @SourceFile('src/controllers/admin/UserController.ts')
86
- * @Controller()
47
+ * @DocumentDesign()
87
48
  * export class UserController { ... }
88
49
  *
89
50
  * @param filepath - The source filepath of the controller
90
51
  */
91
52
  export declare function SourceFile(filepath: string): ClassDecorator;
92
- /**
93
- * Provides a singleton-scoped dependency.
94
- * When called without arguments, the decorated class binds to itself.
95
- *
96
- * Server-side only - registers classes in the DI container.
97
- *
98
- * Usage:
99
- * ```typescript
100
- * @provideSingleton()
101
- * @Controller()
102
- * export class SaveController {
103
- * // ...
104
- * }
105
- * ```
106
- */
107
- export declare function provideSingleton(): (target: any) => any;
108
- /**
109
- * Provides a singleton-scoped dependency bound to a specific token (Symbol or abstract class).
110
- * Use this in libraries/apis-external/** to bind an impl to the Symbol defined in libraries/apis/**.
111
- *
112
- * Usage:
113
- * ```typescript
114
- * import { SOME_API_TOKEN } from '@myorg/some-api';
115
- *
116
- * @provideSingletonAs(SOME_API_TOKEN)
117
- * export class SomeApiImpl { ... }
118
- * ```
119
- */
120
- export declare function provideSingletonAs<T>(serviceIdentifier: ServiceIdentifier<T>): ClassDecorator;
121
- /**
122
- * Provides a transient-scoped dependency (new instance every time).
123
- * When called without arguments, the decorated class binds to itself.
124
- *
125
- * Server-side only - registers classes in the DI container.
126
- *
127
- * Usage:
128
- * ```typescript
129
- * @provideTransient()
130
- * @Controller()
131
- * export class TransientController {
132
- * // ...
133
- * }
134
- * ```
135
- */
136
- export declare function provideTransient(): (target: any) => any;
package/src/decorators.js CHANGED
@@ -1,110 +1,52 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ROUTING_METADATA_KEYS = void 0;
4
- exports.Controller = Controller;
5
- exports.isController = isController;
6
- exports.NotController = NotController;
7
- exports.isNotController = isNotController;
8
- exports.ApiImplementation = ApiImplementation;
9
- exports.isApiImplementation = isApiImplementation;
4
+ exports.DocumentDesign = DocumentDesign;
5
+ exports.isDocumentDesign = isDocumentDesign;
10
6
  exports.SourceFile = SourceFile;
11
- exports.provideSingleton = provideSingleton;
12
- exports.provideSingletonAs = provideSingletonAs;
13
- exports.provideTransient = provideTransient;
14
7
  require("reflect-metadata");
15
- const binding_decorators_1 = require("@inversifyjs/binding-decorators");
16
8
  /**
17
9
  * Metadata keys for server-side routing.
18
10
  * These are specific to the routing package (server-side only).
19
11
  */
20
12
  exports.ROUTING_METADATA_KEYS = {
21
- CONTROLLER: 'webpieces:controller',
22
- NOT_CONTROLLER: 'webpieces:not-controller',
23
- API_IMPLEMENTATION: 'webpieces:api-implementation',
13
+ DOCUMENT_DESIGN: 'webpieces:document-design',
24
14
  SOURCE_FILEPATH: 'webpieces:source-filepath',
25
15
  };
26
16
  /**
27
- * @Controller decorator — marks a controller (server-side only).
17
+ * @DocumentDesign decorator — marks a class as a DI-design ROOT: the top-of-DAG class whose
18
+ * dependency-injection tree the design-doc generator walks and renders into that project's
19
+ * `design.json` / `design.md` / `design.html`.
28
20
  *
29
- * Usage:
30
- * ```typescript
31
- * @Controller()
32
- * export class SaveController {
33
- * // ...
34
- * }
35
- * ```
36
- */
37
- function Controller() {
38
- return (target) => {
39
- Reflect.defineMetadata(exports.ROUTING_METADATA_KEYS.CONTROLLER, true, target);
40
- };
41
- }
42
- /**
43
- * Helper function to check if a class is a controller.
44
- * Server-side only.
45
- */
46
- function isController(controllerClass) {
47
- return Reflect.getMetadata(exports.ROUTING_METADATA_KEYS.CONTROLLER, controllerClass) === true;
48
- }
49
- /**
50
- * @NotController decorator — explicitly marks a class that implements/extends an `*Api` contract
51
- * as deliberately NOT a controller (e.g. a simulator, an in-process client, a test double).
21
+ * It is the single marker for every kind of design root — server controllers (the class an
22
+ * `ApiRoutingFactory(Api, Controller)` binds) and library implementation classes (the top class a
23
+ * `role:designed-lib` project exports and binds in its `ContainerModule`). A `role:designed-lib`
24
+ * project is REQUIRED to have at least one `@DocumentDesign` class otherwise the DI-graph
25
+ * generator has no root and fails.
52
26
  *
53
- * The `enforce-controller-naming` rule requires every class whose heritage ends in `*Api` to declare
54
- * its intent: either `@Controller` (then it must be named `{Something}Controller` and live in a
55
- * `{something}-controller.ts` file) OR `@NotController` (then it is exempt from those naming rules).
56
- * This is a pure marker it registers no route and only records intent for the lint rule.
27
+ * This is a pure marker read STATICALLY by the DI-graph analyzer (by decorator name); nothing reads
28
+ * its runtime metadata. Routing does NOT depend on it routes are wired explicitly by
29
+ * `ApiRoutingFactory(Api, Controller)`, which reads `@ApiPath`/`@Endpoint` off the API class and
30
+ * `@SourceFile` off the controller. The metadata below exists only for symmetry/debuggability.
57
31
  *
58
32
  * Usage:
59
33
  * ```typescript
60
- * @NotController()
61
- * export class Server2Simulator { ... }
62
- * ```
63
- */
64
- function NotController() {
65
- return (target) => {
66
- Reflect.defineMetadata(exports.ROUTING_METADATA_KEYS.NOT_CONTROLLER, true, target);
67
- };
68
- }
69
- /**
70
- * Helper function to check if a class is explicitly marked as NOT a controller.
71
- * Server-side only.
72
- */
73
- function isNotController(controllerClass) {
74
- return Reflect.getMetadata(exports.ROUTING_METADATA_KEYS.NOT_CONTROLLER, controllerClass) === true;
75
- }
76
- /**
77
- * @ApiImplementation decorator — marks the top-of-DAG implementation class in a LIBRARY
78
- * (a `role:designed-lib` project) whose DI design should be generated.
79
- *
80
- * It is the library-side analog of `@Controller`: where a server's design roots on its
81
- * `@Controller` classes, a designed-lib's design roots on its `@ApiImplementation` classes.
82
- * A `role:designed-lib` project is REQUIRED to have at least one such class — otherwise the
83
- * DI-graph generator has no root and fails.
84
- *
85
- * Put it on the top implementation class a library exports and binds in its `ContainerModule`
86
- * (e.g. the class an app injects to drive the library). Like `@Controller`, this is a pure
87
- * marker read by the static DI-graph analyzer (by decorator name); it registers nothing at
88
- * runtime on its own.
89
- *
90
- * Usage:
91
- * ```typescript
92
- * @ApiImplementation()
34
+ * @DocumentDesign()
93
35
  * @injectable()
94
- * export class AgentHandler { ... }
36
+ * export class SaveController extends SaveApi { ... }
95
37
  * ```
96
38
  */
97
- function ApiImplementation() {
39
+ function DocumentDesign() {
98
40
  return (target) => {
99
- Reflect.defineMetadata(exports.ROUTING_METADATA_KEYS.API_IMPLEMENTATION, true, target);
41
+ Reflect.defineMetadata(exports.ROUTING_METADATA_KEYS.DOCUMENT_DESIGN, true, target);
100
42
  };
101
43
  }
102
44
  /**
103
- * Helper function to check if a class is marked as an API implementation (designed-lib root).
45
+ * Helper function to check if a class is marked as a DI-design root.
104
46
  * Server/library side only.
105
47
  */
106
- function isApiImplementation(implClass) {
107
- return Reflect.getMetadata(exports.ROUTING_METADATA_KEYS.API_IMPLEMENTATION, implClass) === true;
48
+ function isDocumentDesign(designClass) {
49
+ return Reflect.getMetadata(exports.ROUTING_METADATA_KEYS.DOCUMENT_DESIGN, designClass) === true;
108
50
  }
109
51
  /**
110
52
  * SourceFile decorator to explicitly set the source filepath for a controller.
@@ -114,7 +56,7 @@ function isApiImplementation(implClass) {
114
56
  *
115
57
  * Usage:
116
58
  * @SourceFile('src/controllers/admin/UserController.ts')
117
- * @Controller()
59
+ * @DocumentDesign()
118
60
  * export class UserController { ... }
119
61
  *
120
62
  * @param filepath - The source filepath of the controller
@@ -124,59 +66,7 @@ function SourceFile(filepath) {
124
66
  Reflect.defineMetadata(exports.ROUTING_METADATA_KEYS.SOURCE_FILEPATH, filepath, target);
125
67
  };
126
68
  }
127
- /**
128
- * Provides a singleton-scoped dependency.
129
- * When called without arguments, the decorated class binds to itself.
130
- *
131
- * Server-side only - registers classes in the DI container.
132
- *
133
- * Usage:
134
- * ```typescript
135
- * @provideSingleton()
136
- * @Controller()
137
- * export class SaveController {
138
- * // ...
139
- * }
140
- * ```
141
- */
142
- function provideSingleton() {
143
- return (target) => {
144
- return (0, binding_decorators_1.provide)(target, (bind) => bind.inSingletonScope())(target);
145
- };
146
- }
147
- /**
148
- * Provides a singleton-scoped dependency bound to a specific token (Symbol or abstract class).
149
- * Use this in libraries/apis-external/** to bind an impl to the Symbol defined in libraries/apis/**.
150
- *
151
- * Usage:
152
- * ```typescript
153
- * import { SOME_API_TOKEN } from '@myorg/some-api';
154
- *
155
- * @provideSingletonAs(SOME_API_TOKEN)
156
- * export class SomeApiImpl { ... }
157
- * ```
158
- */
159
- function provideSingletonAs(serviceIdentifier) {
160
- return (0, binding_decorators_1.provide)(serviceIdentifier, (bind) => bind.inSingletonScope());
161
- }
162
- /**
163
- * Provides a transient-scoped dependency (new instance every time).
164
- * When called without arguments, the decorated class binds to itself.
165
- *
166
- * Server-side only - registers classes in the DI container.
167
- *
168
- * Usage:
169
- * ```typescript
170
- * @provideTransient()
171
- * @Controller()
172
- * export class TransientController {
173
- * // ...
174
- * }
175
- * ```
176
- */
177
- function provideTransient() {
178
- return (target) => {
179
- return (0, binding_decorators_1.provide)(target)(target);
180
- };
181
- }
69
+ // NOTE: provideSingleton / provideSingletonAs / provideTransient moved to
70
+ // @webpieces/core-context (the shared DI seam). http-routing re-exports them
71
+ // from there in index.ts for back-compat.
182
72
  //# sourceMappingURL=decorators.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"decorators.js","sourceRoot":"","sources":["../../../../../packages/http/http-routing/src/decorators.ts"],"names":[],"mappings":";;;AA0BA,gCAIC;AAMD,oCAEC;AAiBD,sCAIC;AAMD,0CAEC;AAuBD,8CAIC;AAMD,kDAEC;AAeD,gCAIC;AAiBD,4CAIC;AAcD,gDAEC;AAiBD,4CAIC;AAnLD,4BAA0B;AAC1B,wEAA0D;AAG1D;;;GAGG;AACU,QAAA,qBAAqB,GAAG;IACjC,UAAU,EAAE,sBAAsB;IAClC,cAAc,EAAE,0BAA0B;IAC1C,kBAAkB,EAAE,8BAA8B;IAClD,eAAe,EAAE,2BAA2B;CAC/C,CAAC;AAEF;;;;;;;;;;GAUG;AACH,SAAgB,UAAU;IACtB,OAAO,CAAC,MAAW,EAAE,EAAE;QACnB,OAAO,CAAC,cAAc,CAAC,6BAAqB,CAAC,UAAU,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IAC3E,CAAC,CAAC;AACN,CAAC;AAED;;;GAGG;AACH,SAAgB,YAAY,CAAC,eAAoB;IAC7C,OAAO,OAAO,CAAC,WAAW,CAAC,6BAAqB,CAAC,UAAU,EAAE,eAAe,CAAC,KAAK,IAAI,CAAC;AAC3F,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,SAAgB,aAAa;IACzB,OAAO,CAAC,MAAc,EAAE,EAAE;QACtB,OAAO,CAAC,cAAc,CAAC,6BAAqB,CAAC,cAAc,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IAC/E,CAAC,CAAC;AACN,CAAC;AAED;;;GAGG;AACH,SAAgB,eAAe,CAAC,eAAuB;IACnD,OAAO,OAAO,CAAC,WAAW,CAAC,6BAAqB,CAAC,cAAc,EAAE,eAAe,CAAC,KAAK,IAAI,CAAC;AAC/F,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,SAAgB,iBAAiB;IAC7B,OAAO,CAAC,MAAc,EAAE,EAAE;QACtB,OAAO,CAAC,cAAc,CAAC,6BAAqB,CAAC,kBAAkB,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACnF,CAAC,CAAC;AACN,CAAC;AAED;;;GAGG;AACH,SAAgB,mBAAmB,CAAC,SAAiB;IACjD,OAAO,OAAO,CAAC,WAAW,CAAC,6BAAqB,CAAC,kBAAkB,EAAE,SAAS,CAAC,KAAK,IAAI,CAAC;AAC7F,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,SAAgB,UAAU,CAAC,QAAgB;IACvC,OAAO,CAAC,MAAW,EAAE,EAAE;QACnB,OAAO,CAAC,cAAc,CAAC,6BAAqB,CAAC,eAAe,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;IACpF,CAAC,CAAC;AACN,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,SAAgB,gBAAgB;IAC5B,OAAO,CAAC,MAAW,EAAE,EAAE;QACnB,OAAO,IAAA,4BAAO,EAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;IACtE,CAAC,CAAC;AACN,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAgB,kBAAkB,CAAI,iBAAuC;IACzE,OAAO,IAAA,4BAAO,EAAC,iBAAiB,EAAE,CAAC,IAAiC,EAAE,EAAE,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC,CAAC;AACtG,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,SAAgB,gBAAgB;IAC5B,OAAO,CAAC,MAAW,EAAE,EAAE;QACnB,OAAO,IAAA,4BAAO,EAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC,CAAC;AACN,CAAC","sourcesContent":["import 'reflect-metadata';\nimport { provide } from '@inversifyjs/binding-decorators';\nimport type { BindInWhenOnFluentSyntax, ServiceIdentifier } from 'inversify';\n\n/**\n * Metadata keys for server-side routing.\n * These are specific to the routing package (server-side only).\n */\nexport const ROUTING_METADATA_KEYS = {\n CONTROLLER: 'webpieces:controller',\n NOT_CONTROLLER: 'webpieces:not-controller',\n API_IMPLEMENTATION: 'webpieces:api-implementation',\n SOURCE_FILEPATH: 'webpieces:source-filepath',\n};\n\n/**\n * @Controller decorator — marks a controller (server-side only).\n *\n * Usage:\n * ```typescript\n * @Controller()\n * export class SaveController {\n * // ...\n * }\n * ```\n */\nexport function Controller(): ClassDecorator {\n return (target: any) => {\n Reflect.defineMetadata(ROUTING_METADATA_KEYS.CONTROLLER, true, target);\n };\n}\n\n/**\n * Helper function to check if a class is a controller.\n * Server-side only.\n */\nexport function isController(controllerClass: any): boolean {\n return Reflect.getMetadata(ROUTING_METADATA_KEYS.CONTROLLER, controllerClass) === true;\n}\n\n/**\n * @NotController decorator — explicitly marks a class that implements/extends an `*Api` contract\n * as deliberately NOT a controller (e.g. a simulator, an in-process client, a test double).\n *\n * The `enforce-controller-naming` rule requires every class whose heritage ends in `*Api` to declare\n * its intent: either `@Controller` (then it must be named `{Something}Controller` and live in a\n * `{something}-controller.ts` file) OR `@NotController` (then it is exempt from those naming rules).\n * This is a pure marker — it registers no route and only records intent for the lint rule.\n *\n * Usage:\n * ```typescript\n * @NotController()\n * export class Server2Simulator { ... }\n * ```\n */\nexport function NotController(): ClassDecorator {\n return (target: object) => {\n Reflect.defineMetadata(ROUTING_METADATA_KEYS.NOT_CONTROLLER, true, target);\n };\n}\n\n/**\n * Helper function to check if a class is explicitly marked as NOT a controller.\n * Server-side only.\n */\nexport function isNotController(controllerClass: object): boolean {\n return Reflect.getMetadata(ROUTING_METADATA_KEYS.NOT_CONTROLLER, controllerClass) === true;\n}\n\n/**\n * @ApiImplementation decorator — marks the top-of-DAG implementation class in a LIBRARY\n * (a `role:designed-lib` project) whose DI design should be generated.\n *\n * It is the library-side analog of `@Controller`: where a server's design roots on its\n * `@Controller` classes, a designed-lib's design roots on its `@ApiImplementation` classes.\n * A `role:designed-lib` project is REQUIRED to have at least one such class — otherwise the\n * DI-graph generator has no root and fails.\n *\n * Put it on the top implementation class a library exports and binds in its `ContainerModule`\n * (e.g. the class an app injects to drive the library). Like `@Controller`, this is a pure\n * marker read by the static DI-graph analyzer (by decorator name); it registers nothing at\n * runtime on its own.\n *\n * Usage:\n * ```typescript\n * @ApiImplementation()\n * @injectable()\n * export class AgentHandler { ... }\n * ```\n */\nexport function ApiImplementation(): ClassDecorator {\n return (target: object) => {\n Reflect.defineMetadata(ROUTING_METADATA_KEYS.API_IMPLEMENTATION, true, target);\n };\n}\n\n/**\n * Helper function to check if a class is marked as an API implementation (designed-lib root).\n * Server/library side only.\n */\nexport function isApiImplementation(implClass: object): boolean {\n return Reflect.getMetadata(ROUTING_METADATA_KEYS.API_IMPLEMENTATION, implClass) === true;\n}\n\n/**\n * SourceFile decorator to explicitly set the source filepath for a controller.\n * This is used by filter matching to determine which filters apply to the controller.\n *\n * If not specified, the system will use a heuristic based on the controller's name.\n *\n * Usage:\n * @SourceFile('src/controllers/admin/UserController.ts')\n * @Controller()\n * export class UserController { ... }\n *\n * @param filepath - The source filepath of the controller\n */\nexport function SourceFile(filepath: string): ClassDecorator {\n return (target: any) => {\n Reflect.defineMetadata(ROUTING_METADATA_KEYS.SOURCE_FILEPATH, filepath, target);\n };\n}\n\n/**\n * Provides a singleton-scoped dependency.\n * When called without arguments, the decorated class binds to itself.\n *\n * Server-side only - registers classes in the DI container.\n *\n * Usage:\n * ```typescript\n * @provideSingleton()\n * @Controller()\n * export class SaveController {\n * // ...\n * }\n * ```\n */\nexport function provideSingleton() {\n return (target: any) => {\n return provide(target, (bind) => bind.inSingletonScope())(target);\n };\n}\n\n/**\n * Provides a singleton-scoped dependency bound to a specific token (Symbol or abstract class).\n * Use this in libraries/apis-external/** to bind an impl to the Symbol defined in libraries/apis/**.\n *\n * Usage:\n * ```typescript\n * import { SOME_API_TOKEN } from '@myorg/some-api';\n *\n * @provideSingletonAs(SOME_API_TOKEN)\n * export class SomeApiImpl { ... }\n * ```\n */\nexport function provideSingletonAs<T>(serviceIdentifier: ServiceIdentifier<T>): ClassDecorator {\n return provide(serviceIdentifier, (bind: BindInWhenOnFluentSyntax<T>) => bind.inSingletonScope());\n}\n\n/**\n * Provides a transient-scoped dependency (new instance every time).\n * When called without arguments, the decorated class binds to itself.\n *\n * Server-side only - registers classes in the DI container.\n *\n * Usage:\n * ```typescript\n * @provideTransient()\n * @Controller()\n * export class TransientController {\n * // ...\n * }\n * ```\n */\nexport function provideTransient() {\n return (target: any) => {\n return provide(target)(target);\n };\n}\n"]}
1
+ {"version":3,"file":"decorators.js","sourceRoot":"","sources":["../../../../../packages/http/http-routing/src/decorators.ts"],"names":[],"mappings":";;;AAkCA,wCAIC;AAMD,4CAEC;AAeD,gCAIC;AAjED,4BAA0B;AAE1B;;;GAGG;AACU,QAAA,qBAAqB,GAAG;IACjC,eAAe,EAAE,2BAA2B;IAC5C,eAAe,EAAE,2BAA2B;CAC/C,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,SAAgB,cAAc;IAC1B,OAAO,CAAC,MAAc,EAAE,EAAE;QACtB,OAAO,CAAC,cAAc,CAAC,6BAAqB,CAAC,eAAe,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IAChF,CAAC,CAAC;AACN,CAAC;AAED;;;GAGG;AACH,SAAgB,gBAAgB,CAAC,WAAmB;IAChD,OAAO,OAAO,CAAC,WAAW,CAAC,6BAAqB,CAAC,eAAe,EAAE,WAAW,CAAC,KAAK,IAAI,CAAC;AAC5F,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,SAAgB,UAAU,CAAC,QAAgB;IACvC,OAAO,CAAC,MAAW,EAAE,EAAE;QACnB,OAAO,CAAC,cAAc,CAAC,6BAAqB,CAAC,eAAe,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;IACpF,CAAC,CAAC;AACN,CAAC;AAED,0EAA0E;AAC1E,6EAA6E;AAC7E,0CAA0C","sourcesContent":["import 'reflect-metadata';\n\n/**\n * Metadata keys for server-side routing.\n * These are specific to the routing package (server-side only).\n */\nexport const ROUTING_METADATA_KEYS = {\n DOCUMENT_DESIGN: 'webpieces:document-design',\n SOURCE_FILEPATH: 'webpieces:source-filepath',\n};\n\n/**\n * @DocumentDesign decorator — marks a class as a DI-design ROOT: the top-of-DAG class whose\n * dependency-injection tree the design-doc generator walks and renders into that project's\n * `design.json` / `design.md` / `design.html`.\n *\n * It is the single marker for every kind of design root server controllers (the class an\n * `ApiRoutingFactory(Api, Controller)` binds) and library implementation classes (the top class a\n * `role:designed-lib` project exports and binds in its `ContainerModule`). A `role:designed-lib`\n * project is REQUIRED to have at least one `@DocumentDesign` class — otherwise the DI-graph\n * generator has no root and fails.\n *\n * This is a pure marker read STATICALLY by the DI-graph analyzer (by decorator name); nothing reads\n * its runtime metadata. Routing does NOT depend on it routes are wired explicitly by\n * `ApiRoutingFactory(Api, Controller)`, which reads `@ApiPath`/`@Endpoint` off the API class and\n * `@SourceFile` off the controller. The metadata below exists only for symmetry/debuggability.\n *\n * Usage:\n * ```typescript\n * @DocumentDesign()\n * @injectable()\n * export class SaveController extends SaveApi { ... }\n * ```\n */\nexport function DocumentDesign(): ClassDecorator {\n return (target: object) => {\n Reflect.defineMetadata(ROUTING_METADATA_KEYS.DOCUMENT_DESIGN, true, target);\n };\n}\n\n/**\n * Helper function to check if a class is marked as a DI-design root.\n * Server/library side only.\n */\nexport function isDocumentDesign(designClass: object): boolean {\n return Reflect.getMetadata(ROUTING_METADATA_KEYS.DOCUMENT_DESIGN, designClass) === true;\n}\n\n/**\n * SourceFile decorator to explicitly set the source filepath for a controller.\n * This is used by filter matching to determine which filters apply to the controller.\n *\n * If not specified, the system will use a heuristic based on the controller's name.\n *\n * Usage:\n * @SourceFile('src/controllers/admin/UserController.ts')\n * @DocumentDesign()\n * export class UserController { ... }\n *\n * @param filepath - The source filepath of the controller\n */\nexport function SourceFile(filepath: string): ClassDecorator {\n return (target: any) => {\n Reflect.defineMetadata(ROUTING_METADATA_KEYS.SOURCE_FILEPATH, filepath, target);\n };\n}\n\n// NOTE: provideSingleton / provideSingletonAs / provideTransient moved to\n// @webpieces/core-context (the shared DI seam). http-routing re-exports them\n// from there in index.ts for back-compat.\n"]}
package/src/index.d.ts CHANGED
@@ -1,11 +1,12 @@
1
- export { ApiPath, Endpoint, Authentication, AuthenticationConfig, Public, AuthJwt, AuthOidc, AuthSharedSecret, Rpc, PubSub, Queue, getApiPath, getEndpoints, isApiPath, getAuthMeta, getAuthMode, assertEveryEndpointHasAuthMode, getApiKind, assertApiKind, assertPubSubConventions, getQueueName, AuthMeta, RouteMetadata, METADATA_KEYS, ValidateImplementation, } from '@webpieces/http-api';
2
- export type { AuthMode, ApiKind } from '@webpieces/http-api';
3
- export { Controller, isController, NotController, isNotController, ApiImplementation, isApiImplementation, provideSingleton, provideSingletonAs, provideTransient, ROUTING_METADATA_KEYS, } from './decorators';
1
+ export { ApiPath, Endpoint, Authentication, AuthenticationConfig, Public, AuthJwt, AuthOidc, AuthSharedSecret, Rpc, PubSub, Queue, getApiPath, getEndpoints, isApiPath, getAuthMeta, getAuthMode, assertEveryEndpointHasAuthMode, getApiKind, assertApiKind, assertPubSubConventions, getQueueName, AuthMeta, RouteMetadata, METADATA_KEYS, ValidateImplementation, } from '@webpieces/core-util';
2
+ export type { AuthMode, ApiKind } from '@webpieces/core-util';
3
+ export { DocumentDesign, isDocumentDesign, SourceFile, ROUTING_METADATA_KEYS, } from './decorators';
4
+ export { provideSingleton, provideSingletonAs, provideTransient } from '@webpieces/core-context';
4
5
  export { ApiRoutingFactory, ClassType } from './ApiRoutingFactory';
5
6
  export { WebAppMeta, WEBAPP_META_TOKEN, Routes, RouteBuilder, RouteDefinition, FilterDefinition, } from './WebAppMeta';
6
- export { MethodMeta } from './MethodMeta';
7
+ export { MethodMeta } from '@webpieces/http-filters';
7
8
  export { RouteHandler } from './RouteHandler';
8
9
  export { RouteBuilderImpl, RouteHandlerWithMeta, FilterWithMeta, ExpressRouteHandler, } from './RouteBuilderImpl';
9
10
  export { FilterMatcher, HttpFilter } from './FilterMatcher';
10
- export { RequestContextReader } from './RequestContextReader';
11
+ export { RequestContextReader } from '@webpieces/core-context';
11
12
  export { WebpiecesConfig, WEBPIECES_CONFIG_TOKEN } from './WebpiecesConfig';
package/src/index.js CHANGED
@@ -1,44 +1,43 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.WEBPIECES_CONFIG_TOKEN = exports.WebpiecesConfig = exports.RequestContextReader = exports.FilterMatcher = exports.FilterWithMeta = exports.RouteHandlerWithMeta = exports.RouteBuilderImpl = exports.RouteHandler = exports.MethodMeta = exports.FilterDefinition = exports.RouteDefinition = exports.WEBAPP_META_TOKEN = exports.ApiRoutingFactory = exports.ROUTING_METADATA_KEYS = exports.provideTransient = exports.provideSingletonAs = exports.provideSingleton = exports.isApiImplementation = exports.ApiImplementation = exports.isNotController = exports.NotController = exports.isController = exports.Controller = exports.METADATA_KEYS = exports.RouteMetadata = exports.AuthMeta = exports.getQueueName = exports.assertPubSubConventions = exports.assertApiKind = exports.getApiKind = exports.assertEveryEndpointHasAuthMode = exports.getAuthMode = exports.getAuthMeta = exports.isApiPath = exports.getEndpoints = exports.getApiPath = exports.Queue = exports.PubSub = exports.Rpc = exports.AuthSharedSecret = exports.AuthOidc = exports.AuthJwt = exports.Public = exports.AuthenticationConfig = exports.Authentication = exports.Endpoint = exports.ApiPath = void 0;
4
- // Re-export API decorators from http-api for convenience
5
- var http_api_1 = require("@webpieces/http-api");
6
- Object.defineProperty(exports, "ApiPath", { enumerable: true, get: function () { return http_api_1.ApiPath; } });
7
- Object.defineProperty(exports, "Endpoint", { enumerable: true, get: function () { return http_api_1.Endpoint; } });
8
- Object.defineProperty(exports, "Authentication", { enumerable: true, get: function () { return http_api_1.Authentication; } });
9
- Object.defineProperty(exports, "AuthenticationConfig", { enumerable: true, get: function () { return http_api_1.AuthenticationConfig; } });
10
- Object.defineProperty(exports, "Public", { enumerable: true, get: function () { return http_api_1.Public; } });
11
- Object.defineProperty(exports, "AuthJwt", { enumerable: true, get: function () { return http_api_1.AuthJwt; } });
12
- Object.defineProperty(exports, "AuthOidc", { enumerable: true, get: function () { return http_api_1.AuthOidc; } });
13
- Object.defineProperty(exports, "AuthSharedSecret", { enumerable: true, get: function () { return http_api_1.AuthSharedSecret; } });
14
- Object.defineProperty(exports, "Rpc", { enumerable: true, get: function () { return http_api_1.Rpc; } });
15
- Object.defineProperty(exports, "PubSub", { enumerable: true, get: function () { return http_api_1.PubSub; } });
16
- Object.defineProperty(exports, "Queue", { enumerable: true, get: function () { return http_api_1.Queue; } });
17
- Object.defineProperty(exports, "getApiPath", { enumerable: true, get: function () { return http_api_1.getApiPath; } });
18
- Object.defineProperty(exports, "getEndpoints", { enumerable: true, get: function () { return http_api_1.getEndpoints; } });
19
- Object.defineProperty(exports, "isApiPath", { enumerable: true, get: function () { return http_api_1.isApiPath; } });
20
- Object.defineProperty(exports, "getAuthMeta", { enumerable: true, get: function () { return http_api_1.getAuthMeta; } });
21
- Object.defineProperty(exports, "getAuthMode", { enumerable: true, get: function () { return http_api_1.getAuthMode; } });
22
- Object.defineProperty(exports, "assertEveryEndpointHasAuthMode", { enumerable: true, get: function () { return http_api_1.assertEveryEndpointHasAuthMode; } });
23
- Object.defineProperty(exports, "getApiKind", { enumerable: true, get: function () { return http_api_1.getApiKind; } });
24
- Object.defineProperty(exports, "assertApiKind", { enumerable: true, get: function () { return http_api_1.assertApiKind; } });
25
- Object.defineProperty(exports, "assertPubSubConventions", { enumerable: true, get: function () { return http_api_1.assertPubSubConventions; } });
26
- Object.defineProperty(exports, "getQueueName", { enumerable: true, get: function () { return http_api_1.getQueueName; } });
27
- Object.defineProperty(exports, "AuthMeta", { enumerable: true, get: function () { return http_api_1.AuthMeta; } });
28
- Object.defineProperty(exports, "RouteMetadata", { enumerable: true, get: function () { return http_api_1.RouteMetadata; } });
29
- Object.defineProperty(exports, "METADATA_KEYS", { enumerable: true, get: function () { return http_api_1.METADATA_KEYS; } });
3
+ exports.WEBPIECES_CONFIG_TOKEN = exports.WebpiecesConfig = exports.RequestContextReader = exports.FilterMatcher = exports.FilterWithMeta = exports.RouteHandlerWithMeta = exports.RouteBuilderImpl = exports.RouteHandler = exports.MethodMeta = exports.FilterDefinition = exports.RouteDefinition = exports.WEBAPP_META_TOKEN = exports.ApiRoutingFactory = exports.provideTransient = exports.provideSingletonAs = exports.provideSingleton = exports.ROUTING_METADATA_KEYS = exports.SourceFile = exports.isDocumentDesign = exports.DocumentDesign = exports.METADATA_KEYS = exports.RouteMetadata = exports.AuthMeta = exports.getQueueName = exports.assertPubSubConventions = exports.assertApiKind = exports.getApiKind = exports.assertEveryEndpointHasAuthMode = exports.getAuthMode = exports.getAuthMeta = exports.isApiPath = exports.getEndpoints = exports.getApiPath = exports.Queue = exports.PubSub = exports.Rpc = exports.AuthSharedSecret = exports.AuthOidc = exports.AuthJwt = exports.Public = exports.AuthenticationConfig = exports.Authentication = exports.Endpoint = exports.ApiPath = void 0;
4
+ // Re-export API decorators from core-util for convenience
5
+ var core_util_1 = require("@webpieces/core-util");
6
+ Object.defineProperty(exports, "ApiPath", { enumerable: true, get: function () { return core_util_1.ApiPath; } });
7
+ Object.defineProperty(exports, "Endpoint", { enumerable: true, get: function () { return core_util_1.Endpoint; } });
8
+ Object.defineProperty(exports, "Authentication", { enumerable: true, get: function () { return core_util_1.Authentication; } });
9
+ Object.defineProperty(exports, "AuthenticationConfig", { enumerable: true, get: function () { return core_util_1.AuthenticationConfig; } });
10
+ Object.defineProperty(exports, "Public", { enumerable: true, get: function () { return core_util_1.Public; } });
11
+ Object.defineProperty(exports, "AuthJwt", { enumerable: true, get: function () { return core_util_1.AuthJwt; } });
12
+ Object.defineProperty(exports, "AuthOidc", { enumerable: true, get: function () { return core_util_1.AuthOidc; } });
13
+ Object.defineProperty(exports, "AuthSharedSecret", { enumerable: true, get: function () { return core_util_1.AuthSharedSecret; } });
14
+ Object.defineProperty(exports, "Rpc", { enumerable: true, get: function () { return core_util_1.Rpc; } });
15
+ Object.defineProperty(exports, "PubSub", { enumerable: true, get: function () { return core_util_1.PubSub; } });
16
+ Object.defineProperty(exports, "Queue", { enumerable: true, get: function () { return core_util_1.Queue; } });
17
+ Object.defineProperty(exports, "getApiPath", { enumerable: true, get: function () { return core_util_1.getApiPath; } });
18
+ Object.defineProperty(exports, "getEndpoints", { enumerable: true, get: function () { return core_util_1.getEndpoints; } });
19
+ Object.defineProperty(exports, "isApiPath", { enumerable: true, get: function () { return core_util_1.isApiPath; } });
20
+ Object.defineProperty(exports, "getAuthMeta", { enumerable: true, get: function () { return core_util_1.getAuthMeta; } });
21
+ Object.defineProperty(exports, "getAuthMode", { enumerable: true, get: function () { return core_util_1.getAuthMode; } });
22
+ Object.defineProperty(exports, "assertEveryEndpointHasAuthMode", { enumerable: true, get: function () { return core_util_1.assertEveryEndpointHasAuthMode; } });
23
+ Object.defineProperty(exports, "getApiKind", { enumerable: true, get: function () { return core_util_1.getApiKind; } });
24
+ Object.defineProperty(exports, "assertApiKind", { enumerable: true, get: function () { return core_util_1.assertApiKind; } });
25
+ Object.defineProperty(exports, "assertPubSubConventions", { enumerable: true, get: function () { return core_util_1.assertPubSubConventions; } });
26
+ Object.defineProperty(exports, "getQueueName", { enumerable: true, get: function () { return core_util_1.getQueueName; } });
27
+ Object.defineProperty(exports, "AuthMeta", { enumerable: true, get: function () { return core_util_1.AuthMeta; } });
28
+ Object.defineProperty(exports, "RouteMetadata", { enumerable: true, get: function () { return core_util_1.RouteMetadata; } });
29
+ Object.defineProperty(exports, "METADATA_KEYS", { enumerable: true, get: function () { return core_util_1.METADATA_KEYS; } });
30
30
  // Server-side routing decorators and utilities
31
31
  var decorators_1 = require("./decorators");
32
- Object.defineProperty(exports, "Controller", { enumerable: true, get: function () { return decorators_1.Controller; } });
33
- Object.defineProperty(exports, "isController", { enumerable: true, get: function () { return decorators_1.isController; } });
34
- Object.defineProperty(exports, "NotController", { enumerable: true, get: function () { return decorators_1.NotController; } });
35
- Object.defineProperty(exports, "isNotController", { enumerable: true, get: function () { return decorators_1.isNotController; } });
36
- Object.defineProperty(exports, "ApiImplementation", { enumerable: true, get: function () { return decorators_1.ApiImplementation; } });
37
- Object.defineProperty(exports, "isApiImplementation", { enumerable: true, get: function () { return decorators_1.isApiImplementation; } });
38
- Object.defineProperty(exports, "provideSingleton", { enumerable: true, get: function () { return decorators_1.provideSingleton; } });
39
- Object.defineProperty(exports, "provideSingletonAs", { enumerable: true, get: function () { return decorators_1.provideSingletonAs; } });
40
- Object.defineProperty(exports, "provideTransient", { enumerable: true, get: function () { return decorators_1.provideTransient; } });
32
+ Object.defineProperty(exports, "DocumentDesign", { enumerable: true, get: function () { return decorators_1.DocumentDesign; } });
33
+ Object.defineProperty(exports, "isDocumentDesign", { enumerable: true, get: function () { return decorators_1.isDocumentDesign; } });
34
+ Object.defineProperty(exports, "SourceFile", { enumerable: true, get: function () { return decorators_1.SourceFile; } });
41
35
  Object.defineProperty(exports, "ROUTING_METADATA_KEYS", { enumerable: true, get: function () { return decorators_1.ROUTING_METADATA_KEYS; } });
36
+ // DI provider decorators moved to core-context; re-exported here for back-compat
37
+ var core_context_1 = require("@webpieces/core-context");
38
+ Object.defineProperty(exports, "provideSingleton", { enumerable: true, get: function () { return core_context_1.provideSingleton; } });
39
+ Object.defineProperty(exports, "provideSingletonAs", { enumerable: true, get: function () { return core_context_1.provideSingletonAs; } });
40
+ Object.defineProperty(exports, "provideTransient", { enumerable: true, get: function () { return core_context_1.provideTransient; } });
42
41
  var ApiRoutingFactory_1 = require("./ApiRoutingFactory");
43
42
  Object.defineProperty(exports, "ApiRoutingFactory", { enumerable: true, get: function () { return ApiRoutingFactory_1.ApiRoutingFactory; } });
44
43
  // Core routing types (moved from core-meta)
@@ -46,9 +45,9 @@ var WebAppMeta_1 = require("./WebAppMeta");
46
45
  Object.defineProperty(exports, "WEBAPP_META_TOKEN", { enumerable: true, get: function () { return WebAppMeta_1.WEBAPP_META_TOKEN; } });
47
46
  Object.defineProperty(exports, "RouteDefinition", { enumerable: true, get: function () { return WebAppMeta_1.RouteDefinition; } });
48
47
  Object.defineProperty(exports, "FilterDefinition", { enumerable: true, get: function () { return WebAppMeta_1.FilterDefinition; } });
49
- // Method metadata and route handler
50
- var MethodMeta_1 = require("./MethodMeta");
51
- Object.defineProperty(exports, "MethodMeta", { enumerable: true, get: function () { return MethodMeta_1.MethodMeta; } });
48
+ // Method metadata (moved to http-filters) re-exported for back-compat; route handler
49
+ var http_filters_1 = require("@webpieces/http-filters");
50
+ Object.defineProperty(exports, "MethodMeta", { enumerable: true, get: function () { return http_filters_1.MethodMeta; } });
52
51
  var RouteHandler_1 = require("./RouteHandler");
53
52
  Object.defineProperty(exports, "RouteHandler", { enumerable: true, get: function () { return RouteHandler_1.RouteHandler; } });
54
53
  // Route builder implementation
@@ -59,9 +58,9 @@ Object.defineProperty(exports, "FilterWithMeta", { enumerable: true, get: functi
59
58
  // Filter matching
60
59
  var FilterMatcher_1 = require("./FilterMatcher");
61
60
  Object.defineProperty(exports, "FilterMatcher", { enumerable: true, get: function () { return FilterMatcher_1.FilterMatcher; } });
62
- // Context readers (Node.js only)
63
- var RequestContextReader_1 = require("./RequestContextReader");
64
- Object.defineProperty(exports, "RequestContextReader", { enumerable: true, get: function () { return RequestContextReader_1.RequestContextReader; } });
61
+ // Context readers (Node.js only) moved to core-context; re-exported for back-compat
62
+ var core_context_2 = require("@webpieces/core-context");
63
+ Object.defineProperty(exports, "RequestContextReader", { enumerable: true, get: function () { return core_context_2.RequestContextReader; } });
65
64
  // Server configuration
66
65
  var WebpiecesConfig_1 = require("./WebpiecesConfig");
67
66
  Object.defineProperty(exports, "WebpiecesConfig", { enumerable: true, get: function () { return WebpiecesConfig_1.WebpiecesConfig; } });
package/src/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/http/http-routing/src/index.ts"],"names":[],"mappings":";;;AAAA,yDAAyD;AACzD,gDA0B6B;AAzBzB,mGAAA,OAAO,OAAA;AACP,oGAAA,QAAQ,OAAA;AACR,0GAAA,cAAc,OAAA;AACd,gHAAA,oBAAoB,OAAA;AACpB,kGAAA,MAAM,OAAA;AACN,mGAAA,OAAO,OAAA;AACP,oGAAA,QAAQ,OAAA;AACR,4GAAA,gBAAgB,OAAA;AAChB,+FAAA,GAAG,OAAA;AACH,kGAAA,MAAM,OAAA;AACN,iGAAA,KAAK,OAAA;AACL,sGAAA,UAAU,OAAA;AACV,wGAAA,YAAY,OAAA;AACZ,qGAAA,SAAS,OAAA;AACT,uGAAA,WAAW,OAAA;AACX,uGAAA,WAAW,OAAA;AACX,0HAAA,8BAA8B,OAAA;AAC9B,sGAAA,UAAU,OAAA;AACV,yGAAA,aAAa,OAAA;AACb,mHAAA,uBAAuB,OAAA;AACvB,wGAAA,YAAY,OAAA;AACZ,oGAAA,QAAQ,OAAA;AACR,yGAAA,aAAa,OAAA;AACb,yGAAA,aAAa,OAAA;AAKjB,+CAA+C;AAC/C,2CAWsB;AAVlB,wGAAA,UAAU,OAAA;AACV,0GAAA,YAAY,OAAA;AACZ,2GAAA,aAAa,OAAA;AACb,6GAAA,eAAe,OAAA;AACf,+GAAA,iBAAiB,OAAA;AACjB,iHAAA,mBAAmB,OAAA;AACnB,8GAAA,gBAAgB,OAAA;AAChB,gHAAA,kBAAkB,OAAA;AAClB,8GAAA,gBAAgB,OAAA;AAChB,mHAAA,qBAAqB,OAAA;AAGzB,yDAAmE;AAA1D,sHAAA,iBAAiB,OAAA;AAE1B,4CAA4C;AAC5C,2CAOsB;AALlB,+GAAA,iBAAiB,OAAA;AAGjB,6GAAA,eAAe,OAAA;AACf,8GAAA,gBAAgB,OAAA;AAGpB,oCAAoC;AACpC,2CAA0C;AAAjC,wGAAA,UAAU,OAAA;AACnB,+CAA8C;AAArC,4GAAA,YAAY,OAAA;AAErB,+BAA+B;AAC/B,uDAK4B;AAJxB,oHAAA,gBAAgB,OAAA;AAChB,wHAAA,oBAAoB,OAAA;AACpB,kHAAA,cAAc,OAAA;AAIlB,kBAAkB;AAClB,iDAA4D;AAAnD,8GAAA,aAAa,OAAA;AAEtB,iCAAiC;AACjC,+DAA8D;AAArD,4HAAA,oBAAoB,OAAA;AAE7B,uBAAuB;AACvB,qDAA4E;AAAnE,kHAAA,eAAe,OAAA;AAAE,yHAAA,sBAAsB,OAAA","sourcesContent":["// Re-export API decorators from http-api for convenience\nexport {\n ApiPath,\n Endpoint,\n Authentication,\n AuthenticationConfig,\n Public,\n AuthJwt,\n AuthOidc,\n AuthSharedSecret,\n Rpc,\n PubSub,\n Queue,\n getApiPath,\n getEndpoints,\n isApiPath,\n getAuthMeta,\n getAuthMode,\n assertEveryEndpointHasAuthMode,\n getApiKind,\n assertApiKind,\n assertPubSubConventions,\n getQueueName,\n AuthMeta,\n RouteMetadata,\n METADATA_KEYS,\n ValidateImplementation,\n} from '@webpieces/http-api';\nexport type { AuthMode, ApiKind } from '@webpieces/http-api';\n\n// Server-side routing decorators and utilities\nexport {\n Controller,\n isController,\n NotController,\n isNotController,\n ApiImplementation,\n isApiImplementation,\n provideSingleton,\n provideSingletonAs,\n provideTransient,\n ROUTING_METADATA_KEYS,\n} from './decorators';\n\nexport { ApiRoutingFactory, ClassType } from './ApiRoutingFactory';\n\n// Core routing types (moved from core-meta)\nexport {\n WebAppMeta,\n WEBAPP_META_TOKEN,\n Routes,\n RouteBuilder,\n RouteDefinition,\n FilterDefinition,\n} from './WebAppMeta';\n\n// Method metadata and route handler\nexport { MethodMeta } from './MethodMeta';\nexport { RouteHandler } from './RouteHandler';\n\n// Route builder implementation\nexport {\n RouteBuilderImpl,\n RouteHandlerWithMeta,\n FilterWithMeta,\n ExpressRouteHandler,\n} from './RouteBuilderImpl';\n\n// Filter matching\nexport { FilterMatcher, HttpFilter } from './FilterMatcher';\n\n// Context readers (Node.js only)\nexport { RequestContextReader } from './RequestContextReader';\n\n// Server configuration\nexport { WebpiecesConfig, WEBPIECES_CONFIG_TOKEN } from './WebpiecesConfig';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/http/http-routing/src/index.ts"],"names":[],"mappings":";;;AAAA,0DAA0D;AAC1D,kDA0B8B;AAzB1B,oGAAA,OAAO,OAAA;AACP,qGAAA,QAAQ,OAAA;AACR,2GAAA,cAAc,OAAA;AACd,iHAAA,oBAAoB,OAAA;AACpB,mGAAA,MAAM,OAAA;AACN,oGAAA,OAAO,OAAA;AACP,qGAAA,QAAQ,OAAA;AACR,6GAAA,gBAAgB,OAAA;AAChB,gGAAA,GAAG,OAAA;AACH,mGAAA,MAAM,OAAA;AACN,kGAAA,KAAK,OAAA;AACL,uGAAA,UAAU,OAAA;AACV,yGAAA,YAAY,OAAA;AACZ,sGAAA,SAAS,OAAA;AACT,wGAAA,WAAW,OAAA;AACX,wGAAA,WAAW,OAAA;AACX,2HAAA,8BAA8B,OAAA;AAC9B,uGAAA,UAAU,OAAA;AACV,0GAAA,aAAa,OAAA;AACb,oHAAA,uBAAuB,OAAA;AACvB,yGAAA,YAAY,OAAA;AACZ,qGAAA,QAAQ,OAAA;AACR,0GAAA,aAAa,OAAA;AACb,0GAAA,aAAa,OAAA;AAKjB,+CAA+C;AAC/C,2CAKsB;AAJlB,4GAAA,cAAc,OAAA;AACd,8GAAA,gBAAgB,OAAA;AAChB,wGAAA,UAAU,OAAA;AACV,mHAAA,qBAAqB,OAAA;AAGzB,iFAAiF;AACjF,wDAAiG;AAAxF,gHAAA,gBAAgB,OAAA;AAAE,kHAAA,kBAAkB,OAAA;AAAE,gHAAA,gBAAgB,OAAA;AAE/D,yDAAmE;AAA1D,sHAAA,iBAAiB,OAAA;AAE1B,4CAA4C;AAC5C,2CAOsB;AALlB,+GAAA,iBAAiB,OAAA;AAGjB,6GAAA,eAAe,OAAA;AACf,8GAAA,gBAAgB,OAAA;AAGpB,qFAAqF;AACrF,wDAAqD;AAA5C,0GAAA,UAAU,OAAA;AACnB,+CAA8C;AAArC,4GAAA,YAAY,OAAA;AAErB,+BAA+B;AAC/B,uDAK4B;AAJxB,oHAAA,gBAAgB,OAAA;AAChB,wHAAA,oBAAoB,OAAA;AACpB,kHAAA,cAAc,OAAA;AAIlB,kBAAkB;AAClB,iDAA4D;AAAnD,8GAAA,aAAa,OAAA;AAEtB,oFAAoF;AACpF,wDAA+D;AAAtD,oHAAA,oBAAoB,OAAA;AAE7B,uBAAuB;AACvB,qDAA4E;AAAnE,kHAAA,eAAe,OAAA;AAAE,yHAAA,sBAAsB,OAAA","sourcesContent":["// Re-export API decorators from core-util for convenience\nexport {\n ApiPath,\n Endpoint,\n Authentication,\n AuthenticationConfig,\n Public,\n AuthJwt,\n AuthOidc,\n AuthSharedSecret,\n Rpc,\n PubSub,\n Queue,\n getApiPath,\n getEndpoints,\n isApiPath,\n getAuthMeta,\n getAuthMode,\n assertEveryEndpointHasAuthMode,\n getApiKind,\n assertApiKind,\n assertPubSubConventions,\n getQueueName,\n AuthMeta,\n RouteMetadata,\n METADATA_KEYS,\n ValidateImplementation,\n} from '@webpieces/core-util';\nexport type { AuthMode, ApiKind } from '@webpieces/core-util';\n\n// Server-side routing decorators and utilities\nexport {\n DocumentDesign,\n isDocumentDesign,\n SourceFile,\n ROUTING_METADATA_KEYS,\n} from './decorators';\n\n// DI provider decorators moved to core-context; re-exported here for back-compat\nexport { provideSingleton, provideSingletonAs, provideTransient } from '@webpieces/core-context';\n\nexport { ApiRoutingFactory, ClassType } from './ApiRoutingFactory';\n\n// Core routing types (moved from core-meta)\nexport {\n WebAppMeta,\n WEBAPP_META_TOKEN,\n Routes,\n RouteBuilder,\n RouteDefinition,\n FilterDefinition,\n} from './WebAppMeta';\n\n// Method metadata (moved to http-filters) re-exported for back-compat; route handler\nexport { MethodMeta } from '@webpieces/http-filters';\nexport { RouteHandler } from './RouteHandler';\n\n// Route builder implementation\nexport {\n RouteBuilderImpl,\n RouteHandlerWithMeta,\n FilterWithMeta,\n ExpressRouteHandler,\n} from './RouteBuilderImpl';\n\n// Filter matching\nexport { FilterMatcher, HttpFilter } from './FilterMatcher';\n\n// Context readers (Node.js only) moved to core-context; re-exported for back-compat\nexport { RequestContextReader } from '@webpieces/core-context';\n\n// Server configuration\nexport { WebpiecesConfig, WEBPIECES_CONFIG_TOKEN } from './WebpiecesConfig';\n"]}
@@ -1,68 +0,0 @@
1
- import { RouteMetadata, AuthMeta } from '@webpieces/http-api';
2
- /**
3
- * Metadata about the method being invoked.
4
- * Passed to filters and contains request information.
5
- *
6
- * MethodMeta is DTO-only - it does NOT contain Express req/res directly.
7
- *
8
- * Fields:
9
- * - routeMeta: Static route information (httpMethod, path, methodName)
10
- * - requestHeaders: HTTP headers from the request (NEW)
11
- * - requestDto: The deserialized request body
12
- * - metadata: Request-scoped data for filters to communicate
13
- */
14
- export declare class MethodMeta {
15
- /**
16
- * Route metadata (httpMethod, path, methodName, parameterTypes)
17
- */
18
- routeMeta: RouteMetadata;
19
- /**
20
- * HTTP headers from the request.
21
- * Map of header name (lowercase) -> array of values.
22
- *
23
- * HTTP spec allows multiple values for same header name,
24
- * so we store as string[] (even though most headers have single value).
25
- *
26
- * LIFECYCLE:
27
- * 1. Set by ExpressWrapper BEFORE filter chain executes
28
- * 2. ContextFilter (priority 2000) transfers headers to RequestContext
29
- * 3. ContextFilter CLEARS this field (sets to undefined) after transfer
30
- * 4. ALL FILTERS AFTER ContextFilter will see this as UNDEFINED
31
- *
32
- * IMPORTANT: Downstream filters should NOT read from requestHeaders!
33
- * Instead, use RequestContext.getHeader() to read headers after ContextFilter.
34
- *
35
- * Example (correct usage in downstream filters):
36
- * ```typescript
37
- * const requestId = RequestContext.getHeader(WebpiecesCoreHeaders.REQUEST_ID);
38
- * ```
39
- */
40
- requestHeaders?: Map<string, string[]>;
41
- /**
42
- * The deserialized request DTO.
43
- */
44
- requestDto?: unknown;
45
- /**
46
- * Auth metadata from @Public/@Authenticated/@Roles decorators.
47
- * Populated by ApiRoutingFactory so filters can read auth requirements.
48
- */
49
- authMeta?: AuthMeta;
50
- /**
51
- * Additional metadata for storing request-scoped data.
52
- * Used by filters to pass data to other filters/controllers.
53
- */
54
- metadata: Map<string, unknown>;
55
- constructor(routeMeta: RouteMetadata, requestHeaders?: Map<string, string[]>, requestDto?: unknown, metadata?: Map<string, unknown>, authMeta?: AuthMeta);
56
- /**
57
- * Get the HTTP method (convenience accessor).
58
- */
59
- get httpMethod(): string;
60
- /**
61
- * Get the request path (convenience accessor).
62
- */
63
- get path(): string;
64
- /**
65
- * Get the method name (convenience accessor).
66
- */
67
- get methodName(): string;
68
- }
package/src/MethodMeta.js DELETED
@@ -1,84 +0,0 @@
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 DTO-only - it does NOT contain Express req/res directly.
9
- *
10
- * Fields:
11
- * - routeMeta: Static route information (httpMethod, path, methodName)
12
- * - requestHeaders: HTTP headers from the request (NEW)
13
- * - requestDto: The deserialized request body
14
- * - metadata: Request-scoped data for filters to communicate
15
- */
16
- class MethodMeta {
17
- /**
18
- * Route metadata (httpMethod, path, methodName, parameterTypes)
19
- */
20
- routeMeta;
21
- /**
22
- * HTTP headers from the request.
23
- * Map of header name (lowercase) -> array of values.
24
- *
25
- * HTTP spec allows multiple values for same header name,
26
- * so we store as string[] (even though most headers have single value).
27
- *
28
- * LIFECYCLE:
29
- * 1. Set by ExpressWrapper BEFORE filter chain executes
30
- * 2. ContextFilter (priority 2000) transfers headers to RequestContext
31
- * 3. ContextFilter CLEARS this field (sets to undefined) after transfer
32
- * 4. ALL FILTERS AFTER ContextFilter will see this as UNDEFINED
33
- *
34
- * IMPORTANT: Downstream filters should NOT read from requestHeaders!
35
- * Instead, use RequestContext.getHeader() to read headers after ContextFilter.
36
- *
37
- * Example (correct usage in downstream filters):
38
- * ```typescript
39
- * const requestId = RequestContext.getHeader(WebpiecesCoreHeaders.REQUEST_ID);
40
- * ```
41
- */
42
- requestHeaders;
43
- /**
44
- * The deserialized request DTO.
45
- */
46
- requestDto;
47
- /**
48
- * Auth metadata from @Public/@Authenticated/@Roles decorators.
49
- * Populated by ApiRoutingFactory so filters can read auth requirements.
50
- */
51
- authMeta;
52
- /**
53
- * Additional metadata for storing request-scoped data.
54
- * Used by filters to pass data to other filters/controllers.
55
- */
56
- metadata;
57
- constructor(routeMeta, requestHeaders, requestDto, metadata, authMeta) {
58
- this.routeMeta = routeMeta;
59
- this.requestHeaders = requestHeaders;
60
- this.requestDto = requestDto;
61
- this.metadata = metadata ?? new Map();
62
- this.authMeta = authMeta ?? routeMeta.authMeta;
63
- }
64
- /**
65
- * Get the HTTP method (convenience accessor).
66
- */
67
- get httpMethod() {
68
- return this.routeMeta.httpMethod;
69
- }
70
- /**
71
- * Get the request path (convenience accessor).
72
- */
73
- get path() {
74
- return this.routeMeta.path;
75
- }
76
- /**
77
- * Get the method name (convenience accessor).
78
- */
79
- get methodName() {
80
- return this.routeMeta.methodName;
81
- }
82
- }
83
- exports.MethodMeta = MethodMeta;
84
- //# sourceMappingURL=MethodMeta.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"MethodMeta.js","sourceRoot":"","sources":["../../../../../packages/http/http-routing/src/MethodMeta.ts"],"names":[],"mappings":";;;AAEA;;;;;;;;;;;GAWG;AACH,MAAa,UAAU;IACnB;;OAEG;IACH,SAAS,CAAgB;IAEzB;;;;;;;;;;;;;;;;;;;;OAoBG;IACI,cAAc,CAAyB;IAE9C;;OAEG;IACH,UAAU,CAAW;IAErB;;;OAGG;IACH,QAAQ,CAAY;IAEpB;;;OAGG;IACH,QAAQ,CAAuB;IAE/B,YACI,SAAwB,EACxB,cAAsC,EACtC,UAAoB,EACpB,QAA+B,EAC/B,QAAmB;QAEnB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;QACrC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,QAAQ,GAAG,QAAQ,IAAI,IAAI,GAAG,EAAE,CAAC;QACtC,IAAI,CAAC,QAAQ,GAAG,QAAQ,IAAI,SAAS,CAAC,QAAQ,CAAC;IACnD,CAAC;IAED;;OAEG;IACH,IAAI,UAAU;QACV,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC;IACrC,CAAC;IAED;;OAEG;IACH,IAAI,IAAI;QACJ,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;IAC/B,CAAC;IAED;;OAEG;IACH,IAAI,UAAU;QACV,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC;IACrC,CAAC;CACJ;AAhFD,gCAgFC","sourcesContent":["import { RouteMetadata, AuthMeta } from '@webpieces/http-api';\n\n/**\n * Metadata about the method being invoked.\n * Passed to filters and contains request information.\n *\n * MethodMeta is DTO-only - it does NOT contain Express req/res directly.\n *\n * Fields:\n * - routeMeta: Static route information (httpMethod, path, methodName)\n * - requestHeaders: HTTP headers from the request (NEW)\n * - requestDto: The deserialized request body\n * - metadata: Request-scoped data for filters to communicate\n */\nexport class MethodMeta {\n /**\n * Route metadata (httpMethod, path, methodName, parameterTypes)\n */\n routeMeta: RouteMetadata;\n\n /**\n * HTTP headers from the request.\n * Map of header name (lowercase) -> array of values.\n *\n * HTTP spec allows multiple values for same header name,\n * so we store as string[] (even though most headers have single value).\n *\n * LIFECYCLE:\n * 1. Set by ExpressWrapper BEFORE filter chain executes\n * 2. ContextFilter (priority 2000) transfers headers to RequestContext\n * 3. ContextFilter CLEARS this field (sets to undefined) after transfer\n * 4. ALL FILTERS AFTER ContextFilter will see this as UNDEFINED\n *\n * IMPORTANT: Downstream filters should NOT read from requestHeaders!\n * Instead, use RequestContext.getHeader() to read headers after ContextFilter.\n *\n * Example (correct usage in downstream filters):\n * ```typescript\n * const requestId = RequestContext.getHeader(WebpiecesCoreHeaders.REQUEST_ID);\n * ```\n */\n public requestHeaders?: Map<string, string[]>;\n\n /**\n * The deserialized request DTO.\n */\n requestDto?: unknown;\n\n /**\n * Auth metadata from @Public/@Authenticated/@Roles decorators.\n * Populated by ApiRoutingFactory so filters can read auth requirements.\n */\n authMeta?: AuthMeta;\n\n /**\n * Additional metadata for storing request-scoped data.\n * Used by filters to pass data to other filters/controllers.\n */\n metadata: Map<string, unknown>;\n\n constructor(\n routeMeta: RouteMetadata,\n requestHeaders?: Map<string, string[]>,\n requestDto?: unknown,\n metadata?: Map<string, unknown>,\n authMeta?: AuthMeta,\n ) {\n this.routeMeta = routeMeta;\n this.requestHeaders = requestHeaders;\n this.requestDto = requestDto;\n this.metadata = metadata ?? new Map();\n this.authMeta = authMeta ?? routeMeta.authMeta;\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,29 +0,0 @@
1
- import { PlatformHeader, ContextReader } from '@webpieces/http-api';
2
- import { ContextKey } from '@webpieces/core-util';
3
- /**
4
- * RequestContextReader - Reads headers from Node.js RequestContext.
5
- *
6
- * Only works in Node.js with active AsyncLocalStorage context.
7
- * This is a server-side only implementation.
8
- *
9
- * NOTE: This class is in @webpieces/http-routing (Node.js only) instead of
10
- * @webpieces/http-client (cross-platform) because it has a hard dependency
11
- * on @webpieces/core-context which uses Node.js AsyncLocalStorage.
12
- *
13
- * For browser environments, use StaticContextReader from @webpieces/http-client.
14
- */
15
- export declare class RequestContextReader implements ContextReader {
16
- /**
17
- * Read a header value from the active RequestContext.
18
- *
19
- * @param header - The platform header to read
20
- * @returns The header value, or undefined if not in context
21
- */
22
- read(header: PlatformHeader): string | undefined;
23
- /**
24
- * Read a non-header context value (e.g. the active TestCaseRecorder under
25
- * RecorderKeys.RECORDER). Lets the isomorphic http-client find server-side
26
- * context without importing core-context itself.
27
- */
28
- readValue(key: ContextKey): unknown;
29
- }
@@ -1,39 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RequestContextReader = void 0;
4
- const core_context_1 = require("@webpieces/core-context");
5
- /**
6
- * RequestContextReader - Reads headers from Node.js RequestContext.
7
- *
8
- * Only works in Node.js with active AsyncLocalStorage context.
9
- * This is a server-side only implementation.
10
- *
11
- * NOTE: This class is in @webpieces/http-routing (Node.js only) instead of
12
- * @webpieces/http-client (cross-platform) because it has a hard dependency
13
- * on @webpieces/core-context which uses Node.js AsyncLocalStorage.
14
- *
15
- * For browser environments, use StaticContextReader from @webpieces/http-client.
16
- */
17
- class RequestContextReader {
18
- /**
19
- * Read a header value from the active RequestContext.
20
- *
21
- * @param header - The platform header to read
22
- * @returns The header value, or undefined if not in context
23
- */
24
- read(header) {
25
- // Use RequestContext.getHeader() which calls header.getHeaderName()
26
- return core_context_1.RequestContext.getHeader(header);
27
- }
28
- /**
29
- * Read a non-header context value (e.g. the active TestCaseRecorder under
30
- * RecorderKeys.RECORDER). Lets the isomorphic http-client find server-side
31
- * context without importing core-context itself.
32
- */
33
- // webpieces-disable no-any-unknown -- context values are heterogeneous (recorder, meta objects)
34
- readValue(key) {
35
- return core_context_1.RequestContext.getHeader(key);
36
- }
37
- }
38
- exports.RequestContextReader = RequestContextReader;
39
- //# sourceMappingURL=RequestContextReader.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"RequestContextReader.js","sourceRoot":"","sources":["../../../../../packages/http/http-routing/src/RequestContextReader.ts"],"names":[],"mappings":";;;AAEA,0DAAyD;AAEzD;;;;;;;;;;;GAWG;AACH,MAAa,oBAAoB;IAC7B;;;;;OAKG;IACH,IAAI,CAAC,MAAsB;QACvB,oEAAoE;QACpE,OAAO,6BAAc,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAC5C,CAAC;IAED;;;;OAIG;IACH,gGAAgG;IAChG,SAAS,CAAC,GAAe;QACrB,OAAO,6BAAc,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IACzC,CAAC;CACJ;AArBD,oDAqBC","sourcesContent":["import { PlatformHeader, ContextReader } from '@webpieces/http-api';\nimport { ContextKey } from '@webpieces/core-util';\nimport { RequestContext } from '@webpieces/core-context';\n\n/**\n * RequestContextReader - Reads headers from Node.js RequestContext.\n *\n * Only works in Node.js with active AsyncLocalStorage context.\n * This is a server-side only implementation.\n *\n * NOTE: This class is in @webpieces/http-routing (Node.js only) instead of\n * @webpieces/http-client (cross-platform) because it has a hard dependency\n * on @webpieces/core-context which uses Node.js AsyncLocalStorage.\n *\n * For browser environments, use StaticContextReader from @webpieces/http-client.\n */\nexport class RequestContextReader implements ContextReader {\n /**\n * Read a header value from the active RequestContext.\n *\n * @param header - The platform header to read\n * @returns The header value, or undefined if not in context\n */\n read(header: PlatformHeader): string | undefined {\n // Use RequestContext.getHeader() which calls header.getHeaderName()\n return RequestContext.getHeader(header);\n }\n\n /**\n * Read a non-header context value (e.g. the active TestCaseRecorder under\n * RecorderKeys.RECORDER). Lets the isomorphic http-client find server-side\n * context without importing core-context itself.\n */\n // webpieces-disable no-any-unknown -- context values are heterogeneous (recorder, meta objects)\n readValue(key: ContextKey): unknown {\n return RequestContext.getHeader(key);\n }\n}\n"]}