@webpieces/core-util 0.4.960 → 0.4.962

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/core-util",
3
- "version": "0.4.960",
3
+ "version": "0.4.962",
4
4
  "description": "Utility functions for WebPieces - works in browser and Node.js",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -52,22 +52,23 @@ export declare class ApiMethodInfo {
52
52
  * The contract CLASS (the `@ApiPath` contract, or an SDK-wrapping api-client's abstract
53
53
  * `XxxApi`) — the key {@link ClientRegistry.classify} resolves the `CallScope` ladder on
54
54
  * (method -> API -> ALL). {@link apiClass} stays the LOGGED name. REQUIRED as a constructor
55
- * argument so every caller states it: an SDK-wrapping client passes its abstract `XxxApi`, and
56
- * only a call with no contract class at all (an IPC hop, an MCP protocol step) passes an explicit
57
- * `undefined`, which reaches only the ALL rung.
55
+ * argument so every caller states it, and never `undefined`: an SDK-wrapping client passes its
56
+ * abstract `XxxApi`, an IPC hop its `@WpInternal` class, and an MCP protocol step (which has no
57
+ * user contract) the framework-owned `McpProtocol` class — which reaches the ALL rung unless
58
+ * somebody registers for that class.
58
59
  *
59
60
  * NON-enumerable on purpose: this object is nested into every `[API-*]` log record as
60
61
  * `jsonPayload.api.method`, and a class reference is not log data.
61
62
  */
62
- readonly contract: Function | undefined;
63
+ readonly contract: Function;
63
64
  constructor(side: ApiSide,
64
65
  /** REQUIRED — the API CONTRACT class name (e.g. 'SaveApi'). Matches client + server so both
65
66
  * sides of one logical call filter together via `jsonPayload.api.method.apiClass`. */
66
67
  apiClass: string,
67
68
  /** REQUIRED — the method on the contract (e.g. 'save'). */
68
69
  methodName: string,
69
- /** REQUIRED — the contract CLASS, or explicit `undefined`; see {@link ApiMethodInfo.contract}. */
70
- contract: Function | undefined,
70
+ /** REQUIRED — the contract CLASS; see {@link ApiMethodInfo.contract}. */
71
+ contract: Function,
71
72
  /** OPTIONAL — server-side impl class (e.g. 'SaveController'). Absent on clients, which have no
72
73
  * impl. Surfaces as `jsonPayload.api.method.controllerName` for server-only drill-down. */
73
74
  controllerName?: string | undefined,
@@ -34,7 +34,7 @@ class ApiMethodInfo {
34
34
  apiClass,
35
35
  /** REQUIRED — the method on the contract (e.g. 'save'). */
36
36
  methodName,
37
- /** REQUIRED — the contract CLASS, or explicit `undefined`; see {@link ApiMethodInfo.contract}. */
37
+ /** REQUIRED — the contract CLASS; see {@link ApiMethodInfo.contract}. */
38
38
  contract,
39
39
  /** OPTIONAL — server-side impl class (e.g. 'SaveController'). Absent on clients, which have no
40
40
  * impl. Surfaces as `jsonPayload.api.method.controllerName` for server-only drill-down. */
@@ -1 +1 @@
1
- {"version":3,"file":"ApiMethodInfo.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/http/ApiMethodInfo.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;GAiBG;;;AAOH,MAAa,aAAa;IAeT;IAGA;IAEA;IAKA;IAMA;IAKA;IAIA;IAIA;IA9Bb,YACa,IAAa;IACtB;2FACuF;IAC9E,QAAgB;IACzB,2DAA2D;IAClD,UAAkB;IAC3B,kGAAkG;IAClG,QAA8B;IAC9B;gGAC4F;IACnF,cAAuB;IAChC;;;;wGAIoG;IAC3F,IAAe;IACxB;;;sGAGkG;IACzF,YAAqB,KAAK;IACnC;;+BAE2B;IAClB,eAAwB,KAAK;IACtC;;qCAEiC;IACxB,uBAAgC,KAAK;QA7BrC,SAAI,GAAJ,IAAI,CAAS;QAGb,aAAQ,GAAR,QAAQ,CAAQ;QAEhB,eAAU,GAAV,UAAU,CAAQ;QAKlB,mBAAc,GAAd,cAAc,CAAS;QAMvB,SAAI,GAAJ,IAAI,CAAW;QAKf,cAAS,GAAT,SAAS,CAAiB;QAI1B,iBAAY,GAAZ,YAAY,CAAiB;QAI7B,yBAAoB,GAApB,oBAAoB,CAAiB;QAE9C,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC;IACpF,CAAC;CACJ;AAhDD,sCAgDC","sourcesContent":["/**\n * ApiMethodInfo - the transport-neutral identity of a single API method call, handed to\n * {@link LogApiCallImpl.execute} by every caller (server inbound, http/in-process clients, cloud tasks,\n * and external wrapped clients like the firestore admin client).\n *\n * WHY generic (not RouteMetadata): LogApiCall runs deep in the stack over MANY shapes — HTTP routes,\n * pubsub/queue enqueues, and multi-param external clients returning Promise<void>/Promise<unknown>.\n * None of those own an `httpMethod`/`path`, so LogApiCall must not depend on the HTTP-shaped\n * `RouteMetadata`. This carries only what identifies the call.\n *\n * MATCHING is the point of {@link apiClass}: a CLIENT call and the SERVER handler for the same logical\n * method must log the SAME identity so `jsonPayload.api.method.apiClass=\"SaveApi\"` filters both sides\n * together. The API CONTRACT class name (e.g. 'SaveApi') is available on both sides — the client only\n * ever knows it, and the server carries it alongside its impl name — so it, not the server's impl\n * class, is the required key.\n *\n * Per CLAUDE.md: data-only structures are classes, not interfaces.\n */\n\nimport {MaskSpec} from \"./LogFieldMask\";\n\n/** Which end of the exchange this process is: the caller ('client') or the handler ('server'). */\nexport type ApiSide = 'client' | 'server';\n\nexport class ApiMethodInfo {\n /**\n * The contract CLASS (the `@ApiPath` contract, or an SDK-wrapping api-client's abstract\n * `XxxApi`) — the key {@link ClientRegistry.classify} resolves the `CallScope` ladder on\n * (method -> API -> ALL). {@link apiClass} stays the LOGGED name. REQUIRED as a constructor\n * argument so every caller states it: an SDK-wrapping client passes its abstract `XxxApi`, and\n * only a call with no contract class at all (an IPC hop, an MCP protocol step) passes an explicit\n * `undefined`, which reaches only the ALL rung.\n *\n * NON-enumerable on purpose: this object is nested into every `[API-*]` log record as\n * `jsonPayload.api.method`, and a class reference is not log data.\n */\n declare readonly contract: Function | undefined;\n\n constructor(\n readonly side: ApiSide,\n /** REQUIRED — the API CONTRACT class name (e.g. 'SaveApi'). Matches client + server so both\n * sides of one logical call filter together via `jsonPayload.api.method.apiClass`. */\n readonly apiClass: string,\n /** REQUIRED — the method on the contract (e.g. 'save'). */\n readonly methodName: string,\n /** REQUIRED — the contract CLASS, or explicit `undefined`; see {@link ApiMethodInfo.contract}. */\n contract: Function | undefined,\n /** OPTIONAL — server-side impl class (e.g. 'SaveController'). Absent on clients, which have no\n * impl. Surfaces as `jsonPayload.api.method.controllerName` for server-only drill-down. */\n readonly controllerName?: string,\n /** OPTIONAL — which DTO fields to mask in the log lines, and how. Absent = log the DTO\n * verbatim exactly as before (the fast path, no per-field walk). Present = {@link LogApiCallImpl}\n * runs {@link maskedStringify} so a declared-sensitive field (an OAuth refresh token, an\n * id-token JWT) is masked in the log while the REAL value still travels on the wire untouched.\n * Rides the call identity so the spec travels with the api definition, not a global app config. */\n readonly mask?: MaskSpec,\n /** OPTIONAL — true when the route declared `@Endpoint(..., { noLogging: true })` (a log\n * shipper, a log-ingest endpoint): {@link LogApiCallImpl} emits NO `[API-*-req]`/`[API-*-resp-*]`\n * line and stamps no {@link ApiCallInfo} tag for it. Read once at route-build time and handed\n * here, exactly as {@link mask} is. Default (absent/false) = the ordinary, fully-logged call. */\n readonly noLogging: boolean = false,\n /** OPTIONAL — `@Endpoint(..., { hideProgress: true })`, carried from the route so the whole\n * call identity travels together. webpieces itself does not act on it; an app's progress UI\n * does. Default false. */\n readonly hideProgress: boolean = false,\n /** OPTIONAL — `@Endpoint(..., { allowUpgradeInFlight: true })`, carried from the route so the\n * whole call identity travels together. webpieces itself does not act on it; an app's upgrade\n * logic does. Default false. */\n readonly allowUpgradeInFlight: boolean = false,\n ) {\n Object.defineProperty(this, 'contract', { value: contract, enumerable: false });\n }\n}\n"]}
1
+ {"version":3,"file":"ApiMethodInfo.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/http/ApiMethodInfo.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;GAiBG;;;AAOH,MAAa,aAAa;IAgBT;IAGA;IAEA;IAKA;IAMA;IAKA;IAIA;IAIA;IA9Bb,YACa,IAAa;IACtB;2FACuF;IAC9E,QAAgB;IACzB,2DAA2D;IAClD,UAAkB;IAC3B,yEAAyE;IACzE,QAAkB;IAClB;gGAC4F;IACnF,cAAuB;IAChC;;;;wGAIoG;IAC3F,IAAe;IACxB;;;sGAGkG;IACzF,YAAqB,KAAK;IACnC;;+BAE2B;IAClB,eAAwB,KAAK;IACtC;;qCAEiC;IACxB,uBAAgC,KAAK;QA7BrC,SAAI,GAAJ,IAAI,CAAS;QAGb,aAAQ,GAAR,QAAQ,CAAQ;QAEhB,eAAU,GAAV,UAAU,CAAQ;QAKlB,mBAAc,GAAd,cAAc,CAAS;QAMvB,SAAI,GAAJ,IAAI,CAAW;QAKf,cAAS,GAAT,SAAS,CAAiB;QAI1B,iBAAY,GAAZ,YAAY,CAAiB;QAI7B,yBAAoB,GAApB,oBAAoB,CAAiB;QAE9C,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC;IACpF,CAAC;CACJ;AAjDD,sCAiDC","sourcesContent":["/**\n * ApiMethodInfo - the transport-neutral identity of a single API method call, handed to\n * {@link LogApiCallImpl.execute} by every caller (server inbound, http/in-process clients, cloud tasks,\n * and external wrapped clients like the firestore admin client).\n *\n * WHY generic (not RouteMetadata): LogApiCall runs deep in the stack over MANY shapes — HTTP routes,\n * pubsub/queue enqueues, and multi-param external clients returning Promise<void>/Promise<unknown>.\n * None of those own an `httpMethod`/`path`, so LogApiCall must not depend on the HTTP-shaped\n * `RouteMetadata`. This carries only what identifies the call.\n *\n * MATCHING is the point of {@link apiClass}: a CLIENT call and the SERVER handler for the same logical\n * method must log the SAME identity so `jsonPayload.api.method.apiClass=\"SaveApi\"` filters both sides\n * together. The API CONTRACT class name (e.g. 'SaveApi') is available on both sides — the client only\n * ever knows it, and the server carries it alongside its impl name — so it, not the server's impl\n * class, is the required key.\n *\n * Per CLAUDE.md: data-only structures are classes, not interfaces.\n */\n\nimport {MaskSpec} from \"./LogFieldMask\";\n\n/** Which end of the exchange this process is: the caller ('client') or the handler ('server'). */\nexport type ApiSide = 'client' | 'server';\n\nexport class ApiMethodInfo {\n /**\n * The contract CLASS (the `@ApiPath` contract, or an SDK-wrapping api-client's abstract\n * `XxxApi`) — the key {@link ClientRegistry.classify} resolves the `CallScope` ladder on\n * (method -> API -> ALL). {@link apiClass} stays the LOGGED name. REQUIRED as a constructor\n * argument so every caller states it, and never `undefined`: an SDK-wrapping client passes its\n * abstract `XxxApi`, an IPC hop its `@WpInternal` class, and an MCP protocol step (which has no\n * user contract) the framework-owned `McpProtocol` class — which reaches the ALL rung unless\n * somebody registers for that class.\n *\n * NON-enumerable on purpose: this object is nested into every `[API-*]` log record as\n * `jsonPayload.api.method`, and a class reference is not log data.\n */\n declare readonly contract: Function;\n\n constructor(\n readonly side: ApiSide,\n /** REQUIRED — the API CONTRACT class name (e.g. 'SaveApi'). Matches client + server so both\n * sides of one logical call filter together via `jsonPayload.api.method.apiClass`. */\n readonly apiClass: string,\n /** REQUIRED — the method on the contract (e.g. 'save'). */\n readonly methodName: string,\n /** REQUIRED — the contract CLASS; see {@link ApiMethodInfo.contract}. */\n contract: Function,\n /** OPTIONAL — server-side impl class (e.g. 'SaveController'). Absent on clients, which have no\n * impl. Surfaces as `jsonPayload.api.method.controllerName` for server-only drill-down. */\n readonly controllerName?: string,\n /** OPTIONAL — which DTO fields to mask in the log lines, and how. Absent = log the DTO\n * verbatim exactly as before (the fast path, no per-field walk). Present = {@link LogApiCallImpl}\n * runs {@link maskedStringify} so a declared-sensitive field (an OAuth refresh token, an\n * id-token JWT) is masked in the log while the REAL value still travels on the wire untouched.\n * Rides the call identity so the spec travels with the api definition, not a global app config. */\n readonly mask?: MaskSpec,\n /** OPTIONAL — true when the route declared `@Endpoint(..., { noLogging: true })` (a log\n * shipper, a log-ingest endpoint): {@link LogApiCallImpl} emits NO `[API-*-req]`/`[API-*-resp-*]`\n * line and stamps no {@link ApiCallInfo} tag for it. Read once at route-build time and handed\n * here, exactly as {@link mask} is. Default (absent/false) = the ordinary, fully-logged call. */\n readonly noLogging: boolean = false,\n /** OPTIONAL — `@Endpoint(..., { hideProgress: true })`, carried from the route so the whole\n * call identity travels together. webpieces itself does not act on it; an app's progress UI\n * does. Default false. */\n readonly hideProgress: boolean = false,\n /** OPTIONAL — `@Endpoint(..., { allowUpgradeInFlight: true })`, carried from the route so the\n * whole call identity travels together. webpieces itself does not act on it; an app's upgrade\n * logic does. Default false. */\n readonly allowUpgradeInFlight: boolean = false,\n ) {\n Object.defineProperty(this, 'contract', { value: contract, enumerable: false });\n }\n}\n"]}
@@ -11,9 +11,14 @@ class CallRegistryCompileAssertions {
11
11
  // @ts-expect-error ALL cannot select a method
12
12
  CallRegistry_1.CallRegistry.setStrategy(undefined, 'ALL', 'work');
13
13
  }
14
+ /** A CallContext's contract is the CLASS, never undefined (#1350). */
15
+ contractIsNeverUndefined() {
16
+ // @ts-expect-error CallContext's contract is a CLASS, never undefined — pass the real contract class
17
+ void new CallStrategy_1.CallContext('Api', 'work', HttpEndpointOptions_1.WRITE, undefined);
18
+ }
14
19
  /** The transport fallback is a TransportDefault (timeout + optional strategy), never a bare number. */
15
20
  fallbackIsATransportDefault() {
16
- const context = new CallStrategy_1.CallContext('Api', 'work', HttpEndpointOptions_1.WRITE, undefined);
21
+ const context = new CallStrategy_1.CallContext('Api', 'work', HttpEndpointOptions_1.WRITE, CallRegistryCompileAssertions);
17
22
  void CallRegistry_1.CallRegistry.execute(CallRegistryCompileAssertions, context, (ms) => Promise.resolve(ms),
18
23
  // @ts-expect-error execute(..., defaultMs: number) became execute(..., fallback: TransportDefault)
19
24
  30_000);
@@ -1 +1 @@
1
- {"version":3,"file":"CallRegistryCompileAssertions.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/http/CallRegistryCompileAssertions.ts"],"names":[],"mappings":";;AAAA,iDAA8C;AAC9C,iDAA6C;AAC7C,+DAA8C;AAE9C,4DAA4D;AAC5D,MAAM,6BAA6B;IAC/B,KAAK;QACD,8CAA8C;QAC9C,2BAAY,CAAC,UAAU,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QAC5C,8CAA8C;QAC9C,2BAAY,CAAC,WAAW,CAAC,SAAS,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IACvD,CAAC;IAED,uGAAuG;IACvG,2BAA2B;QACvB,MAAM,OAAO,GAAG,IAAI,0BAAW,CAAC,KAAK,EAAE,MAAM,EAAE,2BAAK,EAAE,SAAS,CAAC,CAAC;QACjE,KAAK,2BAAY,CAAC,OAAO,CACrB,6BAA6B,EAC7B,OAAO,EACP,CAAC,EAAU,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACnC,mGAAmG;QACnG,MAAM,CACT,CAAC;IACN,CAAC;CACJ","sourcesContent":["import { CallRegistry } from './CallRegistry';\nimport { CallContext } from './CallStrategy';\nimport { WRITE } from './HttpEndpointOptions';\n\n/** Compiled by tsc (spec files are not), never executed. */\nclass CallRegistryCompileAssertions {\n check(): void {\n // @ts-expect-error ALL cannot select a method\n CallRegistry.setTimeout(100, 'ALL', 'work');\n // @ts-expect-error ALL cannot select a method\n CallRegistry.setStrategy(undefined, 'ALL', 'work');\n }\n\n /** The transport fallback is a TransportDefault (timeout + optional strategy), never a bare number. */\n fallbackIsATransportDefault(): void {\n const context = new CallContext('Api', 'work', WRITE, undefined);\n void CallRegistry.execute(\n CallRegistryCompileAssertions,\n context,\n (ms: number) => Promise.resolve(ms),\n // @ts-expect-error execute(..., defaultMs: number) became execute(..., fallback: TransportDefault)\n 30_000,\n );\n }\n}\n"]}
1
+ {"version":3,"file":"CallRegistryCompileAssertions.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/http/CallRegistryCompileAssertions.ts"],"names":[],"mappings":";;AAAA,iDAA8C;AAC9C,iDAA6C;AAC7C,+DAA8C;AAE9C,4DAA4D;AAC5D,MAAM,6BAA6B;IAC/B,KAAK;QACD,8CAA8C;QAC9C,2BAAY,CAAC,UAAU,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QAC5C,8CAA8C;QAC9C,2BAAY,CAAC,WAAW,CAAC,SAAS,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IACvD,CAAC;IAED,sEAAsE;IACtE,wBAAwB;QACpB,qGAAqG;QACrG,KAAK,IAAI,0BAAW,CAAC,KAAK,EAAE,MAAM,EAAE,2BAAK,EAAE,SAAS,CAAC,CAAC;IAC1D,CAAC;IAED,uGAAuG;IACvG,2BAA2B;QACvB,MAAM,OAAO,GAAG,IAAI,0BAAW,CAAC,KAAK,EAAE,MAAM,EAAE,2BAAK,EAAE,6BAA6B,CAAC,CAAC;QACrF,KAAK,2BAAY,CAAC,OAAO,CACrB,6BAA6B,EAC7B,OAAO,EACP,CAAC,EAAU,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACnC,mGAAmG;QACnG,MAAM,CACT,CAAC;IACN,CAAC;CACJ","sourcesContent":["import { CallRegistry } from './CallRegistry';\nimport { CallContext } from './CallStrategy';\nimport { WRITE } from './HttpEndpointOptions';\n\n/** Compiled by tsc (spec files are not), never executed. */\nclass CallRegistryCompileAssertions {\n check(): void {\n // @ts-expect-error ALL cannot select a method\n CallRegistry.setTimeout(100, 'ALL', 'work');\n // @ts-expect-error ALL cannot select a method\n CallRegistry.setStrategy(undefined, 'ALL', 'work');\n }\n\n /** A CallContext's contract is the CLASS, never undefined (#1350). */\n contractIsNeverUndefined(): void {\n // @ts-expect-error CallContext's contract is a CLASS, never undefined — pass the real contract class\n void new CallContext('Api', 'work', WRITE, undefined);\n }\n\n /** The transport fallback is a TransportDefault (timeout + optional strategy), never a bare number. */\n fallbackIsATransportDefault(): void {\n const context = new CallContext('Api', 'work', WRITE, CallRegistryCompileAssertions);\n void CallRegistry.execute(\n CallRegistryCompileAssertions,\n context,\n (ms: number) => Promise.resolve(ms),\n // @ts-expect-error execute(..., defaultMs: number) became execute(..., fallback: TransportDefault)\n 30_000,\n );\n }\n}\n"]}
@@ -25,8 +25,8 @@ export declare class CallScopeLadder<T> {
25
25
  at(...scope: CallScope): T;
26
26
  /**
27
27
  * The registered slots for one call, most specific first: method, then API, then ALL. A rung with
28
- * no slot is skipped. `api` undefined (a call with no contract class — an IPC hop, an MCP protocol
29
- * step, a failure before routing) reaches only the ALL rung.
28
+ * no slot is skipped. `api` undefined (a failure before routing, which has no route and so no
29
+ * contract class) reaches only the ALL rung.
30
30
  */
31
31
  rungs(api: Function | undefined, methodName: string | undefined): T[];
32
32
  clear(): void;
@@ -46,8 +46,8 @@ class CallScopeLadder {
46
46
  }
47
47
  /**
48
48
  * The registered slots for one call, most specific first: method, then API, then ALL. A rung with
49
- * no slot is skipped. `api` undefined (a call with no contract class — an IPC hop, an MCP protocol
50
- * step, a failure before routing) reaches only the ALL rung.
49
+ * no slot is skipped. `api` undefined (a failure before routing, which has no route and so no
50
+ * contract class) reaches only the ALL rung.
51
51
  */
52
52
  rungs(api, methodName) {
53
53
  const found = [];
@@ -1 +1 @@
1
- {"version":3,"file":"CallScope.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/http/CallScope.ts"],"names":[],"mappings":";;;AAaA,MAAM,QAAQ;IACV,GAAG,CAAK;IACC,OAAO,GAAG,IAAI,GAAG,EAAa,CAAC;CAC3C;AAED;;;;;GAKG;AACH,MAAa,eAAe;IAIK;IAHrB,GAAG,CAAgB;IACV,IAAI,GAAG,IAAI,GAAG,EAAyB,CAAC;IAEzD,YAA6B,MAAe;QAAf,WAAM,GAAN,MAAM,CAAS;IAAG,CAAC;IAEhD,0FAA0F;IAC1F,EAAE,CAAC,GAAG,KAAgB;QAClB,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACrB,IAAI,GAAG,KAAK,KAAK,EAAE,CAAC;YAChB,IAAI,IAAI,CAAC,GAAG,KAAK,SAAS;gBAAE,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;YACrD,OAAO,IAAI,CAAC,GAAG,CAAC;QACpB,CAAC;QACD,IAAI,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,CAAC,KAAK,EAAE,CAAC;YACT,KAAK,GAAG,IAAI,QAAQ,EAAK,CAAC;YAC1B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC9B,CAAC;QACD,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QAC5B,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;YAC3B,IAAI,KAAK,CAAC,GAAG,KAAK,SAAS;gBAAE,KAAK,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;YACvD,OAAO,KAAK,CAAC,GAAG,CAAC;QACrB,CAAC;QACD,IAAI,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACzC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACrB,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;YACrB,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QACxC,CAAC;QACD,OAAO,IAAI,CAAC;IAChB,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,GAAyB,EAAE,UAA8B;QAC3D,MAAM,KAAK,GAAQ,EAAE,CAAC;QACtB,MAAM,KAAK,GAAG,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACjE,MAAM,MAAM,GAAG,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACrF,IAAI,MAAM,KAAK,SAAS;YAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC7C,IAAI,KAAK,EAAE,GAAG,KAAK,SAAS;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACpD,IAAI,IAAI,CAAC,GAAG,KAAK,SAAS;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjD,OAAO,KAAK,CAAC;IACjB,CAAC;IAED,KAAK;QACD,IAAI,CAAC,GAAG,GAAG,SAAS,CAAC;QACrB,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IACtB,CAAC;CACJ;AAlDD,0CAkDC","sourcesContent":["/**\n * Where a policy applies: every contract (`'ALL'`, which has no method), one contract, or one method\n * of one contract. The contract is always the CLASS (the `@ApiPath` contract, or an SDK-wrapping\n * api-client's abstract `XxxApi`), never its name — a string key is one typo away from silently\n * matching nothing.\n *\n * Every per-call startup registry scopes its settings with this ONE ladder: `CallRegistry`\n * (strategy, timeout), `ClientRegistry` (error translator, error classifier) and cloudtasks-client's\n * `GcpTaskRegistry` (customizer, gax). Resolution is always method -> API -> ALL -> the registry's\n * own webpieces default.\n */\nexport type CallScope = [api: 'ALL'] | [api: Function, methodName?: string];\n\nclass ApiRungs<T> {\n api?: T;\n readonly methods = new Map<string, T>();\n}\n\n/**\n * The ONE implementation of the {@link CallScope} ladder. It stores one slot per scope (created on\n * first use by `create`) and answers a call's rungs most-specific-first; each registry decides what a\n * rung's slot holds and how a rung \"answers\" (first value present, or first verdict that does not\n * defer).\n */\nexport class CallScopeLadder<T> {\n private all: T | undefined;\n private readonly apis = new Map<Function, ApiRungs<T>>();\n\n constructor(private readonly create: () => T) {}\n\n /** The slot for `scope`, created on first use. Registries write their setting into it. */\n at(...scope: CallScope): T {\n const api = scope[0];\n if (api === 'ALL') {\n if (this.all === undefined) this.all = this.create();\n return this.all;\n }\n let rungs = this.apis.get(api);\n if (!rungs) {\n rungs = new ApiRungs<T>();\n this.apis.set(api, rungs);\n }\n const methodName = scope[1];\n if (methodName === undefined) {\n if (rungs.api === undefined) rungs.api = this.create();\n return rungs.api;\n }\n let slot = rungs.methods.get(methodName);\n if (slot === undefined) {\n slot = this.create();\n rungs.methods.set(methodName, slot);\n }\n return slot;\n }\n\n /**\n * The registered slots for one call, most specific first: method, then API, then ALL. A rung with\n * no slot is skipped. `api` undefined (a call with no contract class — an IPC hop, an MCP protocol\n * step, a failure before routing) reaches only the ALL rung.\n */\n rungs(api: Function | undefined, methodName: string | undefined): T[] {\n const found: T[] = [];\n const rungs = api === undefined ? undefined : this.apis.get(api);\n const method = methodName === undefined ? undefined : rungs?.methods.get(methodName);\n if (method !== undefined) found.push(method);\n if (rungs?.api !== undefined) found.push(rungs.api);\n if (this.all !== undefined) found.push(this.all);\n return found;\n }\n\n clear(): void {\n this.all = undefined;\n this.apis.clear();\n }\n}\n"]}
1
+ {"version":3,"file":"CallScope.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/http/CallScope.ts"],"names":[],"mappings":";;;AAaA,MAAM,QAAQ;IACV,GAAG,CAAK;IACC,OAAO,GAAG,IAAI,GAAG,EAAa,CAAC;CAC3C;AAED;;;;;GAKG;AACH,MAAa,eAAe;IAIK;IAHrB,GAAG,CAAgB;IACV,IAAI,GAAG,IAAI,GAAG,EAAyB,CAAC;IAEzD,YAA6B,MAAe;QAAf,WAAM,GAAN,MAAM,CAAS;IAAG,CAAC;IAEhD,0FAA0F;IAC1F,EAAE,CAAC,GAAG,KAAgB;QAClB,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACrB,IAAI,GAAG,KAAK,KAAK,EAAE,CAAC;YAChB,IAAI,IAAI,CAAC,GAAG,KAAK,SAAS;gBAAE,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;YACrD,OAAO,IAAI,CAAC,GAAG,CAAC;QACpB,CAAC;QACD,IAAI,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,CAAC,KAAK,EAAE,CAAC;YACT,KAAK,GAAG,IAAI,QAAQ,EAAK,CAAC;YAC1B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC9B,CAAC;QACD,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QAC5B,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;YAC3B,IAAI,KAAK,CAAC,GAAG,KAAK,SAAS;gBAAE,KAAK,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;YACvD,OAAO,KAAK,CAAC,GAAG,CAAC;QACrB,CAAC;QACD,IAAI,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACzC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACrB,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;YACrB,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QACxC,CAAC;QACD,OAAO,IAAI,CAAC;IAChB,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,GAAyB,EAAE,UAA8B;QAC3D,MAAM,KAAK,GAAQ,EAAE,CAAC;QACtB,MAAM,KAAK,GAAG,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACjE,MAAM,MAAM,GAAG,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACrF,IAAI,MAAM,KAAK,SAAS;YAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC7C,IAAI,KAAK,EAAE,GAAG,KAAK,SAAS;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACpD,IAAI,IAAI,CAAC,GAAG,KAAK,SAAS;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjD,OAAO,KAAK,CAAC;IACjB,CAAC;IAED,KAAK;QACD,IAAI,CAAC,GAAG,GAAG,SAAS,CAAC;QACrB,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IACtB,CAAC;CACJ;AAlDD,0CAkDC","sourcesContent":["/**\n * Where a policy applies: every contract (`'ALL'`, which has no method), one contract, or one method\n * of one contract. The contract is always the CLASS (the `@ApiPath` contract, or an SDK-wrapping\n * api-client's abstract `XxxApi`), never its name — a string key is one typo away from silently\n * matching nothing.\n *\n * Every per-call startup registry scopes its settings with this ONE ladder: `CallRegistry`\n * (strategy, timeout), `ClientRegistry` (error translator, error classifier) and cloudtasks-client's\n * `GcpTaskRegistry` (customizer, gax). Resolution is always method -> API -> ALL -> the registry's\n * own webpieces default.\n */\nexport type CallScope = [api: 'ALL'] | [api: Function, methodName?: string];\n\nclass ApiRungs<T> {\n api?: T;\n readonly methods = new Map<string, T>();\n}\n\n/**\n * The ONE implementation of the {@link CallScope} ladder. It stores one slot per scope (created on\n * first use by `create`) and answers a call's rungs most-specific-first; each registry decides what a\n * rung's slot holds and how a rung \"answers\" (first value present, or first verdict that does not\n * defer).\n */\nexport class CallScopeLadder<T> {\n private all: T | undefined;\n private readonly apis = new Map<Function, ApiRungs<T>>();\n\n constructor(private readonly create: () => T) {}\n\n /** The slot for `scope`, created on first use. Registries write their setting into it. */\n at(...scope: CallScope): T {\n const api = scope[0];\n if (api === 'ALL') {\n if (this.all === undefined) this.all = this.create();\n return this.all;\n }\n let rungs = this.apis.get(api);\n if (!rungs) {\n rungs = new ApiRungs<T>();\n this.apis.set(api, rungs);\n }\n const methodName = scope[1];\n if (methodName === undefined) {\n if (rungs.api === undefined) rungs.api = this.create();\n return rungs.api;\n }\n let slot = rungs.methods.get(methodName);\n if (slot === undefined) {\n slot = this.create();\n rungs.methods.set(methodName, slot);\n }\n return slot;\n }\n\n /**\n * The registered slots for one call, most specific first: method, then API, then ALL. A rung with\n * no slot is skipped. `api` undefined (a failure before routing, which has no route and so no\n * contract class) reaches only the ALL rung.\n */\n rungs(api: Function | undefined, methodName: string | undefined): T[] {\n const found: T[] = [];\n const rungs = api === undefined ? undefined : this.apis.get(api);\n const method = methodName === undefined ? undefined : rungs?.methods.get(methodName);\n if (method !== undefined) found.push(method);\n if (rungs?.api !== undefined) found.push(rungs.api);\n if (this.all !== undefined) found.push(this.all);\n return found;\n }\n\n clear(): void {\n this.all = undefined;\n this.apis.clear();\n }\n}\n"]}
@@ -17,16 +17,17 @@ export declare class CallContext {
17
17
  /**
18
18
  * The contract CLASS the call belongs to — the key of the `CallScope` ladder, so a strategy's
19
19
  * per-attempt error classification resolves the classifier registered for THIS contract.
20
- * `CallRegistry.execute` guarantees it on the context a strategy sees; undefined only for a
21
- * transport with no contract class (an IPC deadline), which reaches the ALL rung alone.
20
+ * REQUIRED and never `undefined`: every transport knows its contract class (HTTP and Cloud Tasks
21
+ * clients hold it, the IPC client proxy holds its `@WpInternal` class), and
22
+ * `CallRegistry.execute` re-keys the context a strategy sees onto the class it was given.
22
23
  *
23
24
  * NON-enumerable on purpose: this context rides on `ApiCallTimeoutError`, which is logged and
24
25
  * compared as data, and a class reference is not data.
25
26
  */
26
- readonly contract: Function | undefined;
27
+ readonly contract: Function;
27
28
  constructor(apiName: string, methodName: string, operation: EndpointOperation,
28
- /** REQUIRED — the contract CLASS, or explicit `undefined`; see {@link CallContext.contract}. */
29
- contract: Function | undefined);
29
+ /** REQUIRED — the contract CLASS; see {@link CallContext.contract}. */
30
+ contract: Function);
30
31
  }
31
32
  /** Owns all timing and retry decisions. No public cancellation signal. */
32
33
  export type CallStrategy<T> = (call: Attempt<T>, ctx: CallContext) => Promise<T>;
@@ -15,7 +15,7 @@ class CallContext {
15
15
  methodName;
16
16
  operation;
17
17
  constructor(apiName, methodName, operation,
18
- /** REQUIRED — the contract CLASS, or explicit `undefined`; see {@link CallContext.contract}. */
18
+ /** REQUIRED — the contract CLASS; see {@link CallContext.contract}. */
19
19
  contract) {
20
20
  this.apiName = apiName;
21
21
  this.methodName = methodName;
@@ -1 +1 @@
1
- {"version":3,"file":"CallStrategy.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/http/CallStrategy.ts"],"names":[],"mappings":";;;AAKA;;;;;;;;GAQG;AACH,MAAa,WAAW;IAaA;IACA;IACA;IAHpB,YACoB,OAAe,EACf,UAAkB,EAClB,SAA4B;IAC5C,gGAAgG;IAChG,QAA8B;QAJd,YAAO,GAAP,OAAO,CAAQ;QACf,eAAU,GAAV,UAAU,CAAQ;QAClB,cAAS,GAAT,SAAS,CAAmB;QAI5C,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC;IACpF,CAAC;CACJ;AArBD,kCAqBC","sourcesContent":["import { EndpointOperation } from './HttpEndpointOptions';\n\n/** One bounded attempt. Only an explicitly registered strategy may retry it. */\nexport type Attempt<T> = (timeoutMs: number) => Promise<T>;\n\n/**\n * Contract identity for diagnostics; registry keys use the class itself.\n *\n * `operation` is the endpoint's declared `@Endpoint` side-effect contract (`READ`,\n * `WRITE_IDEMPOTENT` or `WRITE`). A {@link CallStrategy} reads it to decide whether a retry is safe,\n * and `ApiCallTimeoutError` reads it to choose the text it shows an end user. A transport with\n * no declared operation (IPC contracts declare none) passes `WRITE`: the conservative answer, since\n * it never invites a blind retry of something that may already have happened.\n */\nexport class CallContext {\n /**\n * The contract CLASS the call belongs to — the key of the `CallScope` ladder, so a strategy's\n * per-attempt error classification resolves the classifier registered for THIS contract.\n * `CallRegistry.execute` guarantees it on the context a strategy sees; undefined only for a\n * transport with no contract class (an IPC deadline), which reaches the ALL rung alone.\n *\n * NON-enumerable on purpose: this context rides on `ApiCallTimeoutError`, which is logged and\n * compared as data, and a class reference is not data.\n */\n declare readonly contract: Function | undefined;\n\n constructor(\n public readonly apiName: string,\n public readonly methodName: string,\n public readonly operation: EndpointOperation,\n /** REQUIRED — the contract CLASS, or explicit `undefined`; see {@link CallContext.contract}. */\n contract: Function | undefined,\n ) {\n Object.defineProperty(this, 'contract', { value: contract, enumerable: false });\n }\n}\n\n/** Owns all timing and retry decisions. No public cancellation signal. */\nexport type CallStrategy<T> = (call: Attempt<T>, ctx: CallContext) => Promise<T>;\n"]}
1
+ {"version":3,"file":"CallStrategy.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/http/CallStrategy.ts"],"names":[],"mappings":";;;AAKA;;;;;;;;GAQG;AACH,MAAa,WAAW;IAcA;IACA;IACA;IAHpB,YACoB,OAAe,EACf,UAAkB,EAClB,SAA4B;IAC5C,uEAAuE;IACvE,QAAkB;QAJF,YAAO,GAAP,OAAO,CAAQ;QACf,eAAU,GAAV,UAAU,CAAQ;QAClB,cAAS,GAAT,SAAS,CAAmB;QAI5C,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC;IACpF,CAAC;CACJ;AAtBD,kCAsBC","sourcesContent":["import { EndpointOperation } from './HttpEndpointOptions';\n\n/** One bounded attempt. Only an explicitly registered strategy may retry it. */\nexport type Attempt<T> = (timeoutMs: number) => Promise<T>;\n\n/**\n * Contract identity for diagnostics; registry keys use the class itself.\n *\n * `operation` is the endpoint's declared `@Endpoint` side-effect contract (`READ`,\n * `WRITE_IDEMPOTENT` or `WRITE`). A {@link CallStrategy} reads it to decide whether a retry is safe,\n * and `ApiCallTimeoutError` reads it to choose the text it shows an end user. A transport with\n * no declared operation (IPC contracts declare none) passes `WRITE`: the conservative answer, since\n * it never invites a blind retry of something that may already have happened.\n */\nexport class CallContext {\n /**\n * The contract CLASS the call belongs to — the key of the `CallScope` ladder, so a strategy's\n * per-attempt error classification resolves the classifier registered for THIS contract.\n * REQUIRED and never `undefined`: every transport knows its contract class (HTTP and Cloud Tasks\n * clients hold it, the IPC client proxy holds its `@WpInternal` class), and\n * `CallRegistry.execute` re-keys the context a strategy sees onto the class it was given.\n *\n * NON-enumerable on purpose: this context rides on `ApiCallTimeoutError`, which is logged and\n * compared as data, and a class reference is not data.\n */\n declare readonly contract: Function;\n\n constructor(\n public readonly apiName: string,\n public readonly methodName: string,\n public readonly operation: EndpointOperation,\n /** REQUIRED — the contract CLASS; see {@link CallContext.contract}. */\n contract: Function,\n ) {\n Object.defineProperty(this, 'contract', { value: contract, enumerable: false });\n }\n}\n\n/** Owns all timing and retry decisions. No public cancellation signal. */\nexport type CallStrategy<T> = (call: Attempt<T>, ctx: CallContext) => Promise<T>;\n"]}
@@ -29,10 +29,14 @@ class ErrorLadderCompileAssertions {
29
29
  ClientRegistry_1.ClientRegistry.setErrorClassifier(classifier, 'ALL', 'work');
30
30
  }
31
31
  callIdentityStatesItsContract() {
32
- // @ts-expect-error ApiMethodInfo's contract CLASS is required (pass undefined only when there is none)
32
+ // @ts-expect-error ApiMethodInfo's contract CLASS is required
33
33
  void new ApiMethodInfo_1.ApiMethodInfo('client', 'SaveApi', 'save');
34
- // @ts-expect-error CallContext's contract CLASS is required (pass undefined only when there is none)
34
+ // @ts-expect-error CallContext's contract CLASS is required
35
35
  void new CallStrategy_1.CallContext('SaveApi', 'save', HttpEndpointOptions_1.WRITE);
36
+ // @ts-expect-error ApiMethodInfo's contract is a CLASS, never undefined — pass the real contract class
37
+ void new ApiMethodInfo_1.ApiMethodInfo('client', 'SaveApi', 'save', undefined);
38
+ // @ts-expect-error CallContext's contract is a CLASS, never undefined — pass the real contract class
39
+ void new CallStrategy_1.CallContext('SaveApi', 'save', HttpEndpointOptions_1.WRITE, undefined);
36
40
  }
37
41
  keyedByClassNeverByName(classifier) {
38
42
  // @ts-expect-error the ladder is keyed by the contract CLASS, never its name
@@ -1 +1 @@
1
- {"version":3,"file":"ErrorLadderCompileAssertions.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/http/ErrorLadderCompileAssertions.ts"],"names":[],"mappings":";;AAAA,qDAAkD;AAGlD,mDAAgD;AAChD,iDAA6C;AAC7C,+DAA8C;AAE9C;;;;GAIG;AACH,MAAM,4BAA4B;IAC9B,eAAe,CAAC,UAA2B,EAAE,UAA2B;QACpE,qGAAqG;QACrG,+BAAc,CAAC,kBAAkB,CAAC,UAAU,CAAC,CAAC;QAC9C,oFAAoF;QACpF,+BAAc,CAAC,yBAAyB,CAAC,UAAU,CAAC,CAAC;QACrD,8GAA8G;QAC9G,+BAAc,CAAC,kBAAkB,CAAC,UAAU,CAAC,CAAC;QAC9C,wEAAwE;QACxE,+BAAc,CAAC,kBAAkB,CAAC,UAAU,CAAC,CAAC;QAC9C,mFAAmF;QACnF,+BAAc,CAAC,kBAAkB,EAAE,CAAC;IACxC,CAAC;IAED,cAAc,CAAC,UAA2B,EAAE,UAA2B;QACnE,8CAA8C;QAC9C,+BAAc,CAAC,kBAAkB,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QAC7D,8CAA8C;QAC9C,+BAAc,CAAC,kBAAkB,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IACjE,CAAC;IAED,6BAA6B;QACzB,uGAAuG;QACvG,KAAK,IAAI,6BAAa,CAAC,QAAQ,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;QACpD,qGAAqG;QACrG,KAAK,IAAI,0BAAW,CAAC,SAAS,EAAE,MAAM,EAAE,2BAAK,CAAC,CAAC;IACnD,CAAC;IAED,uBAAuB,CAAC,UAA2B;QAC/C,6EAA6E;QAC7E,+BAAc,CAAC,kBAAkB,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;IAC7D,CAAC;CACJ","sourcesContent":["import { ClientRegistry } from './ClientRegistry';\nimport { ErrorClassifier } from './ErrorClassifier';\nimport { ErrorTranslator } from './ErrorTranslator';\nimport { ApiMethodInfo } from './ApiMethodInfo';\nimport { CallContext } from './CallStrategy';\nimport { WRITE } from './HttpEndpointOptions';\n\n/**\n * Compiled by tsc (spec files are not), never executed. Pins the ONE spelling of the error ladder:\n * every registration states its `CallScope`, and the unscoped spellings it replaced do not compile.\n * tsc fails the build with TS2578 if any of these ever starts compiling again.\n */\nclass ErrorLadderCompileAssertions {\n scopeIsRequired(translator: ErrorTranslator, classifier: ErrorClassifier): void {\n // @ts-expect-error setErrorTranslator(t) became setErrorTranslator(t, 'ALL') — the scope is required\n ClientRegistry.setErrorTranslator(translator);\n // @ts-expect-error setDefaultErrorClassifier(c) became setErrorClassifier(c, 'ALL')\n ClientRegistry.setDefaultErrorClassifier(classifier);\n // @ts-expect-error addErrorClassifier(new KeyedErrorClassifier('XApi', c)) became setErrorClassifier(c, XApi)\n ClientRegistry.addErrorClassifier(classifier);\n // @ts-expect-error the scope is required — setErrorClassifier(c, 'ALL')\n ClientRegistry.setErrorClassifier(classifier);\n // @ts-expect-error getErrorTranslator() became getErrorTranslator(api, methodName)\n ClientRegistry.getErrorTranslator();\n }\n\n allHasNoMethod(translator: ErrorTranslator, classifier: ErrorClassifier): void {\n // @ts-expect-error ALL cannot select a method\n ClientRegistry.setErrorTranslator(translator, 'ALL', 'work');\n // @ts-expect-error ALL cannot select a method\n ClientRegistry.setErrorClassifier(classifier, 'ALL', 'work');\n }\n\n callIdentityStatesItsContract(): void {\n // @ts-expect-error ApiMethodInfo's contract CLASS is required (pass undefined only when there is none)\n void new ApiMethodInfo('client', 'SaveApi', 'save');\n // @ts-expect-error CallContext's contract CLASS is required (pass undefined only when there is none)\n void new CallContext('SaveApi', 'save', WRITE);\n }\n\n keyedByClassNeverByName(classifier: ErrorClassifier): void {\n // @ts-expect-error the ladder is keyed by the contract CLASS, never its name\n ClientRegistry.setErrorClassifier(classifier, 'SaveApi');\n }\n}\n"]}
1
+ {"version":3,"file":"ErrorLadderCompileAssertions.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/http/ErrorLadderCompileAssertions.ts"],"names":[],"mappings":";;AAAA,qDAAkD;AAGlD,mDAAgD;AAChD,iDAA6C;AAC7C,+DAA8C;AAE9C;;;;GAIG;AACH,MAAM,4BAA4B;IAC9B,eAAe,CAAC,UAA2B,EAAE,UAA2B;QACpE,qGAAqG;QACrG,+BAAc,CAAC,kBAAkB,CAAC,UAAU,CAAC,CAAC;QAC9C,oFAAoF;QACpF,+BAAc,CAAC,yBAAyB,CAAC,UAAU,CAAC,CAAC;QACrD,8GAA8G;QAC9G,+BAAc,CAAC,kBAAkB,CAAC,UAAU,CAAC,CAAC;QAC9C,wEAAwE;QACxE,+BAAc,CAAC,kBAAkB,CAAC,UAAU,CAAC,CAAC;QAC9C,mFAAmF;QACnF,+BAAc,CAAC,kBAAkB,EAAE,CAAC;IACxC,CAAC;IAED,cAAc,CAAC,UAA2B,EAAE,UAA2B;QACnE,8CAA8C;QAC9C,+BAAc,CAAC,kBAAkB,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QAC7D,8CAA8C;QAC9C,+BAAc,CAAC,kBAAkB,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IACjE,CAAC;IAED,6BAA6B;QACzB,8DAA8D;QAC9D,KAAK,IAAI,6BAAa,CAAC,QAAQ,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;QACpD,4DAA4D;QAC5D,KAAK,IAAI,0BAAW,CAAC,SAAS,EAAE,MAAM,EAAE,2BAAK,CAAC,CAAC;QAC/C,uGAAuG;QACvG,KAAK,IAAI,6BAAa,CAAC,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;QAC/D,qGAAqG;QACrG,KAAK,IAAI,0BAAW,CAAC,SAAS,EAAE,MAAM,EAAE,2BAAK,EAAE,SAAS,CAAC,CAAC;IAC9D,CAAC;IAED,uBAAuB,CAAC,UAA2B;QAC/C,6EAA6E;QAC7E,+BAAc,CAAC,kBAAkB,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;IAC7D,CAAC;CACJ","sourcesContent":["import { ClientRegistry } from './ClientRegistry';\nimport { ErrorClassifier } from './ErrorClassifier';\nimport { ErrorTranslator } from './ErrorTranslator';\nimport { ApiMethodInfo } from './ApiMethodInfo';\nimport { CallContext } from './CallStrategy';\nimport { WRITE } from './HttpEndpointOptions';\n\n/**\n * Compiled by tsc (spec files are not), never executed. Pins the ONE spelling of the error ladder:\n * every registration states its `CallScope`, and the unscoped spellings it replaced do not compile.\n * tsc fails the build with TS2578 if any of these ever starts compiling again.\n */\nclass ErrorLadderCompileAssertions {\n scopeIsRequired(translator: ErrorTranslator, classifier: ErrorClassifier): void {\n // @ts-expect-error setErrorTranslator(t) became setErrorTranslator(t, 'ALL') — the scope is required\n ClientRegistry.setErrorTranslator(translator);\n // @ts-expect-error setDefaultErrorClassifier(c) became setErrorClassifier(c, 'ALL')\n ClientRegistry.setDefaultErrorClassifier(classifier);\n // @ts-expect-error addErrorClassifier(new KeyedErrorClassifier('XApi', c)) became setErrorClassifier(c, XApi)\n ClientRegistry.addErrorClassifier(classifier);\n // @ts-expect-error the scope is required — setErrorClassifier(c, 'ALL')\n ClientRegistry.setErrorClassifier(classifier);\n // @ts-expect-error getErrorTranslator() became getErrorTranslator(api, methodName)\n ClientRegistry.getErrorTranslator();\n }\n\n allHasNoMethod(translator: ErrorTranslator, classifier: ErrorClassifier): void {\n // @ts-expect-error ALL cannot select a method\n ClientRegistry.setErrorTranslator(translator, 'ALL', 'work');\n // @ts-expect-error ALL cannot select a method\n ClientRegistry.setErrorClassifier(classifier, 'ALL', 'work');\n }\n\n callIdentityStatesItsContract(): void {\n // @ts-expect-error ApiMethodInfo's contract CLASS is required\n void new ApiMethodInfo('client', 'SaveApi', 'save');\n // @ts-expect-error CallContext's contract CLASS is required\n void new CallContext('SaveApi', 'save', WRITE);\n // @ts-expect-error ApiMethodInfo's contract is a CLASS, never undefined — pass the real contract class\n void new ApiMethodInfo('client', 'SaveApi', 'save', undefined);\n // @ts-expect-error CallContext's contract is a CLASS, never undefined — pass the real contract class\n void new CallContext('SaveApi', 'save', WRITE, undefined);\n }\n\n keyedByClassNeverByName(classifier: ErrorClassifier): void {\n // @ts-expect-error the ladder is keyed by the contract CLASS, never its name\n ClientRegistry.setErrorClassifier(classifier, 'SaveApi');\n }\n}\n"]}
@@ -40,7 +40,13 @@ export declare class IpcConnection {
40
40
  /** Install exactly one factory dispatcher BEFORE exposing this connection to the peer. */
41
41
  setHandler(handler: (request: IpcRequest) => Promise<IpcReply>): void;
42
42
  newContext(parent?: IpcCallContext): IpcCallContext;
43
- request(request: IpcRequest): Promise<IpcReply>;
43
+ /**
44
+ * Send one request and await its reply. `contract` is the `@WpInternal` contract CLASS the client
45
+ * proxy was created for: the wire carries only the string `apiId`, so the class rides beside the
46
+ * request and keys the deadline's {@link CallContext} onto the `CallScope` ladder — an IPC timeout
47
+ * reaches the classifier registered for THIS contract, exactly like HTTP and Cloud Tasks.
48
+ */
49
+ request(request: IpcRequest, contract: Function): Promise<IpcReply>;
44
50
  dispose(): void;
45
51
  private send;
46
52
  private receive;
@@ -95,7 +95,13 @@ class IpcConnection {
95
95
  this.usedIds.add(id);
96
96
  return new IpcProtocol_1.IpcCallContext(parent?.txId ?? id, id, parent?.callId);
97
97
  }
98
- request(request) {
98
+ /**
99
+ * Send one request and await its reply. `contract` is the `@WpInternal` contract CLASS the client
100
+ * proxy was created for: the wire carries only the string `apiId`, so the class rides beside the
101
+ * request and keys the deadline's {@link CallContext} onto the `CallScope` ladder — an IPC timeout
102
+ * reaches the classifier registered for THIS contract, exactly like HTTP and Cloud Tasks.
103
+ */
104
+ request(request, contract) {
99
105
  if (this.closed)
100
106
  return Promise.reject(this.closed);
101
107
  if (this.pending.has(request.context.callId))
@@ -107,7 +113,7 @@ class IpcConnection {
107
113
  this.settle(request.context.callId, new ApiCallTimeoutError_1.ApiCallTimeoutError(this.options.timeoutMs,
108
114
  // IPC contracts declare no @Endpoint operation, so the deadline reports the
109
115
  // conservative WRITE: the user is told to check before repeating the call.
110
- new CallStrategy_1.CallContext(request.apiId, request.methodId, HttpEndpointOptions_1.WRITE, undefined)), 'expired');
116
+ new CallStrategy_1.CallContext(request.apiId, request.methodId, HttpEndpointOptions_1.WRITE, contract)), 'expired');
111
117
  }, this.options.timeoutMs);
