@webpieces/core-util 0.4.790 → 0.4.791
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/README.md +1 -1
- package/package.json +1 -1
- package/src/errors/ReceivedApiErrorRule.d.ts +43 -0
- package/src/errors/ReceivedApiErrorRule.js +65 -0
- package/src/errors/ReceivedApiErrorRule.js.map +1 -0
- package/src/errors/index.d.ts +1 -0
- package/src/errors/index.js +3 -1
- package/src/errors/index.js.map +1 -1
- package/src/http/ClientRegistry.d.ts +29 -18
- package/src/http/ClientRegistry.js +37 -27
- package/src/http/ClientRegistry.js.map +1 -1
- package/src/http/ErrorTranslator.d.ts +115 -0
- package/src/http/{ErrorTranslators.js → ErrorTranslator.js} +1 -1
- package/src/http/ErrorTranslator.js.map +1 -0
- package/src/http/FailureClassifier.d.ts +1 -1
- package/src/http/FailureClassifier.js.map +1 -1
- package/src/http/HttpResponseDto.d.ts +1 -1
- package/src/http/HttpResponseDto.js +1 -1
- package/src/http/HttpResponseDto.js.map +1 -1
- package/src/http/ServiceInfo.d.ts +1 -1
- package/src/http/ServiceInfo.js +1 -1
- package/src/http/ServiceInfo.js.map +1 -1
- package/src/http/Surface.d.ts +39 -0
- package/src/http/Surface.js +28 -0
- package/src/http/Surface.js.map +1 -0
- package/src/http/WebpiecesCoreHeaders.d.ts +18 -0
- package/src/http/WebpiecesCoreHeaders.js +18 -0
- package/src/http/WebpiecesCoreHeaders.js.map +1 -1
- package/src/http/WebpiecesDefaultErrorTranslator.d.ts +70 -0
- package/src/http/WebpiecesDefaultErrorTranslator.js +136 -0
- package/src/http/WebpiecesDefaultErrorTranslator.js.map +1 -0
- package/src/index.d.ts +5 -1
- package/src/index.js +15 -3
- package/src/index.js.map +1 -1
- package/src/ipc/IpcConnection.js +6 -8
- package/src/ipc/IpcConnection.js.map +1 -1
- package/src/ipc/IpcErrorTranslator.d.ts +39 -0
- package/src/ipc/IpcErrorTranslator.js +3 -0
- package/src/ipc/IpcErrorTranslator.js.map +1 -0
- package/src/ipc/IpcRegistry.d.ts +55 -0
- package/src/ipc/IpcRegistry.js +73 -0
- package/src/ipc/IpcRegistry.js.map +1 -0
- package/src/ipc/WebpiecesDefaultIpcErrorTranslator.d.ts +28 -0
- package/src/ipc/WebpiecesDefaultIpcErrorTranslator.js +49 -0
- package/src/ipc/WebpiecesDefaultIpcErrorTranslator.js.map +1 -0
- package/src/ipc/index.d.ts +4 -0
- package/src/ipc/index.js +9 -1
- package/src/ipc/index.js.map +1 -1
- package/src/http/ErrorTranslators.d.ts +0 -106
- package/src/http/ErrorTranslators.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WebpiecesDefaultErrorTranslator.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/http/WebpiecesDefaultErrorTranslator.ts"],"names":[],"mappings":"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","sourcesContent":["import { ApiErrorBoundary } from '../errors/ApiErrorBoundary';\nimport { ApiErrorCodec } from '../errors/ApiErrorCodec';\nimport { ApiCodedError, ApiError } from '../errors/ApiError';\nimport { ReceivedApiErrorRule } from '../errors/ReceivedApiErrorRule';\nimport { ApiErrorHttpStatus, PublishedKind } from './ApiErrorHttpStatus';\nimport { ErrorTranslator } from './ErrorTranslator';\nimport { HttpHeader, HttpResponseDto, HttpResponseStatus } from './HttpResponseDto';\n\n/**\n * THE webpieces default {@link ErrorTranslator} — ONE class, BOTH halves, used by the node server, by\n * every node client and by the browser bundle alike.\n *\n * It is what {@link ClientRegistry.getErrorTranslator} holds until an app installs its own, and it is\n * what an app's own translator calls to DECLINE an error:\n *\n * ```ts\n * private readonly fallback = new WebpiecesDefaultErrorTranslator();\n * ```\n *\n * so \"no translator registered\" and \"a translator that does not claim this error\" produce\n * byte-identical output. It lives in core-util, beside {@link ClientRegistry}, because core-util is\n * the package every API contract already depends on and the only one both a server and a browser\n * bundle can reach. Both halves needed nothing else: the outbound half wants\n * {@link ApiErrorBoundary} + {@link ApiErrorHttpStatus}, the inbound half wants\n * {@link ApiErrorCodec} + {@link ReceivedApiErrorRule}, and all four were already here.\n *\n * Stateless, so {@link WEBPIECES_DEFAULT_ERROR_TRANSLATOR} is a shared instance — but constructing\n * your own costs nothing and reads better at a delegation site.\n */\nexport class WebpiecesDefaultErrorTranslator implements ErrorTranslator {\n private readonly boundary = new ApiErrorBoundary();\n\n private readonly genericMessages: Map<number, string> = new Map<number, string>([\n [266, 'End User Error'],\n [400, 'Bad Request'],\n [401, 'Unauthorized'],\n [403, 'Forbidden'],\n [404, 'Not Found'],\n [408, 'Request Timeout'],\n [409, 'Conflict'],\n [412, 'Precondition Failed'],\n [415, 'Unsupported Media Type'],\n [422, 'Unprocessable Content'],\n [429, 'Too Many Requests'],\n [500, 'Internal Server Error'],\n [501, 'Not Implemented'],\n [502, 'Bad Gateway'],\n [503, 'Service Unavailable'],\n [504, 'Gateway Timeout'],\n ]);\n\n /**\n * SERVER: an exception in, the exact HTTP response out.\n *\n * The payload IS the answer. {@link ApiErrorBoundary.encode} has already applied both shared\n * rules — a caller-local `ApiConnectionError` (and every non-`ApiError`) publishes as\n * `implementation`, and only an `ApiEndUserError`'s own message is disclosed — and the payload\n * carries everything HTTP needs after that: `kind`, `statusCode`, `edgeHttpStatus` and\n * `retryAfterSeconds`. So there is no `instanceof` here and nothing re-derived from the raw\n * error; unknown throws and caller-local failures come out as a 500 implementation failure\n * because that is what the payload says.\n *\n * An `ApiEndUserError` publishes 266 here, ALWAYS. Whether a particular REQUEST republishes that\n * as a real 4xx is a property of the CALLER, not of the error, so it is decided once per request\n * from `WebpiecesCoreHeaders.SURFACE` by the server boundary (`ExpressWrapper.handleError`) —\n * see {@link SurfaceEndUserStatus}. That is why this class takes no constructor argument any\n * more: the old `new ApiErrorHttpMapper('gui' | 'edge')` made every delegating app translator\n * responsible for repeating its router's mode, and repeating it wrongly was silent.\n */\n toWire(error: Error): HttpResponseDto {\n const payload = this.boundary.encode(error);\n // The boundary never publishes kind 'connection' — that is the whole first rule above — so\n // this is the published subset ApiErrorHttpStatus.codeFor accepts.\n const kind = payload.kind as PublishedKind;\n const status = ApiErrorHttpStatus.codeFor(kind, payload.statusCode);\n const headers =\n payload.retryAfterSeconds !== undefined\n ? [new HttpHeader('retry-after', String(payload.retryAfterSeconds))]\n : [];\n return new HttpResponseDto(\n new HttpResponseStatus(status, this.genericMessage(status)),\n headers,\n payload,\n );\n }\n\n /**\n * CLIENT: the response in, a THROW out — or a silent return for an ordinary success.\n *\n * Called for EVERY response, 2xx included (see {@link ErrorTranslator.fromWire}). A 2xx that is\n * not 266 is exactly the case where webpieces has nothing to say, so it returns and the caller\n * gets its DTO. Everything else throws, which is what lets `ProxyClient` call this and then simply\n * stop — a failure response can never fall through to a typed caller.\n *\n * The rule applied is {@link ReceivedApiErrorRule}, shared verbatim with IPC: 4xx is MY bug, 5xx\n * is THEIRS, an `ApiDependencyError` is already attributed and passes through, 266 is the end\n * user's own answer.\n */\n fromWire(response: HttpResponseDto): void {\n const code = response.status.code;\n if (code >= 200 && code < 300 && code !== 266) {\n return;\n }\n const decoded = this.decodeBody(response);\n const message = decoded?.message ?? this.fallbackMessage(response.body, response.status.reason);\n throw ReceivedApiErrorRule.adapt(code, message, decoded);\n }\n\n /** The reason phrase webpieces writes beside a status it chose itself. */\n genericMessage(code: number): string {\n return this.genericMessages.get(code) ?? 'Request Failed';\n }\n\n /**\n * A webpieces peer sends an {@link ApiErrorPayload}; a foreign responder sends anything at all.\n * The status is only believed when it AGREES with the kind the body claims — a body saying\n * `not-found` beside a 500 is a mismatched response, not a 404, and falls back to the status.\n */\n private decodeBody(response: HttpResponseDto): ApiError | undefined {\n if (!ApiErrorCodec.isPayload(response.body)) {\n return undefined;\n }\n const decoded = ApiErrorCodec.decode(response.body);\n if (!ApiErrorHttpStatus.hasCode(decoded)) {\n return undefined;\n }\n // `statusCode` is the 'coded' kind's own status, the one thing the shared table cannot know.\n const statusCode = decoded instanceof ApiCodedError ? decoded.statusCode : undefined;\n const declared = ApiErrorHttpStatus.codeFor(decoded.kind, statusCode);\n return declared === response.status.code ? decoded : undefined;\n }\n\n // webpieces-disable no-any-unknown -- HTTP response bodies are app-owned until this boundary safely inspects them\n private fallbackMessage(body: unknown, reason: string): string {\n if (typeof body === 'object' && body !== null) {\n const message = Object.getOwnPropertyDescriptor(body, 'message')?.value;\n if (typeof message === 'string' && message.length > 0) return message.slice(0, 4096);\n }\n return reason || 'Request Failed';\n }\n}\n\n/** Process-wide built-in instance — stateless, so one shared instance is enough. */\nexport const WEBPIECES_DEFAULT_ERROR_TRANSLATOR = new WebpiecesDefaultErrorTranslator();\n"]}
|
package/src/index.d.ts
CHANGED
|
@@ -56,7 +56,11 @@ export { ServiceInfo } from './http/ServiceInfo';
|
|
|
56
56
|
export { RuntimeLocality } from './http/RuntimeLocality';
|
|
57
57
|
export type { Locality } from './http/RuntimeLocality';
|
|
58
58
|
export { HttpHeader, HttpResponseStatus, HttpResponseDto } from './http/HttpResponseDto';
|
|
59
|
-
export type {
|
|
59
|
+
export type { ErrorTranslator } from './http/ErrorTranslator';
|
|
60
|
+
export { WebpiecesDefaultErrorTranslator, WEBPIECES_DEFAULT_ERROR_TRANSLATOR, } from './http/WebpiecesDefaultErrorTranslator';
|
|
61
|
+
export { SurfaceEndUserStatus } from './http/Surface';
|
|
62
|
+
export type { Surface } from './http/Surface';
|
|
63
|
+
export { ReceivedApiErrorRule } from './errors/ReceivedApiErrorRule';
|
|
60
64
|
export type { FailureClassifier } from './http/FailureClassifier';
|
|
61
65
|
export { KeyedFailureClassifier } from './http/FailureClassifier';
|
|
62
66
|
export { WebpiecesDefaultFailureClassifier, WEBPIECES_DEFAULT_FAILURE_CLASSIFIER, } from './http/WebpiecesDefaultFailureClassifier';
|
package/src/index.js
CHANGED
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
11
|
exports.getIpcEndpoints = exports.getIpcApiId = exports.isInternalApi = exports.WpIpcEndpoint = exports.WpInternal = exports.getHttpParameterDeclarations = exports.QueryParam = exports.PathParam = exports.METADATA_KEYS = exports.validateNoConflictingDecorators = exports.assertEveryWebhookEndpointRetainsRawBody = exports.assertEveryExternalEndpointDeclaresCaller = exports.assertEveryEndpointHasAuthMode = exports.getAuthMode = exports.getAuthMeta = exports.isApiPath = exports.isRawBody = exports.isFormPost = exports.getMaskSpec = exports.getEndpointKinds = exports.getEndpointKind = exports.getEndpointOptions = exports.getEndpoints = exports.getApiPath = exports.MaskLog = exports.WpAuthLocalOnly = exports.WpAuthApiKey = exports.WpAuthWebhook = exports.WpAuthSharedSecret = exports.WpAuthOidc = exports.MISSING_AUTH_DECORATOR_FIX = exports.rolesRequired = exports.WpAuthJwt = exports.WpAuthPublic = exports.Endpoint = exports.ApiPath = exports.GCP_LOG_BUDGET_BYTES = exports.MAX_GCP_LOG_BYTES = exports.LogChunkInfo = exports.LogChunkerImpl = exports.LogChunker = exports.LogManager = exports.ConsoleLoggerFactory = exports.ConsoleLogger = exports.DESIGN_METADATA_KEYS = exports.isDocumentDesign = exports.DocumentDesign = exports.ContextTuple = exports.ContextKey = exports.toError = void 0;
|
|
12
12
|
exports.getEndpointCaller = exports.isExternalSystemKind = exports.ExternalCaller = exports.DEFAULT_CALLER_KIND = exports.EXTERNAL_SYSTEM_KINDS = exports.getQueueName = exports.assertPubSubConventions = exports.assertApiKind = exports.getApiKind = exports.ENDPOINT_KINDS_BY_API_KIND = exports.Queue = exports.PubSub = exports.Rpc = exports.AuthMeta = exports.DtoSchemaBuilder = exports.DtoValidationFailure = exports.ApiJsonSchema = exports.WpResponseDto = exports.WpDtoFieldMetadata = exports.WpDtoMapFieldOptions = exports.WpMcpHeader = exports.WpDtoFieldOptions = exports.WpDtoField = exports.WpDto = exports.getWpMcpAuthJwt = exports.WpMcpJwtAuthMetadata = exports.WpMcpAuthJwt = exports.getWpMcpTools = exports.WpMcpToolMetadata = exports.WpMcpToolHints = exports.WpMcpTool = exports.getStreamingEndpoint = exports.WpStream = exports.StreamWriter = exports.StreamTransportError = exports.StreamEventValidator = exports.StreamingEndpointMetadata = exports.StreamEnvelope = exports.StreamCorrelation = exports.HttpParameterDeclaration = exports.HttpParameterBinding = exports.HttpContractMapper = exports.BoundHttpRequest = exports.RouteMetadataFactory = exports.RouteMetadata = exports.IPC_METADATA_KEYS = exports.assertNotInternalApi = exports.assertInternalApi = exports.getIpcMaskSpec = exports.getIpcEndpointKind = void 0;
|
|
13
|
-
exports.
|
|
14
|
-
exports.ApiErrorHttpStatus = exports.ApiErrorBoundary = exports.ApiErrorPayload = exports.ApiErrorCodec = exports.ApiCodedError = exports.ApiNotImplementedError = exports.ApiUnsupportedMediaTypeError = exports.ApiPreconditionFailedError = exports.ApiUnprocessableError = exports.ApiConflictError = exports.ApiEndpointNotFoundError = exports.ApiConnectionError = exports.ApiDependencyBackoffError = exports.ApiUnauthorizedError = exports.ApiBadRequestError = exports.ApiEndUserError = exports.ApiRequestTimeoutError = exports.ApiForbiddenError = exports.ApiRateLimitedError = exports.ApiImplementationError = exports.ApiDependencyTimeoutError = exports.ApiUnavailableError = exports.ApiDependencyError = exports.ApiNotFoundError = exports.ApiError = exports.FilterChain = void 0;
|
|
13
|
+
exports.getDoNotRecordFields = exports.DoNotRecord = exports.RecordedTestCase = exports.RecordedError = exports.RecordedEndpoint = exports.RecorderKeys = exports.ApiMethodInfo = exports.LOG_API_CALL_LOGGER_NAME = exports.ApiCallLogNameImpl = exports.ApiCallLogName = exports.ApiCallInfo = exports.MaskSpec = exports.LogApiCallImpl = exports.ContextMgr = exports.DestinationTrust = exports.WebpiecesCoreHeaders = exports.templateDeriver = exports.WEBPIECES_DEFAULT_FAILURE_CLASSIFIER = exports.WebpiecesDefaultFailureClassifier = exports.KeyedFailureClassifier = exports.ReceivedApiErrorRule = exports.SurfaceEndUserStatus = exports.WEBPIECES_DEFAULT_ERROR_TRANSLATOR = exports.WebpiecesDefaultErrorTranslator = exports.HttpResponseDto = exports.HttpResponseStatus = exports.HttpHeader = exports.RuntimeLocality = exports.ServiceInfo = exports.ApiCallTimeoutError = exports.CallContext = exports.CallDeadline = exports.CallRegistry = exports.ClientRegistry = exports.HeaderRegistry = exports.DateTimeUtil = exports.TimeUtil = exports.DateUtil = exports.InstantUtil = exports.NetworkRejectClassifier = exports.NO_REG_CODE = exports.WRONG_COMPANY = exports.WRONG_DOMAIN = exports.EMAIL_NOT_CONFIRMED = exports.NOT_APPROVED = exports.WRONG_LOGIN = exports.WRONG_LOGIN_TYPE = exports.ENTITY_NOT_FOUND = exports.SECRETS = exports.Secrets = void 0;
|
|
14
|
+
exports.ApiErrorHttpStatus = exports.ApiErrorBoundary = exports.ApiErrorPayload = exports.ApiErrorCodec = exports.ApiCodedError = exports.ApiNotImplementedError = exports.ApiUnsupportedMediaTypeError = exports.ApiPreconditionFailedError = exports.ApiUnprocessableError = exports.ApiConflictError = exports.ApiEndpointNotFoundError = exports.ApiConnectionError = exports.ApiDependencyBackoffError = exports.ApiUnauthorizedError = exports.ApiBadRequestError = exports.ApiEndUserError = exports.ApiRequestTimeoutError = exports.ApiForbiddenError = exports.ApiRateLimitedError = exports.ApiImplementationError = exports.ApiDependencyTimeoutError = exports.ApiUnavailableError = exports.ApiDependencyError = exports.ApiNotFoundError = exports.ApiError = exports.FilterChain = exports.Filter = exports.SerializedError = exports.SerializedMap = exports.RecordSerializer = void 0;
|
|
15
15
|
var errorUtils_1 = require("./lib/errorUtils");
|
|
16
16
|
Object.defineProperty(exports, "toError", { enumerable: true, get: function () { return errorUtils_1.toError; } });
|
|
17
17
|
var ContextKey_1 = require("./ContextKey");
|
|
@@ -193,11 +193,23 @@ Object.defineProperty(exports, "ServiceInfo", { enumerable: true, get: function
|
|
|
193
193
|
var RuntimeLocality_1 = require("./http/RuntimeLocality");
|
|
194
194
|
Object.defineProperty(exports, "RuntimeLocality", { enumerable: true, get: function () { return RuntimeLocality_1.RuntimeLocality; } });
|
|
195
195
|
// The ENTIRE HTTP response as pure data — the ONE form both transports (express, fetch) are
|
|
196
|
-
// normalised into, so an
|
|
196
|
+
// normalised into, so an ErrorTranslator implementation is written once and serves both.
|
|
197
197
|
var HttpResponseDto_1 = require("./http/HttpResponseDto");
|
|
198
198
|
Object.defineProperty(exports, "HttpHeader", { enumerable: true, get: function () { return HttpResponseDto_1.HttpHeader; } });
|
|
199
199
|
Object.defineProperty(exports, "HttpResponseStatus", { enumerable: true, get: function () { return HttpResponseDto_1.HttpResponseStatus; } });
|
|
200
200
|
Object.defineProperty(exports, "HttpResponseDto", { enumerable: true, get: function () { return HttpResponseDto_1.HttpResponseDto; } });
|
|
201
|
+
// THE webpieces default translator — always installed, and what an app's own translator delegates to
|
|
202
|
+
// in order to decline an error. ONE class, both halves, node and browser alike.
|
|
203
|
+
var WebpiecesDefaultErrorTranslator_1 = require("./http/WebpiecesDefaultErrorTranslator");
|
|
204
|
+
Object.defineProperty(exports, "WebpiecesDefaultErrorTranslator", { enumerable: true, get: function () { return WebpiecesDefaultErrorTranslator_1.WebpiecesDefaultErrorTranslator; } });
|
|
205
|
+
Object.defineProperty(exports, "WEBPIECES_DEFAULT_ERROR_TRANSLATOR", { enumerable: true, get: function () { return WebpiecesDefaultErrorTranslator_1.WEBPIECES_DEFAULT_ERROR_TRANSLATOR; } });
|
|
206
|
+
// WHICH KIND OF CALLER drove this request (gui / llm / public-api), and the per-request end-user
|
|
207
|
+
// status derived from it — the replacement for the deleted per-router EndUserStatus.
|
|
208
|
+
var Surface_1 = require("./http/Surface");
|
|
209
|
+
Object.defineProperty(exports, "SurfaceEndUserStatus", { enumerable: true, get: function () { return Surface_1.SurfaceEndUserStatus; } });
|
|
210
|
+
// The ONE rule for an error RECEIVED from another process, shared verbatim by HTTP and IPC.
|
|
211
|
+
var ReceivedApiErrorRule_1 = require("./errors/ReceivedApiErrorRule");
|
|
212
|
+
Object.defineProperty(exports, "ReceivedApiErrorRule", { enumerable: true, get: function () { return ReceivedApiErrorRule_1.ReceivedApiErrorRule; } });
|
|
201
213
|
var FailureClassifier_1 = require("./http/FailureClassifier");
|
|
202
214
|
Object.defineProperty(exports, "KeyedFailureClassifier", { enumerable: true, get: function () { return FailureClassifier_1.KeyedFailureClassifier; } });
|
|
203
215
|
var WebpiecesDefaultFailureClassifier_1 = require("./http/WebpiecesDefaultFailureClassifier");
|
package/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/core/core-util/src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;;;;AAEH,+CAA2C;AAAlC,qGAAA,OAAO,OAAA;AAChB,2CAA0C;AAAjC,wGAAA,UAAU,OAAA;AAOnB,+CAA8C;AAArC,4GAAA,YAAY,OAAA;AAErB,+EAA+E;AAC/E,kFAAkF;AAClF,yCAAyC;AACzC,mDAA0F;AAAjF,gHAAA,cAAc,OAAA;AAAE,kHAAA,gBAAgB,OAAA;AAAE,sHAAA,oBAAoB,OAAA;AAO/D,yDAAwD;AAA/C,8GAAA,aAAa,OAAA;AACtB,uEAAsE;AAA7D,4HAAA,oBAAoB,OAAA;AAC7B,mDAAkD;AAAzC,wGAAA,UAAU,OAAA;AACnB,mDAM8B;AAL1B,wGAAA,UAAU,OAAA;AACV,4GAAA,cAAc,OAAA;AACd,0GAAA,YAAY,OAAA;AACZ,+GAAA,iBAAiB,OAAA;AACjB,kHAAA,oBAAoB,OAAA;AAGxB,8DAA8D;AAC9D,sEAAsE;AACtE,qEAAqE;AACrE,uEAAuE;AACvE,kEAAkE;AAElE,4BAA4B;AAC5B,gDA8B2B;AA7BvB,qGAAA,OAAO,OAAA;AACP,sGAAA,QAAQ,OAAA;AACR,mEAAmE;AACnE,0GAAA,YAAY,OAAA;AACZ,uGAAA,SAAS,OAAA;AACT,2GAAA,aAAa,OAAA;AACb,wHAAA,0BAA0B,OAAA;AAC1B,wGAAA,UAAU,OAAA;AACV,gHAAA,kBAAkB,OAAA;AAClB,2GAAA,aAAa,OAAA;AACb,0GAAA,YAAY,OAAA;AACZ,6GAAA,eAAe,OAAA;AACf,qGAAA,OAAO,OAAA;AACP,wGAAA,UAAU,OAAA;AACV,0GAAA,YAAY,OAAA;AACZ,gHAAA,kBAAkB,OAAA;AAClB,6GAAA,eAAe,OAAA;AACf,8GAAA,gBAAgB,OAAA;AAChB,yGAAA,WAAW,OAAA;AACX,wGAAA,UAAU,OAAA;AACV,uGAAA,SAAS,OAAA;AACT,uGAAA,SAAS,OAAA;AACT,yGAAA,WAAW,OAAA;AACX,yGAAA,WAAW,OAAA;AACX,4HAAA,8BAA8B,OAAA;AAC9B,uIAAA,yCAAyC,OAAA;AACzC,sIAAA,wCAAwC,OAAA;AACxC,6HAAA,+BAA+B,OAAA;AAC/B,2GAAA,aAAa,OAAA;AAEjB,8EAI0C;AAHtC,sHAAA,SAAS,OAAA;AACT,uHAAA,UAAU,OAAA;AACV,yIAAA,4BAA4B,OAAA;AAEhC,qDAW6B;AAVzB,2GAAA,UAAU,OAAA;AACV,8GAAA,aAAa,OAAA;AACb,8GAAA,aAAa,OAAA;AACb,4GAAA,WAAW,OAAA;AACX,gHAAA,eAAe,OAAA;AACf,mHAAA,kBAAkB,OAAA;AAClB,+GAAA,cAAc,OAAA;AACd,kHAAA,iBAAiB,OAAA;AACjB,qHAAA,oBAAoB,OAAA;AACpB,kHAAA,iBAAiB,OAAA;AAGrB,2FAA2F;AAC3F,sDAAqD;AAA5C,8GAAA,aAAa,OAAA;AACtB,oEAAmE;AAA1D,4HAAA,oBAAoB,OAAA;AAC7B,oDAK6B;AAJzB,gHAAA,gBAAgB,OAAA;AAChB,kHAAA,kBAAkB,OAAA;AAClB,oHAAA,oBAAoB,OAAA;AACpB,wHAAA,wBAAwB,OAAA;AAE5B,8DASkC;AAR9B,sHAAA,iBAAiB,OAAA;AACjB,mHAAA,cAAc,OAAA;AACd,8HAAA,yBAAyB,OAAA;AACzB,yHAAA,oBAAoB,OAAA;AACpB,yHAAA,oBAAoB,OAAA;AACpB,iHAAA,YAAY,OAAA;AACZ,6GAAA,QAAQ,OAAA;AACR,yHAAA,oBAAoB,OAAA;AAexB,iDAAgG;AAAvF,wGAAA,SAAS,OAAA;AAAE,6GAAA,cAAc,OAAA;AAAE,gHAAA,iBAAiB,OAAA;AAAE,4GAAA,aAAa,OAAA;AAEpE,yDAA4F;AAAnF,+GAAA,YAAY,OAAA;AAAE,uHAAA,oBAAoB,OAAA;AAAE,kHAAA,eAAe,OAAA;AAC5D,6CAWyB;AAVrB,kGAAA,KAAK,OAAA;AACL,uGAAA,UAAU,OAAA;AACV,8GAAA,iBAAiB,OAAA;AACjB,wGAAA,WAAW,OAAA;AACX,iHAAA,oBAAoB,OAAA;AACpB,+GAAA,kBAAkB,OAAA;AAClB,0GAAA,aAAa,OAAA;AACb,0GAAA,aAAa,OAAA;AACb,iHAAA,oBAAoB,OAAA;AACpB,6GAAA,gBAAgB,OAAA;AAGpB,+FAA+F;AAC/F,8CAA4C;AAAnC,qGAAA,QAAQ,OAAA;AAQjB,sGAAsG;AACtG,yFAAyF;AACzF,4CASyB;AARrB,+FAAA,GAAG,OAAA;AACH,kGAAA,MAAM,OAAA;AACN,iGAAA,KAAK,OAAA;AACL,sHAAA,0BAA0B,OAAA;AAC1B,sGAAA,UAAU,OAAA;AACV,yGAAA,aAAa,OAAA;AACb,mHAAA,uBAAuB,OAAA;AACvB,wGAAA,YAAY,OAAA;AAGhB,mGAAmG;AACnG,mCAAmC;AACnC,0DAMgC;AAL5B,wHAAA,qBAAqB,OAAA;AACrB,sHAAA,mBAAmB,OAAA;AACnB,iHAAA,cAAc,OAAA;AACd,uHAAA,oBAAoB,OAAA;AACpB,oHAAA,iBAAiB,OAAA;AAGrB,8FAA8F;AAC9F,0CAAkD;AAAzC,kGAAA,OAAO,OAAA;AAAE,kGAAA,OAAO,OAAA;AAKzB,oCAAoC;AACpC,mCASkB;AARd,0GAAA,gBAAgB,OAAA;AAChB,0GAAA,gBAAgB,OAAA;AAChB,qGAAA,WAAW,OAAA;AACX,sGAAA,YAAY,OAAA;AACZ,6GAAA,mBAAmB,OAAA;AACnB,sGAAA,YAAY,OAAA;AACZ,uGAAA,aAAa,OAAA;AACb,qGAAA,WAAW,OAAA;AAGf,sDAA+D;AAAtD,wHAAA,uBAAuB,OAAA;AAEhC,iEAAiE;AACjE,4CASyB;AAJrB,uGAAA,WAAW,OAAA;AACX,oGAAA,QAAQ,OAAA;AACR,oGAAA,QAAQ,OAAA;AACR,wGAAA,YAAY,OAAA;AAGhB,mEAAmE;AACnE,wDAAuD;AAA9C,gHAAA,cAAc,OAAA;AACvB,wDAAuD;AAA9C,gHAAA,cAAc,OAAA;AACvB,oDAAmD;AAA1C,4GAAA,YAAY,OAAA;AACrB,oDAAmD;AAA1C,4GAAA,YAAY,OAAA;AACrB,oDAAkD;AAAzC,2GAAA,WAAW,OAAA;AAEpB,kEAAiE;AAAxD,0HAAA,mBAAmB,OAAA;AAG5B,iFAAiF;AACjF,8EAA8E;AAC9E,kDAAiD;AAAxC,0GAAA,WAAW,OAAA;AACpB,qGAAqG;AACrG,2FAA2F;AAC3F,0DAAyD;AAAhD,kHAAA,eAAe,OAAA;AAExB,4FAA4F;AAC5F,0FAA0F;AAC1F,0DAAyF;AAAhF,6GAAA,UAAU,OAAA;AAAE,qHAAA,kBAAkB,OAAA;AAAE,kHAAA,eAAe,OAAA;AAOxD,8DAAkE;AAAzD,2HAAA,sBAAsB,OAAA;AAC/B,8FAGkD;AAF9C,sJAAA,iCAAiC,OAAA;AACjC,yJAAA,oCAAoC,OAAA;AAExC,0DAAyD;AAAhD,kHAAA,eAAe,OAAA;AACxB,oEAAmE;AAA1D,4HAAA,oBAAoB,OAAA;AAG7B,qGAAqG;AACrG,mFAAmF;AACnF,4DAA2D;AAAlD,oHAAA,gBAAgB,OAAA;AAEzB,iGAAiG;AACjG,gGAAgG;AAChG,kEAAkE;AAClE,gDAA+C;AAAtC,wGAAA,UAAU,OAAA;AAEnB,kGAAkG;AAClG,oGAAoG;AACpG,2EAA2E;AAC3E,gDAAmD;AAA1C,4GAAA,cAAc,OAAA;AAEvB,iGAAiG;AACjG,uGAAuG;AACvG,oDAA+C;AAAtC,wGAAA,QAAQ,OAAA;AAGjB,yFAAyF;AACzF,kFAAkF;AAClF,gGAAgG;AAChG,kDAAiD;AAAxC,0GAAA,WAAW,OAAA;AAEpB,oGAAoG;AACpG,wDAI+B;AAH3B,gHAAA,cAAc,OAAA;AACd,oHAAA,kBAAkB,OAAA;AAClB,0HAAA,wBAAwB,OAAA;AAE5B,sDAAqD;AAA5C,8GAAA,aAAa,OAAA;AAItB,iFAAiF;AACjF,qEAAkF;AAAvD,gHAAA,YAAY,OAAA;AACvC,qEAI0C;AAHtC,oHAAA,gBAAgB,OAAA;AAChB,iHAAA,aAAa,OAAA;AACb,oHAAA,gBAAgB,OAAA;AAEpB,2DAAgF;AAAvE,0GAAA,WAAW,OAAA;AAAE,mHAAA,oBAAoB,OAAA;AAC1C,qEAAoG;AAA3F,oHAAA,gBAAgB,OAAA;AAAE,iHAAA,aAAa,OAAA;AAAE,mHAAA,eAAe,OAAA;AAEzD,gGAAgG;AAChG,2EAA2E;AAC3E,+FAA+F;AAC/F,kGAAkG;AAClG,wFAAwF;AACxF,2CAA0C;AAAjC,gGAAA,MAAM,OAAA;AAEf,qDAAoD;AAA3C,0GAAA,WAAW,OAAA;AAEpB,mCAyBkB;AAxBd,kGAAA,QAAQ,OAAA;AACR,0GAAA,gBAAgB,OAAA;AAChB,4GAAA,kBAAkB,OAAA;AAClB,6GAAA,mBAAmB,OAAA;AACnB,mHAAA,yBAAyB,OAAA;AACzB,gHAAA,sBAAsB,OAAA;AACtB,6GAAA,mBAAmB,OAAA;AACnB,2GAAA,iBAAiB,OAAA;AACjB,gHAAA,sBAAsB,OAAA;AACtB,yGAAA,eAAe,OAAA;AACf,4GAAA,kBAAkB,OAAA;AAClB,8GAAA,oBAAoB,OAAA;AACpB,mHAAA,yBAAyB,OAAA;AACzB,4GAAA,kBAAkB,OAAA;AAClB,kHAAA,wBAAwB,OAAA;AACxB,0GAAA,gBAAgB,OAAA;AAChB,+GAAA,qBAAqB,OAAA;AACrB,oHAAA,0BAA0B,OAAA;AAC1B,sHAAA,4BAA4B,OAAA;AAC5B,gHAAA,sBAAsB,OAAA;AACtB,uGAAA,aAAa,OAAA;AACb,uGAAA,aAAa,OAAA;AACb,yGAAA,eAAe,OAAA;AACf,0GAAA,gBAAgB,OAAA;AAGpB,gEAA+D;AAAtD,wHAAA,kBAAkB,OAAA","sourcesContent":["/**\n * @webpieces/core-util\n *\n * Utility functions for WebPieces applications.\n * This package works in both browser and Node.js environments.\n *\n * @packageDocumentation\n */\n\nexport { toError } from './lib/errorUtils';\nexport { ContextKey } from './ContextKey';\nexport type {\n AnyContextKey,\n AnyTrustedContextKey,\n AnyUntrustedContextKey,\n Trust,\n} from './ContextKey';\nexport { ContextTuple } from './ContextTuple';\n\n// @DocumentDesign — DI-design-root marker. Applies to ANY project kind (server\n// controllers AND library impl classes), so it lives here (browser + Node) rather\n// than in a server-only routing package.\nexport { DocumentDesign, isDocumentDesign, DESIGN_METADATA_KEYS } from './DocumentDesign';\n\n// Logging (merged from former @webpieces/wp-logging).\n// Pluggable logging interface + a browser-safe console default; apps plug in\n// bunyan/winston/pino/etc. via LogManager.setFactory(...). Browser + Node.\nexport type { Logger, LogLevel } from './logging/Logger';\nexport type { LoggerFactory } from './logging/LoggerFactory';\nexport { ConsoleLogger } from './logging/ConsoleLogger';\nexport { ConsoleLoggerFactory } from './logging/ConsoleLoggerFactory';\nexport { LogManager } from './logging/LogManager';\nexport {\n LogChunker,\n LogChunkerImpl,\n LogChunkInfo,\n MAX_GCP_LOG_BYTES,\n GCP_LOG_BUDGET_BYTES,\n} from './logging/LogChunker';\n\n// HTTP API contract (merged from former @webpieces/http-api).\n// Shared HTTP API definition consumed by both client and server: REST\n// decorators, the API error taxonomy, datetime DTOs, platform-header\n// registry/readers, ValidateImplementation, and the test-case recorder\n// contract. Pure definitions — express-free, browser + Node safe.\n\n// API definition decorators\nexport {\n ApiPath,\n Endpoint,\n // Auth mode decorators (clean service-to-service + user JWT model)\n WpAuthPublic,\n WpAuthJwt,\n rolesRequired,\n MISSING_AUTH_DECORATOR_FIX,\n WpAuthOidc,\n WpAuthSharedSecret,\n WpAuthWebhook,\n WpAuthApiKey,\n WpAuthLocalOnly,\n MaskLog,\n getApiPath,\n getEndpoints,\n getEndpointOptions,\n getEndpointKind,\n getEndpointKinds,\n getMaskSpec,\n isFormPost,\n isRawBody,\n isApiPath,\n getAuthMeta,\n getAuthMode,\n assertEveryEndpointHasAuthMode,\n assertEveryExternalEndpointDeclaresCaller,\n assertEveryWebhookEndpointRetainsRawBody,\n validateNoConflictingDecorators,\n METADATA_KEYS,\n} from './http/decorators';\nexport {\n PathParam,\n QueryParam,\n getHttpParameterDeclarations,\n} from './http/http-parameter-decorators';\nexport {\n WpInternal,\n WpIpcEndpoint,\n isInternalApi,\n getIpcApiId,\n getIpcEndpoints,\n getIpcEndpointKind,\n getIpcMaskSpec,\n assertInternalApi,\n assertNotInternalApi,\n IPC_METADATA_KEYS,\n} from './ipc/IpcDecorators';\nexport type { IpcApiType, IpcEndpointKind, IpcEndpointOptions } from './ipc/IpcDecorators';\n// The runtime representation of ONE route (split out of decorators.ts for file size only).\nexport { RouteMetadata } from './http/RouteMetadata';\nexport { RouteMetadataFactory } from './http/RouteMetadataFactory';\nexport {\n BoundHttpRequest,\n HttpContractMapper,\n HttpParameterBinding,\n HttpParameterDeclaration,\n} from './http/HttpContract';\nexport {\n StreamCorrelation,\n StreamEnvelope,\n StreamingEndpointMetadata,\n StreamEventValidator,\n StreamTransportError,\n StreamWriter,\n WpStream,\n getStreamingEndpoint,\n} from './http/StreamingContract';\nexport type {\n RequestStream,\n ResponseStream,\n StreamEnvelopeKind,\n StreamFailureOptions,\n} from './http/StreamingContract';\nexport type {\n ContractHttpMethod,\n EndpointResponseType,\n HttpParameterSource,\n HttpParameterValueType,\n} from './http/HttpContract';\nexport type { EndpointKind, EndpointOptions, ExternalEndpointOptions } from './http/decorators';\nexport { WpMcpTool, WpMcpToolHints, WpMcpToolMetadata, getWpMcpTools } from './mcp/McpMetadata';\nexport type { WpMcpMethodDecorator, WpMcpToolOptions } from './mcp/McpMetadata';\nexport { WpMcpAuthJwt, WpMcpJwtAuthMetadata, getWpMcpAuthJwt } from './mcp/McpAuthMetadata';\nexport {\n WpDto,\n WpDtoField,\n WpDtoFieldOptions,\n WpMcpHeader,\n WpDtoMapFieldOptions,\n WpDtoFieldMetadata,\n WpResponseDto,\n ApiJsonSchema,\n DtoValidationFailure,\n DtoSchemaBuilder,\n} from './mcp/DtoSchema';\nexport type { DtoClass, DtoElementType, DtoValue } from './mcp/DtoSchema';\n// The TYPE layer of the auth surface — likewise split out of decorators.ts for file size only.\nexport { AuthMeta } from './http/auth-mode';\nexport type {\n AuthMode,\n ApiKeyCredential,\n ApiKeyCredentials,\n JwtRoles,\n JwtRequirement,\n} from './http/auth-mode';\n// API kind (RPC vs PubSub/Cloud Tasks) + queue naming. Split out of decorators.ts for file size only;\n// one-way dependency api-kind -> decorators, and the barrel keeps the surface identical.\nexport {\n Rpc,\n PubSub,\n Queue,\n ENDPOINT_KINDS_BY_API_KIND,\n getApiKind,\n assertApiKind,\n assertPubSubConventions,\n getQueueName,\n} from './http/api-kind';\nexport type { ApiKind } from './http/api-kind';\n// WHO calls an `external` endpoint — the caller declaration @Endpoint(..., 'external', {calledBy})\n// requires, and the reader for it.\nexport {\n EXTERNAL_SYSTEM_KINDS,\n DEFAULT_CALLER_KIND,\n ExternalCaller,\n isExternalSystemKind,\n getEndpointCaller,\n} from './http/external-caller';\nexport type { ExternalSystemKind } from './http/external-caller';\n// Client-side shared-secret store (the value THIS service sends per @WpAuthSharedSecret key).\nexport { Secrets, SECRETS } from './http/Secrets';\n\n// Type validators\nexport { ValidateImplementation } from './http/validators';\n\n// Authentication subtype constants.\nexport {\n ENTITY_NOT_FOUND,\n WRONG_LOGIN_TYPE,\n WRONG_LOGIN,\n NOT_APPROVED,\n EMAIL_NOT_CONFIRMED,\n WRONG_DOMAIN,\n WRONG_COMPANY,\n NO_REG_CODE,\n} from './errors';\n\nexport { NetworkRejectClassifier } from './http/networkReject';\n\n// Date/Time DTOs and Utilities (inspired by Java Time / JSR-310)\nexport {\n InstantDto,\n DateDto,\n TimeDto,\n DateTimeDto,\n InstantUtil,\n DateUtil,\n TimeUtil,\n DateTimeUtil,\n} from './http/datetime';\n\n// Context keys + registry (the global magic-context header system)\nexport { HeaderRegistry } from './http/HeaderRegistry';\nexport { ClientRegistry } from './http/ClientRegistry';\nexport { CallRegistry } from './http/CallRegistry';\nexport { CallDeadline } from './http/CallDeadline';\nexport { CallContext } from './http/CallStrategy';\nexport type { Attempt, CallStrategy } from './http/CallStrategy';\nexport { ApiCallTimeoutError } from './http/ApiCallTimeoutError';\nexport type { ServiceUrlDeriver } from './http/ClientRegistry';\n\n// \"What service am I\" — set once at startup, read by the logging backends and by\n// RequestContextHeaders (to stamp requestIdSource on ids this service mints).\nexport { ServiceInfo } from './http/ServiceInfo';\n// \"Where am I running\" — declared once at startup (setupRuntime, from RuntimeSetupOptions.locality).\n// The ONE input to @WpAuthLocalOnly enforcement. Undeclared reads as DEPLOYED (fail safe).\nexport { RuntimeLocality } from './http/RuntimeLocality';\nexport type { Locality } from './http/RuntimeLocality';\n// The ENTIRE HTTP response as pure data — the ONE form both transports (express, fetch) are\n// normalised into, so an ErrorTranslators implementation is written once and serves both.\nexport { HttpHeader, HttpResponseStatus, HttpResponseDto } from './http/HttpResponseDto';\n// Pluggable, bidirectional error translation (app exception <-> the WHOLE response). Set on\n// ClientRegistry at startup; consulted before the built-in webpieces mapping on BOTH sides.\nexport type { ErrorTranslators } from './http/ErrorTranslators';\n// Pluggable per-client failure classification (is a thrown API-call error a real failure or an\n// expected non-failure?). Registered on ClientRegistry at startup; consulted by LogApiCall.\nexport type { FailureClassifier } from './http/FailureClassifier';\nexport { KeyedFailureClassifier } from './http/FailureClassifier';\nexport {\n WebpiecesDefaultFailureClassifier,\n WEBPIECES_DEFAULT_FAILURE_CLASSIFIER,\n} from './http/WebpiecesDefaultFailureClassifier';\nexport { templateDeriver } from './http/templateDeriver';\nexport { WebpiecesCoreHeaders } from './http/WebpiecesCoreHeaders';\nexport { ContextReader } from './http/ContextReader';\n\n// The OUTBOUND half of the trust model: whether a TRUSTED context key may ride to the endpoint being\n// called. Built ONLY from the destination endpoint's AuthMode — see the class doc.\nexport { DestinationTrust } from './http/DestinationTrust';\n\n// BROWSER-ONLY outbound-header propagation (app-held store + registry -> outbound HTTP headers).\n// Only @webpieces/http-client-browser may name it; the server reads RequestContext directly via\n// RequestContextHeaders in the Node-only @webpieces/core-context.\nexport { ContextMgr } from './http/ContextMgr';\n\n// API-call logging helper (uses LogManager above). NOT a singleton: construct one per environment\n// with that environment's ApiCallContext — `new LogApiCallImpl(new RequestContextApiCallContext())`\n// on node, `new LogApiCallImpl(new BrowserApiCallContext())` in a browser.\nexport { LogApiCallImpl } from './http/LogApiCall';\n\n// Opt-in field masking for the LogApiCall log path — declare per-api sensitive fields so secrets\n// (OAuth refresh tokens, id-token JWTs) are masked in the logs while the real value stays on the wire.\nexport { MaskSpec } from './http/LogFieldMask';\nexport type { MaskMode } from './http/LogFieldMask';\n\n// The structured `api` tag + the context-writer seam LogApiCall stamps through. The Node\n// RequestContext-backed impl lives in @webpieces/core-context, the browser one in\n// @webpieces/http-client-browser; each is CONSTRUCTED by its package, never installed globally.\nexport { ApiCallInfo } from './http/ApiCallInfo';\nexport type { ApiType, ApiResult } from './http/ApiCallInfo';\n// Console-render bridge: turns LogApiCall's [LogApiCall] bracket into [API.{side}.{phase}] locally.\nexport {\n ApiCallLogName,\n ApiCallLogNameImpl,\n LOG_API_CALL_LOGGER_NAME,\n} from './http/ApiCallLogName';\nexport { ApiMethodInfo } from './http/ApiMethodInfo';\nexport type { ApiSide } from './http/ApiMethodInfo';\nexport type { ApiCallContext } from './http/ApiCallContext';\n\n// Test-case recording contract (impl lives in http-server; hooks in http-client)\nexport { TestCaseRecorder, RecorderKeys } from './http/recorder/TestCaseRecorder';\nexport {\n RecordedEndpoint,\n RecordedError,\n RecordedTestCase,\n} from './http/recorder/RecordedEndpoint';\nexport { DoNotRecord, getDoNotRecordFields } from './http/recorder/DoNotRecord';\nexport { RecordSerializer, SerializedMap, SerializedError } from './http/recorder/RecordSerializer';\n\n// ---------------------------------------------------------------------------------------------\n// Filter-chain primitives, shared by BOTH chains: the inbound server chain\n// (`Filter<MethodMeta, WpResponse<unknown>>`, @webpieces/http-routing) and the outbound client\n// chain (`Filter<ClientRequest, Response>`, @webpieces/http-client-core). Declared once, here, in\n// the package both depend on — see the class doc for why a second pair would be a shim.\nexport { Filter } from './filters/Filter';\nexport type { Service } from './filters/Filter';\nexport { FilterChain } from './filters/FilterChain';\n\nexport {\n ApiError,\n ApiNotFoundError,\n ApiDependencyError,\n ApiUnavailableError,\n ApiDependencyTimeoutError,\n ApiImplementationError,\n ApiRateLimitedError,\n ApiForbiddenError,\n ApiRequestTimeoutError,\n ApiEndUserError,\n ApiBadRequestError,\n ApiUnauthorizedError,\n ApiDependencyBackoffError,\n ApiConnectionError,\n ApiEndpointNotFoundError,\n ApiConflictError,\n ApiUnprocessableError,\n ApiPreconditionFailedError,\n ApiUnsupportedMediaTypeError,\n ApiNotImplementedError,\n ApiCodedError,\n ApiErrorCodec,\n ApiErrorPayload,\n ApiErrorBoundary,\n} from './errors';\nexport type { ApiErrorKind, ApiStatusCode, EdgeHttpStatus } from './errors';\nexport { ApiErrorHttpStatus } from './http/ApiErrorHttpStatus';\nexport type { PublishedKind, PublishedApiError } from './http/ApiErrorHttpStatus';\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/core/core-util/src/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @webpieces/core-util\n *\n * Utility functions for WebPieces applications.\n * This package works in both browser and Node.js environments.\n *\n * @packageDocumentation\n */\n\nexport { toError } from './lib/errorUtils';\nexport { ContextKey } from './ContextKey';\nexport type {\n AnyContextKey,\n AnyTrustedContextKey,\n AnyUntrustedContextKey,\n Trust,\n} from './ContextKey';\nexport { ContextTuple } from './ContextTuple';\n\n// @DocumentDesign — DI-design-root marker. Applies to ANY project kind (server\n// controllers AND library impl classes), so it lives here (browser + Node) rather\n// than in a server-only routing package.\nexport { DocumentDesign, isDocumentDesign, DESIGN_METADATA_KEYS } from './DocumentDesign';\n\n// Logging (merged from former @webpieces/wp-logging).\n// Pluggable logging interface + a browser-safe console default; apps plug in\n// bunyan/winston/pino/etc. via LogManager.setFactory(...). Browser + Node.\nexport type { Logger, LogLevel } from './logging/Logger';\nexport type { LoggerFactory } from './logging/LoggerFactory';\nexport { ConsoleLogger } from './logging/ConsoleLogger';\nexport { ConsoleLoggerFactory } from './logging/ConsoleLoggerFactory';\nexport { LogManager } from './logging/LogManager';\nexport {\n LogChunker,\n LogChunkerImpl,\n LogChunkInfo,\n MAX_GCP_LOG_BYTES,\n GCP_LOG_BUDGET_BYTES,\n} from './logging/LogChunker';\n\n// HTTP API contract (merged from former @webpieces/http-api).\n// Shared HTTP API definition consumed by both client and server: REST\n// decorators, the API error taxonomy, datetime DTOs, platform-header\n// registry/readers, ValidateImplementation, and the test-case recorder\n// contract. Pure definitions — express-free, browser + Node safe.\n\n// API definition decorators\nexport {\n ApiPath,\n Endpoint,\n // Auth mode decorators (clean service-to-service + user JWT model)\n WpAuthPublic,\n WpAuthJwt,\n rolesRequired,\n MISSING_AUTH_DECORATOR_FIX,\n WpAuthOidc,\n WpAuthSharedSecret,\n WpAuthWebhook,\n WpAuthApiKey,\n WpAuthLocalOnly,\n MaskLog,\n getApiPath,\n getEndpoints,\n getEndpointOptions,\n getEndpointKind,\n getEndpointKinds,\n getMaskSpec,\n isFormPost,\n isRawBody,\n isApiPath,\n getAuthMeta,\n getAuthMode,\n assertEveryEndpointHasAuthMode,\n assertEveryExternalEndpointDeclaresCaller,\n assertEveryWebhookEndpointRetainsRawBody,\n validateNoConflictingDecorators,\n METADATA_KEYS,\n} from './http/decorators';\nexport {\n PathParam,\n QueryParam,\n getHttpParameterDeclarations,\n} from './http/http-parameter-decorators';\nexport {\n WpInternal,\n WpIpcEndpoint,\n isInternalApi,\n getIpcApiId,\n getIpcEndpoints,\n getIpcEndpointKind,\n getIpcMaskSpec,\n assertInternalApi,\n assertNotInternalApi,\n IPC_METADATA_KEYS,\n} from './ipc/IpcDecorators';\nexport type { IpcApiType, IpcEndpointKind, IpcEndpointOptions } from './ipc/IpcDecorators';\n// The runtime representation of ONE route (split out of decorators.ts for file size only).\nexport { RouteMetadata } from './http/RouteMetadata';\nexport { RouteMetadataFactory } from './http/RouteMetadataFactory';\nexport {\n BoundHttpRequest,\n HttpContractMapper,\n HttpParameterBinding,\n HttpParameterDeclaration,\n} from './http/HttpContract';\nexport {\n StreamCorrelation,\n StreamEnvelope,\n StreamingEndpointMetadata,\n StreamEventValidator,\n StreamTransportError,\n StreamWriter,\n WpStream,\n getStreamingEndpoint,\n} from './http/StreamingContract';\nexport type {\n RequestStream,\n ResponseStream,\n StreamEnvelopeKind,\n StreamFailureOptions,\n} from './http/StreamingContract';\nexport type {\n ContractHttpMethod,\n EndpointResponseType,\n HttpParameterSource,\n HttpParameterValueType,\n} from './http/HttpContract';\nexport type { EndpointKind, EndpointOptions, ExternalEndpointOptions } from './http/decorators';\nexport { WpMcpTool, WpMcpToolHints, WpMcpToolMetadata, getWpMcpTools } from './mcp/McpMetadata';\nexport type { WpMcpMethodDecorator, WpMcpToolOptions } from './mcp/McpMetadata';\nexport { WpMcpAuthJwt, WpMcpJwtAuthMetadata, getWpMcpAuthJwt } from './mcp/McpAuthMetadata';\nexport {\n WpDto,\n WpDtoField,\n WpDtoFieldOptions,\n WpMcpHeader,\n WpDtoMapFieldOptions,\n WpDtoFieldMetadata,\n WpResponseDto,\n ApiJsonSchema,\n DtoValidationFailure,\n DtoSchemaBuilder,\n} from './mcp/DtoSchema';\nexport type { DtoClass, DtoElementType, DtoValue } from './mcp/DtoSchema';\n// The TYPE layer of the auth surface — likewise split out of decorators.ts for file size only.\nexport { AuthMeta } from './http/auth-mode';\nexport type {\n AuthMode,\n ApiKeyCredential,\n ApiKeyCredentials,\n JwtRoles,\n JwtRequirement,\n} from './http/auth-mode';\n// API kind (RPC vs PubSub/Cloud Tasks) + queue naming. Split out of decorators.ts for file size only;\n// one-way dependency api-kind -> decorators, and the barrel keeps the surface identical.\nexport {\n Rpc,\n PubSub,\n Queue,\n ENDPOINT_KINDS_BY_API_KIND,\n getApiKind,\n assertApiKind,\n assertPubSubConventions,\n getQueueName,\n} from './http/api-kind';\nexport type { ApiKind } from './http/api-kind';\n// WHO calls an `external` endpoint — the caller declaration @Endpoint(..., 'external', {calledBy})\n// requires, and the reader for it.\nexport {\n EXTERNAL_SYSTEM_KINDS,\n DEFAULT_CALLER_KIND,\n ExternalCaller,\n isExternalSystemKind,\n getEndpointCaller,\n} from './http/external-caller';\nexport type { ExternalSystemKind } from './http/external-caller';\n// Client-side shared-secret store (the value THIS service sends per @WpAuthSharedSecret key).\nexport { Secrets, SECRETS } from './http/Secrets';\n\n// Type validators\nexport { ValidateImplementation } from './http/validators';\n\n// Authentication subtype constants.\nexport {\n ENTITY_NOT_FOUND,\n WRONG_LOGIN_TYPE,\n WRONG_LOGIN,\n NOT_APPROVED,\n EMAIL_NOT_CONFIRMED,\n WRONG_DOMAIN,\n WRONG_COMPANY,\n NO_REG_CODE,\n} from './errors';\n\nexport { NetworkRejectClassifier } from './http/networkReject';\n\n// Date/Time DTOs and Utilities (inspired by Java Time / JSR-310)\nexport {\n InstantDto,\n DateDto,\n TimeDto,\n DateTimeDto,\n InstantUtil,\n DateUtil,\n TimeUtil,\n DateTimeUtil,\n} from './http/datetime';\n\n// Context keys + registry (the global magic-context header system)\nexport { HeaderRegistry } from './http/HeaderRegistry';\nexport { ClientRegistry } from './http/ClientRegistry';\nexport { CallRegistry } from './http/CallRegistry';\nexport { CallDeadline } from './http/CallDeadline';\nexport { CallContext } from './http/CallStrategy';\nexport type { Attempt, CallStrategy } from './http/CallStrategy';\nexport { ApiCallTimeoutError } from './http/ApiCallTimeoutError';\nexport type { ServiceUrlDeriver } from './http/ClientRegistry';\n\n// \"What service am I\" — set once at startup, read by the logging backends and by\n// RequestContextHeaders (to stamp requestIdSource on ids this service mints).\nexport { ServiceInfo } from './http/ServiceInfo';\n// \"Where am I running\" — declared once at startup (setupRuntime, from RuntimeSetupOptions.locality).\n// The ONE input to @WpAuthLocalOnly enforcement. Undeclared reads as DEPLOYED (fail safe).\nexport { RuntimeLocality } from './http/RuntimeLocality';\nexport type { Locality } from './http/RuntimeLocality';\n// The ENTIRE HTTP response as pure data — the ONE form both transports (express, fetch) are\n// normalised into, so an ErrorTranslator implementation is written once and serves both.\nexport { HttpHeader, HttpResponseStatus, HttpResponseDto } from './http/HttpResponseDto';\n// Pluggable, bidirectional error translation (app exception <-> the WHOLE response). Set on\n// ClientRegistry at startup; consulted before the built-in webpieces mapping on BOTH sides.\nexport type { ErrorTranslator } from './http/ErrorTranslator';\n// THE webpieces default translator — always installed, and what an app's own translator delegates to\n// in order to decline an error. ONE class, both halves, node and browser alike.\nexport {\n WebpiecesDefaultErrorTranslator,\n WEBPIECES_DEFAULT_ERROR_TRANSLATOR,\n} from './http/WebpiecesDefaultErrorTranslator';\n// WHICH KIND OF CALLER drove this request (gui / llm / public-api), and the per-request end-user\n// status derived from it — the replacement for the deleted per-router EndUserStatus.\nexport { SurfaceEndUserStatus } from './http/Surface';\nexport type { Surface } from './http/Surface';\n// The ONE rule for an error RECEIVED from another process, shared verbatim by HTTP and IPC.\nexport { ReceivedApiErrorRule } from './errors/ReceivedApiErrorRule';\n// Pluggable per-client failure classification (is a thrown API-call error a real failure or an\n// expected non-failure?). Registered on ClientRegistry at startup; consulted by LogApiCall.\nexport type { FailureClassifier } from './http/FailureClassifier';\nexport { KeyedFailureClassifier } from './http/FailureClassifier';\nexport {\n WebpiecesDefaultFailureClassifier,\n WEBPIECES_DEFAULT_FAILURE_CLASSIFIER,\n} from './http/WebpiecesDefaultFailureClassifier';\nexport { templateDeriver } from './http/templateDeriver';\nexport { WebpiecesCoreHeaders } from './http/WebpiecesCoreHeaders';\nexport { ContextReader } from './http/ContextReader';\n\n// The OUTBOUND half of the trust model: whether a TRUSTED context key may ride to the endpoint being\n// called. Built ONLY from the destination endpoint's AuthMode — see the class doc.\nexport { DestinationTrust } from './http/DestinationTrust';\n\n// BROWSER-ONLY outbound-header propagation (app-held store + registry -> outbound HTTP headers).\n// Only @webpieces/http-client-browser may name it; the server reads RequestContext directly via\n// RequestContextHeaders in the Node-only @webpieces/core-context.\nexport { ContextMgr } from './http/ContextMgr';\n\n// API-call logging helper (uses LogManager above). NOT a singleton: construct one per environment\n// with that environment's ApiCallContext — `new LogApiCallImpl(new RequestContextApiCallContext())`\n// on node, `new LogApiCallImpl(new BrowserApiCallContext())` in a browser.\nexport { LogApiCallImpl } from './http/LogApiCall';\n\n// Opt-in field masking for the LogApiCall log path — declare per-api sensitive fields so secrets\n// (OAuth refresh tokens, id-token JWTs) are masked in the logs while the real value stays on the wire.\nexport { MaskSpec } from './http/LogFieldMask';\nexport type { MaskMode } from './http/LogFieldMask';\n\n// The structured `api` tag + the context-writer seam LogApiCall stamps through. The Node\n// RequestContext-backed impl lives in @webpieces/core-context, the browser one in\n// @webpieces/http-client-browser; each is CONSTRUCTED by its package, never installed globally.\nexport { ApiCallInfo } from './http/ApiCallInfo';\nexport type { ApiType, ApiResult } from './http/ApiCallInfo';\n// Console-render bridge: turns LogApiCall's [LogApiCall] bracket into [API.{side}.{phase}] locally.\nexport {\n ApiCallLogName,\n ApiCallLogNameImpl,\n LOG_API_CALL_LOGGER_NAME,\n} from './http/ApiCallLogName';\nexport { ApiMethodInfo } from './http/ApiMethodInfo';\nexport type { ApiSide } from './http/ApiMethodInfo';\nexport type { ApiCallContext } from './http/ApiCallContext';\n\n// Test-case recording contract (impl lives in http-server; hooks in http-client)\nexport { TestCaseRecorder, RecorderKeys } from './http/recorder/TestCaseRecorder';\nexport {\n RecordedEndpoint,\n RecordedError,\n RecordedTestCase,\n} from './http/recorder/RecordedEndpoint';\nexport { DoNotRecord, getDoNotRecordFields } from './http/recorder/DoNotRecord';\nexport { RecordSerializer, SerializedMap, SerializedError } from './http/recorder/RecordSerializer';\n\n// ---------------------------------------------------------------------------------------------\n// Filter-chain primitives, shared by BOTH chains: the inbound server chain\n// (`Filter<MethodMeta, WpResponse<unknown>>`, @webpieces/http-routing) and the outbound client\n// chain (`Filter<ClientRequest, Response>`, @webpieces/http-client-core). Declared once, here, in\n// the package both depend on — see the class doc for why a second pair would be a shim.\nexport { Filter } from './filters/Filter';\nexport type { Service } from './filters/Filter';\nexport { FilterChain } from './filters/FilterChain';\n\nexport {\n ApiError,\n ApiNotFoundError,\n ApiDependencyError,\n ApiUnavailableError,\n ApiDependencyTimeoutError,\n ApiImplementationError,\n ApiRateLimitedError,\n ApiForbiddenError,\n ApiRequestTimeoutError,\n ApiEndUserError,\n ApiBadRequestError,\n ApiUnauthorizedError,\n ApiDependencyBackoffError,\n ApiConnectionError,\n ApiEndpointNotFoundError,\n ApiConflictError,\n ApiUnprocessableError,\n ApiPreconditionFailedError,\n ApiUnsupportedMediaTypeError,\n ApiNotImplementedError,\n ApiCodedError,\n ApiErrorCodec,\n ApiErrorPayload,\n ApiErrorBoundary,\n} from './errors';\nexport type { ApiErrorKind, ApiStatusCode, EdgeHttpStatus } from './errors';\nexport { ApiErrorHttpStatus } from './http/ApiErrorHttpStatus';\nexport type { PublishedKind, PublishedApiError } from './http/ApiErrorHttpStatus';\n"]}
|
package/src/ipc/IpcConnection.js
CHANGED
|
@@ -5,14 +5,8 @@ const errorUtils_1 = require("../lib/errorUtils");
|
|
|
5
5
|
const ApiCallTimeoutError_1 = require("../http/ApiCallTimeoutError");
|
|
6
6
|
const CallStrategy_1 = require("../http/CallStrategy");
|
|
7
7
|
const errors_1 = require("../errors");
|
|
8
|
+
const IpcRegistry_1 = require("./IpcRegistry");
|
|
8
9
|
const IpcProtocol_1 = require("./IpcProtocol");
|
|
9
|
-
/**
|
|
10
|
-
* The publication rule this OWNING boundary applies before an error crosses the IPC wire — the same
|
|
11
|
-
* one the HTTP server and MCP edges use. It matters here and not only there: an `ApiConnectionError`
|
|
12
|
-
* is OUR outbound call failing, so to the peer this process is what is broken, and it must read
|
|
13
|
-
* `implementation` rather than `connection`.
|
|
14
|
-
*/
|
|
15
|
-
const IPC_ERROR_BOUNDARY = new errors_1.ApiErrorBoundary();
|
|
16
10
|
/** A local connection failed, distinct from a remote implementation's semantic ApiError. */
|
|
17
11
|
class IpcTransportError extends Error {
|
|
18
12
|
constructor(message, cause) {
|
|
@@ -175,7 +169,11 @@ class IpcConnection {
|
|
|
175
169
|
}
|
|
176
170
|
catch (err) {
|
|
177
171
|
const error = (0, errorUtils_1.toError)(err);
|
|
178
|
-
|
|
172
|
+
// The ONE app-reachable seam for an outbound IPC failure. The webpieces default applies the
|
|
173
|
+
// same `ApiErrorBoundary` publication rule this used to call inline — notably that an
|
|
174
|
+
// `ApiConnectionError` publishes as `implementation`, because to the PEER this process is
|
|
175
|
+
// what is broken.
|
|
176
|
+
reply = new IpcProtocol_1.IpcFailure(request.context, IpcRegistry_1.IpcRegistry.getErrorTranslator().toWire(error));
|
|
179
177
|
}
|
|
180
178
|
finally {
|
|
181
179
|
this.activeRequests.delete(request.context.callId);
|
|
@@ -1 +1 @@
|
|
|
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 { ApiErrorBoundary, ApiEndpointNotFoundError, ApiImplementationError } from '../errors';\nimport {\n IpcCallContext,\n IpcFailure,\n IpcMessage,\n IpcReply,\n IpcRequest,\n IpcProtocol,\n} from './IpcProtocol';\n\n/**\n * The publication rule this OWNING boundary applies before an error crosses the IPC wire — the same\n * one the HTTP server and MCP edges use. It matters here and not only there: an `ApiConnectionError`\n * is OUR outbound call failing, so to the peer this process is what is broken, and it must read\n * `implementation` rather than `connection`.\n */\nconst IPC_ERROR_BOUNDARY = new ApiErrorBoundary();\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 new CallContext(request.apiId, request.methodId),\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 reply = new IpcFailure(request.context, IPC_ERROR_BOUNDARY.encode(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 { 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 new CallContext(request.apiId, request.methodId),\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"]}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { ApiErrorPayload } from '../errors/ApiErrorCodec';
|
|
2
|
+
import { IpcReply } from './IpcProtocol';
|
|
3
|
+
/**
|
|
4
|
+
* IpcErrorTranslator - ONE symmetric place an app owns IPC error translation, in BOTH directions.
|
|
5
|
+
*
|
|
6
|
+
* The exact twin of `ErrorTranslator` for HTTP, down to the shape of each half: `toWire` is called in
|
|
7
|
+
* a catch and RETURNS the payload the reply carries, `fromWire` is its mirror and THROWS. It exists
|
|
8
|
+
* for the same reason: IPC already HAD both halves, hand-rolled at three call sites
|
|
9
|
+
* (`IpcServerFactory.handle`, `IpcConnection.dispatch`, `IpcClientFactory`), with no seam an app could
|
|
10
|
+
* reach. An app whose two processes share an error taxonomy had nowhere to put it.
|
|
11
|
+
*
|
|
12
|
+
* Register one with {@link IpcRegistry.setErrorTranslator} — one registry per PROTOCOL, mirroring
|
|
13
|
+
* `ClientRegistry` for HTTP and `McpRegistry` for MCP, because the three speak different wire shapes
|
|
14
|
+
* and an app rarely wants the same answer on all three.
|
|
15
|
+
*
|
|
16
|
+
* There is ALWAYS a translator ({@link IpcRegistry.getErrorTranslator} is non-optional), so every call
|
|
17
|
+
* site is one unconditional line and a registered translator declines by DELEGATING to
|
|
18
|
+
* {@link WebpiecesDefaultIpcErrorTranslator}.
|
|
19
|
+
*
|
|
20
|
+
* This is a business-logic contract (methods, not data), so it is an interface per the webpieces
|
|
21
|
+
* guidelines.
|
|
22
|
+
*/
|
|
23
|
+
export interface IpcErrorTranslator {
|
|
24
|
+
/**
|
|
25
|
+
* SERVER: exception -> the wire payload carried by `IpcFailure`. Always a payload; decline by
|
|
26
|
+
* returning `new WebpiecesDefaultIpcErrorTranslator().toWire(error)`, which applies the shared
|
|
27
|
+
* `ApiErrorBoundary` publication rule (notably: a caller-local `ApiConnectionError` publishes as
|
|
28
|
+
* `implementation`, because to the PEER this process is what is broken).
|
|
29
|
+
*/
|
|
30
|
+
toWire(error: Error): ApiErrorPayload;
|
|
31
|
+
/**
|
|
32
|
+
* CLIENT: the reply -> a THROW. Called for EVERY reply, success or failure, exactly as on the
|
|
33
|
+
* HTTP side, so an app can turn a "successful" reply into a throw. Returning normally means "let
|
|
34
|
+
* this reply through"; the webpieces default returns for an `IpcSuccess` and throws for an
|
|
35
|
+
* `IpcFailure`. Decline by calling
|
|
36
|
+
* `new WebpiecesDefaultIpcErrorTranslator().fromWire(reply)`.
|
|
37
|
+
*/
|
|
38
|
+
fromWire(reply: IpcReply): void;
|
|
39
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IpcErrorTranslator.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/ipc/IpcErrorTranslator.ts"],"names":[],"mappings":"","sourcesContent":["import { ApiErrorPayload } from '../errors/ApiErrorCodec';\nimport { IpcReply } from './IpcProtocol';\n\n/**\n * IpcErrorTranslator - ONE symmetric place an app owns IPC error translation, in BOTH directions.\n *\n * The exact twin of `ErrorTranslator` for HTTP, down to the shape of each half: `toWire` is called in\n * a catch and RETURNS the payload the reply carries, `fromWire` is its mirror and THROWS. It exists\n * for the same reason: IPC already HAD both halves, hand-rolled at three call sites\n * (`IpcServerFactory.handle`, `IpcConnection.dispatch`, `IpcClientFactory`), with no seam an app could\n * reach. An app whose two processes share an error taxonomy had nowhere to put it.\n *\n * Register one with {@link IpcRegistry.setErrorTranslator} — one registry per PROTOCOL, mirroring\n * `ClientRegistry` for HTTP and `McpRegistry` for MCP, because the three speak different wire shapes\n * and an app rarely wants the same answer on all three.\n *\n * There is ALWAYS a translator ({@link IpcRegistry.getErrorTranslator} is non-optional), so every call\n * site is one unconditional line and a registered translator declines by DELEGATING to\n * {@link WebpiecesDefaultIpcErrorTranslator}.\n *\n * This is a business-logic contract (methods, not data), so it is an interface per the webpieces\n * guidelines.\n */\nexport interface IpcErrorTranslator {\n /**\n * SERVER: exception -> the wire payload carried by `IpcFailure`. Always a payload; decline by\n * returning `new WebpiecesDefaultIpcErrorTranslator().toWire(error)`, which applies the shared\n * `ApiErrorBoundary` publication rule (notably: a caller-local `ApiConnectionError` publishes as\n * `implementation`, because to the PEER this process is what is broken).\n */\n toWire(error: Error): ApiErrorPayload;\n\n /**\n * CLIENT: the reply -> a THROW. Called for EVERY reply, success or failure, exactly as on the\n * HTTP side, so an app can turn a \"successful\" reply into a throw. Returning normally means \"let\n * this reply through\"; the webpieces default returns for an `IpcSuccess` and throws for an\n * `IpcFailure`. Decline by calling\n * `new WebpiecesDefaultIpcErrorTranslator().fromWire(reply)`.\n */\n fromWire(reply: IpcReply): void;\n}\n"]}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { IpcErrorTranslator } from './IpcErrorTranslator';
|
|
2
|
+
import { IpcReply, IpcSuccess } from './IpcProtocol';
|
|
3
|
+
/**
|
|
4
|
+
* IpcRegistry - the process-global home of the ONE {@link IpcErrorTranslator}, mirroring
|
|
5
|
+
* `ClientRegistry` for HTTP and `McpRegistry` for MCP.
|
|
6
|
+
*
|
|
7
|
+
* ONE REGISTRY PER PROTOCOL, and that is the design: the three speak different wire shapes
|
|
8
|
+
* (`HttpResponseDto`, `CallToolResult`, `ApiErrorPayload`), so one combined registry would either
|
|
9
|
+
* force an app to answer three unrelated questions in one object or hide two of them behind
|
|
10
|
+
* optionality. Three registries, three unconditional call sites.
|
|
11
|
+
*
|
|
12
|
+
* Configured like `HeaderRegistry` / `ClientRegistry` / LogManager — populated once at startup, then
|
|
13
|
+
* globally accessible with NO DI wiring.
|
|
14
|
+
*
|
|
15
|
+
* ```ts
|
|
16
|
+
* // startup, ONCE per process, in BOTH processes that share the connection
|
|
17
|
+
* IpcRegistry.setErrorTranslator(new MyIpcErrorTranslator());
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare class IpcRegistry {
|
|
21
|
+
/**
|
|
22
|
+
* THE translator. NEVER undefined — it starts life holding
|
|
23
|
+
* {@link WEBPIECES_DEFAULT_IPC_ERROR_TRANSLATOR}, and {@link IpcRegistry.setErrorTranslator}
|
|
24
|
+
* REPLACES it. So no IPC call site asks "did anyone register one".
|
|
25
|
+
*/
|
|
26
|
+
private static errorTranslator;
|
|
27
|
+
/**
|
|
28
|
+
* Install the app's {@link IpcErrorTranslator}. `set`, not `add`: an app with several layers of
|
|
29
|
+
* error policy composes them INSIDE its own `toWire`, where the precedence is written down.
|
|
30
|
+
*/
|
|
31
|
+
static setErrorTranslator(translator: IpcErrorTranslator): void;
|
|
32
|
+
/** THE {@link IpcErrorTranslator} for this process — never `undefined`, so no caller branches. */
|
|
33
|
+
static getErrorTranslator(): IpcErrorTranslator;
|
|
34
|
+
/** Put the process-global back to the webpieces default. For TESTS, so specs cannot leak. */
|
|
35
|
+
static resetForTests(): void;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* The CLIENT half's one call site, and the guarantee behind it — the IPC twin of
|
|
39
|
+
* `ClientErrorTranslator.throwIfFailure`.
|
|
40
|
+
*
|
|
41
|
+
* The `asserts` return type is what lets `IpcClientFactory` read the success body straight afterwards
|
|
42
|
+
* with no `if (reply.type === 'failure')` branch left over: after this call the compiler knows the
|
|
43
|
+
* reply is an {@link IpcSuccess}, because the only way past it is that it is one.
|
|
44
|
+
*/
|
|
45
|
+
export declare class IpcClientErrorTranslator {
|
|
46
|
+
/**
|
|
47
|
+
* Run `fromWire` over a reply, and make it impossible for an `IpcFailure` to be read as data.
|
|
48
|
+
*
|
|
49
|
+
* The second call is BUG CONTAINMENT, not a fallback branch: an app translator that returns
|
|
50
|
+
* normally for a failure reply has a bug whose symptom would otherwise be `undefined` arriving
|
|
51
|
+
* where the contract promised a DTO. For a genuine success the default returns immediately, so
|
|
52
|
+
* the normal path costs one comparison.
|
|
53
|
+
*/
|
|
54
|
+
static throwIfFailure(reply: IpcReply): asserts reply is IpcSuccess;
|
|
55
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.IpcClientErrorTranslator = exports.IpcRegistry = void 0;
|
|
4
|
+
const WebpiecesDefaultIpcErrorTranslator_1 = require("./WebpiecesDefaultIpcErrorTranslator");
|
|
5
|
+
/**
|
|
6
|
+
* IpcRegistry - the process-global home of the ONE {@link IpcErrorTranslator}, mirroring
|
|
7
|
+
* `ClientRegistry` for HTTP and `McpRegistry` for MCP.
|
|
8
|
+
*
|
|
9
|
+
* ONE REGISTRY PER PROTOCOL, and that is the design: the three speak different wire shapes
|
|
10
|
+
* (`HttpResponseDto`, `CallToolResult`, `ApiErrorPayload`), so one combined registry would either
|
|
11
|
+
* force an app to answer three unrelated questions in one object or hide two of them behind
|
|
12
|
+
* optionality. Three registries, three unconditional call sites.
|
|
13
|
+
*
|
|
14
|
+
* Configured like `HeaderRegistry` / `ClientRegistry` / LogManager — populated once at startup, then
|
|
15
|
+
* globally accessible with NO DI wiring.
|
|
16
|
+
*
|
|
17
|
+
* ```ts
|
|
18
|
+
* // startup, ONCE per process, in BOTH processes that share the connection
|
|
19
|
+
* IpcRegistry.setErrorTranslator(new MyIpcErrorTranslator());
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
class IpcRegistry {
|
|
23
|
+
/**
|
|
24
|
+
* THE translator. NEVER undefined — it starts life holding
|
|
25
|
+
* {@link WEBPIECES_DEFAULT_IPC_ERROR_TRANSLATOR}, and {@link IpcRegistry.setErrorTranslator}
|
|
26
|
+
* REPLACES it. So no IPC call site asks "did anyone register one".
|
|
27
|
+
*/
|
|
28
|
+
static errorTranslator = WebpiecesDefaultIpcErrorTranslator_1.WEBPIECES_DEFAULT_IPC_ERROR_TRANSLATOR;
|
|
29
|
+
/**
|
|
30
|
+
* Install the app's {@link IpcErrorTranslator}. `set`, not `add`: an app with several layers of
|
|
31
|
+
* error policy composes them INSIDE its own `toWire`, where the precedence is written down.
|
|
32
|
+
*/
|
|
33
|
+
// webpieces-disable no-function-outside-class -- static global singleton (like HeaderRegistry/ClientRegistry); populated once at startup, never DI-injected
|
|
34
|
+
static setErrorTranslator(translator) {
|
|
35
|
+
IpcRegistry.errorTranslator = translator;
|
|
36
|
+
}
|
|
37
|
+
/** THE {@link IpcErrorTranslator} for this process — never `undefined`, so no caller branches. */
|
|
38
|
+
// webpieces-disable no-function-outside-class -- static global singleton (like HeaderRegistry/ClientRegistry); populated once at startup, never DI-injected
|
|
39
|
+
static getErrorTranslator() {
|
|
40
|
+
return IpcRegistry.errorTranslator;
|
|
41
|
+
}
|
|
42
|
+
/** Put the process-global back to the webpieces default. For TESTS, so specs cannot leak. */
|
|
43
|
+
// webpieces-disable no-function-outside-class -- static global singleton (like HeaderRegistry/ClientRegistry); populated once at startup, never DI-injected
|
|
44
|
+
static resetForTests() {
|
|
45
|
+
IpcRegistry.errorTranslator = WebpiecesDefaultIpcErrorTranslator_1.WEBPIECES_DEFAULT_IPC_ERROR_TRANSLATOR;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.IpcRegistry = IpcRegistry;
|
|
49
|
+
/**
|
|
50
|
+
* The CLIENT half's one call site, and the guarantee behind it — the IPC twin of
|
|
51
|
+
* `ClientErrorTranslator.throwIfFailure`.
|
|
52
|
+
*
|
|
53
|
+
* The `asserts` return type is what lets `IpcClientFactory` read the success body straight afterwards
|
|
54
|
+
* with no `if (reply.type === 'failure')` branch left over: after this call the compiler knows the
|
|
55
|
+
* reply is an {@link IpcSuccess}, because the only way past it is that it is one.
|
|
56
|
+
*/
|
|
57
|
+
class IpcClientErrorTranslator {
|
|
58
|
+
/**
|
|
59
|
+
* Run `fromWire` over a reply, and make it impossible for an `IpcFailure` to be read as data.
|
|
60
|
+
*
|
|
61
|
+
* The second call is BUG CONTAINMENT, not a fallback branch: an app translator that returns
|
|
62
|
+
* normally for a failure reply has a bug whose symptom would otherwise be `undefined` arriving
|
|
63
|
+
* where the contract promised a DTO. For a genuine success the default returns immediately, so
|
|
64
|
+
* the normal path costs one comparison.
|
|
65
|
+
*/
|
|
66
|
+
// webpieces-disable no-function-outside-class -- stateless boundary shared by every IPC client proxy
|
|
67
|
+
static throwIfFailure(reply) {
|
|
68
|
+
IpcRegistry.getErrorTranslator().fromWire(reply);
|
|
69
|
+
WebpiecesDefaultIpcErrorTranslator_1.WEBPIECES_DEFAULT_IPC_ERROR_TRANSLATOR.fromWire(reply);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
exports.IpcClientErrorTranslator = IpcClientErrorTranslator;
|
|
73
|
+
//# sourceMappingURL=IpcRegistry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IpcRegistry.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/ipc/IpcRegistry.ts"],"names":[],"mappings":";;;AAEA,6FAA8F;AAE9F;;;;;;;;;;;;;;;;GAgBG;AACH,MAAa,WAAW;IACpB;;;;OAIG;IACK,MAAM,CAAC,eAAe,GAAuB,2EAAsC,CAAC;IAE5F;;;OAGG;IACH,4JAA4J;IAC5J,MAAM,CAAC,kBAAkB,CAAC,UAA8B;QACpD,WAAW,CAAC,eAAe,GAAG,UAAU,CAAC;IAC7C,CAAC;IAED,kGAAkG;IAClG,4JAA4J;IAC5J,MAAM,CAAC,kBAAkB;QACrB,OAAO,WAAW,CAAC,eAAe,CAAC;IACvC,CAAC;IAED,6FAA6F;IAC7F,4JAA4J;IAC5J,MAAM,CAAC,aAAa;QAChB,WAAW,CAAC,eAAe,GAAG,2EAAsC,CAAC;IACzE,CAAC;;AA3BL,kCA4BC;AAED;;;;;;;GAOG;AACH,MAAa,wBAAwB;IACjC;;;;;;;OAOG;IACH,qGAAqG;IACrG,MAAM,CAAC,cAAc,CAAC,KAAe;QACjC,WAAW,CAAC,kBAAkB,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACjD,2EAAsC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC3D,CAAC;CACJ;AAdD,4DAcC","sourcesContent":["import { IpcErrorTranslator } from './IpcErrorTranslator';\nimport { IpcReply, IpcSuccess } from './IpcProtocol';\nimport { WEBPIECES_DEFAULT_IPC_ERROR_TRANSLATOR } from './WebpiecesDefaultIpcErrorTranslator';\n\n/**\n * IpcRegistry - the process-global home of the ONE {@link IpcErrorTranslator}, mirroring\n * `ClientRegistry` for HTTP and `McpRegistry` for MCP.\n *\n * ONE REGISTRY PER PROTOCOL, and that is the design: the three speak different wire shapes\n * (`HttpResponseDto`, `CallToolResult`, `ApiErrorPayload`), so one combined registry would either\n * force an app to answer three unrelated questions in one object or hide two of them behind\n * optionality. Three registries, three unconditional call sites.\n *\n * Configured like `HeaderRegistry` / `ClientRegistry` / LogManager — populated once at startup, then\n * globally accessible with NO DI wiring.\n *\n * ```ts\n * // startup, ONCE per process, in BOTH processes that share the connection\n * IpcRegistry.setErrorTranslator(new MyIpcErrorTranslator());\n * ```\n */\nexport class IpcRegistry {\n /**\n * THE translator. NEVER undefined — it starts life holding\n * {@link WEBPIECES_DEFAULT_IPC_ERROR_TRANSLATOR}, and {@link IpcRegistry.setErrorTranslator}\n * REPLACES it. So no IPC call site asks \"did anyone register one\".\n */\n private static errorTranslator: IpcErrorTranslator = WEBPIECES_DEFAULT_IPC_ERROR_TRANSLATOR;\n\n /**\n * Install the app's {@link IpcErrorTranslator}. `set`, not `add`: an app with several layers of\n * error policy composes them INSIDE its own `toWire`, where the precedence is written down.\n */\n // webpieces-disable no-function-outside-class -- static global singleton (like HeaderRegistry/ClientRegistry); populated once at startup, never DI-injected\n static setErrorTranslator(translator: IpcErrorTranslator): void {\n IpcRegistry.errorTranslator = translator;\n }\n\n /** THE {@link IpcErrorTranslator} for this process — never `undefined`, so no caller branches. */\n // webpieces-disable no-function-outside-class -- static global singleton (like HeaderRegistry/ClientRegistry); populated once at startup, never DI-injected\n static getErrorTranslator(): IpcErrorTranslator {\n return IpcRegistry.errorTranslator;\n }\n\n /** Put the process-global back to the webpieces default. For TESTS, so specs cannot leak. */\n // webpieces-disable no-function-outside-class -- static global singleton (like HeaderRegistry/ClientRegistry); populated once at startup, never DI-injected\n static resetForTests(): void {\n IpcRegistry.errorTranslator = WEBPIECES_DEFAULT_IPC_ERROR_TRANSLATOR;\n }\n}\n\n/**\n * The CLIENT half's one call site, and the guarantee behind it — the IPC twin of\n * `ClientErrorTranslator.throwIfFailure`.\n *\n * The `asserts` return type is what lets `IpcClientFactory` read the success body straight afterwards\n * with no `if (reply.type === 'failure')` branch left over: after this call the compiler knows the\n * reply is an {@link IpcSuccess}, because the only way past it is that it is one.\n */\nexport class IpcClientErrorTranslator {\n /**\n * Run `fromWire` over a reply, and make it impossible for an `IpcFailure` to be read as data.\n *\n * The second call is BUG CONTAINMENT, not a fallback branch: an app translator that returns\n * normally for a failure reply has a bug whose symptom would otherwise be `undefined` arriving\n * where the contract promised a DTO. For a genuine success the default returns immediately, so\n * the normal path costs one comparison.\n */\n // webpieces-disable no-function-outside-class -- stateless boundary shared by every IPC client proxy\n static throwIfFailure(reply: IpcReply): asserts reply is IpcSuccess {\n IpcRegistry.getErrorTranslator().fromWire(reply);\n WEBPIECES_DEFAULT_IPC_ERROR_TRANSLATOR.fromWire(reply);\n }\n}\n"]}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ApiErrorPayload } from '../errors/ApiErrorCodec';
|
|
2
|
+
import { IpcErrorTranslator } from './IpcErrorTranslator';
|
|
3
|
+
import { IpcReply } from './IpcProtocol';
|
|
4
|
+
/**
|
|
5
|
+
* THE webpieces default {@link IpcErrorTranslator}, and what {@link IpcRegistry} holds until an app
|
|
6
|
+
* installs its own.
|
|
7
|
+
*
|
|
8
|
+
* `toWire` is exactly what the two IPC receivers did inline before this seam existed — the shared
|
|
9
|
+
* {@link ApiErrorBoundary}, so the `ApiConnectionError` -> `implementation` rule survives untouched.
|
|
10
|
+
*
|
|
11
|
+
* `fromWire` is a BEHAVIOUR CHANGE and a deliberate one. `IpcClientFactory` used to rethrow
|
|
12
|
+
* `ApiErrorCodec.decode(reply.error)` verbatim, which handed the caller the PEER's error type as if
|
|
13
|
+
* this process had produced it. IPC now applies the SAME {@link ReceivedApiErrorRule} as HTTP: a
|
|
14
|
+
* caller-error kind coming back means I sent a bad IPC request (MY bug ->
|
|
15
|
+
* `ApiImplementationError`), a server-side kind means the peer broke (NOT my bug ->
|
|
16
|
+
* `ApiDependencyError`), an incoming `ApiDependencyError` is already attributed and rethrows as-is,
|
|
17
|
+
* and an `ApiEndUserError` is the actor's own answer and passes through.
|
|
18
|
+
*
|
|
19
|
+
* The two protocols share ONE rule object rather than two copies for the obvious reason: an app that
|
|
20
|
+
* moves a call from IPC to HTTP or back must not thereby change which team gets paged.
|
|
21
|
+
*/
|
|
22
|
+
export declare class WebpiecesDefaultIpcErrorTranslator implements IpcErrorTranslator {
|
|
23
|
+
private readonly boundary;
|
|
24
|
+
toWire(error: Error): ApiErrorPayload;
|
|
25
|
+
fromWire(reply: IpcReply): void;
|
|
26
|
+
}
|
|
27
|
+
/** Process-wide built-in instance — stateless, so one shared instance is enough. */
|
|
28
|
+
export declare const WEBPIECES_DEFAULT_IPC_ERROR_TRANSLATOR: WebpiecesDefaultIpcErrorTranslator;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WEBPIECES_DEFAULT_IPC_ERROR_TRANSLATOR = exports.WebpiecesDefaultIpcErrorTranslator = void 0;
|
|
4
|
+
const ApiErrorBoundary_1 = require("../errors/ApiErrorBoundary");
|
|
5
|
+
const ApiErrorCodec_1 = require("../errors/ApiErrorCodec");
|
|
6
|
+
const ApiError_1 = require("../errors/ApiError");
|
|
7
|
+
const ReceivedApiErrorRule_1 = require("../errors/ReceivedApiErrorRule");
|
|
8
|
+
const ApiErrorHttpStatus_1 = require("../http/ApiErrorHttpStatus");
|
|
9
|
+
/**
|
|
10
|
+
* THE webpieces default {@link IpcErrorTranslator}, and what {@link IpcRegistry} holds until an app
|
|
11
|
+
* installs its own.
|
|
12
|
+
*
|
|
13
|
+
* `toWire` is exactly what the two IPC receivers did inline before this seam existed — the shared
|
|
14
|
+
* {@link ApiErrorBoundary}, so the `ApiConnectionError` -> `implementation` rule survives untouched.
|
|
15
|
+
*
|
|
16
|
+
* `fromWire` is a BEHAVIOUR CHANGE and a deliberate one. `IpcClientFactory` used to rethrow
|
|
17
|
+
* `ApiErrorCodec.decode(reply.error)` verbatim, which handed the caller the PEER's error type as if
|
|
18
|
+
* this process had produced it. IPC now applies the SAME {@link ReceivedApiErrorRule} as HTTP: a
|
|
19
|
+
* caller-error kind coming back means I sent a bad IPC request (MY bug ->
|
|
20
|
+
* `ApiImplementationError`), a server-side kind means the peer broke (NOT my bug ->
|
|
21
|
+
* `ApiDependencyError`), an incoming `ApiDependencyError` is already attributed and rethrows as-is,
|
|
22
|
+
* and an `ApiEndUserError` is the actor's own answer and passes through.
|
|
23
|
+
*
|
|
24
|
+
* The two protocols share ONE rule object rather than two copies for the obvious reason: an app that
|
|
25
|
+
* moves a call from IPC to HTTP or back must not thereby change which team gets paged.
|
|
26
|
+
*/
|
|
27
|
+
class WebpiecesDefaultIpcErrorTranslator {
|
|
28
|
+
boundary = new ApiErrorBoundary_1.ApiErrorBoundary();
|
|
29
|
+
toWire(error) {
|
|
30
|
+
return this.boundary.encode(error);
|
|
31
|
+
}
|
|
32
|
+
fromWire(reply) {
|
|
33
|
+
if (reply.type === 'success') {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const decoded = ApiErrorCodec_1.ApiErrorCodec.decode(reply.error);
|
|
37
|
+
// IPC has no wire status, so the equivalent is derived from the payload's own kind through
|
|
38
|
+
// the ONE status table HTTP uses. Same table, same verdict, no second ladder to keep in step.
|
|
39
|
+
const statusCode = decoded instanceof ApiError_1.ApiCodedError ? decoded.statusCode : undefined;
|
|
40
|
+
const equivalent = ApiErrorHttpStatus_1.ApiErrorHttpStatus.hasCode(decoded)
|
|
41
|
+
? ApiErrorHttpStatus_1.ApiErrorHttpStatus.codeFor(decoded.kind, statusCode)
|
|
42
|
+
: 500;
|
|
43
|
+
throw ReceivedApiErrorRule_1.ReceivedApiErrorRule.adapt(equivalent, decoded.message, decoded);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
exports.WebpiecesDefaultIpcErrorTranslator = WebpiecesDefaultIpcErrorTranslator;
|
|
47
|
+
/** Process-wide built-in instance — stateless, so one shared instance is enough. */
|
|
48
|
+
exports.WEBPIECES_DEFAULT_IPC_ERROR_TRANSLATOR = new WebpiecesDefaultIpcErrorTranslator();
|
|
49
|
+
//# sourceMappingURL=WebpiecesDefaultIpcErrorTranslator.js.map
|