@webpieces/core-util 0.4.810 → 0.4.812

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.810",
3
+ "version": "0.4.812",
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
@@ -39,7 +39,9 @@ export type { WpMcpMethodDecorator } from './mcp/McpMetadata';
39
39
  export { WpMcpAuthJwt, WpMcpJwtAuthMetadata, getWpMcpAuthJwt } from './mcp/McpAuthMetadata';
40
40
  export { ApiJsonSchema, ApiJsonSchemaDiscriminator, ApiJsonSchemaValidator, DtoValidationFailure, ObjectSchemaBuilder, } from './mcp/DtoSchema';
41
41
  export type { ApiJsonSchemaType, DtoValue } from './mcp/DtoSchema';
42
- export { McpToolCatalog, McpToolCatalogError, McpToolDefinition } from './mcp/McpToolCatalog';
42
+ export { McpToolCatalogFile, McpToolCatalogError, McpToolDefinition } from './mcp/McpToolCatalogFile';
43
+ export { GeneratedApiDocsLayout, GenerateLayoutProblem, GenerateOutputLookup, GenerateOutputTarget, } from './mcp/GeneratedApiDocsLayout';
44
+ export type { LayoutDependsOn, LayoutDependsOnObject, LayoutTarget, LayoutTargets } from './mcp/GeneratedApiDocsLayout';
43
45
  export { AuthMeta } from './http/auth-mode';
44
46
  export type { AuthMode, ApiKeyCredential, ApiKeyCredentials, JwtRoles, JwtRequirement, } from './http/auth-mode';
