@webpieces/http-server 0.3.290 → 0.3.292

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-server",
3
- "version": "0.3.290",
3
+ "version": "0.3.292",
4
4
  "description": "WebPieces server with filter chain and dependency injection",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -22,11 +22,11 @@
22
22
  "access": "public"
23
23
  },
24
24
  "dependencies": {
25
- "@webpieces/core-context": "0.3.290",
26
- "@webpieces/core-util": "0.3.290",
27
- "@webpieces/gcp-identity": "0.3.290",
28
- "@webpieces/http-filters": "0.3.290",
29
- "@webpieces/http-routing": "0.3.290",
25
+ "@webpieces/core-context": "0.3.292",
26
+ "@webpieces/core-util": "0.3.292",
27
+ "@webpieces/gcp-identity": "0.3.292",
28
+ "@webpieces/http-filters": "0.3.292",
29
+ "@webpieces/http-routing": "0.3.292",
30
30
  "cors": "2.8.5",
31
31
  "express": "5.1.0",
32
32
  "inversify": "7.10.4"
@@ -12,8 +12,8 @@ export declare class WebpiecesRouteCreator {
12
12
  /**
13
13
  * @param app - The Express app to mount routes on (yours - never taken over)
14
14
  * @param container - Inversify container used to resolve controllers and filters
15
- * @param routeBuilder - Internal: WebpiecesServerImpl passes its DI singleton; standalone users omit
16
- * @param middleware - Internal: WebpiecesServerImpl passes its DI singleton; standalone users omit
15
+ * @param routeBuilder - Internal: WebpiecesExpress passes its DI singleton; standalone users omit
16
+ * @param middleware - Internal: WebpiecesExpress passes its DI singleton; standalone users omit
17
17
  */
18
18
  constructor(app: Express, container: Container, routeBuilder?: RouteBuilderImpl, middleware?: WebpiecesMiddleware);
19
19
  /**
@@ -29,8 +29,8 @@ export declare class WebpiecesRouteCreator {
29
29
  wireApi<TApi, TController extends TApi>(apiPrototype: ClassType<TApi>, controllerClass: ClassType<TController>): void;
30
30
  /**
31
31
  * Mount every route currently registered on the RouteBuilder.
32
- * Used by WebpiecesServerImpl.start() where routes were registered up front
33
- * from WebAppMeta.getRoutes().
32
+ * Used by WebpiecesExpress (the full-server path) where routes were registered
33
+ * up front on the shared RouteBuilder.
34
34
  *
35
35
  * @returns Number of routes mounted
36
36
  */
@@ -13,12 +13,14 @@ const core_util_1 = require("@webpieces/core-util");
13
13
  * self-contained (own body parsing, own RequestContext, own error->JSON mapping).
14
14
  * This class never calls app.use() - it only registers per-route handlers.
15
15
  *
16
- * Usage:
16
+ * Usage (the legacy-server example app builds the container via the shared
17
+ * setupCompanyRuntime + router.getContainer(); a bare standalone user can also
18
+ * assemble one directly):
17
19
  * ```typescript
18
20
  * const app = express(); // your existing legacy app
19
21
  * const container = new Container();
20
- * await container.load(buildProviderModule()); // picks up @provideSingleton classes
21
- * await container.load(WebpiecesModule); // required if you use ContextFilter
22
+ * await container.load(buildFrameworkModule()); // webpieces framework classes (ContextFilter, ...)
23
+ * await container.load(buildProviderModule()); // your @provideSingleton controllers/filters
22
24
  *
23
25
  * const creator = new WebpiecesRouteCreator(app, container);
24
26
  * creator.wireFilters(
@@ -39,8 +41,8 @@ const core_util_1 = require("@webpieces/core-util");
39
41
  * - Want webpieces' localhost CORS? Opt in yourself:
40
42
  * `app.use(new WebpiecesMiddleware().corsForLocalhost())`.
41
43
  *
42
- * This same class is used internally by WebpiecesServerImpl.start(), so the
43
- * full server and the embeddable adapter share one code path.
44
+ * This same class is used internally by WebpiecesExpress (the full-server express
45
+ * adapter), so the full server and the embeddable adapter share one code path.
44
46
  */
45
47
  const log = core_util_1.LogManager.getLogger('WebpiecesRouteCreator');
46
48
  class WebpiecesRouteCreator {
@@ -53,8 +55,8 @@ class WebpiecesRouteCreator {
53
55
  /**
54
56
  * @param app - The Express app to mount routes on (yours - never taken over)
55
57
  * @param container - Inversify container used to resolve controllers and filters
56
- * @param routeBuilder - Internal: WebpiecesServerImpl passes its DI singleton; standalone users omit
57
- * @param middleware - Internal: WebpiecesServerImpl passes its DI singleton; standalone users omit
58
+ * @param routeBuilder - Internal: WebpiecesExpress passes its DI singleton; standalone users omit
59
+ * @param middleware - Internal: WebpiecesExpress passes its DI singleton; standalone users omit
58
60
  */
59
61
  constructor(app, container, routeBuilder, middleware) {
60
62
  this.app = app;
@@ -95,8 +97,8 @@ class WebpiecesRouteCreator {
95
97
  }
96
98
  /**
97
99
  * Mount every route currently registered on the RouteBuilder.
98
- * Used by WebpiecesServerImpl.start() where routes were registered up front
99
- * from WebAppMeta.getRoutes().
100
+ * Used by WebpiecesExpress (the full-server path) where routes were registered
101
+ * up front on the shared RouteBuilder.
100
102
  *
101
103
  * @returns Number of routes mounted
102
104
  */
@@ -1 +1 @@
1
- {"version":3,"file":"WebpiecesRouteCreator.js","sourceRoot":"","sources":["../../../../../packages/http/http-server/src/WebpiecesRouteCreator.ts"],"names":[],"mappings":"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","sourcesContent":["import { Express } from 'express';\nimport { Container } from 'inversify';\nimport {\n ApiRoutingFactory,\n ClassType,\n FilterDefinition,\n RouteBuilderImpl,\n RouteHandlerWithMeta,\n InProcessApiClientFactory,\n} from '@webpieces/http-routing';\nimport { WebpiecesMiddleware, ExpressRouteHandler } from './WebpiecesMiddleware';\nimport { LogManager } from '@webpieces/core-util';\n\n/**\n * WebpiecesRouteCreator - Embeddable adapter that mounts the webpieces\n * api -> filters -> controller pipeline onto ANY existing Express app.\n *\n * Legacy Express apps can adopt webpieces incrementally: existing routes and\n * middleware keep working untouched; each wired webpieces route is fully\n * self-contained (own body parsing, own RequestContext, own error->JSON mapping).\n * This class never calls app.use() - it only registers per-route handlers.\n *\n * Usage:\n * ```typescript\n * const app = express(); // your existing legacy app\n * const container = new Container();\n * await container.load(buildProviderModule()); // picks up @provideSingleton classes\n * await container.load(WebpiecesModule); // required if you use ContextFilter\n *\n * const creator = new WebpiecesRouteCreator(app, container);\n * creator.wireFilters(\n * new FilterDefinition(2000, ContextFilter, '*'),\n * new FilterDefinition(1900, AuthFilter, 'src/controllers/admin/**'),\n * );\n * creator.wireApi(SaveApi, SaveController); // controller resolved from container\n * creator.wireApi(PublicApi, PublicController);\n * app.listen(8080);\n * ```\n *\n * Notes:\n * - ALL wireFilters() calls must come BEFORE the first wireApi() call. Filter\n * chains are composed per-route at wireApi time, so late filters would be\n * silently ignored - we throw instead.\n * - Scoped filter glob patterns match the controller filepath from the\n * @SourceFile decorator, falling back to the pattern `**\\/{ClassName}.ts`.\n * - Want webpieces' localhost CORS? Opt in yourself:\n * `app.use(new WebpiecesMiddleware().corsForLocalhost())`.\n *\n * This same class is used internally by WebpiecesServerImpl.start(), so the\n * full server and the embeddable adapter share one code path.\n */\nconst log = LogManager.getLogger('WebpiecesRouteCreator');\n\nexport class WebpiecesRouteCreator {\n private routeBuilder: RouteBuilderImpl;\n private middleware: WebpiecesMiddleware;\n private clientFactory: InProcessApiClientFactory;\n\n /** Locks wireFilters() once the first wireApi() has composed a filter chain. */\n private apisWired = false;\n\n /**\n * @param app - The Express app to mount routes on (yours - never taken over)\n * @param container - Inversify container used to resolve controllers and filters\n * @param routeBuilder - Internal: WebpiecesServerImpl passes its DI singleton; standalone users omit\n * @param middleware - Internal: WebpiecesServerImpl passes its DI singleton; standalone users omit\n */\n constructor(\n private app: Express,\n container: Container,\n routeBuilder?: RouteBuilderImpl,\n middleware?: WebpiecesMiddleware,\n ) {\n this.routeBuilder = routeBuilder ?? new RouteBuilderImpl();\n this.routeBuilder.setContainer(container);\n this.middleware = middleware ?? new WebpiecesMiddleware();\n this.clientFactory = new InProcessApiClientFactory(this.routeBuilder);\n }\n\n /**\n * Register filters that wrap every matching route (glob pattern vs controller filepath).\n * Must be called before the first wireApi() - filter chains are composed per-route.\n */\n wireFilters(...defs: FilterDefinition[]): void {\n if (this.apisWired) {\n throw new Error(\n 'wireFilters() must be called before wireApi() - filter chains are composed per-route at wireApi time, so filters added later would never run.',\n );\n }\n for (const def of defs) {\n this.routeBuilder.addFilter(def);\n }\n }\n\n /**\n * Wire an API prototype class (with @ApiPath/@Endpoint decorators) to its\n * controller, mounting one Express route per endpoint with the full filter\n * chain. The controller is resolved from the Inversify container.\n */\n wireApi<TApi, TController extends TApi>(\n apiPrototype: ClassType<TApi>,\n controllerClass: ClassType<TController>,\n ): void {\n this.apisWired = true;\n\n // Reuses all existing validation: @ApiPath present, controller extends\n // api prototype, every endpoint implemented + has @Authentication.\n const factory = new ApiRoutingFactory(apiPrototype, controllerClass);\n\n // Mount only the routes added by THIS call\n const routesBefore = this.routeBuilder.getRoutes().length;\n factory.configure(this.routeBuilder);\n const routes = this.routeBuilder.getRoutes();\n\n for (let i = routesBefore; i < routes.length; i++) {\n this.mountRoute(routes[i]);\n }\n }\n\n /**\n * Mount every route currently registered on the RouteBuilder.\n * Used by WebpiecesServerImpl.start() where routes were registered up front\n * from WebAppMeta.getRoutes().\n *\n * @returns Number of routes mounted\n */\n mountRegisteredRoutes(): number {\n const routes = this.routeBuilder.getRoutes();\n for (const routeWithMeta of routes) {\n this.mountRoute(routeWithMeta);\n }\n return routes.length;\n }\n\n /**\n * Create an in-process API client (full filter chain + controller, no HTTP).\n * Same testing story as WebpiecesServer.createApiClient().\n */\n // webpieces-disable no-any-unknown -- abstract constructor signature requires any[] args\n createApiClient<T>(apiPrototype: abstract new (...args: any[]) => T): T {\n return this.clientFactory.createApiClient(apiPrototype);\n }\n\n /**\n * Escape hatch for advanced wiring (e.g. addRoute with a hand-built RouteDefinition).\n */\n getRouteBuilder(): RouteBuilderImpl {\n return this.routeBuilder;\n }\n\n /**\n * Compose the filter chain for one route and register it on the Express app.\n */\n private mountRoute(routeWithMeta: RouteHandlerWithMeta): void {\n const service = this.routeBuilder.createRouteHandler(routeWithMeta);\n const routeMeta = routeWithMeta.definition.routeMeta;\n\n // ExpressWrapper handles the full request/response cycle per route:\n // RequestContext.run, header read, manual JSON body parse, error->ProtocolError\n const wrapper = this.middleware.createExpressWrapper(service, routeMeta);\n\n this.registerHandler(\n routeMeta.httpMethod,\n routeMeta.path,\n wrapper.execute.bind(wrapper),\n );\n }\n\n private registerHandler(httpMethod: string, path: string, expressHandler: ExpressRouteHandler): void {\n switch (httpMethod.toLowerCase()) {\n case 'get':\n this.app.get(path, expressHandler);\n break;\n case 'post':\n this.app.post(path, expressHandler);\n break;\n case 'put':\n this.app.put(path, expressHandler);\n break;\n case 'delete':\n this.app.delete(path, expressHandler);\n break;\n case 'patch':\n this.app.patch(path, expressHandler);\n break;\n default:\n log.warn(`[WebpiecesRouteCreator] Unknown HTTP method: ${httpMethod}`);\n }\n }\n}\n"]}
1
+ {"version":3,"file":"WebpiecesRouteCreator.js","sourceRoot":"","sources":["../../../../../packages/http/http-server/src/WebpiecesRouteCreator.ts"],"names":[],"mappings":"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","sourcesContent":["import { Express } from 'express';\nimport { Container } from 'inversify';\nimport {\n ApiRoutingFactory,\n ClassType,\n FilterDefinition,\n RouteBuilderImpl,\n RouteHandlerWithMeta,\n InProcessApiClientFactory,\n} from '@webpieces/http-routing';\nimport { WebpiecesMiddleware, ExpressRouteHandler } from './WebpiecesMiddleware';\nimport { LogManager } from '@webpieces/core-util';\n\n/**\n * WebpiecesRouteCreator - Embeddable adapter that mounts the webpieces\n * api -> filters -> controller pipeline onto ANY existing Express app.\n *\n * Legacy Express apps can adopt webpieces incrementally: existing routes and\n * middleware keep working untouched; each wired webpieces route is fully\n * self-contained (own body parsing, own RequestContext, own error->JSON mapping).\n * This class never calls app.use() - it only registers per-route handlers.\n *\n * Usage (the legacy-server example app builds the container via the shared\n * setupCompanyRuntime + router.getContainer(); a bare standalone user can also\n * assemble one directly):\n * ```typescript\n * const app = express(); // your existing legacy app\n * const container = new Container();\n * await container.load(buildFrameworkModule()); // webpieces framework classes (ContextFilter, ...)\n * await container.load(buildProviderModule()); // your @provideSingleton controllers/filters\n *\n * const creator = new WebpiecesRouteCreator(app, container);\n * creator.wireFilters(\n * new FilterDefinition(2000, ContextFilter, '*'),\n * new FilterDefinition(1900, AuthFilter, 'src/controllers/admin/**'),\n * );\n * creator.wireApi(SaveApi, SaveController); // controller resolved from container\n * creator.wireApi(PublicApi, PublicController);\n * app.listen(8080);\n * ```\n *\n * Notes:\n * - ALL wireFilters() calls must come BEFORE the first wireApi() call. Filter\n * chains are composed per-route at wireApi time, so late filters would be\n * silently ignored - we throw instead.\n * - Scoped filter glob patterns match the controller filepath from the\n * @SourceFile decorator, falling back to the pattern `**\\/{ClassName}.ts`.\n * - Want webpieces' localhost CORS? Opt in yourself:\n * `app.use(new WebpiecesMiddleware().corsForLocalhost())`.\n *\n * This same class is used internally by WebpiecesExpress (the full-server express\n * adapter), so the full server and the embeddable adapter share one code path.\n */\nconst log = LogManager.getLogger('WebpiecesRouteCreator');\n\nexport class WebpiecesRouteCreator {\n private routeBuilder: RouteBuilderImpl;\n private middleware: WebpiecesMiddleware;\n private clientFactory: InProcessApiClientFactory;\n\n /** Locks wireFilters() once the first wireApi() has composed a filter chain. */\n private apisWired = false;\n\n /**\n * @param app - The Express app to mount routes on (yours - never taken over)\n * @param container - Inversify container used to resolve controllers and filters\n * @param routeBuilder - Internal: WebpiecesExpress passes its DI singleton; standalone users omit\n * @param middleware - Internal: WebpiecesExpress passes its DI singleton; standalone users omit\n */\n constructor(\n private app: Express,\n container: Container,\n routeBuilder?: RouteBuilderImpl,\n middleware?: WebpiecesMiddleware,\n ) {\n this.routeBuilder = routeBuilder ?? new RouteBuilderImpl();\n this.routeBuilder.setContainer(container);\n this.middleware = middleware ?? new WebpiecesMiddleware();\n this.clientFactory = new InProcessApiClientFactory(this.routeBuilder);\n }\n\n /**\n * Register filters that wrap every matching route (glob pattern vs controller filepath).\n * Must be called before the first wireApi() - filter chains are composed per-route.\n */\n wireFilters(...defs: FilterDefinition[]): void {\n if (this.apisWired) {\n throw new Error(\n 'wireFilters() must be called before wireApi() - filter chains are composed per-route at wireApi time, so filters added later would never run.',\n );\n }\n for (const def of defs) {\n this.routeBuilder.addFilter(def);\n }\n }\n\n /**\n * Wire an API prototype class (with @ApiPath/@Endpoint decorators) to its\n * controller, mounting one Express route per endpoint with the full filter\n * chain. The controller is resolved from the Inversify container.\n */\n wireApi<TApi, TController extends TApi>(\n apiPrototype: ClassType<TApi>,\n controllerClass: ClassType<TController>,\n ): void {\n this.apisWired = true;\n\n // Reuses all existing validation: @ApiPath present, controller extends\n // api prototype, every endpoint implemented + has @Authentication.\n const factory = new ApiRoutingFactory(apiPrototype, controllerClass);\n\n // Mount only the routes added by THIS call\n const routesBefore = this.routeBuilder.getRoutes().length;\n factory.configure(this.routeBuilder);\n const routes = this.routeBuilder.getRoutes();\n\n for (let i = routesBefore; i < routes.length; i++) {\n this.mountRoute(routes[i]);\n }\n }\n\n /**\n * Mount every route currently registered on the RouteBuilder.\n * Used by WebpiecesExpress (the full-server path) where routes were registered\n * up front on the shared RouteBuilder.\n *\n * @returns Number of routes mounted\n */\n mountRegisteredRoutes(): number {\n const routes = this.routeBuilder.getRoutes();\n for (const routeWithMeta of routes) {\n this.mountRoute(routeWithMeta);\n }\n return routes.length;\n }\n\n /**\n * Create an in-process API client (full filter chain + controller, no HTTP).\n * Same testing story as WebpiecesServer.createApiClient().\n */\n // webpieces-disable no-any-unknown -- abstract constructor signature requires any[] args\n createApiClient<T>(apiPrototype: abstract new (...args: any[]) => T): T {\n return this.clientFactory.createApiClient(apiPrototype);\n }\n\n /**\n * Escape hatch for advanced wiring (e.g. addRoute with a hand-built RouteDefinition).\n */\n getRouteBuilder(): RouteBuilderImpl {\n return this.routeBuilder;\n }\n\n /**\n * Compose the filter chain for one route and register it on the Express app.\n */\n private mountRoute(routeWithMeta: RouteHandlerWithMeta): void {\n const service = this.routeBuilder.createRouteHandler(routeWithMeta);\n const routeMeta = routeWithMeta.definition.routeMeta;\n\n // ExpressWrapper handles the full request/response cycle per route:\n // RequestContext.run, header read, manual JSON body parse, error->ProtocolError\n const wrapper = this.middleware.createExpressWrapper(service, routeMeta);\n\n this.registerHandler(\n routeMeta.httpMethod,\n routeMeta.path,\n wrapper.execute.bind(wrapper),\n );\n }\n\n private registerHandler(httpMethod: string, path: string, expressHandler: ExpressRouteHandler): void {\n switch (httpMethod.toLowerCase()) {\n case 'get':\n this.app.get(path, expressHandler);\n break;\n case 'post':\n this.app.post(path, expressHandler);\n break;\n case 'put':\n this.app.put(path, expressHandler);\n break;\n case 'delete':\n this.app.delete(path, expressHandler);\n break;\n case 'patch':\n this.app.patch(path, expressHandler);\n break;\n default:\n log.warn(`[WebpiecesRouteCreator] Unknown HTTP method: ${httpMethod}`);\n }\n }\n}\n"]}