@webpieces/core-util 0.4.750 → 0.4.751
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 +6 -0
- package/package.json +9 -1
- package/src/errors/ApiError.d.ts +70 -0
- package/src/errors/ApiError.js +106 -0
- package/src/errors/ApiError.js.map +1 -0
- package/src/errors/ApiErrorCodec.d.ts +25 -0
- package/src/errors/ApiErrorCodec.js +184 -0
- package/src/errors/ApiErrorCodec.js.map +1 -0
- package/src/errors/index.d.ts +2 -0
- package/src/errors/index.js +23 -0
- package/src/errors/index.js.map +1 -0
- package/src/http/HttpErrorStatus.d.ts +5 -0
- package/src/http/HttpErrorStatus.js +38 -0
- package/src/http/HttpErrorStatus.js.map +1 -0
- package/src/http/LogApiCall.d.ts +1 -1
- package/src/http/LogApiCall.js +7 -2
- package/src/http/LogApiCall.js.map +1 -1
- package/src/http/WebpiecesDefaultFailureClassifier.d.ts +4 -4
- package/src/http/WebpiecesDefaultFailureClassifier.js +11 -11
- package/src/http/WebpiecesDefaultFailureClassifier.js.map +1 -1
- package/src/http/decorators.d.ts +1 -1
- package/src/http/decorators.js +1 -1
- package/src/http/decorators.js.map +1 -1
- package/src/http/errors.d.ts +35 -158
- package/src/http/errors.js +65 -235
- package/src/http/errors.js.map +1 -1
- package/src/index.d.ts +8 -6
- package/src/index.js +20 -2
- package/src/index.js.map +1 -1
- package/src/ipc/IpcCompileAssertions.d.ts +4 -0
- package/src/ipc/IpcCompileAssertions.js +39 -0
- package/src/ipc/IpcCompileAssertions.js.map +1 -0
- package/src/ipc/IpcConnection.d.ts +50 -0
- package/src/ipc/IpcConnection.js +187 -0
- package/src/ipc/IpcConnection.js.map +1 -0
- package/src/ipc/IpcContract.d.ts +32 -0
- package/src/ipc/IpcContract.js +65 -0
- package/src/ipc/IpcContract.js.map +1 -0
- package/src/ipc/IpcLogging.d.ts +11 -0
- package/src/ipc/IpcLogging.js +13 -0
- package/src/ipc/IpcLogging.js.map +1 -0
- package/src/ipc/IpcProtocol.d.ts +37 -0
- package/src/ipc/IpcProtocol.js +103 -0
- package/src/ipc/IpcProtocol.js.map +1 -0
- package/src/ipc/index.d.ts +14 -0
- package/src/ipc/index.js +31 -0
- package/src/ipc/index.js.map +1 -0
package/src/index.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
11
|
exports.assertApiKind = exports.getApiKind = exports.ENDPOINT_KINDS_BY_API_KIND = exports.Queue = exports.PubSub = exports.Rpc = exports.AuthMeta = exports.RouteMetadata = 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.AuthLocalOnly = exports.AuthApiKey = exports.AuthWebhook = exports.AuthSharedSecret = exports.AuthOidc = exports.MISSING_AUTH_DECORATOR_FIX = exports.rolesRequired = exports.AuthJwt = exports.Public = 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.KeyedFailureClassifier = exports.HttpResponseDto = exports.HttpResponseStatus = exports.HttpHeader = exports.RuntimeLocality = exports.ServiceInfo = exports.TimeoutError = 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.OfflineError = exports.HttpUserError = exports.HttpVendorError = exports.HttpTooManyRequestsError = exports.HttpInternalServerError = exports.HttpGatewayTimeoutError = exports.HttpServiceUnavailableError = exports.HttpBadGatewayError = exports.HttpTimeoutError = exports.HttpForbiddenError = exports.HttpUnauthorizedError = exports.HttpBadRequestError = exports.EndpointNotFoundError = exports.HttpNotFoundError = exports.HttpError = exports.ProtocolError = exports.SECRETS = exports.Secrets = exports.getEndpointCaller = exports.isExternalSystemKind = exports.ExternalCaller = exports.DEFAULT_CALLER_KIND = exports.EXTERNAL_SYSTEM_KINDS = exports.getQueueName = exports.assertPubSubConventions = void 0;
|
|
13
|
-
exports.FilterChain = exports.Filter = exports.SerializedError = exports.SerializedMap = exports.RecordSerializer = 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 = void 0;
|
|
13
|
+
exports.HttpErrorStatus = exports.ApiErrorPayload = exports.ApiErrorCodec = exports.VendorError = exports.UnauthorizedError = exports.BadRequestError = exports.UserError = exports.RequestTimeoutError = exports.ForbiddenError = exports.TooManyRequestsError = exports.InternalError = exports.GatewayTimeoutError = exports.ServiceUnavailableError = exports.BadGatewayError = exports.NotFoundError = exports.ApiError = exports.FilterChain = exports.Filter = exports.SerializedError = exports.SerializedMap = exports.RecordSerializer = 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 = void 0;
|
|
14
14
|
var errorUtils_1 = require("./lib/errorUtils");
|
|
15
15
|
Object.defineProperty(exports, "toError", { enumerable: true, get: function () { return errorUtils_1.toError; } });
|
|
16
16
|
var ContextKey_1 = require("./ContextKey");
|
|
@@ -101,7 +101,7 @@ Object.defineProperty(exports, "getEndpointCaller", { enumerable: true, get: fun
|
|
|
101
101
|
var Secrets_1 = require("./http/Secrets");
|
|
102
102
|
Object.defineProperty(exports, "Secrets", { enumerable: true, get: function () { return Secrets_1.Secrets; } });
|
|
103
103
|
Object.defineProperty(exports, "SECRETS", { enumerable: true, get: function () { return Secrets_1.SECRETS; } });
|
|
104
|
-
// HTTP
|
|
104
|
+
// HTTP wire DTO, legacy aliases and subtype constants.
|
|
105
105
|
var errors_1 = require("./http/errors");
|
|
106
106
|
Object.defineProperty(exports, "ProtocolError", { enumerable: true, get: function () { return errors_1.ProtocolError; } });
|
|
107
107
|
Object.defineProperty(exports, "HttpError", { enumerable: true, get: function () { return errors_1.HttpError; } });
|
|
@@ -225,4 +225,22 @@ var Filter_1 = require("./filters/Filter");
|
|
|
225
225
|
Object.defineProperty(exports, "Filter", { enumerable: true, get: function () { return Filter_1.Filter; } });
|
|
226
226
|
var FilterChain_1 = require("./filters/FilterChain");
|
|
227
227
|
Object.defineProperty(exports, "FilterChain", { enumerable: true, get: function () { return FilterChain_1.FilterChain; } });
|
|
228
|
+
var errors_2 = require("./errors");
|
|
229
|
+
Object.defineProperty(exports, "ApiError", { enumerable: true, get: function () { return errors_2.ApiError; } });
|
|
230
|
+
Object.defineProperty(exports, "NotFoundError", { enumerable: true, get: function () { return errors_2.NotFoundError; } });
|
|
231
|
+
Object.defineProperty(exports, "BadGatewayError", { enumerable: true, get: function () { return errors_2.BadGatewayError; } });
|
|
232
|
+
Object.defineProperty(exports, "ServiceUnavailableError", { enumerable: true, get: function () { return errors_2.ServiceUnavailableError; } });
|
|
233
|
+
Object.defineProperty(exports, "GatewayTimeoutError", { enumerable: true, get: function () { return errors_2.GatewayTimeoutError; } });
|
|
234
|
+
Object.defineProperty(exports, "InternalError", { enumerable: true, get: function () { return errors_2.InternalError; } });
|
|
235
|
+
Object.defineProperty(exports, "TooManyRequestsError", { enumerable: true, get: function () { return errors_2.TooManyRequestsError; } });
|
|
236
|
+
Object.defineProperty(exports, "ForbiddenError", { enumerable: true, get: function () { return errors_2.ForbiddenError; } });
|
|
237
|
+
Object.defineProperty(exports, "RequestTimeoutError", { enumerable: true, get: function () { return errors_2.RequestTimeoutError; } });
|
|
238
|
+
Object.defineProperty(exports, "UserError", { enumerable: true, get: function () { return errors_2.UserError; } });
|
|
239
|
+
Object.defineProperty(exports, "BadRequestError", { enumerable: true, get: function () { return errors_2.BadRequestError; } });
|
|
240
|
+
Object.defineProperty(exports, "UnauthorizedError", { enumerable: true, get: function () { return errors_2.UnauthorizedError; } });
|
|
241
|
+
Object.defineProperty(exports, "VendorError", { enumerable: true, get: function () { return errors_2.VendorError; } });
|
|
242
|
+
Object.defineProperty(exports, "ApiErrorCodec", { enumerable: true, get: function () { return errors_2.ApiErrorCodec; } });
|
|
243
|
+
Object.defineProperty(exports, "ApiErrorPayload", { enumerable: true, get: function () { return errors_2.ApiErrorPayload; } });
|
|
244
|
+
var HttpErrorStatus_1 = require("./http/HttpErrorStatus");
|
|
245
|
+
Object.defineProperty(exports, "HttpErrorStatus", { enumerable: true, get: function () { return HttpErrorStatus_1.HttpErrorStatus; } });
|
|
228
246
|
//# sourceMappingURL=index.js.map
|
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":"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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 { AnyContextKey, AnyTrustedContextKey, AnyUntrustedContextKey, Trust } 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 { LogChunker, LogChunkerImpl, LogChunkInfo, MAX_GCP_LOG_BYTES, GCP_LOG_BUDGET_BYTES } 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 HttpError hierarchy, 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 Public,\n AuthJwt,\n rolesRequired,\n MISSING_AUTH_DECORATOR_FIX,\n AuthOidc,\n AuthSharedSecret,\n AuthWebhook,\n AuthApiKey,\n AuthLocalOnly,\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';\n// The runtime representation of ONE route (split out of decorators.ts for file size only).\nexport { RouteMetadata } from './http/RouteMetadata';\nexport type { EndpointKind, EndpointOptions, ExternalEndpointOptions } from './http/decorators';\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 { AuthMode, ApiKeyCredential, ApiKeyCredentials, JwtRoles, JwtRequirement } 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 { EXTERNAL_SYSTEM_KINDS, DEFAULT_CALLER_KIND, ExternalCaller, isExternalSystemKind, getEndpointCaller } from './http/external-caller';\nexport type { ExternalSystemKind } from './http/external-caller';\n// Client-side shared-secret store (the value THIS service sends per @AuthSharedSecret key).\nexport { Secrets, SECRETS } from './http/Secrets';\n\n// Type validators\nexport { ValidateImplementation } from './http/validators';\n\n// HTTP errors\nexport {\n ProtocolError,\n HttpError,\n HttpNotFoundError,\n EndpointNotFoundError,\n HttpBadRequestError,\n HttpUnauthorizedError,\n HttpForbiddenError,\n HttpTimeoutError,\n HttpBadGatewayError,\n HttpServiceUnavailableError,\n HttpGatewayTimeoutError,\n HttpInternalServerError,\n HttpTooManyRequestsError,\n HttpVendorError,\n HttpUserError,\n OfflineError,\n // Error subtype constants\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 './http/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 { TimeoutError } from './http/TimeoutError';\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 @AuthLocalOnly 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 { ApiCallLogName, ApiCallLogNameImpl, LOG_API_CALL_LOGGER_NAME } 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 { RecordedEndpoint, RecordedError, RecordedTestCase } 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"]}
|
|
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 HttpError hierarchy, 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 Public,\n AuthJwt,\n rolesRequired,\n MISSING_AUTH_DECORATOR_FIX,\n AuthOidc,\n AuthSharedSecret,\n AuthWebhook,\n AuthApiKey,\n AuthLocalOnly,\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';\n// The runtime representation of ONE route (split out of decorators.ts for file size only).\nexport { RouteMetadata } from './http/RouteMetadata';\nexport type { EndpointKind, EndpointOptions, ExternalEndpointOptions } from './http/decorators';\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 @AuthSharedSecret key).\nexport { Secrets, SECRETS } from './http/Secrets';\n\n// Type validators\nexport { ValidateImplementation } from './http/validators';\n\n// HTTP wire DTO, legacy aliases and subtype constants.\nexport {\n ProtocolError,\n HttpError,\n HttpNotFoundError,\n EndpointNotFoundError,\n HttpBadRequestError,\n HttpUnauthorizedError,\n HttpForbiddenError,\n HttpTimeoutError,\n HttpBadGatewayError,\n HttpServiceUnavailableError,\n HttpGatewayTimeoutError,\n HttpInternalServerError,\n HttpTooManyRequestsError,\n HttpVendorError,\n HttpUserError,\n OfflineError,\n // Error subtype constants\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 './http/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 { TimeoutError } from './http/TimeoutError';\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 @AuthLocalOnly 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 NotFoundError,\n BadGatewayError,\n ServiceUnavailableError,\n GatewayTimeoutError,\n InternalError,\n TooManyRequestsError,\n ForbiddenError,\n RequestTimeoutError,\n UserError,\n BadRequestError,\n UnauthorizedError,\n VendorError,\n ApiErrorCodec,\n ApiErrorPayload,\n} from './errors';\nexport { HttpErrorStatus } from './http/HttpErrorStatus';\n"]}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.IpcCompileAssertions = void 0;
|
|
4
|
+
const IpcContract_1 = require("./IpcContract");
|
|
5
|
+
const LogFieldMask_1 = require("../http/LogFieldMask");
|
|
6
|
+
class Request {
|
|
7
|
+
id;
|
|
8
|
+
constructor(id) {
|
|
9
|
+
this.id = id;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
class Schema {
|
|
13
|
+
// webpieces-disable no-any-unknown -- untrusted IPC data is schema-validated; generic dispatch cannot assume a DTO type before validation
|
|
14
|
+
parse(value) {
|
|
15
|
+
if (!(value instanceof Request))
|
|
16
|
+
throw new Error('Expected Request');
|
|
17
|
+
return value;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
class Api {
|
|
21
|
+
}
|
|
22
|
+
class Incomplete {
|
|
23
|
+
first = new IpcContract_1.IpcMethod('first', new Schema(), new Schema(), new LogFieldMask_1.MaskSpec({}));
|
|
24
|
+
}
|
|
25
|
+
class MultipleApi {
|
|
26
|
+
}
|
|
27
|
+
/** These assertions compile in package builds, unlike transpiled-only spec files. Never invoked. */
|
|
28
|
+
class IpcCompileAssertions {
|
|
29
|
+
// webpieces-disable no-function-outside-class -- portable stateless IPC primitive; no platform DI container exists on this boundary
|
|
30
|
+
static assertExhaustiveMetadata() {
|
|
31
|
+
// @ts-expect-error every API member needs explicit runtime metadata
|
|
32
|
+
new IpcContract_1.IpcContract('incomplete', Api, new Incomplete());
|
|
33
|
+
// @ts-expect-error multi-argument API methods are not IPC DTO contracts
|
|
34
|
+
const multiple = new Incomplete();
|
|
35
|
+
void multiple;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
exports.IpcCompileAssertions = IpcCompileAssertions;
|
|
39
|
+
//# sourceMappingURL=IpcCompileAssertions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IpcCompileAssertions.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/ipc/IpcCompileAssertions.ts"],"names":[],"mappings":";;;AAAA,+CAA8E;AAC9E,uDAAgD;AAChD,MAAM,OAAO;IACY;IAArB,YAAqB,EAAU;QAAV,OAAE,GAAF,EAAE,CAAQ;IAAG,CAAC;CACtC;AACD,MAAM,MAAM;IACR,0IAA0I;IAC1I,KAAK,CAAC,KAAc;QAChB,IAAI,CAAC,CAAC,KAAK,YAAY,OAAO,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;QACrE,OAAO,KAAK,CAAC;IACjB,CAAC;CACJ;AACD,MAAe,GAAG;CAGjB;AACD,MAAM,UAAU;IACH,KAAK,GAAG,IAAI,uBAAS,CAAC,OAAO,EAAE,IAAI,MAAM,EAAE,EAAE,IAAI,MAAM,EAAE,EAAE,IAAI,uBAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;CACzF;AACD,MAAe,WAAW;CAEzB;AACD,oGAAoG;AACpG,MAAa,oBAAoB;IAC7B,oIAAoI;IACpI,MAAM,CAAC,wBAAwB;QAC3B,oEAAoE;QACpE,IAAI,yBAAW,CAAC,YAAY,EAAE,GAAG,EAAE,IAAI,UAAU,EAAE,CAAC,CAAC;QACrD,wEAAwE;QACxE,MAAM,QAAQ,GAA4B,IAAI,UAAU,EAAE,CAAC;QAC3D,KAAK,QAAQ,CAAC;IAClB,CAAC;CACJ;AATD,oDASC","sourcesContent":["import { IpcContract, IpcMethod, IpcMethods, IpcSchema } from './IpcContract';\nimport { MaskSpec } from '../http/LogFieldMask';\nclass Request {\n constructor(readonly id: string) {}\n}\nclass Schema implements IpcSchema<Request> {\n // webpieces-disable no-any-unknown -- untrusted IPC data is schema-validated; generic dispatch cannot assume a DTO type before validation\n parse(value: unknown): Request {\n if (!(value instanceof Request)) throw new Error('Expected Request');\n return value;\n }\n}\nabstract class Api {\n abstract first(request: Request): Promise<Request>;\n abstract second(request: Request): Promise<Request>;\n}\nclass Incomplete {\n readonly first = new IpcMethod('first', new Schema(), new Schema(), new MaskSpec({}));\n}\nabstract class MultipleApi {\n abstract bad(a: Request, b: Request): Promise<Request>;\n}\n/** These assertions compile in package builds, unlike transpiled-only spec files. Never invoked. */\nexport class IpcCompileAssertions {\n // webpieces-disable no-function-outside-class -- portable stateless IPC primitive; no platform DI container exists on this boundary\n static assertExhaustiveMetadata(): void {\n // @ts-expect-error every API member needs explicit runtime metadata\n new IpcContract('incomplete', Api, new Incomplete());\n // @ts-expect-error multi-argument API methods are not IPC DTO contracts\n const multiple: IpcMethods<MultipleApi> = new Incomplete();\n void multiple;\n }\n}\n"]}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { IpcCallContext, IpcReply, IpcRequest } from './IpcProtocol';
|
|
2
|
+
/** A local connection failed, distinct from a remote implementation's semantic ApiError. */
|
|
3
|
+
export declare class IpcTransportError extends Error {
|
|
4
|
+
constructor(message: string, cause?: Error);
|
|
5
|
+
}
|
|
6
|
+
/** Implement this at the host transport boundary; no vendor or platform declarations leak out. */
|
|
7
|
+
export interface IpcTransport {
|
|
8
|
+
send(message: string): Promise<void> | void;
|
|
9
|
+
subscribe(receive: (message: string) => void, failed: (error: Error) => void, closed: (error: Error) => void): () => void;
|
|
10
|
+
close(): void;
|
|
11
|
+
}
|
|
12
|
+
export interface IpcScheduler {
|
|
13
|
+
schedule(callback: () => void, delayMs: number): () => void;
|
|
14
|
+
}
|
|
15
|
+
export interface IpcErrorOwner {
|
|
16
|
+
report(error: Error): void;
|
|
17
|
+
}
|
|
18
|
+
export declare class IpcConnectionOptions {
|
|
19
|
+
readonly timeoutMs: number;
|
|
20
|
+
readonly nextId: () => string;
|
|
21
|
+
readonly scheduler: IpcScheduler;
|
|
22
|
+
readonly errors: IpcErrorOwner;
|
|
23
|
+
readonly maxMessageCharacters: number;
|
|
24
|
+
constructor(timeoutMs: number, nextId: () => string, scheduler: IpcScheduler, errors: IpcErrorOwner, maxMessageCharacters?: number);
|
|
25
|
+
}
|
|
26
|
+
/** One connection owns both directions, one dispatcher, and all pending-call lifetimes. */
|
|
27
|
+
export declare class IpcConnection {
|
|
28
|
+
private readonly transport;
|
|
29
|
+
private readonly options;
|
|
30
|
+
private readonly pending;
|
|
31
|
+
private readonly activeRequests;
|
|
32
|
+
private readonly usedIds;
|
|
33
|
+
private handler?;
|
|
34
|
+
private closed?;
|
|
35
|
+
private readonly unsubscribe;
|
|
36
|
+
constructor(transport: IpcTransport, options: IpcConnectionOptions);
|
|
37
|
+
/** Install exactly one factory dispatcher BEFORE exposing this connection to the peer. */
|
|
38
|
+
setHandler(handler: (request: IpcRequest) => Promise<IpcReply>): void;
|
|
39
|
+
newContext(parent?: IpcCallContext): IpcCallContext;
|
|
40
|
+
request(request: IpcRequest): Promise<IpcReply>;
|
|
41
|
+
dispose(): void;
|
|
42
|
+
private send;
|
|
43
|
+
private receive;
|
|
44
|
+
private dispatch;
|
|
45
|
+
private settle;
|
|
46
|
+
private fail;
|
|
47
|
+
}
|
|
48
|
+
export declare class IpcErrors {
|
|
49
|
+
static normalize(value: unknown): Error;
|
|
50
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.IpcErrors = exports.IpcConnection = exports.IpcConnectionOptions = exports.IpcTransportError = void 0;
|
|
4
|
+
const errorUtils_1 = require("../lib/errorUtils");
|
|
5
|
+
const TimeoutError_1 = require("../http/TimeoutError");
|
|
6
|
+
const CallStrategy_1 = require("../http/CallStrategy");
|
|
7
|
+
const errors_1 = require("../errors");
|
|
8
|
+
const IpcProtocol_1 = require("./IpcProtocol");
|
|
9
|
+
/** A local connection failed, distinct from a remote implementation's semantic ApiError. */
|
|
10
|
+
class IpcTransportError extends Error {
|
|
11
|
+
constructor(message, cause) {
|
|
12
|
+
super(message, { cause });
|
|
13
|
+
this.name = 'IpcTransportError';
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
exports.IpcTransportError = IpcTransportError;
|
|
17
|
+
class IpcConnectionOptions {
|
|
18
|
+
timeoutMs;
|
|
19
|
+
nextId;
|
|
20
|
+
scheduler;
|
|
21
|
+
errors;
|
|
22
|
+
maxMessageCharacters;
|
|
23
|
+
constructor(timeoutMs, nextId, scheduler, errors, maxMessageCharacters = 1_000_000) {
|
|
24
|
+
this.timeoutMs = timeoutMs;
|
|
25
|
+
this.nextId = nextId;
|
|
26
|
+
this.scheduler = scheduler;
|
|
27
|
+
this.errors = errors;
|
|
28
|
+
this.maxMessageCharacters = maxMessageCharacters;
|
|
29
|
+
if (!Number.isFinite(timeoutMs) ||
|
|
30
|
+
timeoutMs <= 0 ||
|
|
31
|
+
!Number.isSafeInteger(maxMessageCharacters) ||
|
|
32
|
+
maxMessageCharacters < 1) {
|
|
33
|
+
throw new errors_1.InternalError('IPC timeout and message limit must be positive');
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
exports.IpcConnectionOptions = IpcConnectionOptions;
|
|
38
|
+
class PendingCall {
|
|
39
|
+
context;
|
|
40
|
+
resolve;
|
|
41
|
+
reject;
|
|
42
|
+
cancelTimer = () => { };
|
|
43
|
+
constructor(context, resolve, reject) {
|
|
44
|
+
this.context = context;
|
|
45
|
+
this.resolve = resolve;
|
|
46
|
+
this.reject = reject;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/** One connection owns both directions, one dispatcher, and all pending-call lifetimes. */
|
|
50
|
+
class IpcConnection {
|
|
51
|
+
transport;
|
|
52
|
+
options;
|
|
53
|
+
pending = new Map();
|
|
54
|
+
activeRequests = new Set();
|
|
55
|
+
usedIds = new Set();
|
|
56
|
+
handler;
|
|
57
|
+
closed;
|
|
58
|
+
unsubscribe;
|
|
59
|
+
constructor(transport, options) {
|
|
60
|
+
this.transport = transport;
|
|
61
|
+
this.options = options;
|
|
62
|
+
this.unsubscribe = transport.subscribe((message) => this.receive(message), (error) => this.fail(new IpcTransportError('IPC transport failed', error)), (error) => this.fail(new IpcTransportError('IPC connection closed', error)));
|
|
63
|
+
}
|
|
64
|
+
/** Install exactly one factory dispatcher BEFORE exposing this connection to the peer. */
|
|
65
|
+
setHandler(handler) {
|
|
66
|
+
if (this.handler)
|
|
67
|
+
throw new errors_1.InternalError('An IPC connection already has a dispatcher');
|
|
68
|
+
if (this.closed)
|
|
69
|
+
throw this.closed;
|
|
70
|
+
this.handler = handler;
|
|
71
|
+
}
|
|
72
|
+
newContext(parent) {
|
|
73
|
+
const id = this.options.nextId();
|
|
74
|
+
if (this.usedIds.has(id))
|
|
75
|
+
throw new errors_1.InternalError('IPC identity generator reused a call ID');
|
|
76
|
+
this.usedIds.add(id);
|
|
77
|
+
return new IpcProtocol_1.IpcCallContext(parent?.txId ?? id, id, parent?.callId);
|
|
78
|
+
}
|
|
79
|
+
request(request) {
|
|
80
|
+
if (this.closed)
|
|
81
|
+
return Promise.reject(this.closed);
|
|
82
|
+
if (this.pending.has(request.context.callId))
|
|
83
|
+
return Promise.reject(new errors_1.InternalError('Duplicate pending IPC call'));
|
|
84
|
+
return new Promise((resolve, reject) => {
|
|
85
|
+
const pending = new PendingCall(request.context, resolve, reject);
|
|
86
|
+
this.pending.set(request.context.callId, pending);
|
|
87
|
+
pending.cancelTimer = this.options.scheduler.schedule(() => {
|
|
88
|
+
this.settle(request.context.callId, new TimeoutError_1.TimeoutError(this.options.timeoutMs, new CallStrategy_1.CallContext(request.apiId, request.methodId)));
|
|
89
|
+
}, this.options.timeoutMs);
|
|
90
|
+
// This owner observes every async send rejection; a send failure is never a timeout.
|
|
91
|
+
void this.send(request).catch((error) => {
|
|
92
|
+
this.settle(request.context.callId, new IpcTransportError('IPC send failed', IpcErrors.normalize(error)));
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
dispose() {
|
|
97
|
+
this.fail(new IpcTransportError('IPC connection disposed'));
|
|
98
|
+
this.unsubscribe();
|
|
99
|
+
this.transport.close();
|
|
100
|
+
}
|
|
101
|
+
async send(message) {
|
|
102
|
+
if (this.closed)
|
|
103
|
+
throw this.closed;
|
|
104
|
+
const json = JSON.stringify(message);
|
|
105
|
+
if (json.length > this.options.maxMessageCharacters)
|
|
106
|
+
throw new errors_1.InternalError('IPC message exceeds configured limit');
|
|
107
|
+
await this.transport.send(json);
|
|
108
|
+
}
|
|
109
|
+
receive(json) {
|
|
110
|
+
if (this.closed)
|
|
111
|
+
return;
|
|
112
|
+
// eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- transport boundary rejects pending calls or encodes a failure that the client throws
|
|
113
|
+
try {
|
|
114
|
+
if (json.length > this.options.maxMessageCharacters)
|
|
115
|
+
throw new errors_1.InternalError('IPC message exceeds configured limit');
|
|
116
|
+
const message = IpcProtocol_1.IpcProtocol.parse(json);
|
|
117
|
+
if (message.type === 'request') {
|
|
118
|
+
if (this.activeRequests.has(message.context.callId))
|
|
119
|
+
throw new errors_1.InternalError('Duplicate active IPC request');
|
|
120
|
+
this.activeRequests.add(message.context.callId);
|
|
121
|
+
void this.dispatch(message).catch((error) => this.fail(IpcErrors.normalize(error)));
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const pending = this.pending.get(message.context.callId);
|
|
125
|
+
// Late or unsolicited replies are reported, never resolve a different call or replay work.
|
|
126
|
+
if (!pending) {
|
|
127
|
+
this.options.errors.report(new errors_1.InternalError('Late or unknown IPC reply'));
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
if (!IpcProtocol_1.IpcProtocol.sameContext(pending.context, message.context))
|
|
131
|
+
throw new errors_1.InternalError('IPC reply correlation mismatch');
|
|
132
|
+
this.pending.delete(message.context.callId);
|
|
133
|
+
pending.cancelTimer();
|
|
134
|
+
pending.resolve(message);
|
|
135
|
+
}
|
|
136
|
+
catch (err) {
|
|
137
|
+
const error = (0, errorUtils_1.toError)(err);
|
|
138
|
+
this.fail(IpcErrors.normalize(error));
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
async dispatch(request) {
|
|
142
|
+
let reply;
|
|
143
|
+
// eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- transport boundary rejects pending calls or encodes a failure that the client throws
|
|
144
|
+
try {
|
|
145
|
+
if (!this.handler)
|
|
146
|
+
throw new errors_1.EndpointNotFoundError('IPC dispatcher is not installed');
|
|
147
|
+
reply = await this.handler(request);
|
|
148
|
+
if (!IpcProtocol_1.IpcProtocol.sameContext(request.context, reply.context))
|
|
149
|
+
throw new errors_1.InternalError('IPC handler reply correlation mismatch');
|
|
150
|
+
}
|
|
151
|
+
catch (err) {
|
|
152
|
+
const error = (0, errorUtils_1.toError)(err);
|
|
153
|
+
reply = new IpcProtocol_1.IpcFailure(request.context, errors_1.ApiErrorCodec.encode(error));
|
|
154
|
+
}
|
|
155
|
+
finally {
|
|
156
|
+
this.activeRequests.delete(request.context.callId);
|
|
157
|
+
}
|
|
158
|
+
await this.send(reply);
|
|
159
|
+
}
|
|
160
|
+
settle(id, error) {
|
|
161
|
+
const pending = this.pending.get(id);
|
|
162
|
+
if (!pending)
|
|
163
|
+
return;
|
|
164
|
+
this.pending.delete(id);
|
|
165
|
+
pending.cancelTimer();
|
|
166
|
+
pending.reject(error);
|
|
167
|
+
}
|
|
168
|
+
fail(error) {
|
|
169
|
+
if (this.closed)
|
|
170
|
+
return;
|
|
171
|
+
this.closed = error;
|
|
172
|
+
for (const id of this.pending.keys())
|
|
173
|
+
this.settle(id, error);
|
|
174
|
+
this.options.errors.report(error);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
exports.IpcConnection = IpcConnection;
|
|
178
|
+
class IpcErrors {
|
|
179
|
+
// 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
|
|
180
|
+
static normalize(value) {
|
|
181
|
+
return value instanceof Error
|
|
182
|
+
? value
|
|
183
|
+
: new errors_1.InternalError('IPC failed with a non-Error value');
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
exports.IpcErrors = IpcErrors;
|
|
187
|
+
//# sourceMappingURL=IpcConnection.js.map
|
|
@@ -0,0 +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 { TimeoutError } from '../http/TimeoutError';\nimport { CallContext } from '../http/CallStrategy';\nimport { ApiErrorCodec, EndpointNotFoundError, InternalError } from '../errors';\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 ) {\n if (\n !Number.isFinite(timeoutMs) ||\n timeoutMs <= 0 ||\n !Number.isSafeInteger(maxMessageCharacters) ||\n maxMessageCharacters < 1\n ) {\n throw new InternalError('IPC timeout and message limit must be positive');\n }\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 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) throw new InternalError('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 InternalError('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 InternalError('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 TimeoutError(\n this.options.timeoutMs,\n new CallContext(request.apiId, request.methodId),\n ),\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 );\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 InternalError('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 InternalError('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 InternalError('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(new InternalError('Late or unknown IPC reply'));\n return;\n }\n if (!IpcProtocol.sameContext(pending.context, message.context))\n throw new InternalError('IPC reply correlation mismatch');\n this.pending.delete(message.context.callId);\n pending.cancelTimer();\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) throw new EndpointNotFoundError('IPC dispatcher is not installed');\n reply = await this.handler(request);\n if (!IpcProtocol.sameContext(request.context, reply.context))\n throw new InternalError('IPC handler reply correlation mismatch');\n } catch (err: unknown) {\n const error = toError(err);\n reply = new IpcFailure(request.context, ApiErrorCodec.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): void {\n const pending = this.pending.get(id);\n if (!pending) return;\n this.pending.delete(id);\n pending.cancelTimer();\n pending.reject(error);\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);\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 InternalError('IPC failed with a non-Error value');\n }\n}\n"]}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { MaskSpec } from '../http/LogFieldMask';
|
|
2
|
+
/** A portable schema owns parsing and validation, including class reconstruction. */
|
|
3
|
+
export interface IpcSchema<T> {
|
|
4
|
+
parse(value: unknown): T;
|
|
5
|
+
}
|
|
6
|
+
/** Acknowledged void has an explicit null wire representation. */
|
|
7
|
+
export declare class IpcVoidSchema implements IpcSchema<void> {
|
|
8
|
+
parse(value: unknown): void;
|
|
9
|
+
}
|
|
10
|
+
export declare class IpcMethod<Q, R> {
|
|
11
|
+
readonly id: string;
|
|
12
|
+
readonly request: IpcSchema<Q>;
|
|
13
|
+
readonly response: IpcSchema<R>;
|
|
14
|
+
readonly mask: MaskSpec;
|
|
15
|
+
readonly kind: 'request' | 'notification';
|
|
16
|
+
constructor(id: string, request: IpcSchema<Q>, response: IpcSchema<R>, mask: MaskSpec, kind?: 'request' | 'notification');
|
|
17
|
+
}
|
|
18
|
+
/** Every API member must have exactly one DTO argument and a Promise reply. */
|
|
19
|
+
export type IpcMethods<T> = {
|
|
20
|
+
[K in keyof T]: T[K] extends (...args: infer A) => Promise<infer R> ? A extends [infer Q] ? IpcMethod<Q, R> : never : never;
|
|
21
|
+
};
|
|
22
|
+
export type IpcApiType<T> = abstract new (...args: never[]) => T;
|
|
23
|
+
/** Runtime metadata is declared once beside the shared contract. IDs survive minification. */
|
|
24
|
+
export declare class IpcContract<T extends object> {
|
|
25
|
+
readonly id: string;
|
|
26
|
+
readonly api: IpcApiType<T>;
|
|
27
|
+
readonly methods: Readonly<IpcMethods<T>>;
|
|
28
|
+
constructor(id: string, api: IpcApiType<T>, methods: IpcMethods<T>);
|
|
29
|
+
}
|
|
30
|
+
export declare class IpcIdentity {
|
|
31
|
+
static assert(value: unknown, label: string): asserts value is string;
|
|
32
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.IpcIdentity = exports.IpcContract = exports.IpcMethod = exports.IpcVoidSchema = void 0;
|
|
4
|
+
const errors_1 = require("../errors");
|
|
5
|
+
/** Acknowledged void has an explicit null wire representation. */
|
|
6
|
+
class IpcVoidSchema {
|
|
7
|
+
// webpieces-disable no-any-unknown -- untrusted IPC data is schema-validated; generic dispatch cannot assume a DTO type before validation
|
|
8
|
+
parse(value) {
|
|
9
|
+
if (value !== null && value !== undefined) {
|
|
10
|
+
throw new errors_1.BadRequestError('Expected an acknowledged void response');
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
exports.IpcVoidSchema = IpcVoidSchema;
|
|
15
|
+
class IpcMethod {
|
|
16
|
+
id;
|
|
17
|
+
request;
|
|
18
|
+
response;
|
|
19
|
+
mask;
|
|
20
|
+
kind;
|
|
21
|
+
constructor(id, request, response, mask, kind = 'request') {
|
|
22
|
+
this.id = id;
|
|
23
|
+
this.request = request;
|
|
24
|
+
this.response = response;
|
|
25
|
+
this.mask = mask;
|
|
26
|
+
this.kind = kind;
|
|
27
|
+
IpcIdentity.assert(id, 'method');
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
exports.IpcMethod = IpcMethod;
|
|
31
|
+
/** Runtime metadata is declared once beside the shared contract. IDs survive minification. */
|
|
32
|
+
class IpcContract {
|
|
33
|
+
id;
|
|
34
|
+
api;
|
|
35
|
+
methods;
|
|
36
|
+
constructor(id, api, methods) {
|
|
37
|
+
this.id = id;
|
|
38
|
+
this.api = api;
|
|
39
|
+
IpcIdentity.assert(id, 'API');
|
|
40
|
+
const ids = new Set();
|
|
41
|
+
for (const key of Object.keys(methods)) {
|
|
42
|
+
// webpieces-disable no-any-unknown -- untrusted IPC data is schema-validated; generic dispatch cannot assume a DTO type before validation
|
|
43
|
+
const method = methods[key];
|
|
44
|
+
if (!(method instanceof IpcMethod) ||
|
|
45
|
+
ids.has(method.id) ||
|
|
46
|
+
['then', 'constructor', '__proto__'].includes(key)) {
|
|
47
|
+
throw new errors_1.BadRequestError(`Invalid or duplicate IPC metadata: ${id}.${key}`);
|
|
48
|
+
}
|
|
49
|
+
ids.add(method.id);
|
|
50
|
+
Object.freeze(method);
|
|
51
|
+
}
|
|
52
|
+
this.methods = Object.freeze(Object.assign(Object.create(null), methods));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
exports.IpcContract = IpcContract;
|
|
56
|
+
class IpcIdentity {
|
|
57
|
+
// 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
|
|
58
|
+
static assert(value, label) {
|
|
59
|
+
if (typeof value !== 'string' || !/^[a-zA-Z0-9][a-zA-Z0-9_.:-]{0,127}$/.test(value)) {
|
|
60
|
+
throw new errors_1.BadRequestError(`Invalid IPC ${label} identity`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
exports.IpcIdentity = IpcIdentity;
|
|
65
|
+
//# sourceMappingURL=IpcContract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IpcContract.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/ipc/IpcContract.ts"],"names":[],"mappings":";;;AACA,sCAA4C;AAQ5C,kEAAkE;AAClE,MAAa,aAAa;IACtB,0IAA0I;IAC1I,KAAK,CAAC,KAAc;QAChB,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxC,MAAM,IAAI,wBAAe,CAAC,wCAAwC,CAAC,CAAC;QACxE,CAAC;IACL,CAAC;CACJ;AAPD,sCAOC;AAED,MAAa,SAAS;IAEL;IACA;IACA;IACA;IACA;IALb,YACa,EAAU,EACV,OAAqB,EACrB,QAAsB,EACtB,IAAc,EACd,OAAmC,SAAS;QAJ5C,OAAE,GAAF,EAAE,CAAQ;QACV,YAAO,GAAP,OAAO,CAAc;QACrB,aAAQ,GAAR,QAAQ,CAAc;QACtB,SAAI,GAAJ,IAAI,CAAU;QACd,SAAI,GAAJ,IAAI,CAAwC;QAErD,WAAW,CAAC,MAAM,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;IACrC,CAAC;CACJ;AAVD,8BAUC;AAYD,8FAA8F;AAC9F,MAAa,WAAW;IAGP;IACA;IAHJ,OAAO,CAA0B;IAC1C,YACa,EAAU,EACV,GAAkB,EAC3B,OAAsB;QAFb,OAAE,GAAF,EAAE,CAAQ;QACV,QAAG,GAAH,GAAG,CAAe;QAG3B,WAAW,CAAC,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QAC9B,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;QAC9B,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YACrC,0IAA0I;YAC1I,MAAM,MAAM,GAAY,OAAO,CAAC,GAAc,CAAC,CAAC;YAChD,IACI,CAAC,CAAC,MAAM,YAAY,SAAS,CAAC;gBAC9B,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;gBAClB,CAAC,MAAM,EAAE,aAAa,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,EACpD,CAAC;gBACC,MAAM,IAAI,wBAAe,CAAC,sCAAsC,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;YACjF,CAAC;YACD,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACnB,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC1B,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;IAC9E,CAAC;CACJ;AAxBD,kCAwBC;AAED,MAAa,WAAW;IACpB,6QAA6Q;IAC7Q,MAAM,CAAC,MAAM,CAAC,KAAc,EAAE,KAAa;QACvC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,qCAAqC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAClF,MAAM,IAAI,wBAAe,CAAC,eAAe,KAAK,WAAW,CAAC,CAAC;QAC/D,CAAC;IACL,CAAC;CACJ;AAPD,kCAOC","sourcesContent":["import { MaskSpec } from '../http/LogFieldMask';\nimport { BadRequestError } from '../errors';\n\n/** A portable schema owns parsing and validation, including class reconstruction. */\nexport interface IpcSchema<T> {\n // webpieces-disable no-any-unknown -- untrusted IPC data is schema-validated; generic dispatch cannot assume a DTO type before validation\n parse(value: unknown): T;\n}\n\n/** Acknowledged void has an explicit null wire representation. */\nexport class IpcVoidSchema implements IpcSchema<void> {\n // webpieces-disable no-any-unknown -- untrusted IPC data is schema-validated; generic dispatch cannot assume a DTO type before validation\n parse(value: unknown): void {\n if (value !== null && value !== undefined) {\n throw new BadRequestError('Expected an acknowledged void response');\n }\n }\n}\n\nexport class IpcMethod<Q, R> {\n constructor(\n readonly id: string,\n readonly request: IpcSchema<Q>,\n readonly response: IpcSchema<R>,\n readonly mask: MaskSpec,\n readonly kind: 'request' | 'notification' = 'request',\n ) {\n IpcIdentity.assert(id, 'method');\n }\n}\n\n/** Every API member must have exactly one DTO argument and a Promise reply. */\nexport type IpcMethods<T> = {\n [K in keyof T]: T[K] extends (...args: infer A) => Promise<infer R>\n ? A extends [infer Q]\n ? IpcMethod<Q, R>\n : never\n : never;\n};\nexport type IpcApiType<T> = abstract new (...args: never[]) => T;\n\n/** Runtime metadata is declared once beside the shared contract. IDs survive minification. */\nexport class IpcContract<T extends object> {\n readonly methods: Readonly<IpcMethods<T>>;\n constructor(\n readonly id: string,\n readonly api: IpcApiType<T>,\n methods: IpcMethods<T>,\n ) {\n IpcIdentity.assert(id, 'API');\n const ids = new Set<string>();\n for (const key of Object.keys(methods)) {\n // webpieces-disable no-any-unknown -- untrusted IPC data is schema-validated; generic dispatch cannot assume a DTO type before validation\n const method: unknown = methods[key as keyof T];\n if (\n !(method instanceof IpcMethod) ||\n ids.has(method.id) ||\n ['then', 'constructor', '__proto__'].includes(key)\n ) {\n throw new BadRequestError(`Invalid or duplicate IPC metadata: ${id}.${key}`);\n }\n ids.add(method.id);\n Object.freeze(method);\n }\n this.methods = Object.freeze(Object.assign(Object.create(null), methods));\n }\n}\n\nexport class IpcIdentity {\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 assert(value: unknown, label: string): asserts value is string {\n if (typeof value !== 'string' || !/^[a-zA-Z0-9][a-zA-Z0-9_.:-]{0,127}$/.test(value)) {\n throw new BadRequestError(`Invalid IPC ${label} identity`);\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ApiCallContext } from '../http/ApiCallContext';
|
|
2
|
+
import { ApiSide } from '../http/ApiMethodInfo';
|
|
3
|
+
import { MaskSpec } from '../http/LogFieldMask';
|
|
4
|
+
import { IpcCallContext } from './IpcProtocol';
|
|
5
|
+
/** Hosts bind correlation to a per-call logging context; never keep mutable context across awaits. */
|
|
6
|
+
export interface IpcLogging {
|
|
7
|
+
context(call: IpcCallContext): ApiCallContext;
|
|
8
|
+
}
|
|
9
|
+
export declare class IpcCallLogger {
|
|
10
|
+
static execute<Q, R>(logging: IpcLogging, context: IpcCallContext, side: ApiSide, apiId: string, methodId: string, mask: MaskSpec, request: Q, invoke: (request: Q) => Promise<R>): Promise<R>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.IpcCallLogger = void 0;
|
|
4
|
+
const LogApiCall_1 = require("../http/LogApiCall");
|
|
5
|
+
const ApiMethodInfo_1 = require("../http/ApiMethodInfo");
|
|
6
|
+
class IpcCallLogger {
|
|
7
|
+
// webpieces-disable no-function-outside-class -- portable stateless IPC primitive; no platform DI container exists on this boundary
|
|
8
|
+
static execute(logging, context, side, apiId, methodId, mask, request, invoke) {
|
|
9
|
+
return new LogApiCall_1.LogApiCallImpl(logging.context(context)).execute(new ApiMethodInfo_1.ApiMethodInfo(side, apiId, methodId, undefined, mask), request, invoke);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
exports.IpcCallLogger = IpcCallLogger;
|
|
13
|
+
//# sourceMappingURL=IpcLogging.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IpcLogging.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/ipc/IpcLogging.ts"],"names":[],"mappings":";;;AACA,mDAAoD;AACpD,yDAA+D;AAS/D,MAAa,aAAa;IACtB,oIAAoI;IACpI,MAAM,CAAC,OAAO,CACV,OAAmB,EACnB,OAAuB,EACvB,IAAa,EACb,KAAa,EACb,QAAgB,EAChB,IAAc,EACd,OAAU,EACV,MAAkC;QAElC,OAAO,IAAI,2BAAc,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CACvD,IAAI,6BAAa,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,CAAC,EACzD,OAAO,EACP,MAAM,CACK,CAAC;IACpB,CAAC;CACJ;AAlBD,sCAkBC","sourcesContent":["import { ApiCallContext } from '../http/ApiCallContext';\nimport { LogApiCallImpl } from '../http/LogApiCall';\nimport { ApiMethodInfo, ApiSide } from '../http/ApiMethodInfo';\nimport { MaskSpec } from '../http/LogFieldMask';\nimport { IpcCallContext } from './IpcProtocol';\n\n/** Hosts bind correlation to a per-call logging context; never keep mutable context across awaits. */\nexport interface IpcLogging {\n context(call: IpcCallContext): ApiCallContext;\n}\n\nexport class IpcCallLogger {\n // webpieces-disable no-function-outside-class -- portable stateless IPC primitive; no platform DI container exists on this boundary\n static execute<Q, R>(\n logging: IpcLogging,\n context: IpcCallContext,\n side: ApiSide,\n apiId: string,\n methodId: string,\n mask: MaskSpec,\n request: Q,\n invoke: (request: Q) => Promise<R>,\n ): Promise<R> {\n return new LogApiCallImpl(logging.context(context)).execute(\n new ApiMethodInfo(side, apiId, methodId, undefined, mask),\n request,\n invoke,\n ) as Promise<R>;\n }\n}\n"]}
|