112
118
  // This owner observes every async send rejection; a send failure is never a timeout.
113
119
  void this.send(request).catch((error) => {
@@ -1 +1 @@
1
- {"version":3,"file":"IpcConnection.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/ipc/IpcConnection.ts"],"names":[],"mappings":";;;AAAA,kDAA4C;AAC5C,qEAAkE;AAClE,uDAAmD;AACnD,qEAAoD;AACpD,sCAA6E;AAC7E,+CAA4C;AAC5C,+CAOuB;AAEvB,4FAA4F;AAC5F,MAAa,iBAAkB,SAAQ,KAAK;IACxC,YAAY,OAAe,EAAE,KAAa;QACtC,KAAK,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QAC1B,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IACpC,CAAC;CACJ;AALD,8CAKC;AAkBD,MAAa,oBAAoB;IAEhB;IACA;IACA;IACA;IACA;IACA;IACA;IAPb,YACa,SAAiB,EACjB,MAAoB,EACpB,SAAuB,EACvB,MAAqB,EACrB,uBAAuB,SAAS,EAChC,yBAAyB,GAAG,EAC5B,eAAe,aAAa;QAN5B,cAAS,GAAT,SAAS,CAAQ;QACjB,WAAM,GAAN,MAAM,CAAc;QACpB,cAAS,GAAT,SAAS,CAAc;QACvB,WAAM,GAAN,MAAM,CAAe;QACrB,yBAAoB,GAApB,oBAAoB,CAAY;QAChC,2BAAsB,GAAtB,sBAAsB,CAAM;QAC5B,iBAAY,GAAZ,YAAY,CAAgB;QAErC,IACI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC;YAC3B,SAAS,IAAI,CAAC;YACd,CAAC,MAAM,CAAC,aAAa,CAAC,oBAAoB,CAAC;YAC3C,oBAAoB,GAAG,CAAC;YACxB,CAAC,MAAM,CAAC,aAAa,CAAC,sBAAsB,CAAC;YAC7C,sBAAsB,GAAG,CAAC,EAC5B,CAAC;YACC,MAAM,IAAI,+BAAsB,CAAC,gDAAgD,CAAC,CAAC;QACvF,CAAC;IACL,CAAC;CACJ;AArBD,oDAqBC;AAGD,MAAM,gBAAgB;IAEL;IACA;IACA;IAHb,YACa,OAAuB,EACvB,MAAwB,EACxB,SAAiB;QAFjB,YAAO,GAAP,OAAO,CAAgB;QACvB,WAAM,GAAN,MAAM,CAAkB;QACxB,cAAS,GAAT,SAAS,CAAQ;IAC3B,CAAC;CACP;AAED,MAAM,WAAW;IAGA;IACA;IACA;IAJb,WAAW,GAAe,GAAG,EAAE,GAAE,CAAC,CAAC;IACnC,YACa,OAAuB,EACvB,OAAkC,EAClC,MAA8B;QAF9B,YAAO,GAAP,OAAO,CAAgB;QACvB,YAAO,GAAP,OAAO,CAA2B;QAClC,WAAM,GAAN,MAAM,CAAwB;IACxC,CAAC;CACP;AAED,2FAA2F;AAC3F,MAAa,aAAa;IAUD;IACA;IAVJ,OAAO,GAAG,IAAI,GAAG,EAAuB,CAAC;IACzC,WAAW,GAAG,IAAI,GAAG,EAA4B,CAAC;IAClD,cAAc,GAAG,IAAI,GAAG,EAAU,CAAC;IACnC,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IACrC,OAAO,CAA8C;IACrD,MAAM,CAAS;IACN,WAAW,CAAa;IAEzC,YACqB,SAAuB,EACvB,OAA6B;QAD7B,cAAS,GAAT,SAAS,CAAc;QACvB,YAAO,GAAP,OAAO,CAAsB;QAE9C,IAAI,CAAC,WAAW,GAAG,SAAS,CAAC,SAAS,CAClC,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAClC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,iBAAiB,CAAC,sBAAsB,EAAE,KAAK,CAAC,CAAC,EAC1E,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,iBAAiB,CAAC,uBAAuB,EAAE,KAAK,CAAC,CAAC,CAC9E,CAAC;IACN,CAAC;IAED,0FAA0F;IAC1F,UAAU,CAAC,OAAmD;QAC1D,IAAI,IAAI,CAAC,OAAO;YACZ,MAAM,IAAI,+BAAsB,CAAC,4CAA4C,CAAC,CAAC;QACnF,IAAI,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,CAAC,MAAM,CAAC;QACnC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IAC3B,CAAC;IAED,UAAU,CAAC,MAAuB;QAC9B,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;QACjC,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YACpB,MAAM,IAAI,+BAAsB,CAAC,yCAAyC,CAAC,CAAC;QAChF,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACrB,OAAO,IAAI,4BAAc,CAAC,MAAM,EAAE,IAAI,IAAI,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACtE,CAAC;IAED,OAAO,CAAC,OAAmB;QACvB,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACpD,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC;YACxC,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,+BAAsB,CAAC,4BAA4B,CAAC,CAAC,CAAC;QACpF,OAAO,IAAI,OAAO,CAAW,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC7C,MAAM,OAAO,GAAG,IAAI,WAAW,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;YAClE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YAClD,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,EAAE;gBACvD,IAAI,CAAC,MAAM,CACP,OAAO,CAAC,OAAO,CAAC,MAAM,EACtB,IAAI,yCAAmB,CACnB,IAAI,CAAC,OAAO,CAAC,SAAS;gBACtB,4EAA4E;gBAC5E,2EAA2E;gBAC3E,IAAI,0BAAW,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,QAAQ,EAAE,2BAAK,EAAE,SAAS,CAAC,CACrE,EACD,SAAS,CACZ,CAAC;YACN,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAC3B,qFAAqF;YACrF,KAAK,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;gBACpC,IAAI,CAAC,MAAM,CACP,OAAO,CAAC,OAAO,CAAC,MAAM,EACtB,IAAI,iBAAiB,CAAC,iBAAiB,EAAE,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EACpE,UAAU,CACb,CAAC;YACN,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;IACP,CAAC;IAED,OAAO;QACH,IAAI,CAAC,IAAI,CAAC,IAAI,iBAAiB,CAAC,yBAAyB,CAAC,CAAC,CAAC;QAC5D,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;IAC3B,CAAC;IAEO,KAAK,CAAC,IAAI,CAAC,OAAmB;QAClC,IAAI,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,CAAC,MAAM,CAAC;QACnC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACrC,IAAI,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,oBAAoB;YAC/C,MAAM,IAAI,+BAAsB,CAAC,sCAAsC,CAAC,CAAC;QAC7E,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;IAEO,OAAO,CAAC,IAAY;QACxB,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO;QACxB,sJAAsJ;QACtJ,IAAI,CAAC;YACD,IAAI,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,oBAAoB;gBAC/C,MAAM,IAAI,+BAAsB,CAAC,sCAAsC,CAAC,CAAC;YAC7E,MAAM,OAAO,GAAG,yBAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACxC,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;gBAC7B,IAAI,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC;oBAC/C,MAAM,IAAI,+BAAsB,CAAC,8BAA8B,CAAC,CAAC;gBACrE,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;gBAChD,KAAK,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;gBACpF,OAAO;YACX,CAAC;YACD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YACzD,2FAA2F;YAC3F,IAAI,CAAC,OAAO,EAAE,CAAC;gBACX,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;gBACzD,OAAO;YACX,CAAC;YACD,IAAI,CAAC,yBAAW,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC;gBAC1D,MAAM,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;YAC1D,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YAC5C,OAAO,CAAC,WAAW,EAAE,CAAC;YACtB,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;YAC3C,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAC7B,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACpB,MAAM,KAAK,GAAG,IAAA,oBAAO,EAAC,GAAG,CAAC,CAAC;YAC3B,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;QAC1C,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,QAAQ,CAAC,OAAmB;QACtC,IAAI,KAAe,CAAC;QACpB,sJAAsJ;QACtJ,IAAI,CAAC;YACD,IAAI,CAAC,IAAI,CAAC,OAAO;gBACb,MAAM,IAAI,iCAAwB,CAAC,iCAAiC,CAAC,CAAC;YAC1E,KAAK,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YACpC,IAAI,CAAC,yBAAW,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC;gBACxD,MAAM,IAAI,+BAAsB,CAAC,wCAAwC,CAAC,CAAC;QACnF,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACpB,MAAM,KAAK,GAAG,IAAA,oBAAO,EAAC,GAAG,CAAC,CAAC;YAC3B,4FAA4F;YAC5F,sFAAsF;YACtF,0FAA0F;YAC1F,kBAAkB;YAClB,KAAK,GAAG,IAAI,wBAAU,CAAC,OAAO,CAAC,OAAO,EAAE,yBAAW,CAAC,kBAAkB,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC5F,CAAC;gBAAS,CAAC;YACP,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACvD,CAAC;QACD,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3B,CAAC;IAEO,MAAM,CAAC,EAAU,EAAE,KAAY,EAAE,MAAwB;QAC7D,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACrC,IAAI,CAAC,OAAO;YAAE,OAAO;QACrB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACxB,OAAO,CAAC,WAAW,EAAE,CAAC;QACtB,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACvC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC;IAEO,QAAQ,CAAC,OAAuB,EAAE,MAAwB;QAC9D,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACxC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACxF,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,sBAAsB,EAAE,CAAC;YACjE,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;YACpD,IAAI,OAAO,MAAM,KAAK,QAAQ;gBAAE,OAAO;YACvC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACpC,CAAC;IACL,CAAC;IAEO,cAAc,CAAC,KAAe;QAClC,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC5D,IAAI,cAAc,GAAG,SAAS,CAAC;QAC/B,IAAI,QAAQ,EAAE,CAAC;YACX,cAAc,GAAG,yBAAW,CAAC,WAAW,CAAC,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC;gBACrE,CAAC,CAAC,QAAQ,CAAC,MAAM,KAAK,SAAS;oBAC3B,CAAC,CAAC,SAAS;oBACX,CAAC,CAAC,mBAAmB;gBACzB,CAAC,CAAC,wBAAwB,CAAC;QACnC,CAAC;QACD,MAAM,UAAU,GAAG,QAAQ;YACvB,CAAC,CAAC,aAAa,QAAQ,CAAC,MAAM,UAAU,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,EAAE;YAC9F,CAAC,CAAC,EAAE,CAAC;QACT,OAAO,IAAI,+BAAsB,CAC7B,4CAA4C,cAAc,GAAG,UAAU,IAAI,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CACrH,CAAC;IACN,CAAC;IAEO,gBAAgB,CAAC,KAAe,EAAE,QAAwB;QAC9D,OAAO,IAAI,+BAAsB,CAC7B,uEAAuE;YACnE,GAAG,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,OAAO,CAAC,iBAAiB,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAC/F,CAAC;IACN,CAAC;IAEO,iBAAiB,CAAC,OAAuB;QAC7C,OAAO,CACH,UAAU,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG;YAChF,gBAAgB,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,YAAY,IAAI,IAAI,CAAC,GAAG;YAC/D,gBAAgB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAC9D,CAAC;IACN,CAAC;IAEO,IAAI,CAAC,KAAY;QACrB,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO;QACxB,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE;YAAE,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC;QACzE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACtC,CAAC;CACJ;AAhMD,sCAgMC;AAED,MAAa,SAAS;IAClB,6QAA6Q;IAC7Q,MAAM,CAAC,SAAS,CAAC,KAAc;QAC3B,OAAO,KAAK,YAAY,KAAK;YACzB,CAAC,CAAC,KAAK;YACP,CAAC,CAAC,IAAI,+BAAsB,CAAC,mCAAmC,CAAC,CAAC;IAC1E,CAAC;CACJ;AAPD,8BAOC","sourcesContent":["import { toError } from '../lib/errorUtils';\nimport { ApiCallTimeoutError } from '../http/ApiCallTimeoutError';\nimport { CallContext } from '../http/CallStrategy';\nimport { WRITE } from '../http/HttpEndpointOptions';\nimport { ApiEndpointNotFoundError, ApiImplementationError } from '../errors';\nimport { IpcRegistry } from './IpcRegistry';\nimport {\n IpcCallContext,\n IpcFailure,\n IpcMessage,\n IpcReply,\n IpcRequest,\n IpcProtocol,\n} from './IpcProtocol';\n\n/** A local connection failed, distinct from a remote implementation's semantic ApiError. */\nexport class IpcTransportError extends Error {\n constructor(message: string, cause?: Error) {\n super(message, { cause });\n this.name = 'IpcTransportError';\n }\n}\n\n/** Implement this at the host transport boundary; no vendor or platform declarations leak out. */\nexport interface IpcTransport {\n send(message: string): Promise<void> | void;\n subscribe(\n receive: (message: string) => void,\n failed: (error: Error) => void,\n closed: (error: Error) => void,\n ): () => void;\n close(): void;\n}\nexport interface IpcScheduler {\n schedule(callback: () => void, delayMs: number): () => void;\n}\nexport interface IpcErrorOwner {\n report(error: Error): void;\n}\nexport class IpcConnectionOptions {\n constructor(\n readonly timeoutMs: number,\n readonly nextId: () => string,\n readonly scheduler: IpcScheduler,\n readonly errors: IpcErrorOwner,\n readonly maxMessageCharacters = 1_000_000,\n readonly settlementHistoryLimit = 100,\n readonly connectionId = 'unspecified',\n ) {\n if (\n !Number.isFinite(timeoutMs) ||\n timeoutMs <= 0 ||\n !Number.isSafeInteger(maxMessageCharacters) ||\n maxMessageCharacters < 1 ||\n !Number.isSafeInteger(settlementHistoryLimit) ||\n settlementHistoryLimit < 1\n ) {\n throw new ApiImplementationError('IPC timeout and message limit must be positive');\n }\n }\n}\n\ntype SettlementReason = 'resolved' | 'expired' | 'rejected';\nclass SettlementRecord {\n constructor(\n readonly context: IpcCallContext,\n readonly reason: SettlementReason,\n readonly settledAt: number,\n ) {}\n}\n\nclass PendingCall {\n cancelTimer: () => void = () => {};\n constructor(\n readonly context: IpcCallContext,\n readonly resolve: (reply: IpcReply) => void,\n readonly reject: (error: Error) => void,\n ) {}\n}\n\n/** One connection owns both directions, one dispatcher, and all pending-call lifetimes. */\nexport class IpcConnection {\n private readonly pending = new Map<string, PendingCall>();\n private readonly settlements = new Map<string, SettlementRecord>();\n private readonly activeRequests = new Set<string>();\n private readonly usedIds = new Set<string>();\n private handler?: (request: IpcRequest) => Promise<IpcReply>;\n private closed?: Error;\n private readonly unsubscribe: () => void;\n\n constructor(\n private readonly transport: IpcTransport,\n private readonly options: IpcConnectionOptions,\n ) {\n this.unsubscribe = transport.subscribe(\n (message) => this.receive(message),\n (error) => this.fail(new IpcTransportError('IPC transport failed', error)),\n (error) => this.fail(new IpcTransportError('IPC connection closed', error)),\n );\n }\n\n /** Install exactly one factory dispatcher BEFORE exposing this connection to the peer. */\n setHandler(handler: (request: IpcRequest) => Promise<IpcReply>): void {\n if (this.handler)\n throw new ApiImplementationError('An IPC connection already has a dispatcher');\n if (this.closed) throw this.closed;\n this.handler = handler;\n }\n\n newContext(parent?: IpcCallContext): IpcCallContext {\n const id = this.options.nextId();\n if (this.usedIds.has(id))\n throw new ApiImplementationError('IPC identity generator reused a call ID');\n this.usedIds.add(id);\n return new IpcCallContext(parent?.txId ?? id, id, parent?.callId);\n }\n\n request(request: IpcRequest): Promise<IpcReply> {\n if (this.closed) return Promise.reject(this.closed);\n if (this.pending.has(request.context.callId))\n return Promise.reject(new ApiImplementationError('Duplicate pending IPC call'));\n return new Promise<IpcReply>((resolve, reject) => {\n const pending = new PendingCall(request.context, resolve, reject);\n this.pending.set(request.context.callId, pending);\n pending.cancelTimer = this.options.scheduler.schedule(() => {\n this.settle(\n request.context.callId,\n new ApiCallTimeoutError(\n this.options.timeoutMs,\n // IPC contracts declare no @Endpoint operation, so the deadline reports the\n // conservative WRITE: the user is told to check before repeating the call.\n new CallContext(request.apiId, request.methodId, WRITE, undefined),\n ),\n 'expired',\n );\n }, this.options.timeoutMs);\n // This owner observes every async send rejection; a send failure is never a timeout.\n void this.send(request).catch((error) => {\n this.settle(\n request.context.callId,\n new IpcTransportError('IPC send failed', IpcErrors.normalize(error)),\n 'rejected',\n );\n });\n });\n }\n\n dispose(): void {\n this.fail(new IpcTransportError('IPC connection disposed'));\n this.unsubscribe();\n this.transport.close();\n }\n\n private async send(message: IpcMessage): Promise<void> {\n if (this.closed) throw this.closed;\n const json = JSON.stringify(message);\n if (json.length > this.options.maxMessageCharacters)\n throw new ApiImplementationError('IPC message exceeds configured limit');\n await this.transport.send(json);\n }\n\n private receive(json: string): void {\n if (this.closed) return;\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- transport boundary rejects pending calls or encodes a failure that the client throws\n try {\n if (json.length > this.options.maxMessageCharacters)\n throw new ApiImplementationError('IPC message exceeds configured limit');\n const message = IpcProtocol.parse(json);\n if (message.type === 'request') {\n if (this.activeRequests.has(message.context.callId))\n throw new ApiImplementationError('Duplicate active IPC request');\n this.activeRequests.add(message.context.callId);\n void this.dispatch(message).catch((error) => this.fail(IpcErrors.normalize(error)));\n return;\n }\n const pending = this.pending.get(message.context.callId);\n // Late or unsolicited replies are reported, never resolve a different call or replay work.\n if (!pending) {\n this.options.errors.report(this.lateReplyError(message));\n return;\n }\n if (!IpcProtocol.sameContext(pending.context, message.context))\n throw this.correlationError(message, pending.context);\n this.pending.delete(message.context.callId);\n pending.cancelTimer();\n this.remember(pending.context, 'resolved');\n pending.resolve(message);\n } catch (err: unknown) {\n const error = toError(err);\n this.fail(IpcErrors.normalize(error));\n }\n }\n\n private async dispatch(request: IpcRequest): Promise<void> {\n let reply: IpcReply;\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- transport boundary rejects pending calls or encodes a failure that the client throws\n try {\n if (!this.handler)\n throw new ApiEndpointNotFoundError('IPC dispatcher is not installed');\n reply = await this.handler(request);\n if (!IpcProtocol.sameContext(request.context, reply.context))\n throw new ApiImplementationError('IPC handler reply correlation mismatch');\n } catch (err: unknown) {\n const error = toError(err);\n // The ONE app-reachable seam for an outbound IPC failure. The webpieces default applies the\n // same `ApiErrorBoundary` publication rule this used to call inline — notably that an\n // `ApiConnectionError` publishes as `implementation`, because to the PEER this process is\n // what is broken.\n reply = new IpcFailure(request.context, IpcRegistry.getErrorTranslator().toWire(error));\n } finally {\n this.activeRequests.delete(request.context.callId);\n }\n await this.send(reply);\n }\n\n private settle(id: string, error: Error, reason: SettlementReason): void {\n const pending = this.pending.get(id);\n if (!pending) return;\n this.pending.delete(id);\n pending.cancelTimer();\n this.remember(pending.context, reason);\n pending.reject(error);\n }\n\n private remember(context: IpcCallContext, reason: SettlementReason): void {\n this.settlements.delete(context.callId);\n this.settlements.set(context.callId, new SettlementRecord(context, reason, Date.now()));\n while (this.settlements.size > this.options.settlementHistoryLimit) {\n const oldest = this.settlements.keys().next().value;\n if (typeof oldest !== 'string') return;\n this.settlements.delete(oldest);\n }\n }\n\n private lateReplyError(reply: IpcReply): ApiImplementationError {\n const previous = this.settlements.get(reply.context.callId);\n let classification = 'unknown';\n if (previous) {\n classification = IpcProtocol.sameContext(previous.context, reply.context)\n ? previous.reason === 'expired'\n ? 'expired'\n : 'duplicate-settled'\n : 'correlation-mismatched';\n }\n const settlement = previous\n ? ` terminal=${previous.reason} ageMs=${String(Math.max(0, Date.now() - previous.settledAt))}`\n : '';\n return new ApiImplementationError(\n `Late or unknown IPC reply classification=${classification}${settlement} ${this.correlationFields(reply.context)}`,\n );\n }\n\n private correlationError(reply: IpcReply, expected: IpcCallContext): ApiImplementationError {\n return new ApiImplementationError(\n `IPC reply correlation mismatch classification=correlation-mismatched ` +\n `${this.correlationFields(reply.context)} expectedTxId=${JSON.stringify(expected.txId)}`,\n );\n }\n\n private correlationFields(context: IpcCallContext): string {\n return (\n `callId=${JSON.stringify(context.callId)} txId=${JSON.stringify(context.txId)} ` +\n `parentCallId=${JSON.stringify(context.parentCallId ?? null)} ` +\n `connectionId=${JSON.stringify(this.options.connectionId)}`\n );\n }\n\n private fail(error: Error): void {\n if (this.closed) return;\n this.closed = error;\n for (const id of this.pending.keys()) this.settle(id, error, 'rejected');\n this.options.errors.report(error);\n }\n}\n\nexport class IpcErrors {\n // webpieces-disable no-function-outside-class -- portable stateless IPC primitive; no platform DI container exists on this boundary; webpieces-disable no-any-unknown -- untrusted IPC data is schema-validated; generic dispatch cannot assume a DTO type before validation\n static normalize(value: unknown): Error {\n return value instanceof Error\n ? value\n : new ApiImplementationError('IPC failed with a non-Error value');\n }\n}\n"]}
1
+ {"version":3,"file":"IpcConnection.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/ipc/IpcConnection.ts"],"names":[],"mappings":"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","sourcesContent":["import { toError } from '../lib/errorUtils';\nimport { ApiCallTimeoutError } from '../http/ApiCallTimeoutError';\nimport { CallContext } from '../http/CallStrategy';\nimport { WRITE } from '../http/HttpEndpointOptions';\nimport { ApiEndpointNotFoundError, ApiImplementationError } from '../errors';\nimport { IpcRegistry } from './IpcRegistry';\nimport {\n IpcCallContext,\n IpcFailure,\n IpcMessage,\n IpcReply,\n IpcRequest,\n IpcProtocol,\n} from './IpcProtocol';\n\n/** A local connection failed, distinct from a remote implementation's semantic ApiError. */\nexport class IpcTransportError extends Error {\n constructor(message: string, cause?: Error) {\n super(message, { cause });\n this.name = 'IpcTransportError';\n }\n}\n\n/** Implement this at the host transport boundary; no vendor or platform declarations leak out. */\nexport interface IpcTransport {\n send(message: string): Promise<void> | void;\n subscribe(\n receive: (message: string) => void,\n failed: (error: Error) => void,\n closed: (error: Error) => void,\n ): () => void;\n close(): void;\n}\nexport interface IpcScheduler {\n schedule(callback: () => void, delayMs: number): () => void;\n}\nexport interface IpcErrorOwner {\n report(error: Error): void;\n}\nexport class IpcConnectionOptions {\n constructor(\n readonly timeoutMs: number,\n readonly nextId: () => string,\n readonly scheduler: IpcScheduler,\n readonly errors: IpcErrorOwner,\n readonly maxMessageCharacters = 1_000_000,\n readonly settlementHistoryLimit = 100,\n readonly connectionId = 'unspecified',\n ) {\n if (\n !Number.isFinite(timeoutMs) ||\n timeoutMs <= 0 ||\n !Number.isSafeInteger(maxMessageCharacters) ||\n maxMessageCharacters < 1 ||\n !Number.isSafeInteger(settlementHistoryLimit) ||\n settlementHistoryLimit < 1\n ) {\n throw new ApiImplementationError('IPC timeout and message limit must be positive');\n }\n }\n}\n\ntype SettlementReason = 'resolved' | 'expired' | 'rejected';\nclass SettlementRecord {\n constructor(\n readonly context: IpcCallContext,\n readonly reason: SettlementReason,\n readonly settledAt: number,\n ) {}\n}\n\nclass PendingCall {\n cancelTimer: () => void = () => {};\n constructor(\n readonly context: IpcCallContext,\n readonly resolve: (reply: IpcReply) => void,\n readonly reject: (error: Error) => void,\n ) {}\n}\n\n/** One connection owns both directions, one dispatcher, and all pending-call lifetimes. */\nexport class IpcConnection {\n private readonly pending = new Map<string, PendingCall>();\n private readonly settlements = new Map<string, SettlementRecord>();\n private readonly activeRequests = new Set<string>();\n private readonly usedIds = new Set<string>();\n private handler?: (request: IpcRequest) => Promise<IpcReply>;\n private closed?: Error;\n private readonly unsubscribe: () => void;\n\n constructor(\n private readonly transport: IpcTransport,\n private readonly options: IpcConnectionOptions,\n ) {\n this.unsubscribe = transport.subscribe(\n (message) => this.receive(message),\n (error) => this.fail(new IpcTransportError('IPC transport failed', error)),\n (error) => this.fail(new IpcTransportError('IPC connection closed', error)),\n );\n }\n\n /** Install exactly one factory dispatcher BEFORE exposing this connection to the peer. */\n setHandler(handler: (request: IpcRequest) => Promise<IpcReply>): void {\n if (this.handler)\n throw new ApiImplementationError('An IPC connection already has a dispatcher');\n if (this.closed) throw this.closed;\n this.handler = handler;\n }\n\n newContext(parent?: IpcCallContext): IpcCallContext {\n const id = this.options.nextId();\n if (this.usedIds.has(id))\n throw new ApiImplementationError('IPC identity generator reused a call ID');\n this.usedIds.add(id);\n return new IpcCallContext(parent?.txId ?? id, id, parent?.callId);\n }\n\n /**\n * Send one request and await its reply. `contract` is the `@WpInternal` contract CLASS the client\n * proxy was created for: the wire carries only the string `apiId`, so the class rides beside the\n * request and keys the deadline's {@link CallContext} onto the `CallScope` ladder — an IPC timeout\n * reaches the classifier registered for THIS contract, exactly like HTTP and Cloud Tasks.\n */\n request(request: IpcRequest, contract: Function): Promise<IpcReply> {\n if (this.closed) return Promise.reject(this.closed);\n if (this.pending.has(request.context.callId))\n return Promise.reject(new ApiImplementationError('Duplicate pending IPC call'));\n return new Promise<IpcReply>((resolve, reject) => {\n const pending = new PendingCall(request.context, resolve, reject);\n this.pending.set(request.context.callId, pending);\n pending.cancelTimer = this.options.scheduler.schedule(() => {\n this.settle(\n request.context.callId,\n new ApiCallTimeoutError(\n this.options.timeoutMs,\n // IPC contracts declare no @Endpoint operation, so the deadline reports the\n // conservative WRITE: the user is told to check before repeating the call.\n new CallContext(request.apiId, request.methodId, WRITE, contract),\n ),\n 'expired',\n );\n }, this.options.timeoutMs);\n // This owner observes every async send rejection; a send failure is never a timeout.\n void this.send(request).catch((error) => {\n this.settle(\n request.context.callId,\n new IpcTransportError('IPC send failed', IpcErrors.normalize(error)),\n 'rejected',\n );\n });\n });\n }\n\n dispose(): void {\n this.fail(new IpcTransportError('IPC connection disposed'));\n this.unsubscribe();\n this.transport.close();\n }\n\n private async send(message: IpcMessage): Promise<void> {\n if (this.closed) throw this.closed;\n const json = JSON.stringify(message);\n if (json.length > this.options.maxMessageCharacters)\n throw new ApiImplementationError('IPC message exceeds configured limit');\n await this.transport.send(json);\n }\n\n private receive(json: string): void {\n if (this.closed) return;\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- transport boundary rejects pending calls or encodes a failure that the client throws\n try {\n if (json.length > this.options.maxMessageCharacters)\n throw new ApiImplementationError('IPC message exceeds configured limit');\n const message = IpcProtocol.parse(json);\n if (message.type === 'request') {\n if (this.activeRequests.has(message.context.callId))\n throw new ApiImplementationError('Duplicate active IPC request');\n this.activeRequests.add(message.context.callId);\n void this.dispatch(message).catch((error) => this.fail(IpcErrors.normalize(error)));\n return;\n }\n const pending = this.pending.get(message.context.callId);\n // Late or unsolicited replies are reported, never resolve a different call or replay work.\n if (!pending) {\n this.options.errors.report(this.lateReplyError(message));\n return;\n }\n if (!IpcProtocol.sameContext(pending.context, message.context))\n throw this.correlationError(message, pending.context);\n this.pending.delete(message.context.callId);\n pending.cancelTimer();\n this.remember(pending.context, 'resolved');\n pending.resolve(message);\n } catch (err: unknown) {\n const error = toError(err);\n this.fail(IpcErrors.normalize(error));\n }\n }\n\n private async dispatch(request: IpcRequest): Promise<void> {\n let reply: IpcReply;\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- transport boundary rejects pending calls or encodes a failure that the client throws\n try {\n if (!this.handler)\n throw new ApiEndpointNotFoundError('IPC dispatcher is not installed');\n reply = await this.handler(request);\n if (!IpcProtocol.sameContext(request.context, reply.context))\n throw new ApiImplementationError('IPC handler reply correlation mismatch');\n } catch (err: unknown) {\n const error = toError(err);\n // The ONE app-reachable seam for an outbound IPC failure. The webpieces default applies the\n // same `ApiErrorBoundary` publication rule this used to call inline — notably that an\n // `ApiConnectionError` publishes as `implementation`, because to the PEER this process is\n // what is broken.\n reply = new IpcFailure(request.context, IpcRegistry.getErrorTranslator().toWire(error));\n } finally {\n this.activeRequests.delete(request.context.callId);\n }\n await this.send(reply);\n }\n\n private settle(id: string, error: Error, reason: SettlementReason): void {\n const pending = this.pending.get(id);\n if (!pending) return;\n this.pending.delete(id);\n pending.cancelTimer();\n this.remember(pending.context, reason);\n pending.reject(error);\n }\n\n private remember(context: IpcCallContext, reason: SettlementReason): void {\n this.settlements.delete(context.callId);\n this.settlements.set(context.callId, new SettlementRecord(context, reason, Date.now()));\n while (this.settlements.size > this.options.settlementHistoryLimit) {\n const oldest = this.settlements.keys().next().value;\n if (typeof oldest !== 'string') return;\n this.settlements.delete(oldest);\n }\n }\n\n private lateReplyError(reply: IpcReply): ApiImplementationError {\n const previous = this.settlements.get(reply.context.callId);\n let classification = 'unknown';\n if (previous) {\n classification = IpcProtocol.sameContext(previous.context, reply.context)\n ? previous.reason === 'expired'\n ? 'expired'\n : 'duplicate-settled'\n : 'correlation-mismatched';\n }\n const settlement = previous\n ? ` terminal=${previous.reason} ageMs=${String(Math.max(0, Date.now() - previous.settledAt))}`\n : '';\n return new ApiImplementationError(\n `Late or unknown IPC reply classification=${classification}${settlement} ${this.correlationFields(reply.context)}`,\n );\n }\n\n private correlationError(reply: IpcReply, expected: IpcCallContext): ApiImplementationError {\n return new ApiImplementationError(\n `IPC reply correlation mismatch classification=correlation-mismatched ` +\n `${this.correlationFields(reply.context)} expectedTxId=${JSON.stringify(expected.txId)}`,\n );\n }\n\n private correlationFields(context: IpcCallContext): string {\n return (\n `callId=${JSON.stringify(context.callId)} txId=${JSON.stringify(context.txId)} ` +\n `parentCallId=${JSON.stringify(context.parentCallId ?? null)} ` +\n `connectionId=${JSON.stringify(this.options.connectionId)}`\n );\n }\n\n private fail(error: Error): void {\n if (this.closed) return;\n this.closed = error;\n for (const id of this.pending.keys()) this.settle(id, error, 'rejected');\n this.options.errors.report(error);\n }\n}\n\nexport class IpcErrors {\n // webpieces-disable no-function-outside-class -- portable stateless IPC primitive; no platform DI container exists on this boundary; webpieces-disable no-any-unknown -- untrusted IPC data is schema-validated; generic dispatch cannot assume a DTO type before validation\n static normalize(value: unknown): Error {\n return value instanceof Error\n ? value\n : new ApiImplementationError('IPC failed with a non-Error value');\n }\n}\n"]}
@@ -7,5 +7,7 @@ export interface IpcLogging {
7
7
  context(call: IpcCallContext): ApiCallContext;
8
8
  }
