@webpieces/http-routing 0.4.987 → 0.4.989

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.
Files changed (42) hide show
  1. package/README.md +111 -0
  2. package/package.json +7 -7
  3. package/src/ApiClient.d.ts +1 -1
  4. package/src/ApiClient.js.map +1 -1
  5. package/src/ApiClientFactory.js.map +1 -1
  6. package/src/ApiRoutingFactory.d.ts +6 -9
  7. package/src/ApiRoutingFactory.js +14 -7
  8. package/src/ApiRoutingFactory.js.map +1 -1
  9. package/src/BindModule.d.ts +6 -0
  10. package/src/BindModule.js +3 -0
  11. package/src/BindModule.js.map +1 -0
  12. package/src/ClassType.d.ts +4 -0
  13. package/src/ClassType.js +3 -0
  14. package/src/ClassType.js.map +1 -0
  15. package/src/LazyController.d.ts +46 -0
  16. package/src/LazyController.js +184 -0
  17. package/src/LazyController.js.map +1 -0
  18. package/src/LazyControllerCompileAssertions.d.ts +14 -0
  19. package/src/LazyControllerCompileAssertions.js +23 -0
  20. package/src/LazyControllerCompileAssertions.js.map +1 -0
  21. package/src/RouteBuilderImpl.d.ts +8 -0
  22. package/src/RouteBuilderImpl.js +51 -5
  23. package/src/RouteBuilderImpl.js.map +1 -1
  24. package/src/RuntimeStartupTiming.d.ts +44 -0
  25. package/src/RuntimeStartupTiming.js +100 -0
  26. package/src/RuntimeStartupTiming.js.map +1 -0
  27. package/src/WebAppMeta.d.ts +6 -4
  28. package/src/WebAppMeta.js +3 -5
  29. package/src/WebAppMeta.js.map +1 -1
  30. package/src/WebpiecesRouter.d.ts +14 -3
  31. package/src/WebpiecesRouter.js +26 -10
  32. package/src/WebpiecesRouter.js.map +1 -1
  33. package/src/Wiring.d.ts +2 -6
  34. package/src/Wiring.js.map +1 -1
  35. package/src/WiringCompileAssertions.d.ts +2 -1
  36. package/src/WiringCompileAssertions.js.map +1 -1
  37. package/src/index.d.ts +7 -2
  38. package/src/index.js +9 -1
  39. package/src/index.js.map +1 -1
  40. package/src/setupRuntime.d.ts +6 -1
  41. package/src/setupRuntime.js +15 -8
  42. package/src/setupRuntime.js.map +1 -1
@@ -3,6 +3,7 @@ import { Locality, LoggerFactory } from '@webpieces/core-util';
3
3
  import { WebpiecesConfig } from './WebpiecesConfig';
4
4
  import { AppWiring } from './Wiring';
5
5
  import { ApiFactory } from './ApiFactory';
6
+ import { RuntimeStartupObserver } from './RuntimeStartupTiming';
6
7
  /**
7
8
  * RuntimeSetupOptions - the environment/wiring inputs to {@link setupRuntime} (everything NOT
8
9
  * declared by the app's {@link AppWiring}): the logging backend, whether to include the platform
@@ -38,6 +39,8 @@ export declare class RuntimeSetupOptions {
38
39
  readonly platformHeaders: boolean;
39
40
  /** Optional WebpiecesConfig (e.g. recording flags); defaults to a fresh one. */
40
41
  readonly config?: WebpiecesConfig | undefined;
42
+ /** Optional startup span observer; the host owns its clock and bounded output. */
43
+ readonly startupObserver?: RuntimeStartupObserver | undefined;
41
44
  constructor(
42
45
  /** This service's name — published to ServiceInfo. Names every log line and stamps
43
46
  * `requestIdSource` on request-ids this service mints. Must be non-blank. */
@@ -62,7 +65,9 @@ export declare class RuntimeSetupOptions {
62
65
  /** Include the webpieces platform default headers. */
63
66
  platformHeaders?: boolean,
64
67
  /** Optional WebpiecesConfig (e.g. recording flags); defaults to a fresh one. */
65
- config?: WebpiecesConfig | undefined);
68
+ config?: WebpiecesConfig | undefined,
69
+ /** Optional startup span observer; the host owns its clock and bounded output. */
70
+ startupObserver?: RuntimeStartupObserver | undefined);
66
71
  }