45
47
  export { Rpc, PubSub, Queue, ENDPOINT_KINDS_BY_API_KIND, getApiKind, assertApiKind, assertPubSubConventions, getQueueName, } from './http/api-kind';
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.getWpMcpTools = exports.getInvalidEndpointsForMcp = exports.WpMcpToolMetadata = exports.WpMcpToolHints = exports.WpMcpTool = exports.InvalidEndpointForMcpMetadata = exports.InvalidEndpointForMcp = 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.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 = exports.WpMcpJwtAuthMetadata = exports.WpMcpAuthJwt = exports.mcpHintsForOperation = void 0;
14
- 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 = exports.WebpiecesDefaultErrorTranslator = exports.HttpResponseDto = exports.HttpResponseStatus = void 0;
15
- exports.ApiErrorHttpStatus = exports.ApiErrorBoundary = exports.ApiErrorPayload = exports.ApiErrorCodec = exports.ApiCodedError = exports.ApiNotImplementedError = exports.ApiUnsupportedMediaTypeError = void 0;
13
+ 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.GenerateOutputTarget = exports.GenerateOutputLookup = exports.GenerateLayoutProblem = exports.GeneratedApiDocsLayout = exports.McpToolDefinition = exports.McpToolCatalogError = exports.McpToolCatalogFile = exports.ObjectSchemaBuilder = exports.DtoValidationFailure = exports.ApiJsonSchemaValidator = exports.ApiJsonSchemaDiscriminator = exports.ApiJsonSchema = exports.getWpMcpAuthJwt = exports.WpMcpJwtAuthMetadata = exports.WpMcpAuthJwt = exports.mcpHintsForOperation = void 0;
14
+ 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 = exports.WebpiecesDefaultErrorTranslator = exports.HttpResponseDto = exports.HttpResponseStatus = exports.HttpHeader = exports.RuntimeLocality = exports.ServiceInfo = exports.ApiCallTimeoutError = void 0;
15
+ exports.ApiErrorHttpStatus = exports.ApiErrorBoundary = exports.ApiErrorPayload = exports.ApiErrorCodec = exports.ApiCodedError = exports.ApiNotImplementedError = exports.ApiUnsupportedMediaTypeError = exports.ApiPreconditionFailedError = exports.ApiUnprocessableError = exports.ApiConflictError = exports.ApiEndpointNotFoundError = 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");
@@ -155,10 +155,15 @@ Object.defineProperty(exports, "ApiJsonSchemaDiscriminator", { enumerable: true,
155
155
  Object.defineProperty(exports, "ApiJsonSchemaValidator", { enumerable: true, get: function () { return DtoSchema_1.ApiJsonSchemaValidator; } });
156
156
  Object.defineProperty(exports, "DtoValidationFailure", { enumerable: true, get: function () { return DtoSchema_1.DtoValidationFailure; } });
157
157
  Object.defineProperty(exports, "ObjectSchemaBuilder", { enumerable: true, get: function () { return DtoSchema_1.ObjectSchemaBuilder; } });
158
- var McpToolCatalog_1 = require("./mcp/McpToolCatalog");
159
- Object.defineProperty(exports, "McpToolCatalog", { enumerable: true, get: function () { return McpToolCatalog_1.McpToolCatalog; } });
160
- Object.defineProperty(exports, "McpToolCatalogError", { enumerable: true, get: function () { return McpToolCatalog_1.McpToolCatalogError; } });
161
- Object.defineProperty(exports, "McpToolDefinition", { enumerable: true, get: function () { return McpToolCatalog_1.McpToolDefinition; } });
158
+ var McpToolCatalogFile_1 = require("./mcp/McpToolCatalogFile");
159
+ Object.defineProperty(exports, "McpToolCatalogFile", { enumerable: true, get: function () { return McpToolCatalogFile_1.McpToolCatalogFile; } });
160
+ Object.defineProperty(exports, "McpToolCatalogError", { enumerable: true, get: function () { return McpToolCatalogFile_1.McpToolCatalogError; } });
161
+ Object.defineProperty(exports, "McpToolDefinition", { enumerable: true, get: function () { return McpToolCatalogFile_1.McpToolDefinition; } });
162
+ var GeneratedApiDocsLayout_1 = require("./mcp/GeneratedApiDocsLayout");
163
+ Object.defineProperty(exports, "GeneratedApiDocsLayout", { enumerable: true, get: function () { return GeneratedApiDocsLayout_1.GeneratedApiDocsLayout; } });
164
+ Object.defineProperty(exports, "GenerateLayoutProblem", { enumerable: true, get: function () { return GeneratedApiDocsLayout_1.GenerateLayoutProblem; } });
165
+ Object.defineProperty(exports, "GenerateOutputLookup", { enumerable: true, get: function () { return GeneratedApiDocsLayout_1.GenerateOutputLookup; } });
166
+ Object.defineProperty(exports, "GenerateOutputTarget", { enumerable: true, get: function () { return GeneratedApiDocsLayout_1.GenerateOutputTarget; } });
162
167
  // The TYPE layer of the auth surface — likewise split out of decorators.ts for file size only.
163
168
  var auth_mode_1 = require("./http/auth-mode");
164
169
  Object.defineProperty(exports, "AuthMeta", { enumerable: true, get: function () { return auth_mode_1.AuthMeta; } });
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 InvalidEndpointForMcp,\n InvalidEndpointForMcpMetadata,\n WpMcpTool,\n WpMcpToolHints,\n WpMcpToolMetadata,\n getInvalidEndpointsForMcp,\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"]}
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 InvalidEndpointForMcp,\n InvalidEndpointForMcpMetadata,\n WpMcpTool,\n WpMcpToolHints,\n WpMcpToolMetadata,\n getInvalidEndpointsForMcp,\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 { McpToolCatalogFile, McpToolCatalogError, McpToolDefinition } from './mcp/McpToolCatalogFile';\nexport {\n GeneratedApiDocsLayout,\n GenerateLayoutProblem,\n GenerateOutputLookup,\n GenerateOutputTarget,\n} from './mcp/GeneratedApiDocsLayout';\nexport type { LayoutDependsOn, LayoutDependsOnObject, LayoutTarget, LayoutTargets } from './mcp/GeneratedApiDocsLayout';\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"]}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * WHERE an api library's generated documents and MCP tool catalogs live, read from the library's own
3
+ * nx declarations — the ONE lookup both ends use:
4
+ *
5
+ * - the `openapi-generate` executor (`@webpieces/nx-webpieces-rules`) uses it to decide where to WRITE;
6
+ * - `McpToolCatalog.fromPackages` (`@webpieces/mcp-server`) uses it to decide where to READ when the
7
+ * package it resolved is a workspace SOURCE directory (a pnpm link onto `libraries/...`) rather than
8
+ * a built one.
9
+ *
10
+ * The answer is the `outputPath` of the target `openapi-generate` dependsOn — the api library's
11
+ * compile step, which writes the directory the package is packed from. It is never a hardcoded target
12
+ * name and never an assumed `dist/`: webpieces-ts builds into a workspace-root `dist/apps/...` while
13
+ * other repos build into a project-local `<project>/dist`, and either assumption is wrong in the other.
14
+ *
15
+ * Pure and browser-safe on purpose: it reads only the target map it is handed. The caller owns the
16
+ * filesystem and its own error type, which is why a refusal is RETURNED rather than thrown.
17
+ */
18
+ /** nx's object spelling of a `dependsOn` entry. */
19
+ export type LayoutDependsOnObject = {
20
+ readonly target?: string;
21
+ readonly projects?: string | readonly string[];
22
+ readonly dependencies?: boolean;
23
+ };
24
+ /** One `dependsOn` entry, in either of nx's two spellings. */
25
+ export type LayoutDependsOn = string | LayoutDependsOnObject;
26
+ /** One target, as project.json or nx describes it — only the two fields this lookup reads. */
27
+ export type LayoutTarget = {
28
+ readonly dependsOn?: readonly LayoutDependsOn[];
29
+ readonly options?: object;
30
+ };
31
+ /** The project's targets by name, as project.json or nx describes them. */
32
+ export type LayoutTargets = {
33
+ readonly [targetName: string]: LayoutTarget | undefined;
34
+ };
35
+ /** The target `openapi-generate` writes into, and its outputPath. Data-only. */
36
+ export declare class GenerateOutputTarget {
37
+ readonly targetName: string;
38
+ /** Workspace-relative, with nx's `{workspaceRoot}` / `{projectRoot}` / `{projectName}` resolved. */
39
+ readonly outputPath: string;
40
+ constructor(targetName: string,
41
+ /** Workspace-relative, with nx's `{workspaceRoot}` / `{projectRoot}` / `{projectName}` resolved. */
42
+ outputPath: string);
43
+ }
44
+ /** Why the lookup failed, and the one edit that fixes it. Data-only. */
45
+ export declare class GenerateLayoutProblem {
46
+ readonly problem: string;
47
+ readonly cure: string;
48
+ constructor(problem: string, cure: string);
49
+ }
50
+ /** The outcome: exactly one of the two is set. Data-only. */
51
+ export declare class GenerateOutputLookup {
52
+ readonly found: GenerateOutputTarget | undefined;
53
+ readonly problem: GenerateLayoutProblem | undefined;
54
+ constructor(found: GenerateOutputTarget | undefined, problem: GenerateLayoutProblem | undefined);
55
+ }
56
+ export declare class GeneratedApiDocsLayout {
57
+ /** Workspace-relative project root, e.g. `libraries/apis/internal/lang-apis`. */
58
+ readonly projectRoot: string;
59
+ readonly projectName: string;
60
+ readonly targets: LayoutTargets;
61
+ /** The target the nx plugin infers on a project tagged `generate:openapi`. */
62
+ static readonly OPENAPI_TARGET = "openapi-generate";
63
+ /** The target the nx plugin infers on a project tagged `generate:docs-site`. */
64
+ static readonly DOCS_TARGET = "docs-generate";
65
+ constructor(
66
+ /** Workspace-relative project root, e.g. `libraries/apis/internal/lang-apis`. */
67
+ projectRoot: string, projectName: string, targets: LayoutTargets);
68
+ /** The target `openapi-generate` dependsOn, and that target's outputPath. */
69
+ outputTarget(): GenerateOutputLookup;
70
+ /** nx's own tokens, so a path written the way nx accepts it resolves the way nx resolves it. */
71
+ interpolate(text: string): string;
72
+ private siblingName;
73
+ private refuse;
74
+ }
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+ /**
3
+ * WHERE an api library's generated documents and MCP tool catalogs live, read from the library's own
4
+ * nx declarations — the ONE lookup both ends use:
5
+ *
6
+ * - the `openapi-generate` executor (`@webpieces/nx-webpieces-rules`) uses it to decide where to WRITE;
7
+ * - `McpToolCatalog.fromPackages` (`@webpieces/mcp-server`) uses it to decide where to READ when the
8
+ * package it resolved is a workspace SOURCE directory (a pnpm link onto `libraries/...`) rather than
9
+ * a built one.
10
+ *
11
+ * The answer is the `outputPath` of the target `openapi-generate` dependsOn — the api library's
12
+ * compile step, which writes the directory the package is packed from. It is never a hardcoded target
13
+ * name and never an assumed `dist/`: webpieces-ts builds into a workspace-root `dist/apps/...` while
14
+ * other repos build into a project-local `<project>/dist`, and either assumption is wrong in the other.
15
+ *
16
+ * Pure and browser-safe on purpose: it reads only the target map it is handed. The caller owns the
17
+ * filesystem and its own error type, which is why a refusal is RETURNED rather than thrown.
18
+ */
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.GeneratedApiDocsLayout = exports.GenerateOutputLookup = exports.GenerateLayoutProblem = exports.GenerateOutputTarget = void 0;
21
+ /** The target `openapi-generate` writes into, and its outputPath. Data-only. */
22
+ class GenerateOutputTarget {
23
+ targetName;
24
+ outputPath;
25
+ constructor(targetName,
26
+ /** Workspace-relative, with nx's `{workspaceRoot}` / `{projectRoot}` / `{projectName}` resolved. */
27
+ outputPath) {
28
+ this.targetName = targetName;
29
+ this.outputPath = outputPath;
30
+ }
31
+ }
32
+ exports.GenerateOutputTarget = GenerateOutputTarget;
33
+ /** Why the lookup failed, and the one edit that fixes it. Data-only. */
34
+ class GenerateLayoutProblem {
35
+ problem;
36
+ cure;
37
+ constructor(problem, cure) {
38
+ this.problem = problem;
39
+ this.cure = cure;
40
+ }
41
+ }
42
+ exports.GenerateLayoutProblem = GenerateLayoutProblem;
43
+ /** The outcome: exactly one of the two is set. Data-only. */
44
+ class GenerateOutputLookup {
45
+ found;
46
+ problem;
47
+ constructor(found, problem) {
48
+ this.found = found;
49
+ this.problem = problem;
50
+ }
51
+ }
52
+ exports.GenerateOutputLookup = GenerateOutputLookup;
53
+ class GeneratedApiDocsLayout {
54
+ projectRoot;
55
+ projectName;
56
+ targets;
57
+ /** The target the nx plugin infers on a project tagged `generate:openapi`. */
58
+ static OPENAPI_TARGET = 'openapi-generate';
59
+ /** The target the nx plugin infers on a project tagged `generate:docs-site`. */
60
+ static DOCS_TARGET = 'docs-generate';
61
+ constructor(
62
+ /** Workspace-relative project root, e.g. `libraries/apis/internal/lang-apis`. */
63
+ projectRoot, projectName, targets) {
64
+ this.projectRoot = projectRoot;
65
+ this.projectName = projectName;
66
+ this.targets = targets;
67
+ }
68
+ /** The target `openapi-generate` dependsOn, and that target's outputPath. */
69
+ outputTarget() {
70
+ const where = `${this.projectRoot}/project.json`;
71
+ const generate = this.targets[GeneratedApiDocsLayout.OPENAPI_TARGET];
72
+ if (generate === undefined) {
73
+ return this.refuse(`${this.projectName} has no ${GeneratedApiDocsLayout.OPENAPI_TARGET} target.`, `Tag the project "generate:openapi" in ${where} and state targets.` +
74
+ `${GeneratedApiDocsLayout.OPENAPI_TARGET} (its dependsOn and options) there.`);
75
+ }
76
+ const siblings = (generate.dependsOn ?? [])
77
+ .map((entry) => this.siblingName(entry))
78
+ .filter((name) => name !== undefined);
79
+ if (siblings.length !== 1) {
80
+ return this.refuse(`${this.projectName}:${GeneratedApiDocsLayout.OPENAPI_TARGET} must dependsOn exactly ONE ` +
81
+ `target of its own project — the compile step whose outputPath it writes into — and it ` +
82
+ `names ${siblings.length === 0 ? 'none' : siblings.join(', ')}.`, `Set "dependsOn": ["compile"] on targets.${GeneratedApiDocsLayout.OPENAPI_TARGET} in ${where}, ` +
83
+ `where "compile" is the @nx/js:tsc target (and "build" is an nx:noop that dependsOn ` +
84
+ `["compile", "${GeneratedApiDocsLayout.OPENAPI_TARGET}"]).`);
85
+ }
86
+ const targetName = siblings[0];
87
+ const declared = this.targets[targetName]?.options
88
+ ?.outputPath;
89
+ if (typeof declared !== 'string' || declared.trim() === '') {
90
+ return this.refuse(`${this.projectName}:${targetName} — the target ${GeneratedApiDocsLayout.OPENAPI_TARGET} ` +
91
+ `dependsOn — declares no options.outputPath, so there is no build output to write the ` +
92
+ `documents into.`, `Declare targets.${targetName}.options.outputPath in ${where}.`);
93
+ }
94
+ return new GenerateOutputLookup(new GenerateOutputTarget(targetName, this.interpolate(declared)), undefined);
95
+ }
96
+ /** nx's own tokens, so a path written the way nx accepts it resolves the way nx resolves it. */
97
+ interpolate(text) {
98
+ return text
99
+ .replace(/\{workspaceRoot\}\/?/g, '')
100
+ .replace(/\{projectRoot\}/g, this.projectRoot)
101
+ .replace(/\{projectName\}/g, this.projectName);
102
+ }
103
+ siblingName(entry) {
104
+ if (typeof entry === 'string')
105
+ return entry.startsWith('^') ? undefined : entry;
106
+ const projects = entry.projects;
107
+ const self = projects === undefined ||
108
+ projects === 'self' ||
109
+ (Array.isArray(projects) && projects.length === 1 && projects[0] === this.projectName);
110
+ return entry.target !== undefined && entry.dependencies !== true && self ? entry.target : undefined;
111
+ }
112
+ refuse(problem, cure) {
113
+ return new GenerateOutputLookup(undefined, new GenerateLayoutProblem(problem, cure));
114
+ }
115
+ }
116
+ exports.GeneratedApiDocsLayout = GeneratedApiDocsLayout;
117
+ //# sourceMappingURL=GeneratedApiDocsLayout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GeneratedApiDocsLayout.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/mcp/GeneratedApiDocsLayout.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * WHERE an api library's generated documents and MCP tool catalogs live, read from the library's own\n * nx declarations — the ONE lookup both ends use:\n *\n * - the `openapi-generate` executor (`@webpieces/nx-webpieces-rules`) uses it to decide where to WRITE;\n * - `McpToolCatalog.fromPackages` (`@webpieces/mcp-server`) uses it to decide where to READ when the\n * package it resolved is a workspace SOURCE directory (a pnpm link onto `libraries/...`) rather than\n * a built one.\n *\n * The answer is the `outputPath` of the target `openapi-generate` dependsOn — the api library's\n * compile step, which writes the directory the package is packed from. It is never a hardcoded target\n * name and never an assumed `dist/`: webpieces-ts builds into a workspace-root `dist/apps/...` while\n * other repos build into a project-local `<project>/dist`, and either assumption is wrong in the other.\n *\n * Pure and browser-safe on purpose: it reads only the target map it is handed. The caller owns the\n * filesystem and its own error type, which is why a refusal is RETURNED rather than thrown.\n */\n\n/** nx's object spelling of a `dependsOn` entry. */\nexport type LayoutDependsOnObject = {\n readonly target?: string;\n readonly projects?: string | readonly string[];\n readonly dependencies?: boolean;\n};\n\n/** One `dependsOn` entry, in either of nx's two spellings. */\nexport type LayoutDependsOn = string | LayoutDependsOnObject;\n\n/** The one option this lookup reads off the target `openapi-generate` dependsOn. */\ntype OutputPathOptions = { readonly outputPath?: string };\n\n/** One target, as project.json or nx describes it — only the two fields this lookup reads. */\nexport type LayoutTarget = {\n readonly dependsOn?: readonly LayoutDependsOn[];\n readonly options?: object;\n};\n\n/** The project's targets by name, as project.json or nx describes them. */\nexport type LayoutTargets = { readonly [targetName: string]: LayoutTarget | undefined };\n\n/** The target `openapi-generate` writes into, and its outputPath. Data-only. */\nexport class GenerateOutputTarget {\n constructor(\n readonly targetName: string,\n /** Workspace-relative, with nx's `{workspaceRoot}` / `{projectRoot}` / `{projectName}` resolved. */\n readonly outputPath: string,\n ) {}\n}\n\n/** Why the lookup failed, and the one edit that fixes it. Data-only. */\nexport class GenerateLayoutProblem {\n constructor(\n readonly problem: string,\n readonly cure: string,\n ) {}\n}\n\n/** The outcome: exactly one of the two is set. Data-only. */\nexport class GenerateOutputLookup {\n constructor(\n readonly found: GenerateOutputTarget | undefined,\n readonly problem: GenerateLayoutProblem | undefined,\n ) {}\n}\n\nexport class GeneratedApiDocsLayout {\n /** The target the nx plugin infers on a project tagged `generate:openapi`. */\n static readonly OPENAPI_TARGET = 'openapi-generate';\n /** The target the nx plugin infers on a project tagged `generate:docs-site`. */\n static readonly DOCS_TARGET = 'docs-generate';\n\n constructor(\n /** Workspace-relative project root, e.g. `libraries/apis/internal/lang-apis`. */\n readonly projectRoot: string,\n readonly projectName: string,\n readonly targets: LayoutTargets,\n ) {}\n\n /** The target `openapi-generate` dependsOn, and that target's outputPath. */\n outputTarget(): GenerateOutputLookup {\n const where = `${this.projectRoot}/project.json`;\n const generate = this.targets[GeneratedApiDocsLayout.OPENAPI_TARGET];\n if (generate === undefined) {\n return this.refuse(\n `${this.projectName} has no ${GeneratedApiDocsLayout.OPENAPI_TARGET} target.`,\n `Tag the project \"generate:openapi\" in ${where} and state targets.` +\n `${GeneratedApiDocsLayout.OPENAPI_TARGET} (its dependsOn and options) there.`,\n );\n }\n const siblings = (generate.dependsOn ?? [])\n .map((entry: LayoutDependsOn) => this.siblingName(entry))\n .filter((name: string | undefined): name is string => name !== undefined);\n if (siblings.length !== 1) {\n return this.refuse(\n `${this.projectName}:${GeneratedApiDocsLayout.OPENAPI_TARGET} must dependsOn exactly ONE ` +\n `target of its own project — the compile step whose outputPath it writes into — and it ` +\n `names ${siblings.length === 0 ? 'none' : siblings.join(', ')}.`,\n `Set \"dependsOn\": [\"compile\"] on targets.${GeneratedApiDocsLayout.OPENAPI_TARGET} in ${where}, ` +\n `where \"compile\" is the @nx/js:tsc target (and \"build\" is an nx:noop that dependsOn ` +\n `[\"compile\", \"${GeneratedApiDocsLayout.OPENAPI_TARGET}\"]).`,\n );\n }\n const targetName = siblings[0]!;\n const declared = (this.targets[targetName]?.options as OutputPathOptions | undefined)\n ?.outputPath;\n if (typeof declared !== 'string' || declared.trim() === '') {\n return this.refuse(\n `${this.projectName}:${targetName} — the target ${GeneratedApiDocsLayout.OPENAPI_TARGET} ` +\n `dependsOn — declares no options.outputPath, so there is no build output to write the ` +\n `documents into.`,\n `Declare targets.${targetName}.options.outputPath in ${where}.`,\n );\n }\n return new GenerateOutputLookup(new GenerateOutputTarget(targetName, this.interpolate(declared)), undefined);\n }\n\n /** nx's own tokens, so a path written the way nx accepts it resolves the way nx resolves it. */\n interpolate(text: string): string {\n return text\n .replace(/\\{workspaceRoot\\}\\/?/g, '')\n .replace(/\\{projectRoot\\}/g, this.projectRoot)\n .replace(/\\{projectName\\}/g, this.projectName);\n }\n\n private siblingName(entry: LayoutDependsOn): string | undefined {\n if (typeof entry === 'string') return entry.startsWith('^') ? undefined : entry;\n const projects = entry.projects;\n const self =\n projects === undefined ||\n projects === 'self' ||\n (Array.isArray(projects) && projects.length === 1 && projects[0] === this.projectName);\n return entry.target !== undefined && entry.dependencies !== true && self ? entry.target : undefined;\n }\n\n private refuse(problem: string, cure: string): GenerateOutputLookup {\n return new GenerateOutputLookup(undefined, new GenerateLayoutProblem(problem, cure));\n }\n}\n"]}
@@ -48,7 +48,7 @@ export declare class McpToolDefinition {
48
48
  */
49
49
  hints: WpMcpToolHints, inputSchema: ApiJsonSchema, outputSchema: ApiJsonSchema);
50
50
  }
51
- /** Thrown when the catalog a server was handed is not a catalog this release can read. */
51
+ /** Thrown when a catalog is not one this release can read or write. */
52
52
  export declare class McpToolCatalogError extends Error {
53
53
  /** What to do instead, in one sentence. */
54
54
  readonly cure: string;
@@ -57,27 +57,48 @@ export declare class McpToolCatalogError extends Error {
57
57
  cure: string);
58
58
  }
59
59
  /**
60
- * Every MCP tool one build published, keyed by protocol name — the artifact `wp-openapi` writes as
61
- * `mcp-tools.json` and `WpMcpServer` is constructed with.
60
+ * ONE contract's MCP tools, keyed by protocol name — the artifact `wp-openapi` writes as
61
+ * `mcp-<ContractClass>-tools.json`, one file per contract that declares `MCP` and has at least one
62
+ * `@WpMcpTool`, beside the library's OpenAPI documents.
62
63
  *
63
- * A tool the build never saw is a tool whose schema nobody checked, so `McpToolRegistry` fails fast
64
- * at boot rather than publishing a shape derived from a second source.
64
+ * ## Why one file per CONTRACT and not one per library
65
+ *
66
+ * One api library holds many contracts (it is how a public partner API is grouped), and a server binds
67
+ * contracts, not libraries — `McpApiBinding.local(LangCourseAuthorApi, ...)`. With one file per
68
+ * contract the server can check every binding against exactly the file generated from THAT contract,
69
+ * and refuse a file it was handed for a contract it does not bind. A single per-library file could only
70
+ * say "some tool is missing" (#1021).
71
+ *
72
+ * This is the browser-safe CODEC — the bytes and the file name. Reading the files from an installed
73
+ * package is `McpToolCatalog.fromPackages` in `@webpieces/mcp-server`, because only a node process
74
+ * has a filesystem to read them from.
65
75
  */
66
- export declare class McpToolCatalog {
76
+ export declare class McpToolCatalogFile {
77
+ /** The contract CLASS name — `binding.api.name` at runtime, the class declaration at build time. */
78
+ readonly contractName: string;
67
79
  readonly tools: readonly McpToolDefinition[];
68
80
  private readonly byName;
69
- constructor(tools: readonly McpToolDefinition[]);
81
+ constructor(
82
+ /** The contract CLASS name — `binding.api.name` at runtime, the class declaration at build time. */
83
+ contractName: string, tools: readonly McpToolDefinition[]);
84
+ /** `mcp-<ContractClass>-tools.json`. */
85
+ get fileName(): string;
70
86
  find(name: string): McpToolDefinition | undefined;
71
87
  /** The names this catalog carries, sorted, so a failure can print what WAS published. */
72
88
  names(): readonly string[];
73
89
  /** The bytes `wp-openapi` writes. Sorted by name so the artifact is diffable. */
74
90
  toJsonText(): string;
91
+ /** The file name the catalog of `contractName` is written to and read from. */
92
+ static fileNameFor(contractName: string): string;
93
+ /** The contract a file name is the catalog of, or `undefined` when it is not one of these files. */
94
+ static contractNameOf(fileName: string): string | undefined;
75
95
  /**
76
- * Reads `mcp-tools.json`. Every nested value is rebuilt as a real class instance, because this is
77
- * the one place untyped bytes become the schemas a live protocol surface publishes.
96
+ * Reads one `mcp-<ContractClass>-tools.json`. The contract is the one the FILE NAME names. Every
97
+ * nested value is rebuilt as a real class instance, because this is the one place untyped bytes
98
+ * become the schemas a live protocol surface publishes.
78
99
  *
79
100
  * Malformed JSON is not caught here: it throws `SyntaxError` to the caller's own top-level
80
101
  * handler, which is where every other read-the-world failure in webpieces is reported.
81
102
  */
82
- static fromJsonText(text: string): McpToolCatalog;
103
+ static fromJsonText(fileName: string, text: string): McpToolCatalogFile;
83
104
  }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.McpToolCatalog = exports.McpToolCatalogError = exports.McpToolDefinition = void 0;
3
+ exports.McpToolCatalogFile = exports.McpToolCatalogError = exports.McpToolDefinition = void 0;
4
4
  const DtoSchema_1 = require("./DtoSchema");
5
5
  const McpMetadata_1 = require("./McpMetadata");
6
6
  /**
@@ -47,7 +47,7 @@ class McpToolDefinition {
47
47
  }
48
48
  }
49
49
  exports.McpToolDefinition = McpToolDefinition;
50
- /** Thrown when the catalog a server was handed is not a catalog this release can read. */
50
+ /** Thrown when a catalog is not one this release can read or write. */
51
51
  class McpToolCatalogError extends Error {
52
52
  cure;
53
53
  constructor(message,
@@ -61,29 +61,55 @@ class McpToolCatalogError extends Error {
61
61
  }
62
62
  exports.McpToolCatalogError = McpToolCatalogError;
63
63
  /** The one cure every catalog failure prescribes: rebuild the artifact from the contracts. */
64
- const REGENERATE = 'Regenerate it with `wp-openapi --manifest <manifest> --out <dir>`.';
64
+ const REGENERATE = 'Rebuild the api library that declares the contract (its `openapi-generate` target runs ' +
65
+ '`wp-openapi`, which writes one `mcp-<ContractClass>-tools.json` per MCP contract).';
66
+ const FILE_PREFIX = 'mcp-';
67
+ const FILE_SUFFIX = '-tools.json';
68
+ /** A class name, which is what the file name carries. Anything else is not one of these files. */
69
+ const CONTRACT_NAME = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
65
70
  /**
66
- * Every MCP tool one build published, keyed by protocol name — the artifact `wp-openapi` writes as
67
- * `mcp-tools.json` and `WpMcpServer` is constructed with.
71
+ * ONE contract's MCP tools, keyed by protocol name — the artifact `wp-openapi` writes as
72
+ * `mcp-<ContractClass>-tools.json`, one file per contract that declares `MCP` and has at least one
73
+ * `@WpMcpTool`, beside the library's OpenAPI documents.
68
74
  *
69
- * A tool the build never saw is a tool whose schema nobody checked, so `McpToolRegistry` fails fast
70
- * at boot rather than publishing a shape derived from a second source.
75
+ * ## Why one file per CONTRACT and not one per library
76
+ *
77
+ * One api library holds many contracts (it is how a public partner API is grouped), and a server binds
78
+ * contracts, not libraries — `McpApiBinding.local(LangCourseAuthorApi, ...)`. With one file per
79
+ * contract the server can check every binding against exactly the file generated from THAT contract,
80
+ * and refuse a file it was handed for a contract it does not bind. A single per-library file could only
81
+ * say "some tool is missing" (#1021).
82
+ *
83
+ * This is the browser-safe CODEC — the bytes and the file name. Reading the files from an installed
84
+ * package is `McpToolCatalog.fromPackages` in `@webpieces/mcp-server`, because only a node process
85
+ * has a filesystem to read them from.
71
86
  */
72
- class McpToolCatalog {
87
+ class McpToolCatalogFile {
88
+ contractName;
73
89
  tools;
74
90
  byName;
75
- constructor(tools) {
91
+ constructor(
92
+ /** The contract CLASS name — `binding.api.name` at runtime, the class declaration at build time. */
93
+ contractName, tools) {
94
+ this.contractName = contractName;
76
95
  this.tools = tools;
96
+ if (!CONTRACT_NAME.test(contractName)) {
97
+ throw new McpToolCatalogError(`'${contractName}' is not a contract class name, so it cannot name an MCP tool catalog.`, REGENERATE);
98
+ }
77
99
  const byName = new Map();
78
100
  for (const tool of tools) {
79
101
  if (byName.has(tool.name)) {
80
- throw new McpToolCatalogError(`Duplicate MCP tool name '${tool.name}' in the generated catalog.`, 'Tool names are the protocol identity and must be globally unique — rename one ' +
102
+ throw new McpToolCatalogError(`Duplicate MCP tool name '${tool.name}' in the generated catalog of ${contractName}.`, 'Tool names are the protocol identity and must be globally unique — rename one ' +
81
103
  "of the two @WpMcpTool('...') declarations.");
82
104
  }
83
105
  byName.set(tool.name, tool);
84
106
  }
85
107
  this.byName = byName;
86
108
  }
109
+ /** `mcp-<ContractClass>-tools.json`. */
110
+ get fileName() {
111
+ return McpToolCatalogFile.fileNameFor(this.contractName);
112
+ }
87
113
  find(name) {
88
114
  return this.byName.get(name);
89
115
  }
@@ -96,23 +122,42 @@ class McpToolCatalog {
96
122
  const tools = [...this.tools].sort((left, right) => left.name.localeCompare(right.name));
97
123
  return `${JSON.stringify(tools, undefined, 2)}\n`;
98
124
  }
125
+ /** The file name the catalog of `contractName` is written to and read from. */
126
+ // webpieces-disable no-function-outside-class -- static helper of this class
127
+ static fileNameFor(contractName) {
128
+ return `${FILE_PREFIX}${contractName}${FILE_SUFFIX}`;
129
+ }
130
+ /** The contract a file name is the catalog of, or `undefined` when it is not one of these files. */
131
+ // webpieces-disable no-function-outside-class -- static helper of this class
132
+ static contractNameOf(fileName) {
133
+ if (!fileName.startsWith(FILE_PREFIX) || !fileName.endsWith(FILE_SUFFIX))
134
+ return undefined;
135
+ const name = fileName.slice(FILE_PREFIX.length, fileName.length - FILE_SUFFIX.length);
136
+ return CONTRACT_NAME.test(name) ? name : undefined;
137
+ }
99
138
  /**
100
- * Reads `mcp-tools.json`. Every nested value is rebuilt as a real class instance, because this is
101
- * the one place untyped bytes become the schemas a live protocol surface publishes.
139
+ * Reads one `mcp-<ContractClass>-tools.json`. The contract is the one the FILE NAME names. Every
140
+ * nested value is rebuilt as a real class instance, because this is the one place untyped bytes
141
+ * become the schemas a live protocol surface publishes.
102
142
  *
103
143
  * Malformed JSON is not caught here: it throws `SyntaxError` to the caller's own top-level
104
144
  * handler, which is where every other read-the-world failure in webpieces is reported.
105
145
  */
106
146
  // webpieces-disable no-function-outside-class -- static factory of this class
107
- static fromJsonText(text) {
108
- return new McpCatalogJson().parse(text);
147
+ static fromJsonText(fileName, text) {
148
+ const contractName = McpToolCatalogFile.contractNameOf(fileName);
149
+ if (contractName === undefined) {
150
+ throw new McpToolCatalogError(`'${fileName}' is not an MCP tool catalog file name; they are named ` +
151
+ `${FILE_PREFIX}<ContractClass>${FILE_SUFFIX}.`, REGENERATE);
152
+ }
153
+ return new McpToolCatalogFile(contractName, new McpCatalogJson().parse(text));
109
154
  }
110
155
  }
111
- exports.McpToolCatalog = McpToolCatalog;
156
+ exports.McpToolCatalogFile = McpToolCatalogFile;
112
157
  /**
113
158
  * The PARSE BOUNDARY: untyped bytes in, real class instances out.
114
159
  *
115
- * A class of its own rather than statics on {@link McpToolCatalog} so every step is an ordinary
160
+ * A class of its own rather than statics on {@link McpToolCatalogFile} so every step is an ordinary
116
161
  * instance method — and because it is the one place in this file where `unknown` is the correct type
117
162
  * rather than a missing one. Nothing else in webpieces should ever hold a half-narrowed schema.
118
163
  */
@@ -124,7 +169,7 @@ class McpCatalogJson {
124
169
  throw new McpToolCatalogError('The MCP tool catalog must be a JSON array of tool definitions.', REGENERATE);
125
170
  }
126
171
  // webpieces-disable no-any-unknown -- parsing JSON is exactly where unknown belongs
127
- return new McpToolCatalog(parsed.map((entry) => this.toolFrom(entry)));
172
+ return parsed.map((entry) => this.toolFrom(entry));
128
173
  }
129
174
  // webpieces-disable no-any-unknown -- parsing JSON is exactly where unknown belongs
130
175
  toolFrom(entry) {
@@ -203,4 +248,4 @@ class McpCatalogJson {
203
248
  return value;
204
249
  }
205
250
  }
206
- //# sourceMappingURL=McpToolCatalog.js.map
251
+ //# sourceMappingURL=McpToolCatalogFile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"McpToolCatalogFile.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/mcp/McpToolCatalogFile.ts"],"names":[],"mappings":"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","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 a catalog is not one this release can read or write. */\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 =\n 'Rebuild the api library that declares the contract (its `openapi-generate` target runs ' +\n '`wp-openapi`, which writes one `mcp-<ContractClass>-tools.json` per MCP contract).';\n\nconst FILE_PREFIX = 'mcp-';\nconst FILE_SUFFIX = '-tools.json';\n\n/** A class name, which is what the file name carries. Anything else is not one of these files. */\nconst CONTRACT_NAME = /^[A-Za-z_$][A-Za-z0-9_$]*$/;\n\n/**\n * ONE contract's MCP tools, keyed by protocol name — the artifact `wp-openapi` writes as\n * `mcp-<ContractClass>-tools.json`, one file per contract that declares `MCP` and has at least one\n * `@WpMcpTool`, beside the library's OpenAPI documents.\n *\n * ## Why one file per CONTRACT and not one per library\n *\n * One api library holds many contracts (it is how a public partner API is grouped), and a server binds\n * contracts, not libraries — `McpApiBinding.local(LangCourseAuthorApi, ...)`. With one file per\n * contract the server can check every binding against exactly the file generated from THAT contract,\n * and refuse a file it was handed for a contract it does not bind. A single per-library file could only\n * say \"some tool is missing\" (#1021).\n *\n * This is the browser-safe CODEC — the bytes and the file name. Reading the files from an installed\n * package is `McpToolCatalog.fromPackages` in `@webpieces/mcp-server`, because only a node process\n * has a filesystem to read them from.\n */\nexport class McpToolCatalogFile {\n private readonly byName: ReadonlyMap<string, McpToolDefinition>;\n\n constructor(\n /** The contract CLASS name — `binding.api.name` at runtime, the class declaration at build time. */\n readonly contractName: string,\n readonly tools: readonly McpToolDefinition[],\n ) {\n if (!CONTRACT_NAME.test(contractName)) {\n throw new McpToolCatalogError(\n `'${contractName}' is not a contract class name, so it cannot name an MCP tool catalog.`,\n REGENERATE,\n );\n }\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 of ${contractName}.`,\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 /** `mcp-<ContractClass>-tools.json`. */\n get fileName(): string {\n return McpToolCatalogFile.fileNameFor(this.contractName);\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 /** The file name the catalog of `contractName` is written to and read from. */\n // webpieces-disable no-function-outside-class -- static helper of this class\n static fileNameFor(contractName: string): string {\n return `${FILE_PREFIX}${contractName}${FILE_SUFFIX}`;\n }\n\n /** The contract a file name is the catalog of, or `undefined` when it is not one of these files. */\n // webpieces-disable no-function-outside-class -- static helper of this class\n static contractNameOf(fileName: string): string | undefined {\n if (!fileName.startsWith(FILE_PREFIX) || !fileName.endsWith(FILE_SUFFIX)) return undefined;\n const name = fileName.slice(FILE_PREFIX.length, fileName.length - FILE_SUFFIX.length);\n return CONTRACT_NAME.test(name) ? name : undefined;\n }\n\n /**\n * Reads one `mcp-<ContractClass>-tools.json`. The contract is the one the FILE NAME names. Every\n * nested value is rebuilt as a real class instance, because this is the one place untyped bytes\n * 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(fileName: string, text: string): McpToolCatalogFile {\n const contractName = McpToolCatalogFile.contractNameOf(fileName);\n if (contractName === undefined) {\n throw new McpToolCatalogError(\n `'${fileName}' is not an MCP tool catalog file name; they are named ` +\n `${FILE_PREFIX}<ContractClass>${FILE_SUFFIX}.`,\n REGENERATE,\n );\n }\n return new McpToolCatalogFile(contractName, 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 McpToolCatalogFile} 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): readonly McpToolDefinition[] {\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 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"]}
@@ -1 +0,0 @@
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, 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"]}