@webpieces/http-routing 0.4.709 → 0.4.711

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.4.709",
3
+ "version": "0.4.711",
4
4
  "description": "Decorator-based routing with auto-wiring for WebPieces",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -22,9 +22,9 @@
22
22
  },
23
23
  "dependencies": {
24
24
  "@inversifyjs/binding-decorators": "1.1.5",
25
- "@webpieces/core-context": "0.4.709",
26
- "@webpieces/core-util": "0.4.709",
27
- "@webpieces/gcp-identity": "0.4.709",
25
+ "@webpieces/core-context": "0.4.711",
26
+ "@webpieces/core-util": "0.4.711",
27
+ "@webpieces/gcp-identity": "0.4.711",
28
28
  "inversify": "7.10.4",
29
29
  "jsonwebtoken": "9.0.2",
30
30
  "minimatch": "10.0.1"
@@ -2,5 +2,11 @@ import { Filter, Service } from '@webpieces/core-util';
2
2
  import { WpResponse } from '../WpResponse';
3
3
  import { MethodMeta } from '../MethodMeta';
4
4
  export declare class LogApiFilter extends Filter<MethodMeta, WpResponse<unknown>> {
5
+ /**
6
+ * The SERVER's api-call log seam, built here around the RequestContext-backed ApiCallContext.
7
+ * This is the server's inbound construction point; the outbound ones live in each client package
8
+ * (NodeProxyClient, TaskProxyClient, BrowserProxyClient).
9
+ */
10
+ private readonly logApiCall;
5
11
  filter(meta: MethodMeta, nextFilter: Service<MethodMeta, WpResponse<unknown>>): Promise<WpResponse<unknown>>;
6
12
  }
@@ -33,6 +33,12 @@ const WpResponse_1 = require("../WpResponse");
33
33
  */
34
34
  const log = core_util_1.LogManager.getLogger('LogApiFilter');
35
35
  let LogApiFilter = class LogApiFilter extends core_util_2.Filter {
36
+ /**
37
+ * The SERVER's api-call log seam, built here around the RequestContext-backed ApiCallContext.
38
+ * This is the server's inbound construction point; the outbound ones live in each client package
39
+ * (NodeProxyClient, TaskProxyClient, BrowserProxyClient).
40
+ */
41
+ logApiCall = new core_util_1.LogApiCallImpl(new core_context_1.RequestContextApiCallContext());
36
42
  // webpieces-disable no-any-unknown -- Filter generic params use unknown for response flexibility
37
43
  async filter(meta, nextFilter) {
38
44
  // Wrap nextFilter.invoke in a method that returns the response
@@ -41,7 +47,7 @@ let LogApiFilter = class LogApiFilter extends core_util_2.Filter {
41
47
  const wpResponse = await nextFilter.invoke(meta);
42
48
  return wpResponse.response;
43
49
  };
44
- // LogApiCall is a singleton (use it directly, no `new`). It logs the text lines AND stamps the
50
+ // LogApiCall logs the text lines AND stamps the
45
51
  // structured `api={method:{side:'server',...},...}` tag into RequestContext, so every log line
46
52
  // during the request carries jsonPayload.api. Correlation fields (requestId, ...) are added by
47
53
  // the backend. apiClass is the CONTRACT name (routeMeta.apiName, e.g. 'SaveApi') so a server log
@@ -59,7 +65,7 @@ let LogApiFilter = class LogApiFilter extends core_util_2.Filter {
59
65
  core_context_1.RequestContext.putUntrusted(core_util_1.WebpiecesCoreHeaders.METHOD, rm.methodName);
60
66
  }
61
67
  const info = new core_util_1.ApiMethodInfo('server', rm.apiName ?? rm.controllerClassName ?? 'Unknown', rm.methodName, rm.controllerClassName, rm.mask);
62
- const response = await core_util_1.LogApiCall.execute(info, meta.requestDto, method);
68
+ const response = await this.logApiCall.execute(info, meta.requestDto, method);
63
69
  return new WpResponse_1.WpResponse(response);
64
70
  }
65
71
  };
@@ -1 +1 @@
1
- {"version":3,"file":"LogApiFilter.js","sourceRoot":"","sources":["../../../../../../packages/http/http-routing/src/filters/LogApiFilter.ts"],"names":[],"mappings":";;;;AAAA,0DAAoF;AACpF,oDAAmG;AACnG,oDAAuD;AACvD,8CAA2C;AAG3C;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,GAAG,GAAG,sBAAU,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;AAI1C,IAAM,YAAY,GAAlB,MAAM,YAAa,SAAQ,kBAAuC;IAErE,iGAAiG;IACjG,KAAK,CAAC,MAAM,CACR,IAAgB,EAChB,UAAoD;QAEpD,+DAA+D;QAC/D,uFAAuF;QACvF,MAAM,MAAM,GAAG,KAAK,IAAsB,EAAE;YACxC,MAAM,UAAU,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACjD,OAAO,UAAU,CAAC,QAAQ,CAAC;QAC/B,CAAC,CAAC;QAEF,+FAA+F;QAC/F,+FAA+F;QAC/F,+FAA+F;QAC/F,iGAAiG;QACjG,sGAAsG;QACtG,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC;QAE1B,iGAAiG;QACjG,4FAA4F;QAC5F,kGAAkG;QAClG,kGAAkG;QAClG,oGAAoG;QACpG,IAAI,EAAE,CAAC,mBAAmB,EAAE,CAAC;YACzB,6BAAc,CAAC,YAAY,CAAC,gCAAoB,CAAC,UAAU,EAAE,EAAE,CAAC,mBAAmB,CAAC,CAAC;QACzF,CAAC;QACD,IAAI,EAAE,CAAC,UAAU,EAAE,CAAC;YAChB,6BAAc,CAAC,YAAY,CAAC,gCAAoB,CAAC,MAAM,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC;QAC5E,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,yBAAa,CAC1B,QAAQ,EACR,EAAE,CAAC,OAAO,IAAI,EAAE,CAAC,mBAAmB,IAAI,SAAS,EACjD,EAAE,CAAC,UAAU,EACb,EAAE,CAAC,mBAAmB,EACtB,EAAE,CAAC,IAAI,CACV,CAAC;QACF,MAAM,QAAQ,GAAG,MAAM,sBAAU,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QACzE,OAAO,IAAI,uBAAU,CAAC,QAAQ,CAAC,CAAC;IACpC,CAAC;CACJ,CAAA;AA3CY,oCAAY;uBAAZ,YAAY;IAFxB,IAAA,wCAAyB,GAAE;IAC5B,iGAAiG;GACpF,YAAY,CA2CxB","sourcesContent":["import { provideFrameworkSingleton, RequestContext } from '@webpieces/core-context';\nimport { LogManager, WebpiecesCoreHeaders, LogApiCall, ApiMethodInfo } from '@webpieces/core-util';\nimport { Filter, Service } from '@webpieces/core-util';\nimport { WpResponse } from '../WpResponse';\nimport { MethodMeta } from '../MethodMeta';\n\n/**\n * LogApiFilter - the OUTERMOST fixed framework filter (auto-installed at priority 1,000,000 on\n * every route, above AuthFilter). It logs the request AND the response/failure for EVERY call —\n * over HTTP or via createApiClient — and stamps the routed controller identity so every log line\n * of the request carries [Controller.method].\n *\n * Being outermost is deliberate: a request rejected by AuthFilter (401), or any other below-it\n * filter, is STILL logged here with its request body and controller identity. (The former\n * ErrorLogFilter sat above auth but logged only a bare error line — no request, no identity;\n * LogApiFilter replaces it and subsumes its error-logging via LogApiCall.)\n *\n * Logging patterns (via LogApiCall):\n * - [API-server-req] Class.method request={...}\n * - [API-server-resp-SUCCESS] Class.method response={...}\n * - [API-server-resp-FAIL] Class.method error=... (server errors: 500, 502, 504)\n * - [API-server-resp-OTHER] Class.method errorType=... (user errors: 400, 401, 403, 404, 266)\n *\n * User errors (HttpUnauthorizedError, HttpBadRequestError, etc.) are logged as OTHER, not FAIL,\n * because they are expected behavior from the server's perspective. LogApiCall re-throws the\n * error unchanged; the transport (express adapter, or another framework's adapter) maps\n * HttpError subclasses → HTTP status, so in-process and HTTP paths log identically.\n *\n * Headers are read from RequestContext (NOT from meta.requestHeaders which is undefined\n * after ContextFilter runs).\n */\nconst log = LogManager.getLogger('LogApiFilter');\n\n@provideFrameworkSingleton()\n// webpieces-disable no-any-unknown -- Filter generic params use unknown for response flexibility\nexport class LogApiFilter extends Filter<MethodMeta, WpResponse<unknown>> {\n\n // webpieces-disable no-any-unknown -- Filter generic params use unknown for response flexibility\n async filter(\n meta: MethodMeta,\n nextFilter: Service<MethodMeta, WpResponse<unknown>>,\n ): Promise<WpResponse<unknown>> {\n // Wrap nextFilter.invoke in a method that returns the response\n // webpieces-disable no-any-unknown -- response DTO is erased at the api/proxy boundary\n const method = async (): Promise<unknown> => {\n const wpResponse = await nextFilter.invoke(meta);\n return wpResponse.response;\n };\n\n // LogApiCall is a singleton (use it directly, no `new`). It logs the text lines AND stamps the\n // structured `api={method:{side:'server',...},...}` tag into RequestContext, so every log line\n // during the request carries jsonPayload.api. Correlation fields (requestId, ...) are added by\n // the backend. apiClass is the CONTRACT name (routeMeta.apiName, e.g. 'SaveApi') so a server log\n // line MATCHES the client's for the same call; controllerName keeps the impl (e.g. 'SaveController').\n const rm = meta.routeMeta;\n\n // Stamp the routed endpoint's IMPLEMENTATION identity onto the request context so EVERY log line\n // of this request (not just the api req/resp lines) carries the concrete controller class +\n // handler method name — what you actually grep for, and more useful than the raw requestPath. GCP\n // gets them as separate jsonPayload.controller / jsonPayload.method; the local console formatters\n // render them together as a compact [Controller.method] bracket. They clear with the request scope.\n if (rm.controllerClassName) {\n RequestContext.putUntrusted(WebpiecesCoreHeaders.CONTROLLER, rm.controllerClassName);\n }\n if (rm.methodName) {\n RequestContext.putUntrusted(WebpiecesCoreHeaders.METHOD, rm.methodName);\n }\n\n const info = new ApiMethodInfo(\n 'server',\n rm.apiName ?? rm.controllerClassName ?? 'Unknown',\n rm.methodName,\n rm.controllerClassName,\n rm.mask,\n );\n const response = await LogApiCall.execute(info, meta.requestDto, method);\n return new WpResponse(response);\n }\n}\n"]}
1
+ {"version":3,"file":"LogApiFilter.js","sourceRoot":"","sources":["../../../../../../packages/http/http-routing/src/filters/LogApiFilter.ts"],"names":[],"mappings":";;;;AAAA,0DAIiC;AACjC,oDAAuG;AACvG,oDAAuD;AACvD,8CAA2C;AAG3C;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,GAAG,GAAG,sBAAU,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;AAI1C,IAAM,YAAY,GAAlB,MAAM,YAAa,SAAQ,kBAAuC;IAErE;;;;OAIG;IACc,UAAU,GAAG,IAAI,0BAAc,CAAC,IAAI,2CAA4B,EAAE,CAAC,CAAC;IAErF,iGAAiG;IACjG,KAAK,CAAC,MAAM,CACR,IAAgB,EAChB,UAAoD;QAEpD,+DAA+D;QAC/D,uFAAuF;QACvF,MAAM,MAAM,GAAG,KAAK,IAAsB,EAAE;YACxC,MAAM,UAAU,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACjD,OAAO,UAAU,CAAC,QAAQ,CAAC;QAC/B,CAAC,CAAC;QAEF,gDAAgD;QAChD,+FAA+F;QAC/F,+FAA+F;QAC/F,iGAAiG;QACjG,sGAAsG;QACtG,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC;QAE1B,iGAAiG;QACjG,4FAA4F;QAC5F,kGAAkG;QAClG,kGAAkG;QAClG,oGAAoG;QACpG,IAAI,EAAE,CAAC,mBAAmB,EAAE,CAAC;YACzB,6BAAc,CAAC,YAAY,CAAC,gCAAoB,CAAC,UAAU,EAAE,EAAE,CAAC,mBAAmB,CAAC,CAAC;QACzF,CAAC;QACD,IAAI,EAAE,CAAC,UAAU,EAAE,CAAC;YAChB,6BAAc,CAAC,YAAY,CAAC,gCAAoB,CAAC,MAAM,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC;QAC5E,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,yBAAa,CAC1B,QAAQ,EACR,EAAE,CAAC,OAAO,IAAI,EAAE,CAAC,mBAAmB,IAAI,SAAS,EACjD,EAAE,CAAC,UAAU,EACb,EAAE,CAAC,mBAAmB,EACtB,EAAE,CAAC,IAAI,CACV,CAAC;QACF,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QAC9E,OAAO,IAAI,uBAAU,CAAC,QAAQ,CAAC,CAAC;IACpC,CAAC;CACJ,CAAA;AAlDY,oCAAY;uBAAZ,YAAY;IAFxB,IAAA,wCAAyB,GAAE;IAC5B,iGAAiG;GACpF,YAAY,CAkDxB","sourcesContent":["import {\n provideFrameworkSingleton,\n RequestContext,\n RequestContextApiCallContext,\n} from '@webpieces/core-context';\nimport { LogManager, WebpiecesCoreHeaders, LogApiCallImpl, ApiMethodInfo } from '@webpieces/core-util';\nimport { Filter, Service } from '@webpieces/core-util';\nimport { WpResponse } from '../WpResponse';\nimport { MethodMeta } from '../MethodMeta';\n\n/**\n * LogApiFilter - the OUTERMOST fixed framework filter (auto-installed at priority 1,000,000 on\n * every route, above AuthFilter). It logs the request AND the response/failure for EVERY call —\n * over HTTP or via createApiClient — and stamps the routed controller identity so every log line\n * of the request carries [Controller.method].\n *\n * Being outermost is deliberate: a request rejected by AuthFilter (401), or any other below-it\n * filter, is STILL logged here with its request body and controller identity. (The former\n * ErrorLogFilter sat above auth but logged only a bare error line — no request, no identity;\n * LogApiFilter replaces it and subsumes its error-logging via LogApiCall.)\n *\n * Logging patterns (via LogApiCall):\n * - [API-server-req] Class.method request={...}\n * - [API-server-resp-SUCCESS] Class.method response={...}\n * - [API-server-resp-FAIL] Class.method error=... (server errors: 500, 502, 504)\n * - [API-server-resp-OTHER] Class.method errorType=... (user errors: 400, 401, 403, 404, 266)\n *\n * User errors (HttpUnauthorizedError, HttpBadRequestError, etc.) are logged as OTHER, not FAIL,\n * because they are expected behavior from the server's perspective. LogApiCall re-throws the\n * error unchanged; the transport (express adapter, or another framework's adapter) maps\n * HttpError subclasses → HTTP status, so in-process and HTTP paths log identically.\n *\n * Headers are read from RequestContext (NOT from meta.requestHeaders which is undefined\n * after ContextFilter runs).\n */\nconst log = LogManager.getLogger('LogApiFilter');\n\n@provideFrameworkSingleton()\n// webpieces-disable no-any-unknown -- Filter generic params use unknown for response flexibility\nexport class LogApiFilter extends Filter<MethodMeta, WpResponse<unknown>> {\n\n /**\n * The SERVER's api-call log seam, built here around the RequestContext-backed ApiCallContext.\n * This is the server's inbound construction point; the outbound ones live in each client package\n * (NodeProxyClient, TaskProxyClient, BrowserProxyClient).\n */\n private readonly logApiCall = new LogApiCallImpl(new RequestContextApiCallContext());\n\n // webpieces-disable no-any-unknown -- Filter generic params use unknown for response flexibility\n async filter(\n meta: MethodMeta,\n nextFilter: Service<MethodMeta, WpResponse<unknown>>,\n ): Promise<WpResponse<unknown>> {\n // Wrap nextFilter.invoke in a method that returns the response\n // webpieces-disable no-any-unknown -- response DTO is erased at the api/proxy boundary\n const method = async (): Promise<unknown> => {\n const wpResponse = await nextFilter.invoke(meta);\n return wpResponse.response;\n };\n\n // LogApiCall logs the text lines AND stamps the\n // structured `api={method:{side:'server',...},...}` tag into RequestContext, so every log line\n // during the request carries jsonPayload.api. Correlation fields (requestId, ...) are added by\n // the backend. apiClass is the CONTRACT name (routeMeta.apiName, e.g. 'SaveApi') so a server log\n // line MATCHES the client's for the same call; controllerName keeps the impl (e.g. 'SaveController').\n const rm = meta.routeMeta;\n\n // Stamp the routed endpoint's IMPLEMENTATION identity onto the request context so EVERY log line\n // of this request (not just the api req/resp lines) carries the concrete controller class +\n // handler method name — what you actually grep for, and more useful than the raw requestPath. GCP\n // gets them as separate jsonPayload.controller / jsonPayload.method; the local console formatters\n // render them together as a compact [Controller.method] bracket. They clear with the request scope.\n if (rm.controllerClassName) {\n RequestContext.putUntrusted(WebpiecesCoreHeaders.CONTROLLER, rm.controllerClassName);\n }\n if (rm.methodName) {\n RequestContext.putUntrusted(WebpiecesCoreHeaders.METHOD, rm.methodName);\n }\n\n const info = new ApiMethodInfo(\n 'server',\n rm.apiName ?? rm.controllerClassName ?? 'Unknown',\n rm.methodName,\n rm.controllerClassName,\n rm.mask,\n );\n const response = await this.logApiCall.execute(info, meta.requestDto, method);\n return new WpResponse(response);\n }\n}\n"]}
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RuntimeSetupOptions = void 0;
4
4
  exports.setupRuntime = setupRuntime;
5
5
  const core_util_1 = require("@webpieces/core-util");
6
- const core_context_1 = require("@webpieces/core-context");
7
6
  const WebpiecesConfig_1 = require("./WebpiecesConfig");
8
7
  const WebpiecesRouter_1 = require("./WebpiecesRouter");
9
8
  /**
@@ -90,10 +89,6 @@ appOverrides) {
90
89
  core_util_1.HeaderRegistry.configure(appModules.getHeaders(), options.platformHeaders);
91
90
  // 2. Install the logging backend ONCE, before anything else logs.
92
91
  core_util_1.LogManager.setFactory(options.loggerFactory);
93
- // 2b. Bind the SERVER ApiCallContext so LogApiCall (browser-safe core-util) stamps the structured
94
- // `api` tag into the real RequestContext. Installed here — the one startup that runs on EVERY
95
- // server — so both inbound (LogApiFilter) and outbound (clients) log lines carry jsonPayload.api.
96
- core_util_1.ApiCallContextHolder.install(new core_context_1.RequestContextApiCallContext());
97
92
  // 3. Build the node-only router + DI container.
98
93
  const router = await WebpiecesRouter_1.WebpiecesRouterFactory.create({
99
94
  appBindings: [...appModules.getBindingModules()],
@@ -1 +1 @@
1
- {"version":3,"file":"setupRuntime.js","sourceRoot":"","sources":["../../../../../packages/http/http-routing/src/setupRuntime.ts"],"names":[],"mappings":";;;AA6DA,oCA2CC;AAvGD,oDAA+I;AAC/I,0DAAuE;AACvE,uDAAoD;AACpD,uDAA2D;AAI3D;;;;;;;;;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,UAAsB;AACtB;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,+FAA+F;IAC/F,6EAA6E;IAC7E,2BAAe,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAE1C,8FAA8F;IAC9F,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,kGAAkG;IAClG,8FAA8F;IAC9F,kGAAkG;IAClG,gCAAoB,CAAC,OAAO,CAAC,IAAI,2CAA4B,EAAE,CAAC,CAAC;IAEjE,gDAAgD;IAChD,MAAM,MAAM,GAAG,MAAM,wCAAsB,CAAC,MAAM,CAAC;QAC/C,WAAW,EAAE,CAAC,GAAG,UAAU,CAAC,iBAAiB,EAAE,CAAC;QAChD,YAAY,EAAE,YAAY;QAC1B,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,IAAI,iCAAe,EAAE;KAClD,CAAC,CAAC;IAEH,6FAA6F;IAC7F,KAAK,MAAM,WAAW,IAAI,UAAU,CAAC,iBAAiB,EAAE,EAAE,CAAC;QACvD,WAAW,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,MAAM,CAAC;AAClB,CAAC","sourcesContent":["import { ContainerModule } from 'inversify';\nimport { ApiCallContextHolder, HeaderRegistry, Locality, LoggerFactory, LogManager, RuntimeLocality, ServiceInfo } from '@webpieces/core-util';\nimport { RequestContextApiCallContext } from '@webpieces/core-context';\nimport { WebpiecesConfig } from './WebpiecesConfig';\nimport { WebpiecesRouterFactory } from './WebpiecesRouter';\nimport { AppModules } from './AppModules';\nimport { ApiFactory } from './ApiFactory';\n\n/**\n * RuntimeSetupOptions - the environment/wiring inputs to {@link setupRuntime} (everything NOT\n * declared by the app's {@link AppModules}): 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 binding modules + route groups + headers come from the AppModules 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 AppModules.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 `@AuthLocalOnly` 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.getBindingModules())\n * 4. configure each appModules.getRoutingModules() 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: AppModules,\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 @AuthLocalOnly 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 AppModules).\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 // 2b. Bind the SERVER ApiCallContext so LogApiCall (browser-safe core-util) stamps the structured\n // `api` tag into the real RequestContext. Installed here — the one startup that runs on EVERY\n // server — so both inbound (LogApiFilter) and outbound (clients) log lines carry jsonPayload.api.\n ApiCallContextHolder.install(new RequestContextApiCallContext());\n\n // 3. Build the node-only router + DI container.\n const router = await WebpiecesRouterFactory.create({\n appBindings: [...appModules.getBindingModules()],\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 appModules.getRoutingModules()) {\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":";;;AA4DA,oCAsCC;AAjGD,oDAAyH;AACzH,uDAAoD;AACpD,uDAA2D;AAI3D;;;;;;;;;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,UAAsB;AACtB;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,+FAA+F;IAC/F,6EAA6E;IAC7E,2BAAe,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAE1C,8FAA8F;IAC9F,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,MAAM,GAAG,MAAM,wCAAsB,CAAC,MAAM,CAAC;QAC/C,WAAW,EAAE,CAAC,GAAG,UAAU,CAAC,iBAAiB,EAAE,CAAC;QAChD,YAAY,EAAE,YAAY;QAC1B,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,IAAI,iCAAe,EAAE;KAClD,CAAC,CAAC;IAEH,6FAA6F;IAC7F,KAAK,MAAM,WAAW,IAAI,UAAU,CAAC,iBAAiB,EAAE,EAAE,CAAC;QACvD,WAAW,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,MAAM,CAAC;AAClB,CAAC","sourcesContent":["import { ContainerModule } from 'inversify';\nimport { HeaderRegistry, Locality, LoggerFactory, LogManager, RuntimeLocality, ServiceInfo } from '@webpieces/core-util';\nimport { WebpiecesConfig } from './WebpiecesConfig';\nimport { WebpiecesRouterFactory } from './WebpiecesRouter';\nimport { AppModules } from './AppModules';\nimport { ApiFactory } from './ApiFactory';\n\n/**\n * RuntimeSetupOptions - the environment/wiring inputs to {@link setupRuntime} (everything NOT\n * declared by the app's {@link AppModules}): 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 binding modules + route groups + headers come from the AppModules 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 AppModules.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 `@AuthLocalOnly` 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.getBindingModules())\n * 4. configure each appModules.getRoutingModules() 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: AppModules,\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 @AuthLocalOnly 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 AppModules).\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 router = await WebpiecesRouterFactory.create({\n appBindings: [...appModules.getBindingModules()],\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 appModules.getRoutingModules()) {\n routeModule.configure(router);\n }\n return router;\n}\n"]}