67
72
  /**
68
73
  * setupRuntime - the ONE canonical, TRANSPORT-FREE startup sequence, reusable by any company/app
@@ -8,6 +8,7 @@ const WebpiecesConfig_1 = require("./WebpiecesConfig");
8
8
  const WebpiecesRouter_1 = require("./WebpiecesRouter");
9
9
  const Wiring_1 = require("./Wiring");
10
10
  const Binder_1 = require("./Binder");
11
+ const RuntimeStartupTiming_1 = require("./RuntimeStartupTiming");
11
12
  /**
12
13
  * RuntimeSetupOptions - the environment/wiring inputs to {@link setupRuntime} (everything NOT
13
14
  * declared by the app's {@link AppWiring}): the logging backend, whether to include the platform
@@ -25,6 +26,7 @@ class RuntimeSetupOptions {
25
26
  loggerFactory;
26
27
  platformHeaders;
27
28
  config;
29
+ startupObserver;
28
30
  constructor(
29
31
  /** This service's name — published to ServiceInfo. Names every log line and stamps
30
32
  * `requestIdSource` on request-ids this service mints. Must be non-blank. */
@@ -49,13 +51,16 @@ class RuntimeSetupOptions {
49
51
  /** Include the webpieces platform default headers. */
50
52
  platformHeaders = true,
51
53
  /** Optional WebpiecesConfig (e.g. recording flags); defaults to a fresh one. */
52
- config) {
54
+ config,
55
+ /** Optional startup span observer; the host owns its clock and bounded output. */
56
+ startupObserver) {
53
57
  this.svcName = svcName;
54
58
  this.svcVersion = svcVersion;
55
59
  this.locality = locality;
56
60
  this.loggerFactory = loggerFactory;
57
61
  this.platformHeaders = platformHeaders;
58
62
  this.config = config;
63
+ this.startupObserver = startupObserver;
59
64
  }
60
65
  }
61
66
  exports.RuntimeSetupOptions = RuntimeSetupOptions;
@@ -83,25 +88,27 @@ appOverrides) {
83
88
  // that cannot say which build emitted them. Reads of ServiceInfo elsewhere never throw (a missing
84
89
  // log field must never 500 live traffic); the "say which build you are" guarantee lives HERE, the
85
90
  // one startup every server runs.
91
+ const timing = new RuntimeStartupTiming_1.RuntimeStartupTiming(options.startupObserver);
86
92
  core_util_1.ServiceInfo.setInfo(options.svcName, options.svcVersion);
87
93
  // 0b. Declare WHERE we run, before any route is built: ApiRoutingFactory reads it in step 4 to
88
94
  // decide whether @WpLocalOnly routes are registered at all. Undeclared reads as DEPLOYED, so
89
95
  // this call is what lets a local-only endpoint exist — never what hides one.
90
96
  core_util_1.RuntimeLocality.declare(options.locality);
91
97
  // 1. Register the global HeaderRegistry FIRST (this service's own keys come from AppWiring).
92
- core_util_1.HeaderRegistry.configure(appModules.getHeaders(), options.platformHeaders);
98
+ timing.run(RuntimeStartupTiming_1.RuntimeStartupPhase.HEADERS, 'HeaderRegistry', () => core_util_1.HeaderRegistry.configure(appModules.getHeaders(), options.platformHeaders));
93
99
  // 2. Install the logging backend ONCE, before anything else logs.
94
- core_util_1.LogManager.setFactory(options.loggerFactory);
100
+ timing.run(RuntimeStartupTiming_1.RuntimeStartupPhase.LOGGING, 'LogManager', () => core_util_1.LogManager.setFactory(options.loggerFactory));
95
101
  // 3. Build the node-only router + DI container.
96
- const modules = new Wiring_1.NodeWiringModules(appModules);
97
- const router = await WebpiecesRouter_1.WebpiecesRouterFactory.create({
98
- appBindings: modules.bindModules.map((module) => new inversify_1.ContainerModule((load) => module.configure(new Binder_1.ContainerBinder(load)))),
102
+ const modules = timing.run(RuntimeStartupTiming_1.RuntimeStartupPhase.WIRING, appModules.constructor.name, () => new Wiring_1.NodeWiringModules(appModules));
103
+ const router = await timing.runAsync(RuntimeStartupTiming_1.RuntimeStartupPhase.CONTAINER, 'WebpiecesRouter', () => WebpiecesRouter_1.WebpiecesRouterFactory.create({
104
+ appBindings: modules.bindModules.map((module) => new inversify_1.ContainerModule((load) => timing.runAsync(RuntimeStartupTiming_1.RuntimeStartupPhase.BIND_MODULE, module.constructor.name, () => module.configure(new Binder_1.ContainerBinder(load))))),
99
105
  appOverrides: appOverrides,
100
106
  config: options.config ?? new WebpiecesConfig_1.WebpiecesConfig(),
101
- });
107
+ startupObserver: options.startupObserver,
108
+ }));
102
109
  // 4. Let each route group declare its routes + filters, then hand back the consumer surface.
103
110
  for (const routeModule of modules.routeModules) {
104
- routeModule.configure(router);
111
+ timing.run(RuntimeStartupTiming_1.RuntimeStartupPhase.ROUTE_MODULE, routeModule.constructor.name, () => routeModule.configure(router));
105
112
  }
106
113
  return router;
107
114
  }
