@webpieces/core-util 0.4.772 → 0.4.774
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -0
- package/package.json +1 -1
- package/src/errors/ApiError.d.ts +14 -2
- package/src/errors/ApiError.js +14 -2
- package/src/errors/ApiError.js.map +1 -1
- package/src/errors/ApiErrorBoundary.d.ts +24 -0
- package/src/errors/ApiErrorBoundary.js +57 -0
- package/src/errors/ApiErrorBoundary.js.map +1 -0
- package/src/errors/index.d.ts +1 -0
- package/src/errors/index.js +3 -1
- package/src/errors/index.js.map +1 -1
- package/src/http/RouteMetadata.d.ts +6 -1
- package/src/http/RouteMetadata.js +6 -1
- package/src/http/RouteMetadata.js.map +1 -1
- package/src/http/RouteMetadataFactory.d.ts +2 -0
- package/src/http/RouteMetadataFactory.js +27 -8
- package/src/http/RouteMetadataFactory.js.map +1 -1
- package/src/http/StreamingContract.d.ts +82 -0
- package/src/http/StreamingContract.js +157 -0
- package/src/http/StreamingContract.js.map +1 -0
- package/src/http/decorators.d.ts +4 -0
- package/src/http/decorators.js +4 -0
- package/src/http/decorators.js.map +1 -1
- package/src/index.d.ts +6 -3
- package/src/index.js +19 -3
- package/src/index.js.map +1 -1
- package/src/mcp/DtoSchema.d.ts +54 -9
- package/src/mcp/DtoSchema.js +150 -34
- package/src/mcp/DtoSchema.js.map +1 -1
- package/src/mcp/McpAuthMetadata.d.ts +9 -0
- package/src/mcp/McpAuthMetadata.js +31 -0
- package/src/mcp/McpAuthMetadata.js.map +1 -0
- package/src/mcp/McpCompileAssertions.js +10 -0
- package/src/mcp/McpCompileAssertions.js.map +1 -1
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 getEndpointOptions,\n getEndpointKind,\n getEndpointKinds,\n getMaskSpec,\n isFormPost,\n isRawBody,\n isApiPath,\n getAuthMeta,\n getAuthMode,\n assertEveryEndpointHasAuthMode,\n assertEveryExternalEndpointDeclaresCaller,\n assertEveryWebhookEndpointRetainsRawBody,\n validateNoConflictingDecorators,\n METADATA_KEYS,\n} from './http/decorators';\nexport {\n PathParam,\n QueryParam,\n getHttpParameterDeclarations,\n} from './http/http-parameter-decorators';\nexport {\n WpInternal,\n WpIpcEndpoint,\n isInternalApi,\n getIpcApiId,\n getIpcEndpoints,\n getIpcEndpointKind,\n getIpcMaskSpec,\n assertInternalApi,\n assertNotInternalApi,\n IPC_METADATA_KEYS,\n} from './ipc/IpcDecorators';\nexport type { IpcApiType, IpcEndpointKind, IpcEndpointOptions } from './ipc/IpcDecorators';\n// The runtime representation of ONE route (split out of decorators.ts for file size only).\nexport { RouteMetadata } from './http/RouteMetadata';\nexport { RouteMetadataFactory } from './http/RouteMetadataFactory';\nexport {\n BoundHttpRequest,\n HttpContractMapper,\n HttpParameterBinding,\n HttpParameterDeclaration,\n} from './http/HttpContract';\nexport type {\n ContractHttpMethod,\n EndpointResponseType,\n HttpParameterSource,\n HttpParameterValueType,\n} from './http/HttpContract';\nexport type { EndpointKind, EndpointOptions, ExternalEndpointOptions } from './http/decorators';\nexport { WpMcpTool, WpMcpToolHints, WpMcpToolMetadata, getWpMcpTools } from './mcp/McpMetadata';\nexport type { WpMcpMethodDecorator, WpMcpToolOptions } from './mcp/McpMetadata';\nexport {\n WpDto,\n WpDtoField,\n WpDtoFieldOptions,\n WpDtoFieldMetadata,\n WpResponseDto,\n ApiJsonSchema,\n DtoValidationFailure,\n DtoSchemaBuilder,\n} from './mcp/DtoSchema';\nexport type { DtoClass, DtoArrayItem, DtoValue } from './mcp/DtoSchema';\n// The TYPE layer of the auth surface — likewise split out of decorators.ts for file size only.\nexport { AuthMeta } from './http/auth-mode';\nexport type {\n AuthMode,\n ApiKeyCredential,\n ApiKeyCredentials,\n JwtRoles,\n JwtRequirement,\n} from './http/auth-mode';\n// API kind (RPC vs PubSub/Cloud Tasks) + queue naming. Split out of decorators.ts for file size only;\n// one-way dependency api-kind -> decorators, and the barrel keeps the surface identical.\nexport {\n Rpc,\n PubSub,\n Queue,\n ENDPOINT_KINDS_BY_API_KIND,\n getApiKind,\n assertApiKind,\n assertPubSubConventions,\n getQueueName,\n} from './http/api-kind';\nexport type { ApiKind } from './http/api-kind';\n// WHO calls an `external` endpoint — the caller declaration @Endpoint(..., 'external', {calledBy})\n// requires, and the reader for it.\nexport {\n EXTERNAL_SYSTEM_KINDS,\n DEFAULT_CALLER_KIND,\n ExternalCaller,\n isExternalSystemKind,\n getEndpointCaller,\n} from './http/external-caller';\nexport type { ExternalSystemKind } from './http/external-caller';\n// Client-side shared-secret store (the value THIS service sends per @WpAuthSharedSecret key).\nexport { Secrets, SECRETS } from './http/Secrets';\n\n// Type validators\nexport { ValidateImplementation } from './http/validators';\n\n// Authentication subtype constants.\nexport {\n ENTITY_NOT_FOUND,\n WRONG_LOGIN_TYPE,\n WRONG_LOGIN,\n NOT_APPROVED,\n EMAIL_NOT_CONFIRMED,\n WRONG_DOMAIN,\n WRONG_COMPANY,\n NO_REG_CODE,\n} from './errors';\n\nexport { NetworkRejectClassifier } from './http/networkReject';\n\n// Date/Time DTOs and Utilities (inspired by Java Time / JSR-310)\nexport {\n InstantDto,\n DateDto,\n TimeDto,\n DateTimeDto,\n InstantUtil,\n DateUtil,\n TimeUtil,\n DateTimeUtil,\n} from './http/datetime';\n\n// Context keys + registry (the global magic-context header system)\nexport { HeaderRegistry } from './http/HeaderRegistry';\nexport { ClientRegistry } from './http/ClientRegistry';\nexport { CallRegistry } from './http/CallRegistry';\nexport { CallDeadline } from './http/CallDeadline';\nexport { CallContext } from './http/CallStrategy';\nexport type { Attempt, CallStrategy } from './http/CallStrategy';\nexport { ApiCallTimeoutError } from './http/ApiCallTimeoutError';\nexport type { ServiceUrlDeriver } from './http/ClientRegistry';\n\n// \"What service am I\" — set once at startup, read by the logging backends and by\n// RequestContextHeaders (to stamp requestIdSource on ids this service mints).\nexport { ServiceInfo } from './http/ServiceInfo';\n// \"Where am I running\" — declared once at startup (setupRuntime, from RuntimeSetupOptions.locality).\n// The ONE input to @WpAuthLocalOnly enforcement. Undeclared reads as DEPLOYED (fail safe).\nexport { RuntimeLocality } from './http/RuntimeLocality';\nexport type { Locality } from './http/RuntimeLocality';\n// The ENTIRE HTTP response as pure data — the ONE form both transports (express, fetch) are\n// normalised into, so an ErrorTranslators implementation is written once and serves both.\nexport { HttpHeader, HttpResponseStatus, HttpResponseDto } from './http/HttpResponseDto';\n// Pluggable, bidirectional error translation (app exception <-> the WHOLE response). Set on\n// ClientRegistry at startup; consulted before the built-in webpieces mapping on BOTH sides.\nexport type { ErrorTranslators } from './http/ErrorTranslators';\n// Pluggable per-client failure classification (is a thrown API-call error a real failure or an\n// expected non-failure?). Registered on ClientRegistry at startup; consulted by LogApiCall.\nexport type { FailureClassifier } from './http/FailureClassifier';\nexport { KeyedFailureClassifier } from './http/FailureClassifier';\nexport {\n WebpiecesDefaultFailureClassifier,\n WEBPIECES_DEFAULT_FAILURE_CLASSIFIER,\n} from './http/WebpiecesDefaultFailureClassifier';\nexport { templateDeriver } from './http/templateDeriver';\nexport { WebpiecesCoreHeaders } from './http/WebpiecesCoreHeaders';\nexport { ContextReader } from './http/ContextReader';\n\n// The OUTBOUND half of the trust model: whether a TRUSTED context key may ride to the endpoint being\n// called. Built ONLY from the destination endpoint's AuthMode — see the class doc.\nexport { DestinationTrust } from './http/DestinationTrust';\n\n// BROWSER-ONLY outbound-header propagation (app-held store + registry -> outbound HTTP headers).\n// Only @webpieces/http-client-browser may name it; the server reads RequestContext directly via\n// RequestContextHeaders in the Node-only @webpieces/core-context.\nexport { ContextMgr } from './http/ContextMgr';\n\n// API-call logging helper (uses LogManager above). NOT a singleton: construct one per environment\n// with that environment's ApiCallContext — `new LogApiCallImpl(new RequestContextApiCallContext())`\n// on node, `new LogApiCallImpl(new BrowserApiCallContext())` in a browser.\nexport { LogApiCallImpl } from './http/LogApiCall';\n\n// Opt-in field masking for the LogApiCall log path — declare per-api sensitive fields so secrets\n// (OAuth refresh tokens, id-token JWTs) are masked in the logs while the real value stays on the wire.\nexport { MaskSpec } from './http/LogFieldMask';\nexport type { MaskMode } from './http/LogFieldMask';\n\n// The structured `api` tag + the context-writer seam LogApiCall stamps through. The Node\n// RequestContext-backed impl lives in @webpieces/core-context, the browser one in\n// @webpieces/http-client-browser; each is CONSTRUCTED by its package, never installed globally.\nexport { ApiCallInfo } from './http/ApiCallInfo';\nexport type { ApiType, ApiResult } from './http/ApiCallInfo';\n// Console-render bridge: turns LogApiCall's [LogApiCall] bracket into [API.{side}.{phase}] locally.\nexport {\n ApiCallLogName,\n ApiCallLogNameImpl,\n LOG_API_CALL_LOGGER_NAME,\n} from './http/ApiCallLogName';\nexport { ApiMethodInfo } from './http/ApiMethodInfo';\nexport type { ApiSide } from './http/ApiMethodInfo';\nexport type { ApiCallContext } from './http/ApiCallContext';\n\n// Test-case recording contract (impl lives in http-server; hooks in http-client)\nexport { TestCaseRecorder, RecorderKeys } from './http/recorder/TestCaseRecorder';\nexport {\n RecordedEndpoint,\n RecordedError,\n RecordedTestCase,\n} from './http/recorder/RecordedEndpoint';\nexport { DoNotRecord, getDoNotRecordFields } from './http/recorder/DoNotRecord';\nexport { RecordSerializer, SerializedMap, SerializedError } from './http/recorder/RecordSerializer';\n\n// ---------------------------------------------------------------------------------------------\n// Filter-chain primitives, shared by BOTH chains: the inbound server chain\n// (`Filter<MethodMeta, WpResponse<unknown>>`, @webpieces/http-routing) and the outbound client\n// chain (`Filter<ClientRequest, Response>`, @webpieces/http-client-core). Declared once, here, in\n// the package both depend on — see the class doc for why a second pair would be a shim.\nexport { Filter } from './filters/Filter';\nexport type { Service } from './filters/Filter';\nexport { FilterChain } from './filters/FilterChain';\n\nexport {\n ApiError,\n ApiNotFoundError,\n ApiDependencyError,\n ApiUnavailableError,\n ApiDependencyTimeoutError,\n ApiImplementationError,\n ApiRateLimitedError,\n ApiForbiddenError,\n ApiRequestTimeoutError,\n ApiEndUserError,\n ApiBadRequestError,\n ApiUnauthorizedError,\n ApiDependencyBackoffError,\n ApiConnectionError,\n ApiEndpointNotFoundError,\n ApiErrorCodec,\n ApiErrorPayload,\n} from './errors';\nexport type { ApiErrorKind } from './errors';\nexport { ApiErrorHttpStatus } from './http/ApiErrorHttpStatus';\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/core/core-util/src/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @webpieces/core-util\n *\n * Utility functions for WebPieces applications.\n * This package works in both browser and Node.js environments.\n *\n * @packageDocumentation\n */\n\nexport { toError } from './lib/errorUtils';\nexport { ContextKey } from './ContextKey';\nexport type {\n AnyContextKey,\n AnyTrustedContextKey,\n AnyUntrustedContextKey,\n Trust,\n} from './ContextKey';\nexport { ContextTuple } from './ContextTuple';\n\n// @DocumentDesign — DI-design-root marker. Applies to ANY project kind (server\n// controllers AND library impl classes), so it lives here (browser + Node) rather\n// than in a server-only routing package.\nexport { DocumentDesign, isDocumentDesign, DESIGN_METADATA_KEYS } from './DocumentDesign';\n\n// Logging (merged from former @webpieces/wp-logging).\n// Pluggable logging interface + a browser-safe console default; apps plug in\n// bunyan/winston/pino/etc. via LogManager.setFactory(...). Browser + Node.\nexport type { Logger, LogLevel } from './logging/Logger';\nexport type { LoggerFactory } from './logging/LoggerFactory';\nexport { ConsoleLogger } from './logging/ConsoleLogger';\nexport { ConsoleLoggerFactory } from './logging/ConsoleLoggerFactory';\nexport { LogManager } from './logging/LogManager';\nexport {\n LogChunker,\n LogChunkerImpl,\n LogChunkInfo,\n MAX_GCP_LOG_BYTES,\n GCP_LOG_BUDGET_BYTES,\n} from './logging/LogChunker';\n\n// HTTP API contract (merged from former @webpieces/http-api).\n// Shared HTTP API definition consumed by both client and server: REST\n// decorators, the API error taxonomy, datetime DTOs, platform-header\n// registry/readers, ValidateImplementation, and the test-case recorder\n// contract. Pure definitions — express-free, browser + Node safe.\n\n// API definition decorators\nexport {\n ApiPath,\n Endpoint,\n // Auth mode decorators (clean service-to-service + user JWT model)\n WpAuthPublic,\n WpAuthJwt,\n rolesRequired,\n MISSING_AUTH_DECORATOR_FIX,\n WpAuthOidc,\n WpAuthSharedSecret,\n WpAuthWebhook,\n WpAuthApiKey,\n WpAuthLocalOnly,\n MaskLog,\n getApiPath,\n getEndpoints,\n getEndpointOptions,\n getEndpointKind,\n getEndpointKinds,\n getMaskSpec,\n isFormPost,\n isRawBody,\n isApiPath,\n getAuthMeta,\n getAuthMode,\n assertEveryEndpointHasAuthMode,\n assertEveryExternalEndpointDeclaresCaller,\n assertEveryWebhookEndpointRetainsRawBody,\n validateNoConflictingDecorators,\n METADATA_KEYS,\n} from './http/decorators';\nexport {\n PathParam,\n QueryParam,\n getHttpParameterDeclarations,\n} from './http/http-parameter-decorators';\nexport {\n WpInternal,\n WpIpcEndpoint,\n isInternalApi,\n getIpcApiId,\n getIpcEndpoints,\n getIpcEndpointKind,\n getIpcMaskSpec,\n assertInternalApi,\n assertNotInternalApi,\n IPC_METADATA_KEYS,\n} from './ipc/IpcDecorators';\nexport type { IpcApiType, IpcEndpointKind, IpcEndpointOptions } from './ipc/IpcDecorators';\n// The runtime representation of ONE route (split out of decorators.ts for file size only).\nexport { RouteMetadata } from './http/RouteMetadata';\nexport { RouteMetadataFactory } from './http/RouteMetadataFactory';\nexport {\n BoundHttpRequest,\n HttpContractMapper,\n HttpParameterBinding,\n HttpParameterDeclaration,\n} from './http/HttpContract';\nexport {\n StreamCorrelation,\n StreamEnvelope,\n StreamingEndpointMetadata,\n StreamEventValidator,\n StreamTransportError,\n StreamWriter,\n WpStream,\n getStreamingEndpoint,\n} from './http/StreamingContract';\nexport type {\n RequestStream,\n ResponseStream,\n StreamEnvelopeKind,\n StreamFailureOptions,\n} from './http/StreamingContract';\nexport type {\n ContractHttpMethod,\n EndpointResponseType,\n HttpParameterSource,\n HttpParameterValueType,\n} from './http/HttpContract';\nexport type { EndpointKind, EndpointOptions, ExternalEndpointOptions } from './http/decorators';\nexport { WpMcpTool, WpMcpToolHints, WpMcpToolMetadata, getWpMcpTools } from './mcp/McpMetadata';\nexport type { WpMcpMethodDecorator, WpMcpToolOptions } from './mcp/McpMetadata';\nexport { WpMcpAuthJwt, WpMcpJwtAuthMetadata, getWpMcpAuthJwt } from './mcp/McpAuthMetadata';\nexport {\n WpDto,\n WpDtoField,\n WpDtoFieldOptions,\n WpMcpHeader,\n WpDtoMapFieldOptions,\n WpDtoFieldMetadata,\n WpResponseDto,\n ApiJsonSchema,\n DtoValidationFailure,\n DtoSchemaBuilder,\n} from './mcp/DtoSchema';\nexport type { DtoClass, DtoElementType, DtoValue } from './mcp/DtoSchema';\n// The TYPE layer of the auth surface — likewise split out of decorators.ts for file size only.\nexport { AuthMeta } from './http/auth-mode';\nexport type {\n AuthMode,\n ApiKeyCredential,\n ApiKeyCredentials,\n JwtRoles,\n JwtRequirement,\n} from './http/auth-mode';\n// API kind (RPC vs PubSub/Cloud Tasks) + queue naming. Split out of decorators.ts for file size only;\n// one-way dependency api-kind -> decorators, and the barrel keeps the surface identical.\nexport {\n Rpc,\n PubSub,\n Queue,\n ENDPOINT_KINDS_BY_API_KIND,\n getApiKind,\n assertApiKind,\n assertPubSubConventions,\n getQueueName,\n} from './http/api-kind';\nexport type { ApiKind } from './http/api-kind';\n// WHO calls an `external` endpoint — the caller declaration @Endpoint(..., 'external', {calledBy})\n// requires, and the reader for it.\nexport {\n EXTERNAL_SYSTEM_KINDS,\n DEFAULT_CALLER_KIND,\n ExternalCaller,\n isExternalSystemKind,\n getEndpointCaller,\n} from './http/external-caller';\nexport type { ExternalSystemKind } from './http/external-caller';\n// Client-side shared-secret store (the value THIS service sends per @WpAuthSharedSecret key).\nexport { Secrets, SECRETS } from './http/Secrets';\n\n// Type validators\nexport { ValidateImplementation } from './http/validators';\n\n// Authentication subtype constants.\nexport {\n ENTITY_NOT_FOUND,\n WRONG_LOGIN_TYPE,\n WRONG_LOGIN,\n NOT_APPROVED,\n EMAIL_NOT_CONFIRMED,\n WRONG_DOMAIN,\n WRONG_COMPANY,\n NO_REG_CODE,\n} from './errors';\n\nexport { NetworkRejectClassifier } from './http/networkReject';\n\n// Date/Time DTOs and Utilities (inspired by Java Time / JSR-310)\nexport {\n InstantDto,\n DateDto,\n TimeDto,\n DateTimeDto,\n InstantUtil,\n DateUtil,\n TimeUtil,\n DateTimeUtil,\n} from './http/datetime';\n\n// Context keys + registry (the global magic-context header system)\nexport { HeaderRegistry } from './http/HeaderRegistry';\nexport { ClientRegistry } from './http/ClientRegistry';\nexport { CallRegistry } from './http/CallRegistry';\nexport { CallDeadline } from './http/CallDeadline';\nexport { CallContext } from './http/CallStrategy';\nexport type { Attempt, CallStrategy } from './http/CallStrategy';\nexport { ApiCallTimeoutError } from './http/ApiCallTimeoutError';\nexport type { ServiceUrlDeriver } from './http/ClientRegistry';\n\n// \"What service am I\" — set once at startup, read by the logging backends and by\n// RequestContextHeaders (to stamp requestIdSource on ids this service mints).\nexport { ServiceInfo } from './http/ServiceInfo';\n// \"Where am I running\" — declared once at startup (setupRuntime, from RuntimeSetupOptions.locality).\n// The ONE input to @WpAuthLocalOnly enforcement. Undeclared reads as DEPLOYED (fail safe).\nexport { RuntimeLocality } from './http/RuntimeLocality';\nexport type { Locality } from './http/RuntimeLocality';\n// The ENTIRE HTTP response as pure data — the ONE form both transports (express, fetch) are\n// normalised into, so an ErrorTranslators implementation is written once and serves both.\nexport { HttpHeader, HttpResponseStatus, HttpResponseDto } from './http/HttpResponseDto';\n// Pluggable, bidirectional error translation (app exception <-> the WHOLE response). Set on\n// ClientRegistry at startup; consulted before the built-in webpieces mapping on BOTH sides.\nexport type { ErrorTranslators } from './http/ErrorTranslators';\n// Pluggable per-client failure classification (is a thrown API-call error a real failure or an\n// expected non-failure?). Registered on ClientRegistry at startup; consulted by LogApiCall.\nexport type { FailureClassifier } from './http/FailureClassifier';\nexport { KeyedFailureClassifier } from './http/FailureClassifier';\nexport {\n WebpiecesDefaultFailureClassifier,\n WEBPIECES_DEFAULT_FAILURE_CLASSIFIER,\n} from './http/WebpiecesDefaultFailureClassifier';\nexport { templateDeriver } from './http/templateDeriver';\nexport { WebpiecesCoreHeaders } from './http/WebpiecesCoreHeaders';\nexport { ContextReader } from './http/ContextReader';\n\n// The OUTBOUND half of the trust model: whether a TRUSTED context key may ride to the endpoint being\n// called. Built ONLY from the destination endpoint's AuthMode — see the class doc.\nexport { DestinationTrust } from './http/DestinationTrust';\n\n// BROWSER-ONLY outbound-header propagation (app-held store + registry -> outbound HTTP headers).\n// Only @webpieces/http-client-browser may name it; the server reads RequestContext directly via\n// RequestContextHeaders in the Node-only @webpieces/core-context.\nexport { ContextMgr } from './http/ContextMgr';\n\n// API-call logging helper (uses LogManager above). NOT a singleton: construct one per environment\n// with that environment's ApiCallContext — `new LogApiCallImpl(new RequestContextApiCallContext())`\n// on node, `new LogApiCallImpl(new BrowserApiCallContext())` in a browser.\nexport { LogApiCallImpl } from './http/LogApiCall';\n\n// Opt-in field masking for the LogApiCall log path — declare per-api sensitive fields so secrets\n// (OAuth refresh tokens, id-token JWTs) are masked in the logs while the real value stays on the wire.\nexport { MaskSpec } from './http/LogFieldMask';\nexport type { MaskMode } from './http/LogFieldMask';\n\n// The structured `api` tag + the context-writer seam LogApiCall stamps through. The Node\n// RequestContext-backed impl lives in @webpieces/core-context, the browser one in\n// @webpieces/http-client-browser; each is CONSTRUCTED by its package, never installed globally.\nexport { ApiCallInfo } from './http/ApiCallInfo';\nexport type { ApiType, ApiResult } from './http/ApiCallInfo';\n// Console-render bridge: turns LogApiCall's [LogApiCall] bracket into [API.{side}.{phase}] locally.\nexport {\n ApiCallLogName,\n ApiCallLogNameImpl,\n LOG_API_CALL_LOGGER_NAME,\n} from './http/ApiCallLogName';\nexport { ApiMethodInfo } from './http/ApiMethodInfo';\nexport type { ApiSide } from './http/ApiMethodInfo';\nexport type { ApiCallContext } from './http/ApiCallContext';\n\n// Test-case recording contract (impl lives in http-server; hooks in http-client)\nexport { TestCaseRecorder, RecorderKeys } from './http/recorder/TestCaseRecorder';\nexport {\n RecordedEndpoint,\n RecordedError,\n RecordedTestCase,\n} from './http/recorder/RecordedEndpoint';\nexport { DoNotRecord, getDoNotRecordFields } from './http/recorder/DoNotRecord';\nexport { RecordSerializer, SerializedMap, SerializedError } from './http/recorder/RecordSerializer';\n\n// ---------------------------------------------------------------------------------------------\n// Filter-chain primitives, shared by BOTH chains: the inbound server chain\n// (`Filter<MethodMeta, WpResponse<unknown>>`, @webpieces/http-routing) and the outbound client\n// chain (`Filter<ClientRequest, Response>`, @webpieces/http-client-core). Declared once, here, in\n// the package both depend on — see the class doc for why a second pair would be a shim.\nexport { Filter } from './filters/Filter';\nexport type { Service } from './filters/Filter';\nexport { FilterChain } from './filters/FilterChain';\n\nexport {\n ApiError,\n ApiNotFoundError,\n ApiDependencyError,\n ApiUnavailableError,\n ApiDependencyTimeoutError,\n ApiImplementationError,\n ApiRateLimitedError,\n ApiForbiddenError,\n ApiRequestTimeoutError,\n ApiEndUserError,\n ApiBadRequestError,\n ApiUnauthorizedError,\n ApiDependencyBackoffError,\n ApiConnectionError,\n ApiEndpointNotFoundError,\n ApiErrorCodec,\n ApiErrorPayload,\n ApiErrorBoundary,\n} from './errors';\nexport type { ApiErrorKind } from './errors';\nexport { ApiErrorHttpStatus } from './http/ApiErrorHttpStatus';\n"]}
|
package/src/mcp/DtoSchema.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import 'reflect-metadata';
|
|
2
2
|
export type DtoClass = abstract new (...args: any[]) => unknown;
|
|
3
|
-
|
|
3
|
+
/** The element type of an array or the value type of a map; TypeScript erases both at runtime. */
|
|
4
|
+
export type DtoElementType = 'string' | 'number' | 'integer' | 'boolean' | DtoClass;
|
|
4
5
|
/** Runtime values accepted at the DTO validation boundary. */
|
|
5
6
|
export type DtoValue = object | string | number | boolean | null;
|
|
6
7
|
/** Additive field metadata; the scalar/object type itself comes from `design:type`. */
|
|
@@ -9,24 +10,51 @@ export declare class WpDtoFieldOptions {
|
|
|
9
10
|
/** Required/optional is explicit because TypeScript erases `?` at runtime. */
|
|
10
11
|
readonly required: boolean;
|
|
11
12
|
/** Required for arrays because TypeScript erases their element type. */
|
|
12
|
-
readonly arrayItems?:
|
|
13
|
+
readonly arrayItems?: DtoElementType | undefined;
|
|
13
14
|
/** A reflected Number is otherwise emitted as JSON Schema `number`. */
|
|
14
15
|
readonly integer: boolean;
|
|
15
16
|
readonly minimum?: number | undefined;
|
|
16
17
|
readonly maximum?: number | undefined;
|
|
17
18
|
readonly enumValues?: readonly [string, ...string[]] | undefined;
|
|
19
|
+
/** MCP 2026 SEP-2243 header mirrored as `Mcp-Param-{name}`. */
|
|
20
|
+
readonly mcpHeader?: WpMcpHeader | undefined;
|
|
18
21
|
constructor(description: string,
|
|
19
22
|
/** Required/optional is explicit because TypeScript erases `?` at runtime. */
|
|
20
23
|
required: boolean,
|
|
21
24
|
/** Required for arrays because TypeScript erases their element type. */
|
|
22
|
-
arrayItems?:
|
|
25
|
+
arrayItems?: DtoElementType | undefined,
|
|
23
26
|
/** A reflected Number is otherwise emitted as JSON Schema `number`. */
|
|
24
|
-
integer?: boolean, minimum?: number | undefined, maximum?: number | undefined, enumValues?: readonly [string, ...string[]] | undefined
|
|
27
|
+
integer?: boolean, minimum?: number | undefined, maximum?: number | undefined, enumValues?: readonly [string, ...string[]] | undefined,
|
|
28
|
+
/** MCP 2026 SEP-2243 header mirrored as `Mcp-Param-{name}`. */
|
|
29
|
+
mcpHeader?: WpMcpHeader | undefined);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Names the `x-mcp-header` a primitive tool parameter is mirrored into (`Mcp-Param-{name}`). A class,
|
|
33
|
+
* not a bare string, so the 8th `WpDtoFieldOptions` argument can never be mistaken for a map value
|
|
34
|
+
* type (maps use `WpDtoMapFieldOptions`).
|
|
35
|
+
*/
|
|
36
|
+
export declare class WpMcpHeader {
|
|
37
|
+
readonly name: string;
|
|
38
|
+
constructor(name: string);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Field metadata for a typed map such as `Record<string, string>` or `Record<string, SomeDto>`.
|
|
42
|
+
* Keys are open strings; every VALUE must match `mapValues`. The value type is explicit for the same
|
|
43
|
+
* reason `arrayItems` is: TypeScript erases it, and a `Record` reflects as plain `Object`.
|
|
44
|
+
*/
|
|
45
|
+
export declare class WpDtoMapFieldOptions {
|
|
46
|
+
readonly description: string;
|
|
47
|
+
/** Required/optional is explicit because TypeScript erases `?` at runtime. */
|
|
48
|
+
readonly required: boolean;
|
|
49
|
+
readonly mapValues: DtoElementType;
|
|
50
|
+
constructor(description: string,
|
|
51
|
+
/** Required/optional is explicit because TypeScript erases `?` at runtime. */
|
|
52
|
+
required: boolean, mapValues: DtoElementType);
|
|
25
53
|
}
|
|
26
54
|
export declare class WpDtoFieldMetadata {
|
|
27
55
|
readonly propertyKey: string;
|
|
28
|
-
readonly options: WpDtoFieldOptions;
|
|
29
|
-
constructor(propertyKey: string, options: WpDtoFieldOptions);
|
|
56
|
+
readonly options: WpDtoFieldOptions | WpDtoMapFieldOptions;
|
|
57
|
+
constructor(propertyKey: string, options: WpDtoFieldOptions | WpDtoMapFieldOptions);
|
|
30
58
|
}
|
|
31
59
|
/** The JSON Schema subset emitted for Webpieces API DTOs. */
|
|
32
60
|
export declare class ApiJsonSchema {
|
|
@@ -34,37 +62,54 @@ export declare class ApiJsonSchema {
|
|
|
34
62
|
description?: string;
|
|
35
63
|
properties?: Record<string, ApiJsonSchema>;
|
|
36
64
|
required?: string[];
|
|
37
|
-
|
|
65
|
+
/** `false` closes an object; a schema makes it a typed map whose values all match that schema. */
|
|
66
|
+
additionalProperties?: boolean | ApiJsonSchema;
|
|
38
67
|
items?: ApiJsonSchema;
|
|
39
68
|
enum?: string[];
|
|
40
69
|
minimum?: number;
|
|
41
70
|
maximum?: number;
|
|
71
|
+
/** MCP 2026 SEP-2243 schema extension consumed by the official SDK. */
|
|
72
|
+
'x-mcp-header'?: string;
|
|
42
73
|
constructor(type?: 'object' | 'string' | 'number' | 'integer' | 'boolean' | 'array');
|
|
43
74
|
}
|
|
44
75
|
/** A validation result safe to show to an API caller/model. */
|
|
45
76
|
export declare class DtoValidationFailure {
|
|
77
|
+
/** JSON path of the offending value, e.g. `$.address.city`. */
|
|
78
|
+
readonly field: string;
|
|
46
79
|
readonly message: string;
|
|
47
|
-
constructor(
|
|
80
|
+
constructor(
|
|
81
|
+
/** JSON path of the offending value, e.g. `$.address.city`. */
|
|
82
|
+
field: string, message: string);
|
|
48
83
|
}
|
|
49
84
|
/** Marks a request/response class as a schema-bearing DTO, including intentionally empty DTOs. */
|
|
50
85
|
export declare function WpDto(): ClassDecorator;
|
|
51
86
|
/** Adds documentation and runtime-only shape facts to a DTO property. */
|
|
52
|
-
export declare function WpDtoField(options: WpDtoFieldOptions): PropertyDecorator;
|
|
87
|
+
export declare function WpDtoField(options: WpDtoFieldOptions | WpDtoMapFieldOptions): PropertyDecorator;
|
|
53
88
|
/** Declares an async API method's response DTO because reflection sees Promise, not its generic. */
|
|
54
89
|
export declare function WpResponseDto(responseDto: () => DtoClass): MethodDecorator;
|
|
55
90
|
/** Builds and validates the same DTO schema used for MCP input and structured output. */
|
|
56
91
|
export declare class DtoSchemaBuilder {
|
|
57
92
|
requestClassOf(apiClass: Function, methodName: string): DtoClass;
|
|
58
93
|
responseClassOf(apiClass: Function, methodName: string): DtoClass;
|
|
94
|
+
/**
|
|
95
|
+
* The one closure gate for an object schema. Closed means no key can carry an unspecified value:
|
|
96
|
+
* either extra keys are forbidden (`additionalProperties: false`) or every extra key's value is
|
|
97
|
+
* typed (`additionalProperties: <schema>`, a typed map). A missing or `true` value is open.
|
|
98
|
+
* Use this instead of `schema.additionalProperties === false`, which rejects typed maps.
|
|
99
|
+
*/
|
|
100
|
+
isClosedSchema(schema: ApiJsonSchema): boolean;
|
|
59
101
|
build(dtoClass: DtoClass): ApiJsonSchema;
|
|
60
102
|
validate(dtoClass: DtoClass, value: DtoValue): DtoValidationFailure | undefined;
|
|
61
103
|
private buildAt;
|
|
62
104
|
private fieldSchema;
|
|
63
105
|
private validateOptions;
|
|
64
106
|
private itemSchema;
|
|
107
|
+
private validateMcpHeaders;
|
|
65
108
|
private validateAt;
|
|
66
109
|
private validateField;
|
|
67
110
|
private validateArray;
|
|
111
|
+
private validateMap;
|
|
112
|
+
private validateElement;
|
|
68
113
|
private fields;
|
|
69
114
|
private requireDto;
|
|
70
115
|
}
|
package/src/mcp/DtoSchema.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DtoSchemaBuilder = exports.DtoValidationFailure = exports.ApiJsonSchema = exports.WpDtoFieldMetadata = exports.WpDtoFieldOptions = void 0;
|
|
3
|
+
exports.DtoSchemaBuilder = exports.DtoValidationFailure = exports.ApiJsonSchema = exports.WpDtoFieldMetadata = exports.WpDtoMapFieldOptions = exports.WpMcpHeader = exports.WpDtoFieldOptions = void 0;
|
|
4
4
|
exports.WpDto = WpDto;
|
|
5
5
|
exports.WpDtoField = WpDtoField;
|
|
6
6
|
exports.WpResponseDto = WpResponseDto;
|
|
@@ -17,13 +17,16 @@ class WpDtoFieldOptions {
|
|
|
17
17
|
minimum;
|
|
18
18
|
maximum;
|
|
19
19
|
enumValues;
|
|
20
|
+
mcpHeader;
|
|
20
21
|
constructor(description,
|
|
21
22
|
/** Required/optional is explicit because TypeScript erases `?` at runtime. */
|
|
22
23
|
required,
|
|
23
24
|
/** Required for arrays because TypeScript erases their element type. */
|
|
24
25
|
arrayItems,
|
|
25
26
|
/** A reflected Number is otherwise emitted as JSON Schema `number`. */
|
|
26
|
-
integer = false, minimum, maximum, enumValues
|
|
27
|
+
integer = false, minimum, maximum, enumValues,
|
|
28
|
+
/** MCP 2026 SEP-2243 header mirrored as `Mcp-Param-{name}`. */
|
|
29
|
+
mcpHeader) {
|
|
27
30
|
this.description = description;
|
|
28
31
|
this.required = required;
|
|
29
32
|
this.arrayItems = arrayItems;
|
|
@@ -31,9 +34,40 @@ class WpDtoFieldOptions {
|
|
|
31
34
|
this.minimum = minimum;
|
|
32
35
|
this.maximum = maximum;
|
|
33
36
|
this.enumValues = enumValues;
|
|
37
|
+
this.mcpHeader = mcpHeader;
|
|
34
38
|
}
|
|
35
39
|
}
|
|
36
40
|
exports.WpDtoFieldOptions = WpDtoFieldOptions;
|
|
41
|
+
/**
|
|
42
|
+
* Names the `x-mcp-header` a primitive tool parameter is mirrored into (`Mcp-Param-{name}`). A class,
|
|
43
|
+
* not a bare string, so the 8th `WpDtoFieldOptions` argument can never be mistaken for a map value
|
|
44
|
+
* type (maps use `WpDtoMapFieldOptions`).
|
|
45
|
+
*/
|
|
46
|
+
class WpMcpHeader {
|
|
47
|
+
name;
|
|
48
|
+
constructor(name) {
|
|
49
|
+
this.name = name;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
exports.WpMcpHeader = WpMcpHeader;
|
|
53
|
+
/**
|
|
54
|
+
* Field metadata for a typed map such as `Record<string, string>` or `Record<string, SomeDto>`.
|
|
55
|
+
* Keys are open strings; every VALUE must match `mapValues`. The value type is explicit for the same
|
|
56
|
+
* reason `arrayItems` is: TypeScript erases it, and a `Record` reflects as plain `Object`.
|
|
57
|
+
*/
|
|
58
|
+
class WpDtoMapFieldOptions {
|
|
59
|
+
description;
|
|
60
|
+
required;
|
|
61
|
+
mapValues;
|
|
62
|
+
constructor(description,
|
|
63
|
+
/** Required/optional is explicit because TypeScript erases `?` at runtime. */
|
|
64
|
+
required, mapValues) {
|
|
65
|
+
this.description = description;
|
|
66
|
+
this.required = required;
|
|
67
|
+
this.mapValues = mapValues;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
exports.WpDtoMapFieldOptions = WpDtoMapFieldOptions;
|
|
37
71
|
class WpDtoFieldMetadata {
|
|
38
72
|
propertyKey;
|
|
39
73
|
options;
|
|
@@ -49,6 +83,7 @@ class ApiJsonSchema {
|
|
|
49
83
|
description;
|
|
50
84
|
properties;
|
|
51
85
|
required;
|
|
86
|
+
/** `false` closes an object; a schema makes it a typed map whose values all match that schema. */
|
|
52
87
|
additionalProperties;
|
|
53
88
|
items;
|
|
54
89
|
enum;
|
|
@@ -61,8 +96,12 @@ class ApiJsonSchema {
|
|
|
61
96
|
exports.ApiJsonSchema = ApiJsonSchema;
|
|
62
97
|
/** A validation result safe to show to an API caller/model. */
|
|
63
98
|
class DtoValidationFailure {
|
|
99
|
+
field;
|
|
64
100
|
message;
|
|
65
|
-
constructor(
|
|
101
|
+
constructor(
|
|
102
|
+
/** JSON path of the offending value, e.g. `$.address.city`. */
|
|
103
|
+
field, message) {
|
|
104
|
+
this.field = field;
|
|
66
105
|
this.message = message;
|
|
67
106
|
}
|
|
68
107
|
}
|
|
@@ -114,8 +153,20 @@ class DtoSchemaBuilder {
|
|
|
114
153
|
}
|
|
115
154
|
return response();
|
|
116
155
|
}
|
|
156
|
+
/**
|
|
157
|
+
* The one closure gate for an object schema. Closed means no key can carry an unspecified value:
|
|
158
|
+
* either extra keys are forbidden (`additionalProperties: false`) or every extra key's value is
|
|
159
|
+
* typed (`additionalProperties: <schema>`, a typed map). A missing or `true` value is open.
|
|
160
|
+
* Use this instead of `schema.additionalProperties === false`, which rejects typed maps.
|
|
161
|
+
*/
|
|
162
|
+
isClosedSchema(schema) {
|
|
163
|
+
const extra = schema.additionalProperties;
|
|
164
|
+
return extra === false || (typeof extra === 'object' && extra !== null);
|
|
165
|
+
}
|
|
117
166
|
build(dtoClass) {
|
|
118
|
-
|
|
167
|
+
const schema = this.buildAt(dtoClass, new Set());
|
|
168
|
+
this.validateMcpHeaders(schema, new Map());
|
|
169
|
+
return schema;
|
|
119
170
|
}
|
|
120
171
|
validate(dtoClass, value) {
|
|
121
172
|
return this.validateAt(dtoClass, value, '$');
|
|
@@ -145,8 +196,14 @@ class DtoSchemaBuilder {
|
|
|
145
196
|
const reflected = Reflect.getMetadata('design:type', dtoClass.prototype, field.propertyKey);
|
|
146
197
|
if (!reflected)
|
|
147
198
|
throw new Error(`No reflected type for ${dtoClass.name}.${field.propertyKey}.`);
|
|
148
|
-
const options = field.options;
|
|
149
199
|
this.validateOptions(dtoClass, field, reflected);
|
|
200
|
+
const options = field.options;
|
|
201
|
+
if (options instanceof WpDtoMapFieldOptions) {
|
|
202
|
+
const mapSchema = new ApiJsonSchema('object');
|
|
203
|
+
mapSchema.description = options.description;
|
|
204
|
+
mapSchema.additionalProperties = this.itemSchema(options.mapValues, parents);
|
|
205
|
+
return mapSchema;
|
|
206
|
+
}
|
|
150
207
|
let schema;
|
|
151
208
|
switch (reflected.name) {
|
|
152
209
|
case 'String':
|
|
@@ -175,11 +232,23 @@ class DtoSchemaBuilder {
|
|
|
175
232
|
schema.maximum = options.maximum;
|
|
176
233
|
if (options.enumValues)
|
|
177
234
|
schema.enum = [...options.enumValues];
|
|
235
|
+
if (options.mcpHeader)
|
|
236
|
+
schema['x-mcp-header'] = options.mcpHeader.name;
|
|
178
237
|
return schema;
|
|
179
238
|
}
|
|
180
239
|
validateOptions(dtoClass, field, reflected) {
|
|
181
240
|
const label = `${dtoClass.name}.${field.propertyKey}`;
|
|
182
241
|
const options = field.options;
|
|
242
|
+
if (options instanceof WpDtoMapFieldOptions) {
|
|
243
|
+
if (reflected !== Object) {
|
|
244
|
+
throw new Error(`${label} declares mapValues but is not a map (Record<string, V>).`);
|
|
245
|
+
}
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
if (reflected === Object) {
|
|
249
|
+
throw new Error(`${label} has type Object: an interface or Record can never be a @WpDto. ` +
|
|
250
|
+
'For a map, use WpDtoMapFieldOptions.');
|
|
251
|
+
}
|
|
183
252
|
if (reflected.name !== 'Array' && options.arrayItems) {
|
|
184
253
|
throw new Error(`${label} declares arrayItems but is not an array.`);
|
|
185
254
|
}
|
|
@@ -187,34 +256,61 @@ class DtoSchemaBuilder {
|
|
|
187
256
|
(options.integer || options.minimum !== undefined || options.maximum !== undefined)) {
|
|
188
257
|
throw new Error(`${label} declares numeric constraints but is not a number.`);
|
|
189
258
|
}
|
|
190
|
-
if (options.minimum !== undefined &&
|
|
259
|
+
if (options.minimum !== undefined &&
|
|
260
|
+
options.maximum !== undefined &&
|
|
261
|
+
options.minimum > options.maximum) {
|
|
191
262
|
throw new Error(`${label} minimum cannot exceed maximum.`);
|
|
192
263
|
}
|
|
193
264
|
if (options.enumValues && reflected.name !== 'String') {
|
|
194
265
|
throw new Error(`${label} enumValues require a string field.`);
|
|
195
266
|
}
|
|
267
|
+
if (options.mcpHeader !== undefined) {
|
|
268
|
+
if (!/^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/.test(options.mcpHeader.name)) {
|
|
269
|
+
throw new Error(`${label} mcpHeader must be an RFC 9110 token.`);
|
|
270
|
+
}
|
|
271
|
+
if (!['String', 'Number', 'Boolean'].includes(reflected.name)) {
|
|
272
|
+
throw new Error(`${label} mcpHeader requires a primitive field.`);
|
|
273
|
+
}
|
|
274
|
+
if (reflected.name === 'Number' && !options.integer) {
|
|
275
|
+
throw new Error(`${label} mcpHeader cannot mirror a non-integer number (MCP 2026-07-28).`);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
196
278
|
}
|
|
197
279
|
itemSchema(item, parents) {
|
|
198
280
|
if (typeof item !== 'string')
|
|
199
281
|
return this.buildAt(item, parents);
|
|
200
282
|
return new ApiJsonSchema(item === 'integer' ? 'integer' : item);
|
|
201
283
|
}
|
|
284
|
+
validateMcpHeaders(schema, seen) {
|
|
285
|
+
const header = schema['x-mcp-header'];
|
|
286
|
+
if (header) {
|
|
287
|
+
const key = header.toLowerCase();
|
|
288
|
+
const prior = seen.get(key);
|
|
289
|
+
if (prior) {
|
|
290
|
+
throw new Error(`mcpHeader '${header}' duplicates '${prior}' case-insensitively.`);
|
|
291
|
+
}
|
|
292
|
+
seen.set(key, header);
|
|
293
|
+
}
|
|
294
|
+
for (const child of Object.values(schema.properties ?? {})) {
|
|
295
|
+
this.validateMcpHeaders(child, seen);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
202
298
|
validateAt(dtoClass, value, path) {
|
|
203
299
|
this.requireDto(dtoClass);
|
|
204
300
|
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
205
|
-
return new DtoValidationFailure(`${path} must be an object`);
|
|
301
|
+
return new DtoValidationFailure(path, `${path} must be an object`);
|
|
206
302
|
}
|
|
207
303
|
const fields = this.fields(dtoClass);
|
|
208
304
|
const known = new Set(fields.map((field) => field.propertyKey));
|
|
209
305
|
for (const key of Object.keys(value)) {
|
|
210
306
|
if (!known.has(key))
|
|
211
|
-
return new DtoValidationFailure(`${path}.${key} is not allowed`);
|
|
307
|
+
return new DtoValidationFailure(`${path}.${key}`, `${path}.${key} is not allowed`);
|
|
212
308
|
}
|
|
213
309
|
for (const field of fields) {
|
|
214
310
|
const fieldValue = Object.getOwnPropertyDescriptor(value, field.propertyKey)?.value;
|
|
215
311
|
if (fieldValue === undefined) {
|
|
216
312
|
if (field.options.required) {
|
|
217
|
-
return new DtoValidationFailure(`${path}.${field.propertyKey} is required`);
|
|
313
|
+
return new DtoValidationFailure(`${path}.${field.propertyKey}`, `${path}.${field.propertyKey} is required`);
|
|
218
314
|
}
|
|
219
315
|
continue;
|
|
220
316
|
}
|
|
@@ -227,56 +323,76 @@ class DtoSchemaBuilder {
|
|
|
227
323
|
validateField(dtoClass, field, value, path) {
|
|
228
324
|
// webpieces-disable no-any-unknown -- reflect-metadata returns an erased constructor token
|
|
229
325
|
const reflected = Reflect.getMetadata('design:type', dtoClass.prototype, field.propertyKey);
|
|
326
|
+
const options = field.options;
|
|
327
|
+
if (options instanceof WpDtoMapFieldOptions)
|
|
328
|
+
return this.validateMap(options, value, path);
|
|
230
329
|
const expected = reflected?.name;
|
|
231
330
|
if (expected === 'Array')
|
|
232
|
-
return this.validateArray(
|
|
331
|
+
return this.validateArray(options, value, path);
|
|
233
332
|
if (expected === 'String') {
|
|
234
333
|
if (typeof value !== 'string')
|
|
235
|
-
return new DtoValidationFailure(`${path} must be a string`);
|
|
236
|
-
if (
|
|
237
|
-
return new DtoValidationFailure(`${path} must be one of: ${
|
|
334
|
+
return new DtoValidationFailure(path, `${path} must be a string`);
|
|
335
|
+
if (options.enumValues && !options.enumValues.includes(value)) {
|
|
336
|
+
return new DtoValidationFailure(path, `${path} must be one of: ${options.enumValues.join(', ')}`);
|
|
238
337
|
}
|
|
239
338
|
return undefined;
|
|
240
339
|
}
|
|
241
340
|
if (expected === 'Number') {
|
|
242
341
|
if (typeof value !== 'number' || !Number.isFinite(value)) {
|
|
243
|
-
return new DtoValidationFailure(`${path} must be a number`);
|
|
342
|
+
return new DtoValidationFailure(path, `${path} must be a number`);
|
|
244
343
|
}
|
|
245
|
-
if (
|
|
246
|
-
return new DtoValidationFailure(`${path} must be an integer`);
|
|
344
|
+
if (options.integer && !Number.isInteger(value)) {
|
|
345
|
+
return new DtoValidationFailure(path, `${path} must be an integer`);
|
|
247
346
|
}
|
|
248
|
-
if (
|
|
249
|
-
return new DtoValidationFailure(`${path} must be >= ${
|
|
347
|
+
if (options.minimum !== undefined && value < options.minimum) {
|
|
348
|
+
return new DtoValidationFailure(path, `${path} must be >= ${options.minimum}`);
|
|
250
349
|
}
|
|
251
|
-
if (
|
|
252
|
-
return new DtoValidationFailure(`${path} must be <= ${
|
|
350
|
+
if (options.maximum !== undefined && value > options.maximum) {
|
|
351
|
+
return new DtoValidationFailure(path, `${path} must be <= ${options.maximum}`);
|
|
253
352
|
}
|
|
254
353
|
return undefined;
|
|
255
354
|
}
|
|
256
355
|
if (expected === 'Boolean') {
|
|
257
356
|
return typeof value === 'boolean'
|
|
258
357
|
? undefined
|
|
259
|
-
: new DtoValidationFailure(`${path} must be a boolean`);
|
|
358
|
+
: new DtoValidationFailure(path, `${path} must be a boolean`);
|
|
260
359
|
}
|
|
261
360
|
return this.validateAt(reflected, value, path);
|
|
262
361
|
}
|
|
263
362
|
validateArray(options, value, path) {
|
|
264
363
|
if (!Array.isArray(value))
|
|
265
|
-
return new DtoValidationFailure(`${path} must be an array`);
|
|
364
|
+
return new DtoValidationFailure(path, `${path} must be an array`);
|
|
266
365
|
if (!options.arrayItems)
|
|
267
|
-
return new DtoValidationFailure(`${path} has no item type`);
|
|
366
|
+
return new DtoValidationFailure(path, `${path} has no item type`);
|
|
268
367
|
for (let index = 0; index < value.length; index += 1) {
|
|
269
|
-
const
|
|
270
|
-
if (
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
368
|
+
const failure = this.validateElement(options.arrayItems, value[index], `${path}[${index}]`);
|
|
369
|
+
if (failure)
|
|
370
|
+
return failure;
|
|
371
|
+
}
|
|
372
|
+
return undefined;
|
|
373
|
+
}
|
|
374
|
+
validateMap(options, value, path) {
|
|
375
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
376
|
+
return new DtoValidationFailure(path, `${path} must be an object map`);
|
|
377
|
+
}
|
|
378
|
+
const prototype = Object.getPrototypeOf(value);
|
|
379
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
380
|
+
return new DtoValidationFailure(path, `${path} must be a plain object map`);
|
|
381
|
+
}
|
|
382
|
+
for (const key of Object.keys(value)) {
|
|
383
|
+
const entry = Object.getOwnPropertyDescriptor(value, key)?.value;
|
|
384
|
+
const failure = this.validateElement(options.mapValues, entry, `${path}.${key}`);
|
|
385
|
+
if (failure)
|
|
386
|
+
return failure;
|
|
387
|
+
}
|
|
388
|
+
return undefined;
|
|
389
|
+
}
|
|
390
|
+
validateElement(type, item, path) {
|
|
391
|
+
if (typeof type !== 'string')
|
|
392
|
+
return this.validateAt(type, item, path);
|
|
393
|
+
const wanted = type === 'integer' ? 'number' : type;
|
|
394
|
+
if (typeof item !== wanted || (type === 'integer' && !Number.isInteger(item))) {
|
|
395
|
+
return new DtoValidationFailure(path, `${path} must be ${type}`);
|
|
280
396
|
}
|
|
281
397
|
return undefined;
|
|
282
398
|
}
|