9
9
  export declare class IpcCallLogger {
10
- static execute<Q, R>(logging: IpcLogging, context: IpcCallContext, side: ApiSide, apiId: string, methodId: string, mask: MaskSpec, request: Q, invoke: (request: Q) => Promise<R>): Promise<R>;
10
+ static execute<Q, R>(logging: IpcLogging, context: IpcCallContext, side: ApiSide,
11
+ /** The `@WpInternal` contract CLASS — the `CallScope` ladder key (see {@link ApiMethodInfo.contract}). */
12
+ contract: Function, apiId: string, methodId: string, mask: MaskSpec, request: Q, invoke: (request: Q) => Promise<R>): Promise<R>;
11
13
  }
@@ -5,8 +5,10 @@ const LogApiCall_1 = require("../http/LogApiCall");
5
5
  const ApiMethodInfo_1 = require("../http/ApiMethodInfo");
6
6
  class IpcCallLogger {
7
7
  // webpieces-disable no-function-outside-class -- portable stateless IPC primitive; no platform DI container exists on this boundary
8
- static execute(logging, context, side, apiId, methodId, mask, request, invoke) {
9
- return new LogApiCall_1.LogApiCallImpl(logging.context(context)).execute(new ApiMethodInfo_1.ApiMethodInfo(side, apiId, methodId, undefined, undefined, mask), request, invoke);
8
+ static execute(logging, context, side,
9
+ /** The `@WpInternal` contract CLASS — the `CallScope` ladder key (see {@link ApiMethodInfo.contract}). */
10
+ contract, apiId, methodId, mask, request, invoke) {
11
+ return new LogApiCall_1.LogApiCallImpl(logging.context(context)).execute(new ApiMethodInfo_1.ApiMethodInfo(side, apiId, methodId, contract, undefined, mask), request, invoke);
10
12
  }
11
13
  }
12
14
  exports.IpcCallLogger = IpcCallLogger;
@@ -1 +1 @@
1
- {"version":3,"file":"IpcLogging.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/ipc/IpcLogging.ts"],"names":[],"mappings":";;;AACA,mDAAoD;AACpD,yDAA+D;AAS/D,MAAa,aAAa;IACtB,oIAAoI;IACpI,MAAM,CAAC,OAAO,CACV,OAAmB,EACnB,OAAuB,EACvB,IAAa,EACb,KAAa,EACb,QAAgB,EAChB,IAAc,EACd,OAAU,EACV,MAAkC;QAElC,OAAO,IAAI,2BAAc,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CACvD,IAAI,6BAAa,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,EACpE,OAAO,EACP,MAAM,CACK,CAAC;IACpB,CAAC;CACJ;AAlBD,sCAkBC","sourcesContent":["import { ApiCallContext } from '../http/ApiCallContext';\nimport { LogApiCallImpl } from '../http/LogApiCall';\nimport { ApiMethodInfo, ApiSide } from '../http/ApiMethodInfo';\nimport { MaskSpec } from '../http/LogFieldMask';\nimport { IpcCallContext } from './IpcProtocol';\n\n/** Hosts bind correlation to a per-call logging context; never keep mutable context across awaits. */\nexport interface IpcLogging {\n context(call: IpcCallContext): ApiCallContext;\n}\n\nexport class IpcCallLogger {\n // webpieces-disable no-function-outside-class -- portable stateless IPC primitive; no platform DI container exists on this boundary\n static execute<Q, R>(\n logging: IpcLogging,\n context: IpcCallContext,\n side: ApiSide,\n apiId: string,\n methodId: string,\n mask: MaskSpec,\n request: Q,\n invoke: (request: Q) => Promise<R>,\n ): Promise<R> {\n return new LogApiCallImpl(logging.context(context)).execute(\n new ApiMethodInfo(side, apiId, methodId, undefined, undefined, mask),\n request,\n invoke,\n ) as Promise<R>;\n }\n}\n"]}
1
+ {"version":3,"file":"IpcLogging.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/ipc/IpcLogging.ts"],"names":[],"mappings":";;;AACA,mDAAoD;AACpD,yDAA+D;AAS/D,MAAa,aAAa;IACtB,oIAAoI;IACpI,MAAM,CAAC,OAAO,CACV,OAAmB,EACnB,OAAuB,EACvB,IAAa;IACb,0GAA0G;IAC1G,QAAkB,EAClB,KAAa,EACb,QAAgB,EAChB,IAAc,EACd,OAAU,EACV,MAAkC;QAElC,OAAO,IAAI,2BAAc,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CACvD,IAAI,6BAAa,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,CAAC,EACnE,OAAO,EACP,MAAM,CACK,CAAC;IACpB,CAAC;CACJ;AApBD,sCAoBC","sourcesContent":["import { ApiCallContext } from '../http/ApiCallContext';\nimport { LogApiCallImpl } from '../http/LogApiCall';\nimport { ApiMethodInfo, ApiSide } from '../http/ApiMethodInfo';\nimport { MaskSpec } from '../http/LogFieldMask';\nimport { IpcCallContext } from './IpcProtocol';\n\n/** Hosts bind correlation to a per-call logging context; never keep mutable context across awaits. */\nexport interface IpcLogging {\n context(call: IpcCallContext): ApiCallContext;\n}\n\nexport class IpcCallLogger {\n // webpieces-disable no-function-outside-class -- portable stateless IPC primitive; no platform DI container exists on this boundary\n static execute<Q, R>(\n logging: IpcLogging,\n context: IpcCallContext,\n side: ApiSide,\n /** The `@WpInternal` contract CLASS — the `CallScope` ladder key (see {@link ApiMethodInfo.contract}). */\n contract: Function,\n apiId: string,\n methodId: string,\n mask: MaskSpec,\n request: Q,\n invoke: (request: Q) => Promise<R>,\n ): Promise<R> {\n return new LogApiCallImpl(logging.context(context)).execute(\n new ApiMethodInfo(side, apiId, methodId, contract, undefined, mask),\n request,\n invoke,\n ) as Promise<R>;\n }\n}\n"]}