@@ -1 +1 @@
1
- {"version":3,"file":"setupRuntime.js","sourceRoot":"","sources":["../../../../../packages/http/http-routing/src/setupRuntime.ts"],"names":[],"mappings":";;;AAoEA,oCAyCC;AA7GD,yCAAwE;AACxE,oDAO8B;AAC9B,uDAAoD;AACpD,uDAA2D;AAC3D,qCAAoE;AACpE,qCAA2C;AAG3C;;;;;;;;;GASG;AACH,MAAa,mBAAmB;IAIR;IAIA;IAWA;IAEA;IAEA;IAEA;IAxBpB;IACI;iFAC6E;IAC7D,OAAe;IAC/B;;+DAE2D;IAC3C,UAAkB;IAClC;;;;;;;;;OASG;IACa,QAAkB;IAClC,0DAA0D;IAC1C,aAA4B;IAC5C,sDAAsD;IACtC,kBAA2B,IAAI;IAC/C,gFAAgF;IAChE,MAAwB;QArBxB,YAAO,GAAP,OAAO,CAAQ;QAIf,eAAU,GAAV,UAAU,CAAQ;QAWlB,aAAQ,GAAR,QAAQ,CAAU;QAElB,kBAAa,GAAb,aAAa,CAAe;QAE5B,oBAAe,GAAf,eAAe,CAAgB;QAE/B,WAAM,GAAN,MAAM,CAAkB;IACzC,CAAC;CACP;AA3BD,kDA2BC;AAED;;;;;;;;;;;;;GAaG;AACI,KAAK,UAAU,YAAY,CAC9B,OAA4B,EAC5B,UAAqB;AACrB;mEACmE;AACnE,YAA8B;IAE9B,gGAAgG;IAChG,6FAA6F;IAC7F,kGAAkG;IAClG,kGAAkG;IAClG,kGAAkG;IAClG,iCAAiC;IACjC,uBAAW,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAEzD,+FAA+F;IAC/F,6FAA6F;IAC7F,6EAA6E;IAC7E,2BAAe,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAE1C,6FAA6F;IAC7F,0BAAc,CAAC,SAAS,CAAC,UAAU,CAAC,UAAU,EAAE,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IAE3E,kEAAkE;IAClE,sBAAU,CAAC,UAAU,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IAE7C,gDAAgD;IAChD,MAAM,OAAO,GAAG,IAAI,0BAAiB,CAAC,UAAU,CAAC,CAAC;IAClD,MAAM,MAAM,GAAG,MAAM,wCAAsB,CAAC,MAAM,CAAC;QAC/C,WAAW,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,CAChC,CAAC,MAAkB,EAAE,EAAE,CAAC,IAAI,2BAAe,CAAC,CAAC,IAAgC,EAAE,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,wBAAe,CAAC,IAAI,CAAC,CAAC,CAAC,CACjI;QACD,YAAY,EAAE,YAAY;QAC1B,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,IAAI,iCAAe,EAAE;KAClD,CAAC,CAAC;IAEH,6FAA6F;IAC7F,KAAK,MAAM,WAAW,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;QAC7C,WAAW,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,MAAM,CAAC;AAClB,CAAC","sourcesContent":["import { ContainerModule, ContainerModuleLoadOptions } from 'inversify';\nimport {\n HeaderRegistry,\n Locality,\n LoggerFactory,\n LogManager,\n RuntimeLocality,\n ServiceInfo,\n} from '@webpieces/core-util';\nimport { WebpiecesConfig } from './WebpiecesConfig';\nimport { WebpiecesRouterFactory } from './WebpiecesRouter';\nimport { AppWiring, BindModule, NodeWiringModules } from './Wiring';\nimport { ContainerBinder } from './Binder';\nimport { ApiFactory } from './ApiFactory';\n\n/**\n * RuntimeSetupOptions - the environment/wiring inputs to {@link setupRuntime} (everything NOT\n * declared by the app's {@link AppWiring}): the logging backend, whether to include the platform\n * default headers, and config. Data-only structure (a class, per the webpieces guidelines). The\n * app's own bind modules + route groups + headers come from the AppWiring passed alongside;\n * the test-override module is the separate `appOverrides` param of {@link setupRuntime}.\n *\n * Headers: {@link HeaderRegistry.configure} registers the platform defaults (when\n * `platformHeaders` is true) plus AppWiring.getHeaders() (by convention the company-wide set).\n */\nexport class RuntimeSetupOptions {\n constructor(\n /** This service's name — published to ServiceInfo. Names every log line and stamps\n * `requestIdSource` on request-ids this service mints. Must be non-blank. */\n public readonly svcName: string,\n /** This build's version — published to ServiceInfo alongside svcName. Opaque to webpieces\n * (a git SHA, a semver tag, a CI build number); it just has to identify THIS build so a log\n * line can say which one emitted it. Must be non-blank. */\n public readonly svcVersion: string,\n /**\n * WHERE this process runs — `'local'` (a developer's machine) or `'deployed'` (everything\n * else). Published to {@link RuntimeLocality}; the ONE input to `@WpLocalOnly` enforcement.\n *\n * REQUIRED and POSITIONAL on purpose, exactly like `@Endpoint(path, kind)`: only the app\n * knows how its platform is detected (Cloud Run's `K_SERVICE`, an ECS metadata URL, the\n * absence of both), the framework must not guess, and a defaulted field would mean \"forgot\n * to say\" and \"said deployed\" are the same line of code. Derive it at your startup, e.g.\n * `getServiceName() === 'local' ? 'local' : 'deployed'`.\n */\n public readonly locality: Locality,\n /** Logging backend to install (LogManager.setFactory). */\n public readonly loggerFactory: LoggerFactory,\n /** Include the webpieces platform default headers. */\n public readonly platformHeaders: boolean = true,\n /** Optional WebpiecesConfig (e.g. recording flags); defaults to a fresh one. */\n public readonly config?: WebpiecesConfig,\n ) {}\n}\n\n/**\n * setupRuntime - the ONE canonical, TRANSPORT-FREE startup sequence, reusable by any company/app\n * AND any framework adapter (express, fastify, a serverless handler, ...). It runs, in the correct\n * fail-fast order:\n *\n * 1. HeaderRegistry.configure (filters read it at construction; logging masks off it)\n * 2. LogManager.setFactory (fails fast unless the registry is configured first)\n * 3. build the router + DI container (from appModules.getBindModules(), each handed a Binder)\n * 4. configure each appModules.getRouteModules() onto the router (addRoutes/addFilter)\n *\n * and returns the built {@link ApiFactory} — `apiClients()` for a transport to bind, or\n * `createApiClient()` for in-process tests. There is NO express (or any transport) here; a\n * transport adapter (e.g. WebpiecesExpressRouter in @webpieces/http-server) serves the result.\n */\nexport async function setupRuntime(\n options: RuntimeSetupOptions,\n appModules: AppWiring,\n /** A single DI module loaded LAST so tests can rebind bindings to mocks.\n * Or special case servers that want to override specific things */\n appOverrides?: ContainerModule,\n): Promise<ApiFactory> {\n // 0. IDENTIFY this service (name + build version) FIRST, before anything logs. Name and version\n // are REQUIRED inputs to this call, so a build cannot boot anonymously — setInfo throws on a\n // blank value, which kills the deploy (the revision never goes healthy) rather than shipping logs\n // that cannot say which build emitted them. Reads of ServiceInfo elsewhere never throw (a missing\n // log field must never 500 live traffic); the \"say which build you are\" guarantee lives HERE, the\n // one startup every server runs.\n ServiceInfo.setInfo(options.svcName, options.svcVersion);\n\n // 0b. Declare WHERE we run, before any route is built: ApiRoutingFactory reads it in step 4 to\n // decide whether @WpLocalOnly routes are registered at all. Undeclared reads as DEPLOYED, so\n // this call is what lets a local-only endpoint exist — never what hides one.\n RuntimeLocality.declare(options.locality);\n\n // 1. Register the global HeaderRegistry FIRST (this service's own keys come from AppWiring).\n HeaderRegistry.configure(appModules.getHeaders(), options.platformHeaders);\n\n // 2. Install the logging backend ONCE, before anything else logs.\n LogManager.setFactory(options.loggerFactory);\n\n // 3. Build the node-only router + DI container.\n const modules = new NodeWiringModules(appModules);\n const router = await WebpiecesRouterFactory.create({\n appBindings: modules.bindModules.map(\n (module: BindModule) => new ContainerModule((load: ContainerModuleLoadOptions) => module.configure(new ContainerBinder(load))),\n ),\n appOverrides: appOverrides,\n config: options.config ?? new WebpiecesConfig(),\n });\n\n // 4. Let each route group declare its routes + filters, then hand back the consumer surface.\n for (const routeModule of modules.routeModules) {\n routeModule.configure(router);\n }\n return router;\n}\n"]}
1
+ {"version":3,"file":"setupRuntime.js","sourceRoot":"","sources":["../../../../../packages/http/http-routing/src/setupRuntime.ts"],"names":[],"mappings":"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","sourcesContent":["import { ContainerModule, ContainerModuleLoadOptions } from 'inversify';\nimport {\n HeaderRegistry,\n Locality,\n LoggerFactory,\n LogManager,\n RuntimeLocality,\n ServiceInfo,\n} from '@webpieces/core-util';\nimport { WebpiecesConfig } from './WebpiecesConfig';\nimport { WebpiecesRouterFactory } from './WebpiecesRouter';\nimport { AppWiring, NodeWiringModules } from './Wiring';\nimport type { BindModule } from './BindModule';\nimport { ContainerBinder } from './Binder';\nimport { ApiFactory } from './ApiFactory';\nimport {\n RuntimeStartupObserver,\n RuntimeStartupPhase,\n RuntimeStartupTiming,\n} from './RuntimeStartupTiming';\n\n/**\n * RuntimeSetupOptions - the environment/wiring inputs to {@link setupRuntime} (everything NOT\n * declared by the app's {@link AppWiring}): the logging backend, whether to include the platform\n * default headers, and config. Data-only structure (a class, per the webpieces guidelines). The\n * app's own bind modules + route groups + headers come from the AppWiring passed alongside;\n * the test-override module is the separate `appOverrides` param of {@link setupRuntime}.\n *\n * Headers: {@link HeaderRegistry.configure} registers the platform defaults (when\n * `platformHeaders` is true) plus AppWiring.getHeaders() (by convention the company-wide set).\n */\nexport class RuntimeSetupOptions {\n constructor(\n /** This service's name — published to ServiceInfo. Names every log line and stamps\n * `requestIdSource` on request-ids this service mints. Must be non-blank. */\n public readonly svcName: string,\n /** This build's version — published to ServiceInfo alongside svcName. Opaque to webpieces\n * (a git SHA, a semver tag, a CI build number); it just has to identify THIS build so a log\n * line can say which one emitted it. Must be non-blank. */\n public readonly svcVersion: string,\n /**\n * WHERE this process runs — `'local'` (a developer's machine) or `'deployed'` (everything\n * else). Published to {@link RuntimeLocality}; the ONE input to `@WpLocalOnly` enforcement.\n *\n * REQUIRED and POSITIONAL on purpose, exactly like `@Endpoint(path, kind)`: only the app\n * knows how its platform is detected (Cloud Run's `K_SERVICE`, an ECS metadata URL, the\n * absence of both), the framework must not guess, and a defaulted field would mean \"forgot\n * to say\" and \"said deployed\" are the same line of code. Derive it at your startup, e.g.\n * `getServiceName() === 'local' ? 'local' : 'deployed'`.\n */\n public readonly locality: Locality,\n /** Logging backend to install (LogManager.setFactory). */\n public readonly loggerFactory: LoggerFactory,\n /** Include the webpieces platform default headers. */\n public readonly platformHeaders: boolean = true,\n /** Optional WebpiecesConfig (e.g. recording flags); defaults to a fresh one. */\n public readonly config?: WebpiecesConfig,\n /** Optional startup span observer; the host owns its clock and bounded output. */\n public readonly startupObserver?: RuntimeStartupObserver,\n ) {}\n}\n\n/**\n * setupRuntime - the ONE canonical, TRANSPORT-FREE startup sequence, reusable by any company/app\n * AND any framework adapter (express, fastify, a serverless handler, ...). It runs, in the correct\n * fail-fast order:\n *\n * 1. HeaderRegistry.configure (filters read it at construction; logging masks off it)\n * 2. LogManager.setFactory (fails fast unless the registry is configured first)\n * 3. build the router + DI container (from appModules.getBindModules(), each handed a Binder)\n * 4. configure each appModules.getRouteModules() onto the router (addRoutes/addFilter)\n *\n * and returns the built {@link ApiFactory} — `apiClients()` for a transport to bind, or\n * `createApiClient()` for in-process tests. There is NO express (or any transport) here; a\n * transport adapter (e.g. WebpiecesExpressRouter in @webpieces/http-server) serves the result.\n */\nexport async function setupRuntime(\n options: RuntimeSetupOptions,\n appModules: AppWiring,\n /** A single DI module loaded LAST so tests can rebind bindings to mocks.\n * Or special case servers that want to override specific things */\n appOverrides?: ContainerModule,\n): Promise<ApiFactory> {\n // 0. IDENTIFY this service (name + build version) FIRST, before anything logs. Name and version\n // are REQUIRED inputs to this call, so a build cannot boot anonymously — setInfo throws on a\n // blank value, which kills the deploy (the revision never goes healthy) rather than shipping logs\n // that cannot say which build emitted them. Reads of ServiceInfo elsewhere never throw (a missing\n // log field must never 500 live traffic); the \"say which build you are\" guarantee lives HERE, the\n // one startup every server runs.\n const timing = new RuntimeStartupTiming(options.startupObserver);\n ServiceInfo.setInfo(options.svcName, options.svcVersion);\n\n // 0b. Declare WHERE we run, before any route is built: ApiRoutingFactory reads it in step 4 to\n // decide whether @WpLocalOnly routes are registered at all. Undeclared reads as DEPLOYED, so\n // this call is what lets a local-only endpoint exist — never what hides one.\n RuntimeLocality.declare(options.locality);\n\n // 1. Register the global HeaderRegistry FIRST (this service's own keys come from AppWiring).\n timing.run(RuntimeStartupPhase.HEADERS, 'HeaderRegistry', () =>\n HeaderRegistry.configure(appModules.getHeaders(), options.platformHeaders),\n );\n\n // 2. Install the logging backend ONCE, before anything else logs.\n timing.run(RuntimeStartupPhase.LOGGING, 'LogManager', () =>\n LogManager.setFactory(options.loggerFactory),\n );\n\n // 3. Build the node-only router + DI container.\n const modules = timing.run(\n RuntimeStartupPhase.WIRING,\n appModules.constructor.name,\n () => new NodeWiringModules(appModules),\n );\n const router = await timing.runAsync(RuntimeStartupPhase.CONTAINER, 'WebpiecesRouter', () =>\n WebpiecesRouterFactory.create({\n appBindings: modules.bindModules.map(\n (module: BindModule) =>\n new ContainerModule((load: ContainerModuleLoadOptions) =>\n timing.runAsync(\n RuntimeStartupPhase.BIND_MODULE,\n module.constructor.name,\n () => module.configure(new ContainerBinder(load)),\n ),\n ),\n ),\n appOverrides: appOverrides,\n config: options.config ?? new WebpiecesConfig(),\n startupObserver: options.startupObserver,\n }),\n );\n\n // 4. Let each route group declare its routes + filters, then hand back the consumer surface.\n for (const routeModule of modules.routeModules) {\n timing.run(RuntimeStartupPhase.ROUTE_MODULE, routeModule.constructor.name, () =>\n routeModule.configure(router),\n );\n }\n return router;\n}\n"]}