@webpieces/core-util 0.4.807 → 0.4.808

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webpieces/core-util",
3
- "version": "0.4.807",
3
+ "version": "0.4.808",
4
4
  "description": "Utility functions for WebPieces - works in browser and Node.js",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
package/src/index.d.ts CHANGED
@@ -37,7 +37,7 @@ export { RPC, CLOUDTASKS, CRON, EXTERNAL, READ, WRITE_IDEMPOTENT, WRITE } from '
37
37
  export { WpMcpTool, WpMcpToolHints, WpMcpToolMetadata, getWpMcpTools, mcpHintsForOperation, } from './mcp/McpMetadata';
38
38
  export type { WpMcpMethodDecorator } from './mcp/McpMetadata';
39
39
  export { WpMcpAuthJwt, WpMcpJwtAuthMetadata, getWpMcpAuthJwt } from './mcp/McpAuthMetadata';
40
- export { ApiJsonSchema, ApiJsonSchemaValidator, DtoValidationFailure, ObjectSchemaBuilder, } from './mcp/DtoSchema';
40
+ export { ApiJsonSchema, ApiJsonSchemaDiscriminator, ApiJsonSchemaValidator, DtoValidationFailure, ObjectSchemaBuilder, } from './mcp/DtoSchema';
41
41
  export type { ApiJsonSchemaType, DtoValue } from './mcp/DtoSchema';
42
42
  export { McpToolCatalog, McpToolCatalogError, McpToolDefinition } from './mcp/McpToolCatalog';
43
43
  export { AuthMeta } from './http/auth-mode';
package/src/index.js CHANGED
@@ -10,9 +10,9 @@
10
10
  Object.defineProperty(exports, "__esModule", { value: true });
11
11
  exports.WpMax = exports.WpMin = exports.WpInt = 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.getEndpointOperation = exports.getEndpointOptions = exports.getEndpointHttpMethod = 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.WpMcpJwtAuthMetadata = exports.WpMcpAuthJwt = exports.mcpHintsForOperation = exports.getWpMcpTools = exports.WpMcpToolMetadata = exports.WpMcpToolHints = exports.WpMcpTool = exports.WRITE = exports.WRITE_IDEMPOTENT = exports.READ = exports.EXTERNAL = exports.CRON = exports.CLOUDTASKS = exports.RPC = exports.POST = exports.GET = 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 = exports.getIpcEndpoints = exports.getIpcApiId = exports.isInternalApi = exports.WpIpcEndpoint = exports.WpInternal = exports.assertApiTypeMatchesMcpTools = exports.getApiTypeEndpointNames = exports.getApiTypes = exports.DEFAULT_API_TYPES = exports.API_TYPE_METADATA_KEY = exports.MCP = exports.EXTERNAL_CUSTOMER = exports.SVC_TO_SVC = exports.ApiType = exports.NUMERIC_METADATA_KEYS = void 0;
13
- 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 = 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.McpToolDefinition = exports.McpToolCatalogError = exports.McpToolCatalog = exports.ObjectSchemaBuilder = exports.DtoValidationFailure = exports.ApiJsonSchemaValidator = exports.ApiJsonSchema = exports.getWpMcpAuthJwt = void 0;
14
- 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.ApiBadGatewayError = exports.ApiDependencyError = exports.ApiNotFoundError = 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 = exports.KeyedFailureClassifier = exports.ReceivedApiErrorRule = exports.SurfaceEndUserStatus = void 0;
15
- exports.ApiErrorHttpStatus = exports.ApiErrorBoundary = exports.ApiErrorPayload = void 0;
13
+ 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 = 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.McpToolDefinition = exports.McpToolCatalogError = exports.McpToolCatalog = exports.ObjectSchemaBuilder = exports.DtoValidationFailure = exports.ApiJsonSchemaValidator = exports.ApiJsonSchemaDiscriminator = exports.ApiJsonSchema = exports.getWpMcpAuthJwt = void 0;
14
+ 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.ApiBadGatewayError = exports.ApiDependencyError = exports.ApiNotFoundError = 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 = exports.KeyedFailureClassifier = exports.ReceivedApiErrorRule = exports.SurfaceEndUserStatus = exports.WEBPIECES_DEFAULT_ERROR_TRANSLATOR = void 0;
15
+ exports.ApiErrorHttpStatus = exports.ApiErrorBoundary = exports.ApiErrorPayload = exports.ApiErrorCodec = void 0;
16
16
  var errorUtils_1 = require("./lib/errorUtils");
17
17
  Object.defineProperty(exports, "toError", { enumerable: true, get: function () { return errorUtils_1.toError; } });
18
18
  var ContextKey_1 = require("./ContextKey");
@@ -148,6 +148,7 @@ Object.defineProperty(exports, "WpMcpJwtAuthMetadata", { enumerable: true, get:
148
148
  Object.defineProperty(exports, "getWpMcpAuthJwt", { enumerable: true, get: function () { return McpAuthMetadata_1.getWpMcpAuthJwt; } });
149
149
  var DtoSchema_1 = require("./mcp/DtoSchema");
150
150
  Object.defineProperty(exports, "ApiJsonSchema", { enumerable: true, get: function () { return DtoSchema_1.ApiJsonSchema; } });
151
+ Object.defineProperty(exports, "ApiJsonSchemaDiscriminator", { enumerable: true, get: function () { return DtoSchema_1.ApiJsonSchemaDiscriminator; } });
151
152
  Object.defineProperty(exports, "ApiJsonSchemaValidator", { enumerable: true, get: function () { return DtoSchema_1.ApiJsonSchemaValidator; } });
152
153
  Object.defineProperty(exports, "DtoValidationFailure", { enumerable: true, get: function () { return DtoSchema_1.DtoValidationFailure; } });
153
154
  Object.defineProperty(exports, "ObjectSchemaBuilder", { enumerable: true, get: function () { return DtoSchema_1.ObjectSchemaBuilder; } });
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 {\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 getEndpointHttpMethod,\n getEndpointOptions,\n getEndpointOperation,\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 { WpInt, WpMin, WpMax, NUMERIC_METADATA_KEYS } from './http/numeric-field-decorators';\nexport type { Integer } from './http/numeric-field-decorators';\nexport {\n ApiType,\n SVC_TO_SVC,\n EXTERNAL_CUSTOMER,\n MCP,\n API_TYPE_METADATA_KEY,\n DEFAULT_API_TYPES,\n getApiTypes,\n getApiTypeEndpointNames,\n assertApiTypeMatchesMcpTools,\n} from './http/api-type';\nexport type { ApiTypeKind } from './http/api-type';\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 EndpointResponseType,\n HttpMethod,\n HttpParameterSource,\n HttpParameterValueType,\n} from './http/HttpContract';\nexport { GET, POST } from './http/HttpContract';\nexport type {\n EndpointKind,\n EndpointOperation,\n EndpointOptions,\n ExternalEndpointOptions,\n} from './http/decorators';\nexport { RPC, CLOUDTASKS, CRON, EXTERNAL, READ, WRITE_IDEMPOTENT, WRITE } from './http/decorators';\nexport {\n WpMcpTool,\n WpMcpToolHints,\n WpMcpToolMetadata,\n getWpMcpTools,\n mcpHintsForOperation,\n} from './mcp/McpMetadata';\nexport type { WpMcpMethodDecorator } from './mcp/McpMetadata';\nexport { WpMcpAuthJwt, WpMcpJwtAuthMetadata, getWpMcpAuthJwt } from './mcp/McpAuthMetadata';\nexport {\n ApiJsonSchema,\n ApiJsonSchemaValidator,\n DtoValidationFailure,\n ObjectSchemaBuilder,\n} from './mcp/DtoSchema';\nexport type { ApiJsonSchemaType, DtoValue } from './mcp/DtoSchema';\nexport { McpToolCatalog, McpToolCatalogError, McpToolDefinition } from './mcp/McpToolCatalog';\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\n// @Endpoint(POST, ..., WRITE, 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';\nexport { ContextWriter, ContextStore } from './http/ContextWriter';\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 { ApiCallDirection, 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 ApiBadGatewayError,\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 getEndpointHttpMethod,\n getEndpointOptions,\n getEndpointOperation,\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 { WpInt, WpMin, WpMax, NUMERIC_METADATA_KEYS } from './http/numeric-field-decorators';\nexport type { Integer } from './http/numeric-field-decorators';\nexport {\n ApiType,\n SVC_TO_SVC,\n EXTERNAL_CUSTOMER,\n MCP,\n API_TYPE_METADATA_KEY,\n DEFAULT_API_TYPES,\n getApiTypes,\n getApiTypeEndpointNames,\n assertApiTypeMatchesMcpTools,\n} from './http/api-type';\nexport type { ApiTypeKind } from './http/api-type';\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 EndpointResponseType,\n HttpMethod,\n HttpParameterSource,\n HttpParameterValueType,\n} from './http/HttpContract';\nexport { GET, POST } from './http/HttpContract';\nexport type {\n EndpointKind,\n EndpointOperation,\n EndpointOptions,\n ExternalEndpointOptions,\n} from './http/decorators';\nexport { RPC, CLOUDTASKS, CRON, EXTERNAL, READ, WRITE_IDEMPOTENT, WRITE } from './http/decorators';\nexport {\n WpMcpTool,\n WpMcpToolHints,\n WpMcpToolMetadata,\n getWpMcpTools,\n mcpHintsForOperation,\n} from './mcp/McpMetadata';\nexport type { WpMcpMethodDecorator } from './mcp/McpMetadata';\nexport { WpMcpAuthJwt, WpMcpJwtAuthMetadata, getWpMcpAuthJwt } from './mcp/McpAuthMetadata';\nexport {\n ApiJsonSchema,\n ApiJsonSchemaDiscriminator,\n ApiJsonSchemaValidator,\n DtoValidationFailure,\n ObjectSchemaBuilder,\n} from './mcp/DtoSchema';\nexport type { ApiJsonSchemaType, DtoValue } from './mcp/DtoSchema';\nexport { McpToolCatalog, McpToolCatalogError, McpToolDefinition } from './mcp/McpToolCatalog';\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\n// @Endpoint(POST, ..., WRITE, 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';\nexport { ContextWriter, ContextStore } from './http/ContextWriter';\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 { ApiCallDirection, 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 ApiBadGatewayError,\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"]}
@@ -22,6 +22,31 @@ export type DtoValue = object | string | number | boolean | null;
22
22
  * ABSENT property, and one the reflect-metadata runtime could neither see nor write down.
23
23
  */
24
24
  export type ApiJsonSchemaType = 'object' | 'string' | 'number' | 'integer' | 'boolean' | 'array' | 'null';
25
+ /**
26
+ * The DISCRIMINATOR of a {@link ApiJsonSchema.oneOf} — which property narrows the union, and what
27
+ * each of its values names.
28
+ *
29
+ * The shape MIRRORS what `OpenApiGenerator`'s `SchemaRenderer` already emits for the same union
30
+ * (`propertyName` + `mapping`), because a union has exactly ONE published spelling in this repo and
31
+ * the OpenAPI renderer is the reference implementation of it. The one difference is what a mapping
32
+ * VALUE holds: OpenAPI maps a value to `#/components/schemas/ScheduledWindow`, and an MCP tool
33
+ * schema is INLINE and has no `$ref` to point at, so it maps to the branch's type NAME.
34
+ *
35
+ * `mapping` is DOCUMENTATION for the reader. {@link ApiJsonSchemaValidator} never narrows with it:
36
+ * it selects the branch whose own `enum` carries the value, so the accepted request and the
37
+ * published document cannot disagree about which branch a value means.
38
+ */
39
+ export declare class ApiJsonSchemaDiscriminator {
40
+ /** The property every branch declares as exactly one string literal, e.g. `kind`. */
41
+ propertyName: string;
42
+ /** discriminator value -> the branch's TYPE NAME (MCP is inline: there is no `$ref`). */
43
+ mapping: Record<string, string>;
44
+ constructor(
45
+ /** The property every branch declares as exactly one string literal, e.g. `kind`. */
46
+ propertyName: string,
47
+ /** discriminator value -> the branch's TYPE NAME (MCP is inline: there is no `$ref`). */
48
+ mapping: Record<string, string>);
49
+ }
25
50
  /** The JSON Schema subset emitted for Webpieces API DTOs. */
26
51
  export declare class ApiJsonSchema {
27
52
  /** One type, or `[T, "null"]` for a nullable field. */
@@ -35,6 +60,22 @@ export declare class ApiJsonSchema {
35
60
  enum?: string[];
36
61
  minimum?: number;
37
62
  maximum?: number;
63
+ /**
64
+ * The branches of a union, INLINE (MCP tool schemas have no `$ref`), in declaration order.
65
+ *
66
+ * A union is legal NESTED, inside a property. It is NOT legal at the ROOT of a tool's parameter
67
+ * schema — both the OpenAI and the Anthropic function-calling APIs reject a top-level
68
+ * `oneOf`/`anyOf`/`allOf`, and because a server sends its whole tool list on every request, one
69
+ * such tool makes EVERY request 400. That is refused at build time by the `no-root-union-api-type`
70
+ * rule, before a contract can be published at all.
71
+ */
72
+ oneOf?: readonly ApiJsonSchema[];
73
+ /**
74
+ * Set ONLY when every branch carries the same property typed as one string literal — DERIVED,
75
+ * never invented. A union TypeScript itself cannot narrow is published as a bare {@link oneOf},
76
+ * because claiming a narrowing the source does not have is worse than admitting there is none.
77
+ */
78
+ discriminator?: ApiJsonSchemaDiscriminator;
38
79
  /** MCP 2026 SEP-2243 schema extension consumed by the official SDK. */
39
80
  'x-mcp-header'?: string;
40
81
  constructor(type?: ApiJsonSchemaType | readonly ApiJsonSchemaType[]);
@@ -95,6 +136,28 @@ export declare class DtoValidationFailure {
95
136
  export declare class ApiJsonSchemaValidator {
96
137
  validate(schema: ApiJsonSchema, value: DtoValue): DtoValidationFailure | undefined;
97
138
  private validateAt;
139
+ /**
140
+ * A union, validated BY DISCRIMINATOR.
141
+ *
142
+ * The discriminator property is read FIRST and the branch chosen from it, so a value naming no
143
+ * branch is reported as what it is — `$.window.kind must be one of: scheduled | asap`, naming the
144
+ * field that is wrong and the values it may hold. Trying every branch and reporting "no branch
145
+ * matched" tells a caller nothing they can act on: it names neither the offending property nor
146
+ * the legal values, and it hides a branch that matched on `kind` and failed three levels down.
147
+ *
148
+ * The branch is selected by the branches' own `enum`s, never by
149
+ * {@link ApiJsonSchemaDiscriminator.mapping} — the branches ARE the schema, so selection and
150
+ * validation read one source and cannot disagree.
151
+ */
152
+ private validateUnion;
153
+ /**
154
+ * A union with NO discriminator — one TypeScript itself cannot narrow. Every branch is tried and
155
+ * the value accepted when one matches. There is no better report when none does: the source does
156
+ * not narrow, so no property can honestly be named as the wrong one.
157
+ */
158
+ private validateAnyBranch;
159
+ /** The string literals ONE branch declares for the discriminator property. */
160
+ private static branchValuesOf;
98
161
  private validateObject;
99
162
  private validateArray;
100
163
  private validateString;
@@ -16,7 +16,34 @@
16
16
  * validator that reads the schema instead of a decorator.
17
17
  */
18
18
  Object.defineProperty(exports, "__esModule", { value: true });
19
- exports.ApiJsonSchemaValidator = exports.DtoValidationFailure = exports.ObjectSchemaBuilder = exports.ApiJsonSchema = void 0;
19
+ exports.ApiJsonSchemaValidator = exports.DtoValidationFailure = exports.ObjectSchemaBuilder = exports.ApiJsonSchema = exports.ApiJsonSchemaDiscriminator = void 0;
20
+ /**
21
+ * The DISCRIMINATOR of a {@link ApiJsonSchema.oneOf} — which property narrows the union, and what
22
+ * each of its values names.
23
+ *
24
+ * The shape MIRRORS what `OpenApiGenerator`'s `SchemaRenderer` already emits for the same union
25
+ * (`propertyName` + `mapping`), because a union has exactly ONE published spelling in this repo and
26
+ * the OpenAPI renderer is the reference implementation of it. The one difference is what a mapping
27
+ * VALUE holds: OpenAPI maps a value to `#/components/schemas/ScheduledWindow`, and an MCP tool
28
+ * schema is INLINE and has no `$ref` to point at, so it maps to the branch's type NAME.
29
+ *
30
+ * `mapping` is DOCUMENTATION for the reader. {@link ApiJsonSchemaValidator} never narrows with it:
31
+ * it selects the branch whose own `enum` carries the value, so the accepted request and the
32
+ * published document cannot disagree about which branch a value means.
33
+ */
34
+ class ApiJsonSchemaDiscriminator {
35
+ propertyName;
36
+ mapping;
37
+ constructor(
38
+ /** The property every branch declares as exactly one string literal, e.g. `kind`. */
39
+ propertyName,
40
+ /** discriminator value -> the branch's TYPE NAME (MCP is inline: there is no `$ref`). */
41
+ mapping) {
42
+ this.propertyName = propertyName;
43
+ this.mapping = mapping;
44
+ }
45
+ }
46
+ exports.ApiJsonSchemaDiscriminator = ApiJsonSchemaDiscriminator;
20
47
  /** The JSON Schema subset emitted for Webpieces API DTOs. */
21
48
  class ApiJsonSchema {
22
49
  /** One type, or `[T, "null"]` for a nullable field. */
@@ -30,6 +57,22 @@ class ApiJsonSchema {
30
57
  enum;
31
58
  minimum;
32
59
  maximum;
60
+ /**
61
+ * The branches of a union, INLINE (MCP tool schemas have no `$ref`), in declaration order.
62
+ *
63
+ * A union is legal NESTED, inside a property. It is NOT legal at the ROOT of a tool's parameter
64
+ * schema — both the OpenAI and the Anthropic function-calling APIs reject a top-level
65
+ * `oneOf`/`anyOf`/`allOf`, and because a server sends its whole tool list on every request, one
66
+ * such tool makes EVERY request 400. That is refused at build time by the `no-root-union-api-type`
67
+ * rule, before a contract can be published at all.
68
+ */
69
+ oneOf;
70
+ /**
71
+ * Set ONLY when every branch carries the same property typed as one string literal — DERIVED,
72
+ * never invented. A union TypeScript itself cannot narrow is published as a bare {@link oneOf},
73
+ * because claiming a narrowing the source does not have is worse than admitting there is none.
74
+ */
75
+ discriminator;
33
76
  constructor(type) {
34
77
  this.type = type;
35
78
  }
@@ -129,6 +172,9 @@ class ApiJsonSchemaValidator {
129
172
  ? undefined
130
173
  : new DtoValidationFailure(path, `${path} must not be null`);
131
174
  }
175
+ if (schema.oneOf !== undefined) {
176
+ return this.validateUnion(schema, value, path);
177
+ }
132
178
  switch (ApiJsonSchema.baseTypeOf(schema)) {
133
179
  case 'object':
134
180
  return this.validateObject(schema, value, path);
@@ -147,6 +193,59 @@ class ApiJsonSchemaValidator {
147
193
  return undefined;
148
194
  }
149
195
  }
196
+ /**
197
+ * A union, validated BY DISCRIMINATOR.
198
+ *
199
+ * The discriminator property is read FIRST and the branch chosen from it, so a value naming no
200
+ * branch is reported as what it is — `$.window.kind must be one of: scheduled | asap`, naming the
201
+ * field that is wrong and the values it may hold. Trying every branch and reporting "no branch
202
+ * matched" tells a caller nothing they can act on: it names neither the offending property nor
203
+ * the legal values, and it hides a branch that matched on `kind` and failed three levels down.
204
+ *
205
+ * The branch is selected by the branches' own `enum`s, never by
206
+ * {@link ApiJsonSchemaDiscriminator.mapping} — the branches ARE the schema, so selection and
207
+ * validation read one source and cannot disagree.
208
+ */
209
+ validateUnion(schema, value, path) {
210
+ const branches = schema.oneOf ?? [];
211
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
212
+ return new DtoValidationFailure(path, `${path} must be an object`);
213
+ }
214
+ const discriminator = schema.discriminator;
215
+ if (discriminator === undefined) {
216
+ return this.validateAnyBranch(branches, value, path);
217
+ }
218
+ const property = discriminator.propertyName;
219
+ const held = Object.getOwnPropertyDescriptor(value, property)?.value;
220
+ const branch = branches.find((one) => ApiJsonSchemaValidator.branchValuesOf(one, property).includes(held));
221
+ if (branch === undefined) {
222
+ const legal = branches
223
+ .flatMap((one) => ApiJsonSchemaValidator.branchValuesOf(one, property))
224
+ .join(' | ');
225
+ return new DtoValidationFailure(`${path}.${property}`, `${path}.${property} must be one of: ${legal}`);
226
+ }
227
+ return this.validateAt(branch, value, path);
228
+ }
229
+ /**
230
+ * A union with NO discriminator — one TypeScript itself cannot narrow. Every branch is tried and
231
+ * the value accepted when one matches. There is no better report when none does: the source does
232
+ * not narrow, so no property can honestly be named as the wrong one.
233
+ */
234
+ validateAnyBranch(branches, value, path) {
235
+ for (const branch of branches) {
236
+ if (this.validateAt(branch, value, path) === undefined) {
237
+ return undefined;
238
+ }
239
+ }
240
+ return new DtoValidationFailure(path, `${path} matches none of the ${branches.length} accepted shapes`);
241
+ }
242
+ /** The string literals ONE branch declares for the discriminator property. */
243
+ // webpieces-disable no-function-outside-class -- private static reader of a branch schema
244
+ static branchValuesOf(branch, property) {
245
+ const declared = Object.getOwnPropertyDescriptor(branch.properties ?? {}, property)
246
+ ?.value;
247
+ return declared?.enum ?? [];
248
+ }
150
249
  validateObject(schema, value, path) {
151
250
  if (typeof value !== 'object' || value === null || Array.isArray(value)) {
152
251
  return new DtoValidationFailure(path, `${path} must be an object`);
@@ -1 +1 @@
1
- {"version":3,"file":"DtoSchema.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/mcp/DtoSchema.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;;AAmBH,6DAA6D;AAC7D,MAAa,aAAa;IACtB,uDAAuD;IACvD,IAAI,CAAoD;IACxD,WAAW,CAAU;IACrB,UAAU,CAAiC;IAC3C,QAAQ,CAAY;IACpB,kGAAkG;IAClG,oBAAoB,CAA2B;IAC/C,KAAK,CAAiB;IACtB,IAAI,CAAY;IAChB,OAAO,CAAU;IACjB,OAAO,CAAU;IAIjB,YAAY,IAAuD;QAC/D,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACrB,CAAC;IAED;;;;;;;OAOG;IACH,6EAA6E;IAC7E,MAAM,CAAC,UAAU,CAAC,MAAqB;QACnC,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS;YAAE,OAAO,SAAS,CAAC;QAChD,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,MAAM,CAAC,IAAI,CAAC;QACxD,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAsB,EAAE,EAAE,CAAC,GAAG,KAAK,MAAM,CAAC,CAAC;IACxE,CAAC;IAED,yFAAyF;IACzF,6EAA6E;IAC7E,MAAM,CAAC,UAAU,CAAC,MAAqB;QACnC,OAAO,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,CAAC;IACvF,CAAC;IAED;;;;;OAKG;IACH,6EAA6E;IAC7E,MAAM,CAAC,QAAQ,CAAC,MAAqB;QACjC,MAAM,KAAK,GAAG,MAAM,CAAC,oBAAoB,CAAC;QAC1C,OAAO,KAAK,KAAK,KAAK,IAAI,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC;IAC5E,CAAC;CACJ;AAnDD,sCAmDC;AAED;;;;;;;;GAQG;AACH,MAAa,mBAAmB;IACX,MAAM,GAAG,IAAI,aAAa,CAAC,QAAQ,CAAC,CAAC;IACrC,aAAa,GAAa,EAAE,CAAC;IAE9C;QACI,IAAI,CAAC,MAAM,CAAC,UAAU,GAAG,EAAE,CAAC;QAC5B,IAAI,CAAC,MAAM,CAAC,oBAAoB,GAAG,KAAK,CAAC;IAC7C,CAAC;IAED,QAAQ,CAAC,IAAY,EAAE,IAAmB;QACtC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9B,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACrC,CAAC;IAED,QAAQ,CAAC,IAAY,EAAE,IAAmB;QACtC,IAAI,CAAC,MAAM,CAAC,UAAW,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;QACrC,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,KAAK;QACD,IAAI,IAAI,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC;YAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,GAAG,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC;QAClF,OAAO,IAAI,CAAC,MAAM,CAAC;IACvB,CAAC;CACJ;AAvBD,kDAuBC;AAED,+DAA+D;AAC/D,MAAa,oBAAoB;IAGT;IACA;IAHpB;IACI,+DAA+D;IAC/C,KAAa,EACb,OAAe;QADf,UAAK,GAAL,KAAK,CAAQ;QACb,YAAO,GAAP,OAAO,CAAQ;IAChC,CAAC;CACP;AAND,oDAMC;AAED;;;;;;;;GAQG;AACH,MAAa,sBAAsB;IAC/B,QAAQ,CAAC,MAAqB,EAAE,KAAe;QAC3C,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;IAC/C,CAAC;IAEO,UAAU,CACd,MAAqB,EACrB,KAAe,EACf,IAAY;QAEZ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACjB,OAAO,aAAa,CAAC,UAAU,CAAC,MAAM,CAAC;gBACnC,CAAC,CAAC,SAAS;gBACX,CAAC,CAAC,IAAI,oBAAoB,CAAC,IAAI,EAAE,GAAG,IAAI,mBAAmB,CAAC,CAAC;QACrE,CAAC;QACD,QAAQ,aAAa,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YACvC,KAAK,QAAQ;gBACT,OAAO,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;YACpD,KAAK,OAAO;gBACR,OAAO,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;YACnD,KAAK,QAAQ;gBACT,OAAO,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;YACpD,KAAK,QAAQ,CAAC;YACd,KAAK,SAAS;gBACV,OAAO,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;YACpD,KAAK,SAAS;gBACV,OAAO,OAAO,KAAK,KAAK,SAAS;oBAC7B,CAAC,CAAC,SAAS;oBACX,CAAC,CAAC,IAAI,oBAAoB,CAAC,IAAI,EAAE,GAAG,IAAI,oBAAoB,CAAC,CAAC;YACtE;gBACI,OAAO,SAAS,CAAC;QACzB,CAAC;IACL,CAAC;IAEO,cAAc,CAClB,MAAqB,EACrB,KAAe,EACf,IAAY;QAEZ,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACtE,OAAO,IAAI,oBAAoB,CAAC,IAAI,EAAE,GAAG,IAAI,oBAAoB,CAAC,CAAC;QACvE,CAAC;QACD,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC;QAC3C,MAAM,KAAK,GAAG,MAAM,CAAC,oBAAoB,CAAC;QAC1C,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACnC,MAAM,KAAK,GAAa,MAAM,CAAC,wBAAwB,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,KAAK,CAAC;YAC3E,MAAM,QAAQ,GAAG,MAAM,CAAC,wBAAwB,CAAC,UAAU,EAAE,GAAG,CAAC,EAAE,KAEpD,CAAC;YAChB,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;gBACzB,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;oBAC9C,OAAO,IAAI,oBAAoB,CAC3B,GAAG,IAAI,IAAI,GAAG,EAAE,EAChB,GAAG,IAAI,IAAI,GAAG,iBAAiB,CAClC,CAAC;gBACN,CAAC;gBACD,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,IAAI,IAAI,GAAG,EAAE,CAAC,CAAC;gBAChE,IAAI,OAAO;oBAAE,OAAO,OAAO,CAAC;gBAC5B,SAAS;YACb,CAAC;YACD,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,KAAK,EAAE,GAAG,IAAI,IAAI,GAAG,EAAE,CAAC,CAAC;YACnE,IAAI,OAAO;gBAAE,OAAO,OAAO,CAAC;QAChC,CAAC;QACD,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,QAAQ,IAAI,EAAE,EAAE,CAAC;YACvC,IAAI,MAAM,CAAC,wBAAwB,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,KAAK,KAAK,SAAS,EAAE,CAAC;gBACpE,OAAO,IAAI,oBAAoB,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,EAAE,GAAG,IAAI,IAAI,IAAI,cAAc,CAAC,CAAC;YACtF,CAAC;QACL,CAAC;QACD,OAAO,SAAS,CAAC;IACrB,CAAC;IAEO,aAAa,CACjB,MAAqB,EACrB,KAAe,EACf,IAAY;QAEZ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO,IAAI,oBAAoB,CAAC,IAAI,EAAE,GAAG,IAAI,mBAAmB,CAAC,CAAC;QACtE,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;QAC3B,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,SAAS,CAAC;QAC1C,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;YACnD,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,EAAE,GAAG,IAAI,IAAI,KAAK,GAAG,CAAC,CAAC;YAC1E,IAAI,OAAO;gBAAE,OAAO,OAAO,CAAC;QAChC,CAAC;QACD,OAAO,SAAS,CAAC;IACrB,CAAC;IAEO,cAAc,CAClB,MAAqB,EACrB,KAAe,EACf,IAAY;QAEZ,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC5B,OAAO,IAAI,oBAAoB,CAAC,IAAI,EAAE,GAAG,IAAI,mBAAmB,CAAC,CAAC;QACtE,CAAC;QACD,IAAI,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAC9C,OAAO,IAAI,oBAAoB,CAC3B,IAAI,EACJ,GAAG,IAAI,oBAAoB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACtD,CAAC;QACN,CAAC;QACD,OAAO,SAAS,CAAC;IACrB,CAAC;IAEO,cAAc,CAClB,MAAqB,EACrB,KAAe,EACf,IAAY;QAEZ,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACvD,OAAO,IAAI,oBAAoB,CAAC,IAAI,EAAE,GAAG,IAAI,mBAAmB,CAAC,CAAC;QACtE,CAAC;QACD,IAAI,aAAa,CAAC,UAAU,CAAC,MAAM,CAAC,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;YAC7E,OAAO,IAAI,oBAAoB,CAAC,IAAI,EAAE,GAAG,IAAI,qBAAqB,CAAC,CAAC;QACxE,CAAC;QACD,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS,IAAI,KAAK,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;YACzD,OAAO,IAAI,oBAAoB,CAAC,IAAI,EAAE,GAAG,IAAI,eAAe,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;QAClF,CAAC;QACD,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS,IAAI,KAAK,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;YACzD,OAAO,IAAI,oBAAoB,CAAC,IAAI,EAAE,GAAG,IAAI,eAAe,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;QAClF,CAAC;QACD,OAAO,SAAS,CAAC;IACrB,CAAC;CACJ;AA5HD,wDA4HC","sourcesContent":["/**\n * The JSON Schema subset webpieces publishes on its API boundaries, and the ONE runtime validator of\n * it.\n *\n * ## Nothing here reads reflect-metadata any more\n *\n * Until #984 this file also carried `@WpDto`, `@WpDtoField`, `WpDtoFieldOptions`,\n * `WpDtoMapFieldOptions`, `WpMcpHeader`, `@WpResponseDto` and `DtoSchemaBuilder` — a second, runtime\n * spelling of facts the TypeScript compiler already holds. #983 measured the two against each other\n * and found the compiler reproduces every one of those arguments byte for byte, so they are deleted\n * rather than deprecated (`.claude/rules/no-backwards-compat.md`): a schema is now BUILT at build\n * time from the source by `@webpieces/api-doc-model`, and the runtime is HANDED the result.\n *\n * What survives is the schema itself, a builder for the boundaries that construct one by hand, and a\n * validator that reads the schema instead of a decorator.\n */\n\n/** Runtime values accepted at the DTO validation boundary. */\nexport type DtoValue = object | string | number | boolean | null;\n\n/**\n * One JSON Schema `type`. `null` is a member because NULLABLE is expressed as `[\"string\", \"null\"]`,\n * which is how JSON Schema says \"present, and may hold null\" — a different wire document from an\n * ABSENT property, and one the reflect-metadata runtime could neither see nor write down.\n */\nexport type ApiJsonSchemaType =\n | 'object'\n | 'string'\n | 'number'\n | 'integer'\n | 'boolean'\n | 'array'\n | 'null';\n\n/** The JSON Schema subset emitted for Webpieces API DTOs. */\nexport class ApiJsonSchema {\n /** One type, or `[T, \"null\"]` for a nullable field. */\n type?: ApiJsonSchemaType | readonly ApiJsonSchemaType[];\n description?: string;\n properties?: Record<string, ApiJsonSchema>;\n required?: string[];\n /** `false` closes an object; a schema makes it a typed map whose values all match that schema. */\n additionalProperties?: boolean | ApiJsonSchema;\n items?: ApiJsonSchema;\n enum?: string[];\n minimum?: number;\n maximum?: number;\n /** MCP 2026 SEP-2243 schema extension consumed by the official SDK. */\n declare 'x-mcp-header'?: string;\n\n constructor(type?: ApiJsonSchemaType | readonly ApiJsonSchemaType[]) {\n this.type = type;\n }\n\n /**\n * The non-`null` member of the type, which is the one that decides how a value is checked.\n *\n * These three are STATIC and not instance methods on purpose: an instance method would put a\n * function on the structural type, and this class is handed straight to the MCP SDK, whose\n * parameter types are index-signature JSON objects that a class carrying methods no longer\n * satisfies. It stays a data-only structure (`CLAUDE.md` §1) and the helpers live beside it.\n */\n // webpieces-disable no-function-outside-class -- static reader of this class\n static baseTypeOf(schema: ApiJsonSchema): ApiJsonSchemaType | undefined {\n if (schema.type === undefined) return undefined;\n if (typeof schema.type === 'string') return schema.type;\n return schema.type.find((one: ApiJsonSchemaType) => one !== 'null');\n }\n\n /** True when the schema was widened with `\"null\"`, i.e. the property may hold `null`. */\n // webpieces-disable no-function-outside-class -- static reader of this class\n static allowsNull(schema: ApiJsonSchema): boolean {\n return typeof schema.type !== 'string' && (schema.type?.includes('null') ?? false);\n }\n\n /**\n * The one closure gate for an object schema. Closed means no key can carry an unspecified value:\n * either extra keys are forbidden (`additionalProperties: false`) or every extra key's value is\n * typed (`additionalProperties: <schema>`, a typed map). A missing or `true` value is open.\n * Use this instead of `schema.additionalProperties === false`, which rejects typed maps.\n */\n // webpieces-disable no-function-outside-class -- static reader of this class\n static isClosed(schema: ApiJsonSchema): boolean {\n const extra = schema.additionalProperties;\n return extra === false || (typeof extra === 'object' && extra !== null);\n }\n}\n\n/**\n * Builds the CLOSED object schema a hand-written runtime boundary validates against — `@WpStream`'s\n * two event schemas are the whole of its client list today.\n *\n * It exists because the alternative spellings are both worse: a decorator that re-states the field\n * types the compiler already knows is exactly what #984 deleted, and a bare object literal is what\n * `CLAUDE.md` §3 forbids. A generated schema never comes through here — it is read from the build's\n * own artifact.\n */\nexport class ObjectSchemaBuilder {\n private readonly schema = new ApiJsonSchema('object');\n private readonly requiredNames: string[] = [];\n\n constructor() {\n this.schema.properties = {};\n this.schema.additionalProperties = false;\n }\n\n required(name: string, type: ApiJsonSchema): this {\n this.requiredNames.push(name);\n return this.optional(name, type);\n }\n\n optional(name: string, type: ApiJsonSchema): this {\n this.schema.properties![name] = type;\n return this;\n }\n\n build(): ApiJsonSchema {\n if (this.requiredNames.length > 0) this.schema.required = [...this.requiredNames];\n return this.schema;\n }\n}\n\n/** A validation result safe to show to an API caller/model. */\nexport class DtoValidationFailure {\n constructor(\n /** JSON path of the offending value, e.g. `$.address.city`. */\n public readonly field: string,\n public readonly message: string,\n ) {}\n}\n\n/**\n * Validates a value against an {@link ApiJsonSchema} — the ONE runtime narrowing boundary for MCP\n * tool arguments, MCP structured output and typed stream events.\n *\n * It reads the SCHEMA, which is the same object the build published to agents, so a document that\n * says a field is required and a server that accepts it missing cannot disagree. The predecessor\n * walked reflect-metadata instead, which meant the published document and the accepted request were\n * derived from two different declarations.\n */\nexport class ApiJsonSchemaValidator {\n validate(schema: ApiJsonSchema, value: DtoValue): DtoValidationFailure | undefined {\n return this.validateAt(schema, value, '$');\n }\n\n private validateAt(\n schema: ApiJsonSchema,\n value: DtoValue,\n path: string,\n ): DtoValidationFailure | undefined {\n if (value === null) {\n return ApiJsonSchema.allowsNull(schema)\n ? undefined\n : new DtoValidationFailure(path, `${path} must not be null`);\n }\n switch (ApiJsonSchema.baseTypeOf(schema)) {\n case 'object':\n return this.validateObject(schema, value, path);\n case 'array':\n return this.validateArray(schema, value, path);\n case 'string':\n return this.validateString(schema, value, path);\n case 'number':\n case 'integer':\n return this.validateNumber(schema, value, path);\n case 'boolean':\n return typeof value === 'boolean'\n ? undefined\n : new DtoValidationFailure(path, `${path} must be a boolean`);\n default:\n return undefined;\n }\n }\n\n private validateObject(\n schema: ApiJsonSchema,\n value: DtoValue,\n path: string,\n ): DtoValidationFailure | undefined {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n return new DtoValidationFailure(path, `${path} must be an object`);\n }\n const properties = schema.properties ?? {};\n const extra = schema.additionalProperties;\n for (const key of Object.keys(value)) {\n const entry: DtoValue = Object.getOwnPropertyDescriptor(value, key)?.value;\n const declared = Object.getOwnPropertyDescriptor(properties, key)?.value as\n | ApiJsonSchema\n | undefined;\n if (declared === undefined) {\n if (typeof extra !== 'object' || extra === null) {\n return new DtoValidationFailure(\n `${path}.${key}`,\n `${path}.${key} is not allowed`,\n );\n }\n const failure = this.validateAt(extra, entry, `${path}.${key}`);\n if (failure) return failure;\n continue;\n }\n const failure = this.validateAt(declared, entry, `${path}.${key}`);\n if (failure) return failure;\n }\n for (const name of schema.required ?? []) {\n if (Object.getOwnPropertyDescriptor(value, name)?.value === undefined) {\n return new DtoValidationFailure(`${path}.${name}`, `${path}.${name} is required`);\n }\n }\n return undefined;\n }\n\n private validateArray(\n schema: ApiJsonSchema,\n value: DtoValue,\n path: string,\n ): DtoValidationFailure | undefined {\n if (!Array.isArray(value)) {\n return new DtoValidationFailure(path, `${path} must be an array`);\n }\n const items = schema.items;\n if (items === undefined) return undefined;\n for (let index = 0; index < value.length; index += 1) {\n const failure = this.validateAt(items, value[index], `${path}[${index}]`);\n if (failure) return failure;\n }\n return undefined;\n }\n\n private validateString(\n schema: ApiJsonSchema,\n value: DtoValue,\n path: string,\n ): DtoValidationFailure | undefined {\n if (typeof value !== 'string') {\n return new DtoValidationFailure(path, `${path} must be a string`);\n }\n if (schema.enum && !schema.enum.includes(value)) {\n return new DtoValidationFailure(\n path,\n `${path} must be one of: ${schema.enum.join(', ')}`,\n );\n }\n return undefined;\n }\n\n private validateNumber(\n schema: ApiJsonSchema,\n value: DtoValue,\n path: string,\n ): DtoValidationFailure | undefined {\n if (typeof value !== 'number' || !Number.isFinite(value)) {\n return new DtoValidationFailure(path, `${path} must be a number`);\n }\n if (ApiJsonSchema.baseTypeOf(schema) === 'integer' && !Number.isInteger(value)) {\n return new DtoValidationFailure(path, `${path} must be an integer`);\n }\n if (schema.minimum !== undefined && value < schema.minimum) {\n return new DtoValidationFailure(path, `${path} must be >= ${schema.minimum}`);\n }\n if (schema.maximum !== undefined && value > schema.maximum) {\n return new DtoValidationFailure(path, `${path} must be <= ${schema.maximum}`);\n }\n return undefined;\n }\n}\n"]}
1
+ {"version":3,"file":"DtoSchema.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/mcp/DtoSchema.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The JSON Schema subset webpieces publishes on its API boundaries, and the ONE runtime validator of\n * it.\n *\n * ## Nothing here reads reflect-metadata any more\n *\n * Until #984 this file also carried `@WpDto`, `@WpDtoField`, `WpDtoFieldOptions`,\n * `WpDtoMapFieldOptions`, `WpMcpHeader`, `@WpResponseDto` and `DtoSchemaBuilder` — a second, runtime\n * spelling of facts the TypeScript compiler already holds. #983 measured the two against each other\n * and found the compiler reproduces every one of those arguments byte for byte, so they are deleted\n * rather than deprecated (`.claude/rules/no-backwards-compat.md`): a schema is now BUILT at build\n * time from the source by `@webpieces/api-doc-model`, and the runtime is HANDED the result.\n *\n * What survives is the schema itself, a builder for the boundaries that construct one by hand, and a\n * validator that reads the schema instead of a decorator.\n */\n\n/** Runtime values accepted at the DTO validation boundary. */\nexport type DtoValue = object | string | number | boolean | null;\n\n/**\n * One JSON Schema `type`. `null` is a member because NULLABLE is expressed as `[\"string\", \"null\"]`,\n * which is how JSON Schema says \"present, and may hold null\" — a different wire document from an\n * ABSENT property, and one the reflect-metadata runtime could neither see nor write down.\n */\nexport type ApiJsonSchemaType =\n | 'object'\n | 'string'\n | 'number'\n | 'integer'\n | 'boolean'\n | 'array'\n | 'null';\n\n/**\n * The DISCRIMINATOR of a {@link ApiJsonSchema.oneOf} — which property narrows the union, and what\n * each of its values names.\n *\n * The shape MIRRORS what `OpenApiGenerator`'s `SchemaRenderer` already emits for the same union\n * (`propertyName` + `mapping`), because a union has exactly ONE published spelling in this repo and\n * the OpenAPI renderer is the reference implementation of it. The one difference is what a mapping\n * VALUE holds: OpenAPI maps a value to `#/components/schemas/ScheduledWindow`, and an MCP tool\n * schema is INLINE and has no `$ref` to point at, so it maps to the branch's type NAME.\n *\n * `mapping` is DOCUMENTATION for the reader. {@link ApiJsonSchemaValidator} never narrows with it:\n * it selects the branch whose own `enum` carries the value, so the accepted request and the\n * published document cannot disagree about which branch a value means.\n */\nexport class ApiJsonSchemaDiscriminator {\n constructor(\n /** The property every branch declares as exactly one string literal, e.g. `kind`. */\n public propertyName: string,\n /** discriminator value -> the branch's TYPE NAME (MCP is inline: there is no `$ref`). */\n public mapping: Record<string, string>,\n ) {}\n}\n\n/** The JSON Schema subset emitted for Webpieces API DTOs. */\nexport class ApiJsonSchema {\n /** One type, or `[T, \"null\"]` for a nullable field. */\n type?: ApiJsonSchemaType | readonly ApiJsonSchemaType[];\n description?: string;\n properties?: Record<string, ApiJsonSchema>;\n required?: string[];\n /** `false` closes an object; a schema makes it a typed map whose values all match that schema. */\n additionalProperties?: boolean | ApiJsonSchema;\n items?: ApiJsonSchema;\n enum?: string[];\n minimum?: number;\n maximum?: number;\n /**\n * The branches of a union, INLINE (MCP tool schemas have no `$ref`), in declaration order.\n *\n * A union is legal NESTED, inside a property. It is NOT legal at the ROOT of a tool's parameter\n * schema — both the OpenAI and the Anthropic function-calling APIs reject a top-level\n * `oneOf`/`anyOf`/`allOf`, and because a server sends its whole tool list on every request, one\n * such tool makes EVERY request 400. That is refused at build time by the `no-root-union-api-type`\n * rule, before a contract can be published at all.\n */\n oneOf?: readonly ApiJsonSchema[];\n /**\n * Set ONLY when every branch carries the same property typed as one string literal — DERIVED,\n * never invented. A union TypeScript itself cannot narrow is published as a bare {@link oneOf},\n * because claiming a narrowing the source does not have is worse than admitting there is none.\n */\n discriminator?: ApiJsonSchemaDiscriminator;\n /** MCP 2026 SEP-2243 schema extension consumed by the official SDK. */\n declare 'x-mcp-header'?: string;\n\n constructor(type?: ApiJsonSchemaType | readonly ApiJsonSchemaType[]) {\n this.type = type;\n }\n\n /**\n * The non-`null` member of the type, which is the one that decides how a value is checked.\n *\n * These three are STATIC and not instance methods on purpose: an instance method would put a\n * function on the structural type, and this class is handed straight to the MCP SDK, whose\n * parameter types are index-signature JSON objects that a class carrying methods no longer\n * satisfies. It stays a data-only structure (`CLAUDE.md` §1) and the helpers live beside it.\n */\n // webpieces-disable no-function-outside-class -- static reader of this class\n static baseTypeOf(schema: ApiJsonSchema): ApiJsonSchemaType | undefined {\n if (schema.type === undefined) return undefined;\n if (typeof schema.type === 'string') return schema.type;\n return schema.type.find((one: ApiJsonSchemaType) => one !== 'null');\n }\n\n /** True when the schema was widened with `\"null\"`, i.e. the property may hold `null`. */\n // webpieces-disable no-function-outside-class -- static reader of this class\n static allowsNull(schema: ApiJsonSchema): boolean {\n return typeof schema.type !== 'string' && (schema.type?.includes('null') ?? false);\n }\n\n /**\n * The one closure gate for an object schema. Closed means no key can carry an unspecified value:\n * either extra keys are forbidden (`additionalProperties: false`) or every extra key's value is\n * typed (`additionalProperties: <schema>`, a typed map). A missing or `true` value is open.\n * Use this instead of `schema.additionalProperties === false`, which rejects typed maps.\n */\n // webpieces-disable no-function-outside-class -- static reader of this class\n static isClosed(schema: ApiJsonSchema): boolean {\n const extra = schema.additionalProperties;\n return extra === false || (typeof extra === 'object' && extra !== null);\n }\n}\n\n/**\n * Builds the CLOSED object schema a hand-written runtime boundary validates against — `@WpStream`'s\n * two event schemas are the whole of its client list today.\n *\n * It exists because the alternative spellings are both worse: a decorator that re-states the field\n * types the compiler already knows is exactly what #984 deleted, and a bare object literal is what\n * `CLAUDE.md` §3 forbids. A generated schema never comes through here — it is read from the build's\n * own artifact.\n */\nexport class ObjectSchemaBuilder {\n private readonly schema = new ApiJsonSchema('object');\n private readonly requiredNames: string[] = [];\n\n constructor() {\n this.schema.properties = {};\n this.schema.additionalProperties = false;\n }\n\n required(name: string, type: ApiJsonSchema): this {\n this.requiredNames.push(name);\n return this.optional(name, type);\n }\n\n optional(name: string, type: ApiJsonSchema): this {\n this.schema.properties![name] = type;\n return this;\n }\n\n build(): ApiJsonSchema {\n if (this.requiredNames.length > 0) this.schema.required = [...this.requiredNames];\n return this.schema;\n }\n}\n\n/** A validation result safe to show to an API caller/model. */\nexport class DtoValidationFailure {\n constructor(\n /** JSON path of the offending value, e.g. `$.address.city`. */\n public readonly field: string,\n public readonly message: string,\n ) {}\n}\n\n/**\n * Validates a value against an {@link ApiJsonSchema} — the ONE runtime narrowing boundary for MCP\n * tool arguments, MCP structured output and typed stream events.\n *\n * It reads the SCHEMA, which is the same object the build published to agents, so a document that\n * says a field is required and a server that accepts it missing cannot disagree. The predecessor\n * walked reflect-metadata instead, which meant the published document and the accepted request were\n * derived from two different declarations.\n */\nexport class ApiJsonSchemaValidator {\n validate(schema: ApiJsonSchema, value: DtoValue): DtoValidationFailure | undefined {\n return this.validateAt(schema, value, '$');\n }\n\n private validateAt(\n schema: ApiJsonSchema,\n value: DtoValue,\n path: string,\n ): DtoValidationFailure | undefined {\n if (value === null) {\n return ApiJsonSchema.allowsNull(schema)\n ? undefined\n : new DtoValidationFailure(path, `${path} must not be null`);\n }\n if (schema.oneOf !== undefined) {\n return this.validateUnion(schema, value, path);\n }\n switch (ApiJsonSchema.baseTypeOf(schema)) {\n case 'object':\n return this.validateObject(schema, value, path);\n case 'array':\n return this.validateArray(schema, value, path);\n case 'string':\n return this.validateString(schema, value, path);\n case 'number':\n case 'integer':\n return this.validateNumber(schema, value, path);\n case 'boolean':\n return typeof value === 'boolean'\n ? undefined\n : new DtoValidationFailure(path, `${path} must be a boolean`);\n default:\n return undefined;\n }\n }\n\n /**\n * A union, validated BY DISCRIMINATOR.\n *\n * The discriminator property is read FIRST and the branch chosen from it, so a value naming no\n * branch is reported as what it is — `$.window.kind must be one of: scheduled | asap`, naming the\n * field that is wrong and the values it may hold. Trying every branch and reporting \"no branch\n * matched\" tells a caller nothing they can act on: it names neither the offending property nor\n * the legal values, and it hides a branch that matched on `kind` and failed three levels down.\n *\n * The branch is selected by the branches' own `enum`s, never by\n * {@link ApiJsonSchemaDiscriminator.mapping} — the branches ARE the schema, so selection and\n * validation read one source and cannot disagree.\n */\n private validateUnion(\n schema: ApiJsonSchema,\n value: DtoValue,\n path: string,\n ): DtoValidationFailure | undefined {\n const branches = schema.oneOf ?? [];\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n return new DtoValidationFailure(path, `${path} must be an object`);\n }\n const discriminator = schema.discriminator;\n if (discriminator === undefined) {\n return this.validateAnyBranch(branches, value, path);\n }\n const property = discriminator.propertyName;\n const held: DtoValue = Object.getOwnPropertyDescriptor(value, property)?.value;\n const branch = branches.find((one: ApiJsonSchema) =>\n ApiJsonSchemaValidator.branchValuesOf(one, property).includes(held as string),\n );\n if (branch === undefined) {\n const legal = branches\n .flatMap((one: ApiJsonSchema) =>\n ApiJsonSchemaValidator.branchValuesOf(one, property),\n )\n .join(' | ');\n return new DtoValidationFailure(\n `${path}.${property}`,\n `${path}.${property} must be one of: ${legal}`,\n );\n }\n return this.validateAt(branch, value, path);\n }\n\n /**\n * A union with NO discriminator — one TypeScript itself cannot narrow. Every branch is tried and\n * the value accepted when one matches. There is no better report when none does: the source does\n * not narrow, so no property can honestly be named as the wrong one.\n */\n private validateAnyBranch(\n branches: readonly ApiJsonSchema[],\n value: DtoValue,\n path: string,\n ): DtoValidationFailure | undefined {\n for (const branch of branches) {\n if (this.validateAt(branch, value, path) === undefined) {\n return undefined;\n }\n }\n return new DtoValidationFailure(\n path,\n `${path} matches none of the ${branches.length} accepted shapes`,\n );\n }\n\n /** The string literals ONE branch declares for the discriminator property. */\n // webpieces-disable no-function-outside-class -- private static reader of a branch schema\n private static branchValuesOf(branch: ApiJsonSchema, property: string): readonly string[] {\n const declared = Object.getOwnPropertyDescriptor(branch.properties ?? {}, property)\n ?.value as ApiJsonSchema | undefined;\n return declared?.enum ?? [];\n }\n\n private validateObject(\n schema: ApiJsonSchema,\n value: DtoValue,\n path: string,\n ): DtoValidationFailure | undefined {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n return new DtoValidationFailure(path, `${path} must be an object`);\n }\n const properties = schema.properties ?? {};\n const extra = schema.additionalProperties;\n for (const key of Object.keys(value)) {\n const entry: DtoValue = Object.getOwnPropertyDescriptor(value, key)?.value;\n const declared = Object.getOwnPropertyDescriptor(properties, key)?.value as\n | ApiJsonSchema\n | undefined;\n if (declared === undefined) {\n if (typeof extra !== 'object' || extra === null) {\n return new DtoValidationFailure(\n `${path}.${key}`,\n `${path}.${key} is not allowed`,\n );\n }\n const failure = this.validateAt(extra, entry, `${path}.${key}`);\n if (failure) return failure;\n continue;\n }\n const failure = this.validateAt(declared, entry, `${path}.${key}`);\n if (failure) return failure;\n }\n for (const name of schema.required ?? []) {\n if (Object.getOwnPropertyDescriptor(value, name)?.value === undefined) {\n return new DtoValidationFailure(`${path}.${name}`, `${path}.${name} is required`);\n }\n }\n return undefined;\n }\n\n private validateArray(\n schema: ApiJsonSchema,\n value: DtoValue,\n path: string,\n ): DtoValidationFailure | undefined {\n if (!Array.isArray(value)) {\n return new DtoValidationFailure(path, `${path} must be an array`);\n }\n const items = schema.items;\n if (items === undefined) return undefined;\n for (let index = 0; index < value.length; index += 1) {\n const failure = this.validateAt(items, value[index], `${path}[${index}]`);\n if (failure) return failure;\n }\n return undefined;\n }\n\n private validateString(\n schema: ApiJsonSchema,\n value: DtoValue,\n path: string,\n ): DtoValidationFailure | undefined {\n if (typeof value !== 'string') {\n return new DtoValidationFailure(path, `${path} must be a string`);\n }\n if (schema.enum && !schema.enum.includes(value)) {\n return new DtoValidationFailure(\n path,\n `${path} must be one of: ${schema.enum.join(', ')}`,\n );\n }\n return undefined;\n }\n\n private validateNumber(\n schema: ApiJsonSchema,\n value: DtoValue,\n path: string,\n ): DtoValidationFailure | undefined {\n if (typeof value !== 'number' || !Number.isFinite(value)) {\n return new DtoValidationFailure(path, `${path} must be a number`);\n }\n if (ApiJsonSchema.baseTypeOf(schema) === 'integer' && !Number.isInteger(value)) {\n return new DtoValidationFailure(path, `${path} must be an integer`);\n }\n if (schema.minimum !== undefined && value < schema.minimum) {\n return new DtoValidationFailure(path, `${path} must be >= ${schema.minimum}`);\n }\n if (schema.maximum !== undefined && value > schema.maximum) {\n return new DtoValidationFailure(path, `${path} must be <= ${schema.maximum}`);\n }\n return undefined;\n }\n}\n"]}
@@ -164,8 +164,29 @@ class McpCatalogJson {
164
164
  }
165
165
  schema.properties = built;
166
166
  }
167
+ const oneOf = record['oneOf'];
168
+ if (Array.isArray(oneOf)) {
169
+ // webpieces-disable no-any-unknown -- parsing JSON is exactly where unknown belongs
170
+ schema.oneOf = oneOf.map((branch) => this.schemaFrom(branch));
171
+ schema.discriminator = this.discriminatorFrom(record['discriminator']);
172
+ }
167
173
  return schema;
168
174
  }
175
+ /**
176
+ * The `discriminator` block, or undefined — a union TypeScript cannot narrow is published WITHOUT
177
+ * one, so an absent block is a legal document and not a missing field.
178
+ */
179
+ // webpieces-disable no-any-unknown -- parsing JSON is exactly where unknown belongs
180
+ discriminatorFrom(value) {
181
+ if (value === undefined)
182
+ return undefined;
183
+ const record = this.record(value, 'a schema discriminator block');
184
+ const mapping = {};
185
+ for (const [key, branch] of Object.entries(this.record(record['mapping'], 'a discriminator mapping block'))) {
186
+ mapping[key] = this.text(branch, `discriminator mapping '${key}'`);
187
+ }
188
+ return new DtoSchema_1.ApiJsonSchemaDiscriminator(this.text(record['propertyName'], 'discriminator propertyName'), mapping);
189
+ }
169
190
  // webpieces-disable no-any-unknown -- parsing JSON is exactly where unknown belongs
170
191
  record(value, what) {
171
192
  if (typeof value !== 'object' || value === null || Array.isArray(value)) {
@@ -1 +1 @@
1
- {"version":3,"file":"McpToolCatalog.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/mcp/McpToolCatalog.ts"],"names":[],"mappings":"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","sourcesContent":["import { ApiJsonSchema, ApiJsonSchemaType } from './DtoSchema';\nimport { WpMcpToolHints } from './McpMetadata';\n\n/**\n * ONE MCP tool, as `tools/list` publishes it.\n *\n * It is BUILT from the source by `@webpieces/api-doc-model`'s `McpSchemaRenderer` at build time, and\n * READ here at boot — so the tool an agent is shown and the tool the server accepts are the same\n * bytes by construction, not by two declarations agreeing.\n *\n * It lives in `core-util` rather than in the extractor package because both ends need it and only\n * one end may depend on the TypeScript compiler API. `ApiJsonSchema` and {@link WpMcpToolHints},\n * which it is made of, are already here for the same reason.\n */\nexport class McpToolDefinition {\n constructor(\n /** The stable protocol name from `@WpMcpTool('...')`. */\n readonly name: string,\n /** The contract method it was rendered from, so a mismatch report can name the source. */\n readonly methodName: string,\n /**\n * The tool documentation: the method's `@mcp` tag when it has one, its JSDoc body otherwise.\n * Documentation has exactly ONE source — the doc comment above the declaration — for the\n * partner reading OpenAPI and the agent reading `tools/list` alike.\n */\n readonly description: string,\n /**\n * All four hints. Three are COMPUTED from `@Endpoint`'s `operation` by\n * `mcpHintsForOperation`, which is the one place that mapping lives; `openWorldHint` comes\n * from `@Endpoint`'s `openWorld` option.\n */\n readonly hints: WpMcpToolHints,\n readonly inputSchema: ApiJsonSchema,\n readonly outputSchema: ApiJsonSchema,\n ) {}\n}\n\n/** Thrown when the catalog a server was handed is not a catalog this release can read. */\nexport class McpToolCatalogError extends Error {\n constructor(\n message: string,\n /** What to do instead, in one sentence. */\n readonly cure: string,\n ) {\n super(`${message} ${cure}`);\n this.name = 'McpToolCatalogError';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** The one cure every catalog failure prescribes: rebuild the artifact from the contracts. */\nconst REGENERATE = 'Regenerate it with `wp-openapi --manifest <manifest> --out <dir>`.';\n\n/**\n * Every MCP tool one build published, keyed by protocol name — the artifact `wp-openapi` writes as\n * `mcp-tools.json` and `WpMcpServer` is constructed with.\n *\n * A tool the build never saw is a tool whose schema nobody checked, so `McpToolRegistry` fails fast\n * at boot rather than publishing a shape derived from a second source.\n */\nexport class McpToolCatalog {\n private readonly byName: ReadonlyMap<string, McpToolDefinition>;\n\n constructor(readonly tools: readonly McpToolDefinition[]) {\n const byName = new Map<string, McpToolDefinition>();\n for (const tool of tools) {\n if (byName.has(tool.name)) {\n throw new McpToolCatalogError(\n `Duplicate MCP tool name '${tool.name}' in the generated catalog.`,\n 'Tool names are the protocol identity and must be globally unique — rename one ' +\n \"of the two @WpMcpTool('...') declarations.\",\n );\n }\n byName.set(tool.name, tool);\n }\n this.byName = byName;\n }\n\n find(name: string): McpToolDefinition | undefined {\n return this.byName.get(name);\n }\n\n /** The names this catalog carries, sorted, so a failure can print what WAS published. */\n names(): readonly string[] {\n return [...this.byName.keys()].sort();\n }\n\n /** The bytes `wp-openapi` writes. Sorted by name so the artifact is diffable. */\n toJsonText(): string {\n const tools = [...this.tools].sort((left: McpToolDefinition, right: McpToolDefinition) =>\n left.name.localeCompare(right.name),\n );\n return `${JSON.stringify(tools, undefined, 2)}\\n`;\n }\n\n /**\n * Reads `mcp-tools.json`. Every nested value is rebuilt as a real class instance, because this is\n * the one place untyped bytes become the schemas a live protocol surface publishes.\n *\n * Malformed JSON is not caught here: it throws `SyntaxError` to the caller's own top-level\n * handler, which is where every other read-the-world failure in webpieces is reported.\n */\n // webpieces-disable no-function-outside-class -- static factory of this class\n static fromJsonText(text: string): McpToolCatalog {\n return new McpCatalogJson().parse(text);\n }\n}\n\n/**\n * The PARSE BOUNDARY: untyped bytes in, real class instances out.\n *\n * A class of its own rather than statics on {@link McpToolCatalog} so every step is an ordinary\n * instance method — and because it is the one place in this file where `unknown` is the correct type\n * rather than a missing one. Nothing else in webpieces should ever hold a half-narrowed schema.\n */\nclass McpCatalogJson {\n parse(text: string): McpToolCatalog {\n // webpieces-disable no-any-unknown -- this IS the untyped-bytes boundary; every step below narrows it\n const parsed: unknown = JSON.parse(text);\n if (!Array.isArray(parsed)) {\n throw new McpToolCatalogError(\n 'The MCP tool catalog must be a JSON array of tool definitions.',\n REGENERATE,\n );\n }\n // webpieces-disable no-any-unknown -- parsing JSON is exactly where unknown belongs\n return new McpToolCatalog(parsed.map((entry: unknown) => this.toolFrom(entry)));\n }\n\n // webpieces-disable no-any-unknown -- parsing JSON is exactly where unknown belongs\n private toolFrom(entry: unknown): McpToolDefinition {\n const record = this.record(entry, 'a tool definition');\n const hints = this.record(record['hints'], 'a tool definition hints block');\n return new McpToolDefinition(\n this.text(record['name'], 'name'),\n this.text(record['methodName'], 'methodName'),\n this.text(record['description'], 'description'),\n new WpMcpToolHints(\n hints['readOnlyHint'] === true,\n hints['destructiveHint'] === true,\n hints['idempotentHint'] === true,\n hints['openWorldHint'] === true,\n ),\n this.schemaFrom(record['inputSchema']),\n this.schemaFrom(record['outputSchema']),\n );\n }\n\n // webpieces-disable no-any-unknown -- parsing JSON is exactly where unknown belongs\n private schemaFrom(value: unknown): ApiJsonSchema {\n const record = this.record(value, 'a JSON schema');\n const schema = new ApiJsonSchema(\n record['type'] as ApiJsonSchemaType | readonly ApiJsonSchemaType[],\n );\n if (typeof record['description'] === 'string') schema.description = record['description'];\n if (typeof record['minimum'] === 'number') schema.minimum = record['minimum'];\n if (typeof record['maximum'] === 'number') schema.maximum = record['maximum'];\n if (Array.isArray(record['required'])) schema.required = record['required'] as string[];\n if (Array.isArray(record['enum'])) schema.enum = record['enum'] as string[];\n if (typeof record['x-mcp-header'] === 'string') {\n schema['x-mcp-header'] = record['x-mcp-header'];\n }\n if (record['items'] !== undefined) schema.items = this.schemaFrom(record['items']);\n const extra = record['additionalProperties'];\n if (typeof extra === 'boolean') schema.additionalProperties = extra;\n else if (extra !== undefined) schema.additionalProperties = this.schemaFrom(extra);\n const properties = record['properties'];\n if (properties !== undefined) {\n const built: Record<string, ApiJsonSchema> = {};\n for (const [key, child] of Object.entries(\n this.record(properties, 'a schema properties block'),\n )) {\n built[key] = this.schemaFrom(child);\n }\n schema.properties = built;\n }\n return schema;\n }\n\n // webpieces-disable no-any-unknown -- parsing JSON is exactly where unknown belongs\n private record(value: unknown, what: string): Record<string, unknown> {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw new McpToolCatalogError(`The MCP tool catalog is missing ${what}.`, REGENERATE);\n }\n // webpieces-disable no-any-unknown -- the narrowed result of the check above\n return value as Record<string, unknown>;\n }\n\n // webpieces-disable no-any-unknown -- parsing JSON is exactly where unknown belongs\n private text(value: unknown, field: string): string {\n if (typeof value !== 'string') {\n throw new McpToolCatalogError(\n `The MCP tool catalog has no '${field}' on a tool definition.`,\n REGENERATE,\n );\n }\n return value;\n }\n}\n"]}
1
+ {"version":3,"file":"McpToolCatalog.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/mcp/McpToolCatalog.ts"],"names":[],"mappings":";;;AAAA,2CAA2F;AAC3F,+CAA+C;AAE/C;;;;;;;;;;GAUG;AACH,MAAa,iBAAiB;IAGb;IAEA;IAMA;IAMA;IACA;IACA;IAlBb;IACI,yDAAyD;IAChD,IAAY;IACrB,0FAA0F;IACjF,UAAkB;IAC3B;;;;OAIG;IACM,WAAmB;IAC5B;;;;OAIG;IACM,KAAqB,EACrB,WAA0B,EAC1B,YAA2B;QAhB3B,SAAI,GAAJ,IAAI,CAAQ;QAEZ,eAAU,GAAV,UAAU,CAAQ;QAMlB,gBAAW,GAAX,WAAW,CAAQ;QAMnB,UAAK,GAAL,KAAK,CAAgB;QACrB,gBAAW,GAAX,WAAW,CAAe;QAC1B,iBAAY,GAAZ,YAAY,CAAe;IACrC,CAAC;CACP;AArBD,8CAqBC;AAED,0FAA0F;AAC1F,MAAa,mBAAoB,SAAQ,KAAK;IAI7B;IAHb,YACI,OAAe;IACf,2CAA2C;IAClC,IAAY;QAErB,KAAK,CAAC,GAAG,OAAO,IAAI,IAAI,EAAE,CAAC,CAAC;QAFnB,SAAI,GAAJ,IAAI,CAAQ;QAGrB,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;QAClC,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACtD,CAAC;CACJ;AAVD,kDAUC;AAED,8FAA8F;AAC9F,MAAM,UAAU,GAAG,oEAAoE,CAAC;AAExF;;;;;;GAMG;AACH,MAAa,cAAc;IAGF;IAFJ,MAAM,CAAyC;IAEhE,YAAqB,KAAmC;QAAnC,UAAK,GAAL,KAAK,CAA8B;QACpD,MAAM,MAAM,GAAG,IAAI,GAAG,EAA6B,CAAC;QACpD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACvB,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBACxB,MAAM,IAAI,mBAAmB,CACzB,4BAA4B,IAAI,CAAC,IAAI,6BAA6B,EAClE,gFAAgF;oBAC5E,4CAA4C,CACnD,CAAC;YACN,CAAC;YACD,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAChC,CAAC;QACD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACzB,CAAC;IAED,IAAI,CAAC,IAAY;QACb,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACjC,CAAC;IAED,yFAAyF;IACzF,KAAK;QACD,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC1C,CAAC;IAED,iFAAiF;IACjF,UAAU;QACN,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,IAAuB,EAAE,KAAwB,EAAE,EAAE,CACrF,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,CACtC,CAAC;QACF,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC;IACtD,CAAC;IAED;;;;;;OAMG;IACH,8EAA8E;IAC9E,MAAM,CAAC,YAAY,CAAC,IAAY;QAC5B,OAAO,IAAI,cAAc,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5C,CAAC;CACJ;AA9CD,wCA8CC;AAED;;;;;;GAMG;AACH,MAAM,cAAc;IAChB,KAAK,CAAC,IAAY;QACd,sGAAsG;QACtG,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACzC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,mBAAmB,CACzB,gEAAgE,EAChE,UAAU,CACb,CAAC;QACN,CAAC;QACD,oFAAoF;QACpF,OAAO,IAAI,cAAc,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAc,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACpF,CAAC;IAED,oFAAoF;IAC5E,QAAQ,CAAC,KAAc;QAC3B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,mBAAmB,CAAC,CAAC;QACvD,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,+BAA+B,CAAC,CAAC;QAC5E,OAAO,IAAI,iBAAiB,CACxB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,EACjC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC,EAC7C,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC,EAC/C,IAAI,4BAAc,CACd,KAAK,CAAC,cAAc,CAAC,KAAK,IAAI,EAC9B,KAAK,CAAC,iBAAiB,CAAC,KAAK,IAAI,EACjC,KAAK,CAAC,gBAAgB,CAAC,KAAK,IAAI,EAChC,KAAK,CAAC,eAAe,CAAC,KAAK,IAAI,CAClC,EACD,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,EACtC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAC1C,CAAC;IACN,CAAC;IAED,oFAAoF;IAC5E,UAAU,CAAC,KAAc;QAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,eAAe,CAAC,CAAC;QACnD,MAAM,MAAM,GAAG,IAAI,yBAAa,CAC5B,MAAM,CAAC,MAAM,CAAqD,CACrE,CAAC;QACF,IAAI,OAAO,MAAM,CAAC,aAAa,CAAC,KAAK,QAAQ;YAAE,MAAM,CAAC,WAAW,GAAG,MAAM,CAAC,aAAa,CAAC,CAAC;QAC1F,IAAI,OAAO,MAAM,CAAC,SAAS,CAAC,KAAK,QAAQ;YAAE,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;QAC9E,IAAI,OAAO,MAAM,CAAC,SAAS,CAAC,KAAK,QAAQ;YAAE,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;QAC9E,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YAAE,MAAM,CAAC,QAAQ,GAAG,MAAM,CAAC,UAAU,CAAa,CAAC;QACxF,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAAE,MAAM,CAAC,IAAI,GAAG,MAAM,CAAC,MAAM,CAAa,CAAC;QAC5E,IAAI,OAAO,MAAM,CAAC,cAAc,CAAC,KAAK,QAAQ,EAAE,CAAC;YAC7C,MAAM,CAAC,cAAc,CAAC,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC;QACpD,CAAC;QACD,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,SAAS;YAAE,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;QACnF,MAAM,KAAK,GAAG,MAAM,CAAC,sBAAsB,CAAC,CAAC;QAC7C,IAAI,OAAO,KAAK,KAAK,SAAS;YAAE,MAAM,CAAC,oBAAoB,GAAG,KAAK,CAAC;aAC/D,IAAI,KAAK,KAAK,SAAS;YAAE,MAAM,CAAC,oBAAoB,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QACnF,MAAM,UAAU,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;QACxC,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;YAC3B,MAAM,KAAK,GAAkC,EAAE,CAAC;YAChD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CACrC,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,2BAA2B,CAAC,CACvD,EAAE,CAAC;gBACA,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;YACxC,CAAC;YACD,MAAM,CAAC,UAAU,GAAG,KAAK,CAAC;QAC9B,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;QAC9B,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACvB,oFAAoF;YACpF,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,MAAe,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;YACvE,MAAM,CAAC,aAAa,GAAG,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC;QAC3E,CAAC;QACD,OAAO,MAAM,CAAC;IAClB,CAAC;IAED;;;OAGG;IACH,oFAAoF;IAC5E,iBAAiB,CAAC,KAAc;QACpC,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,SAAS,CAAC;QAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,8BAA8B,CAAC,CAAC;QAClE,MAAM,OAAO,GAA2B,EAAE,CAAC;QAC3C,KAAK,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CACtC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,+BAA+B,CAAC,CAClE,EAAE,CAAC;YACA,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,0BAA0B,GAAG,GAAG,CAAC,CAAC;QACvE,CAAC;QACD,OAAO,IAAI,sCAA0B,CACjC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,4BAA4B,CAAC,EAC/D,OAAO,CACV,CAAC;IACN,CAAC;IAED,oFAAoF;IAC5E,MAAM,CAAC,KAAc,EAAE,IAAY;QACvC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACtE,MAAM,IAAI,mBAAmB,CAAC,mCAAmC,IAAI,GAAG,EAAE,UAAU,CAAC,CAAC;QAC1F,CAAC;QACD,6EAA6E;QAC7E,OAAO,KAAgC,CAAC;IAC5C,CAAC;IAED,oFAAoF;IAC5E,IAAI,CAAC,KAAc,EAAE,KAAa;QACtC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC5B,MAAM,IAAI,mBAAmB,CACzB,gCAAgC,KAAK,yBAAyB,EAC9D,UAAU,CACb,CAAC;QACN,CAAC;QACD,OAAO,KAAK,CAAC;IACjB,CAAC;CACJ","sourcesContent":["import { ApiJsonSchema, ApiJsonSchemaDiscriminator, ApiJsonSchemaType } from './DtoSchema';\nimport { WpMcpToolHints } from './McpMetadata';\n\n/**\n * ONE MCP tool, as `tools/list` publishes it.\n *\n * It is BUILT from the source by `@webpieces/api-doc-model`'s `McpSchemaRenderer` at build time, and\n * READ here at boot — so the tool an agent is shown and the tool the server accepts are the same\n * bytes by construction, not by two declarations agreeing.\n *\n * It lives in `core-util` rather than in the extractor package because both ends need it and only\n * one end may depend on the TypeScript compiler API. `ApiJsonSchema` and {@link WpMcpToolHints},\n * which it is made of, are already here for the same reason.\n */\nexport class McpToolDefinition {\n constructor(\n /** The stable protocol name from `@WpMcpTool('...')`. */\n readonly name: string,\n /** The contract method it was rendered from, so a mismatch report can name the source. */\n readonly methodName: string,\n /**\n * The tool documentation: the method's `@mcp` tag when it has one, its JSDoc body otherwise.\n * Documentation has exactly ONE source — the doc comment above the declaration — for the\n * partner reading OpenAPI and the agent reading `tools/list` alike.\n */\n readonly description: string,\n /**\n * All four hints. Three are COMPUTED from `@Endpoint`'s `operation` by\n * `mcpHintsForOperation`, which is the one place that mapping lives; `openWorldHint` comes\n * from `@Endpoint`'s `openWorld` option.\n */\n readonly hints: WpMcpToolHints,\n readonly inputSchema: ApiJsonSchema,\n readonly outputSchema: ApiJsonSchema,\n ) {}\n}\n\n/** Thrown when the catalog a server was handed is not a catalog this release can read. */\nexport class McpToolCatalogError extends Error {\n constructor(\n message: string,\n /** What to do instead, in one sentence. */\n readonly cure: string,\n ) {\n super(`${message} ${cure}`);\n this.name = 'McpToolCatalogError';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** The one cure every catalog failure prescribes: rebuild the artifact from the contracts. */\nconst REGENERATE = 'Regenerate it with `wp-openapi --manifest <manifest> --out <dir>`.';\n\n/**\n * Every MCP tool one build published, keyed by protocol name — the artifact `wp-openapi` writes as\n * `mcp-tools.json` and `WpMcpServer` is constructed with.\n *\n * A tool the build never saw is a tool whose schema nobody checked, so `McpToolRegistry` fails fast\n * at boot rather than publishing a shape derived from a second source.\n */\nexport class McpToolCatalog {\n private readonly byName: ReadonlyMap<string, McpToolDefinition>;\n\n constructor(readonly tools: readonly McpToolDefinition[]) {\n const byName = new Map<string, McpToolDefinition>();\n for (const tool of tools) {\n if (byName.has(tool.name)) {\n throw new McpToolCatalogError(\n `Duplicate MCP tool name '${tool.name}' in the generated catalog.`,\n 'Tool names are the protocol identity and must be globally unique — rename one ' +\n \"of the two @WpMcpTool('...') declarations.\",\n );\n }\n byName.set(tool.name, tool);\n }\n this.byName = byName;\n }\n\n find(name: string): McpToolDefinition | undefined {\n return this.byName.get(name);\n }\n\n /** The names this catalog carries, sorted, so a failure can print what WAS published. */\n names(): readonly string[] {\n return [...this.byName.keys()].sort();\n }\n\n /** The bytes `wp-openapi` writes. Sorted by name so the artifact is diffable. */\n toJsonText(): string {\n const tools = [...this.tools].sort((left: McpToolDefinition, right: McpToolDefinition) =>\n left.name.localeCompare(right.name),\n );\n return `${JSON.stringify(tools, undefined, 2)}\\n`;\n }\n\n /**\n * Reads `mcp-tools.json`. Every nested value is rebuilt as a real class instance, because this is\n * the one place untyped bytes become the schemas a live protocol surface publishes.\n *\n * Malformed JSON is not caught here: it throws `SyntaxError` to the caller's own top-level\n * handler, which is where every other read-the-world failure in webpieces is reported.\n */\n // webpieces-disable no-function-outside-class -- static factory of this class\n static fromJsonText(text: string): McpToolCatalog {\n return new McpCatalogJson().parse(text);\n }\n}\n\n/**\n * The PARSE BOUNDARY: untyped bytes in, real class instances out.\n *\n * A class of its own rather than statics on {@link McpToolCatalog} so every step is an ordinary\n * instance method — and because it is the one place in this file where `unknown` is the correct type\n * rather than a missing one. Nothing else in webpieces should ever hold a half-narrowed schema.\n */\nclass McpCatalogJson {\n parse(text: string): McpToolCatalog {\n // webpieces-disable no-any-unknown -- this IS the untyped-bytes boundary; every step below narrows it\n const parsed: unknown = JSON.parse(text);\n if (!Array.isArray(parsed)) {\n throw new McpToolCatalogError(\n 'The MCP tool catalog must be a JSON array of tool definitions.',\n REGENERATE,\n );\n }\n // webpieces-disable no-any-unknown -- parsing JSON is exactly where unknown belongs\n return new McpToolCatalog(parsed.map((entry: unknown) => this.toolFrom(entry)));\n }\n\n // webpieces-disable no-any-unknown -- parsing JSON is exactly where unknown belongs\n private toolFrom(entry: unknown): McpToolDefinition {\n const record = this.record(entry, 'a tool definition');\n const hints = this.record(record['hints'], 'a tool definition hints block');\n return new McpToolDefinition(\n this.text(record['name'], 'name'),\n this.text(record['methodName'], 'methodName'),\n this.text(record['description'], 'description'),\n new WpMcpToolHints(\n hints['readOnlyHint'] === true,\n hints['destructiveHint'] === true,\n hints['idempotentHint'] === true,\n hints['openWorldHint'] === true,\n ),\n this.schemaFrom(record['inputSchema']),\n this.schemaFrom(record['outputSchema']),\n );\n }\n\n // webpieces-disable no-any-unknown -- parsing JSON is exactly where unknown belongs\n private schemaFrom(value: unknown): ApiJsonSchema {\n const record = this.record(value, 'a JSON schema');\n const schema = new ApiJsonSchema(\n record['type'] as ApiJsonSchemaType | readonly ApiJsonSchemaType[],\n );\n if (typeof record['description'] === 'string') schema.description = record['description'];\n if (typeof record['minimum'] === 'number') schema.minimum = record['minimum'];\n if (typeof record['maximum'] === 'number') schema.maximum = record['maximum'];\n if (Array.isArray(record['required'])) schema.required = record['required'] as string[];\n if (Array.isArray(record['enum'])) schema.enum = record['enum'] as string[];\n if (typeof record['x-mcp-header'] === 'string') {\n schema['x-mcp-header'] = record['x-mcp-header'];\n }\n if (record['items'] !== undefined) schema.items = this.schemaFrom(record['items']);\n const extra = record['additionalProperties'];\n if (typeof extra === 'boolean') schema.additionalProperties = extra;\n else if (extra !== undefined) schema.additionalProperties = this.schemaFrom(extra);\n const properties = record['properties'];\n if (properties !== undefined) {\n const built: Record<string, ApiJsonSchema> = {};\n for (const [key, child] of Object.entries(\n this.record(properties, 'a schema properties block'),\n )) {\n built[key] = this.schemaFrom(child);\n }\n schema.properties = built;\n }\n const oneOf = record['oneOf'];\n if (Array.isArray(oneOf)) {\n // webpieces-disable no-any-unknown -- parsing JSON is exactly where unknown belongs\n schema.oneOf = oneOf.map((branch: unknown) => this.schemaFrom(branch));\n schema.discriminator = this.discriminatorFrom(record['discriminator']);\n }\n return schema;\n }\n\n /**\n * The `discriminator` block, or undefined — a union TypeScript cannot narrow is published WITHOUT\n * one, so an absent block is a legal document and not a missing field.\n */\n // webpieces-disable no-any-unknown -- parsing JSON is exactly where unknown belongs\n private discriminatorFrom(value: unknown): ApiJsonSchemaDiscriminator | undefined {\n if (value === undefined) return undefined;\n const record = this.record(value, 'a schema discriminator block');\n const mapping: Record<string, string> = {};\n for (const [key, branch] of Object.entries(\n this.record(record['mapping'], 'a discriminator mapping block'),\n )) {\n mapping[key] = this.text(branch, `discriminator mapping '${key}'`);\n }\n return new ApiJsonSchemaDiscriminator(\n this.text(record['propertyName'], 'discriminator propertyName'),\n mapping,\n );\n }\n\n // webpieces-disable no-any-unknown -- parsing JSON is exactly where unknown belongs\n private record(value: unknown, what: string): Record<string, unknown> {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw new McpToolCatalogError(`The MCP tool catalog is missing ${what}.`, REGENERATE);\n }\n // webpieces-disable no-any-unknown -- the narrowed result of the check above\n return value as Record<string, unknown>;\n }\n\n // webpieces-disable no-any-unknown -- parsing JSON is exactly where unknown belongs\n private text(value: unknown, field: string): string {\n if (typeof value !== 'string') {\n throw new McpToolCatalogError(\n `The MCP tool catalog has no '${field}' on a tool definition.`,\n REGENERATE,\n );\n }\n return value;\n }\n}\n"]}