/** * This contains: * - Static type checks to verify the Spec's types are compatible with the SDK's types * (mutually assignable, w/ slight affordances to get rid of ZodObject.passthrough() index signatures, etc) * - Runtime checks to verify each Spec type has a static check * (note: a few don't have SDK types, see TODOs in this file) */ import * as SDKTypes from "./types.js"; import * as SpecTypes from "./spec.types.js"; /* eslint-disable @typescript-eslint/no-unused-vars */ /* eslint-disable @typescript-eslint/no-unsafe-function-type */ /* eslint-disable @typescript-eslint/no-require-imports */ // Removes index signatures added by ZodObject.passthrough(). type RemovePassthrough = T extends object ? T extends Array ? Array> : T extends Function ? T : {[K in keyof T as string extends K ? never : K]: RemovePassthrough} : T; type IsUnknown = [unknown] extends [T] ? [T] extends [unknown] ? true : false : false; // Turns {x?: unknown} into {x: unknown} but keeps {_meta?: unknown} unchanged (and leaves other optional properties unchanged, e.g. {x?: string}). // This works around an apparent quirk of ZodObject.unknown() (makes fields optional) type MakeUnknownsNotOptional = IsUnknown extends true ? unknown : (T extends object ? (T extends Array ? Array> : (T extends Function ? T : Pick & { // Start with empty object to avoid duplicates // Make unknown properties required (except _meta) [K in keyof T as '_meta' extends K ? never : IsUnknown extends true ? K : never]-?: unknown; } & Pick extends true ? never : K }[keyof T]> & { // Recurse on the picked properties [K in keyof Pick extends true ? never : K}[keyof T]>]: MakeUnknownsNotOptional })) : T); function checkCancelledNotification( sdk: SDKTypes.CancelledNotification, spec: SpecTypes.CancelledNotification ) { sdk = spec; spec = sdk; } function checkBaseMetadata( sdk: RemovePassthrough, spec: SpecTypes.BaseMetadata ) { sdk = spec; spec = sdk; } function checkImplementation( sdk: RemovePassthrough, spec: SpecTypes.Implementation ) { sdk = spec; spec = sdk; } function checkProgressNotification( sdk: SDKTypes.ProgressNotification, spec: SpecTypes.ProgressNotification ) { sdk = spec; spec = sdk; } function checkSubscribeRequest( sdk: SDKTypes.SubscribeRequest, spec: SpecTypes.SubscribeRequest ) { sdk = spec; spec = sdk; } function checkUnsubscribeRequest( sdk: SDKTypes.UnsubscribeRequest, spec: SpecTypes.UnsubscribeRequest ) { sdk = spec; spec = sdk; } function checkPaginatedRequest( sdk: SDKTypes.PaginatedRequest, spec: SpecTypes.PaginatedRequest ) { sdk = spec; spec = sdk; } function checkPaginatedResult( sdk: SDKTypes.PaginatedResult, spec: SpecTypes.PaginatedResult ) { sdk = spec; spec = sdk; } function checkListRootsRequest( sdk: SDKTypes.ListRootsRequest, spec: SpecTypes.ListRootsRequest ) { sdk = spec; spec = sdk; } function checkListRootsResult( sdk: RemovePassthrough, spec: SpecTypes.ListRootsResult ) { sdk = spec; spec = sdk; } function checkRoot( sdk: RemovePassthrough, spec: SpecTypes.Root ) { sdk = spec; spec = sdk; } function checkElicitRequest( sdk: RemovePassthrough, spec: SpecTypes.ElicitRequest ) { sdk = spec; spec = sdk; } function checkElicitResult( sdk: RemovePassthrough, spec: SpecTypes.ElicitResult ) { sdk = spec; spec = sdk; } function checkCompleteRequest( sdk: RemovePassthrough, spec: SpecTypes.CompleteRequest ) { sdk = spec; spec = sdk; } function checkCompleteResult( sdk: SDKTypes.CompleteResult, spec: SpecTypes.CompleteResult ) { sdk = spec; spec = sdk; } function checkProgressToken( sdk: SDKTypes.ProgressToken, spec: SpecTypes.ProgressToken ) { sdk = spec; spec = sdk; } function checkCursor( sdk: SDKTypes.Cursor, spec: SpecTypes.Cursor ) { sdk = spec; spec = sdk; } function checkRequest( sdk: SDKTypes.Request, spec: SpecTypes.Request ) { sdk = spec; spec = sdk; } function checkResult( sdk: SDKTypes.Result, spec: SpecTypes.Result ) { sdk = spec; spec = sdk; } function checkRequestId( sdk: SDKTypes.RequestId, spec: SpecTypes.RequestId ) { sdk = spec; spec = sdk; } function checkJSONRPCRequest( sdk: SDKTypes.JSONRPCRequest, spec: SpecTypes.JSONRPCRequest ) { sdk = spec; spec = sdk; } function checkJSONRPCNotification( sdk: SDKTypes.JSONRPCNotification, spec: SpecTypes.JSONRPCNotification ) { sdk = spec; spec = sdk; } function checkJSONRPCResponse( sdk: SDKTypes.JSONRPCResponse, spec: SpecTypes.JSONRPCResponse ) { sdk = spec; spec = sdk; } function checkEmptyResult( sdk: SDKTypes.EmptyResult, spec: SpecTypes.EmptyResult ) { sdk = spec; spec = sdk; } function checkNotification( sdk: SDKTypes.Notification, spec: SpecTypes.Notification ) { sdk = spec; spec = sdk; } function checkClientResult( sdk: SDKTypes.ClientResult, spec: SpecTypes.ClientResult ) { sdk = spec; spec = sdk; } function checkClientNotification( sdk: SDKTypes.ClientNotification, spec: SpecTypes.ClientNotification ) { sdk = spec; spec = sdk; } function checkServerResult( sdk: SDKTypes.ServerResult, spec: SpecTypes.ServerResult ) { sdk = spec; spec = sdk; } function checkResourceTemplateReference( sdk: RemovePassthrough, spec: SpecTypes.ResourceTemplateReference ) { sdk = spec; spec = sdk; } function checkPromptReference( sdk: RemovePassthrough, spec: SpecTypes.PromptReference ) { sdk = spec; spec = sdk; } function checkResourceReference( sdk: RemovePassthrough, spec: SpecTypes.ResourceTemplateReference ) { sdk = spec; spec = sdk; } function checkToolAnnotations( sdk: RemovePassthrough, spec: SpecTypes.ToolAnnotations ) { sdk = spec; spec = sdk; } function checkTool( sdk: RemovePassthrough, spec: SpecTypes.Tool ) { sdk = spec; spec = sdk; } function checkListToolsRequest( sdk: SDKTypes.ListToolsRequest, spec: SpecTypes.ListToolsRequest ) { sdk = spec; spec = sdk; } function checkListToolsResult( sdk: RemovePassthrough, spec: SpecTypes.ListToolsResult ) { sdk = spec; spec = sdk; } function checkCallToolResult( sdk: RemovePassthrough, spec: SpecTypes.CallToolResult ) { sdk = spec; spec = sdk; } function checkCallToolRequest( sdk: SDKTypes.CallToolRequest, spec: SpecTypes.CallToolRequest ) { sdk = spec; spec = sdk; } function checkToolListChangedNotification( sdk: SDKTypes.ToolListChangedNotification, spec: SpecTypes.ToolListChangedNotification ) { sdk = spec; spec = sdk; } function checkResourceListChangedNotification( sdk: SDKTypes.ResourceListChangedNotification, spec: SpecTypes.ResourceListChangedNotification ) { sdk = spec; spec = sdk; } function checkPromptListChangedNotification( sdk: SDKTypes.PromptListChangedNotification, spec: SpecTypes.PromptListChangedNotification ) { sdk = spec; spec = sdk; } function checkRootsListChangedNotification( sdk: SDKTypes.RootsListChangedNotification, spec: SpecTypes.RootsListChangedNotification ) { sdk = spec; spec = sdk; } function checkResourceUpdatedNotification( sdk: SDKTypes.ResourceUpdatedNotification, spec: SpecTypes.ResourceUpdatedNotification ) { sdk = spec; spec = sdk; } function checkSamplingMessage( sdk: RemovePassthrough, spec: SpecTypes.SamplingMessage ) { sdk = spec; spec = sdk; } function checkCreateMessageResult( sdk: RemovePassthrough, spec: SpecTypes.CreateMessageResult ) { sdk = spec; spec = sdk; } function checkSetLevelRequest( sdk: SDKTypes.SetLevelRequest, spec: SpecTypes.SetLevelRequest ) { sdk = spec; spec = sdk; } function checkPingRequest( sdk: SDKTypes.PingRequest, spec: SpecTypes.PingRequest ) { sdk = spec; spec = sdk; } function checkInitializedNotification( sdk: SDKTypes.InitializedNotification, spec: SpecTypes.InitializedNotification ) { sdk = spec; spec = sdk; } function checkListResourcesRequest( sdk: SDKTypes.ListResourcesRequest, spec: SpecTypes.ListResourcesRequest ) { sdk = spec; spec = sdk; } function checkListResourcesResult( sdk: RemovePassthrough, spec: SpecTypes.ListResourcesResult ) { sdk = spec; spec = sdk; } function checkListResourceTemplatesRequest( sdk: SDKTypes.ListResourceTemplatesRequest, spec: SpecTypes.ListResourceTemplatesRequest ) { sdk = spec; spec = sdk; } function checkListResourceTemplatesResult( sdk: RemovePassthrough, spec: SpecTypes.ListResourceTemplatesResult ) { sdk = spec; spec = sdk; } function checkReadResourceRequest( sdk: SDKTypes.ReadResourceRequest, spec: SpecTypes.ReadResourceRequest ) { sdk = spec; spec = sdk; } function checkReadResourceResult( sdk: RemovePassthrough, spec: SpecTypes.ReadResourceResult ) { sdk = spec; spec = sdk; } function checkResourceContents( sdk: RemovePassthrough, spec: SpecTypes.ResourceContents ) { sdk = spec; spec = sdk; } function checkTextResourceContents( sdk: RemovePassthrough, spec: SpecTypes.TextResourceContents ) { sdk = spec; spec = sdk; } function checkBlobResourceContents( sdk: RemovePassthrough, spec: SpecTypes.BlobResourceContents ) { sdk = spec; spec = sdk; } function checkResource( sdk: RemovePassthrough, spec: SpecTypes.Resource ) { sdk = spec; spec = sdk; } function checkResourceTemplate( sdk: RemovePassthrough, spec: SpecTypes.ResourceTemplate ) { sdk = spec; spec = sdk; } function checkPromptArgument( sdk: RemovePassthrough, spec: SpecTypes.PromptArgument ) { sdk = spec; spec = sdk; } function checkPrompt( sdk: RemovePassthrough, spec: SpecTypes.Prompt ) { sdk = spec; spec = sdk; } function checkListPromptsRequest( sdk: SDKTypes.ListPromptsRequest, spec: SpecTypes.ListPromptsRequest ) { sdk = spec; spec = sdk; } function checkListPromptsResult( sdk: RemovePassthrough, spec: SpecTypes.ListPromptsResult ) { sdk = spec; spec = sdk; } function checkGetPromptRequest( sdk: SDKTypes.GetPromptRequest, spec: SpecTypes.GetPromptRequest ) { sdk = spec; spec = sdk; } function checkTextContent( sdk: RemovePassthrough, spec: SpecTypes.TextContent ) { sdk = spec; spec = sdk; } function checkImageContent( sdk: RemovePassthrough, spec: SpecTypes.ImageContent ) { sdk = spec; spec = sdk; } function checkAudioContent( sdk: RemovePassthrough, spec: SpecTypes.AudioContent ) { sdk = spec; spec = sdk; } function checkEmbeddedResource( sdk: RemovePassthrough, spec: SpecTypes.EmbeddedResource ) { sdk = spec; spec = sdk; } function checkResourceLink( sdk: RemovePassthrough, spec: SpecTypes.ResourceLink ) { sdk = spec; spec = sdk; } function checkContentBlock( sdk: RemovePassthrough, spec: SpecTypes.ContentBlock ) { sdk = spec; spec = sdk; } function checkPromptMessage( sdk: RemovePassthrough, spec: SpecTypes.PromptMessage ) { sdk = spec; spec = sdk; } function checkGetPromptResult( sdk: RemovePassthrough, spec: SpecTypes.GetPromptResult ) { sdk = spec; spec = sdk; } function checkBooleanSchema( sdk: RemovePassthrough, spec: SpecTypes.BooleanSchema ) { sdk = spec; spec = sdk; } function checkStringSchema( sdk: RemovePassthrough, spec: SpecTypes.StringSchema ) { sdk = spec; spec = sdk; } function checkNumberSchema( sdk: RemovePassthrough, spec: SpecTypes.NumberSchema ) { sdk = spec; spec = sdk; } function checkEnumSchema( sdk: RemovePassthrough, spec: SpecTypes.EnumSchema ) { sdk = spec; spec = sdk; } function checkPrimitiveSchemaDefinition( sdk: RemovePassthrough, spec: SpecTypes.PrimitiveSchemaDefinition ) { sdk = spec; spec = sdk; } function checkJSONRPCError( sdk: SDKTypes.JSONRPCError, spec: SpecTypes.JSONRPCError ) { sdk = spec; spec = sdk; } function checkJSONRPCMessage( sdk: SDKTypes.JSONRPCMessage, spec: SpecTypes.JSONRPCMessage ) { sdk = spec; spec = sdk; } function checkCreateMessageRequest( sdk: RemovePassthrough, spec: SpecTypes.CreateMessageRequest ) { sdk = spec; spec = sdk; } function checkInitializeRequest( sdk: RemovePassthrough, spec: SpecTypes.InitializeRequest ) { sdk = spec; spec = sdk; } function checkInitializeResult( sdk: RemovePassthrough, spec: SpecTypes.InitializeResult ) { sdk = spec; spec = sdk; } function checkClientCapabilities( sdk: RemovePassthrough, spec: SpecTypes.ClientCapabilities ) { sdk = spec; spec = sdk; } function checkServerCapabilities( sdk: RemovePassthrough, spec: SpecTypes.ServerCapabilities ) { sdk = spec; spec = sdk; } function checkClientRequest( sdk: RemovePassthrough, spec: SpecTypes.ClientRequest ) { sdk = spec; spec = sdk; } function checkServerRequest( sdk: RemovePassthrough, spec: SpecTypes.ServerRequest ) { sdk = spec; spec = sdk; } function checkLoggingMessageNotification( sdk: MakeUnknownsNotOptional, spec: SpecTypes.LoggingMessageNotification ) { sdk = spec; spec = sdk; } function checkServerNotification( sdk: MakeUnknownsNotOptional, spec: SpecTypes.ServerNotification ) { sdk = spec; spec = sdk; } // TODO(bug): missing type in SDK. This dead code is checked by the test suite below. // function checkModelHint( // RemovePassthrough< sdk: SDKTypes.ModelHint>, // spec: SpecTypes.ModelHint // ) { // sdk = spec; // spec = sdk; // } // TODO(bug): missing type in SDK. This dead code is checked by the test suite below. // function checkModelPreferences( // RemovePassthrough< sdk: SDKTypes.ModelPreferences>, // spec: SpecTypes.ModelPreferences // ) { // sdk = spec; // spec = sdk; // } // TODO(bug): missing type in SDK. This dead code is checked by the test suite below. // function checkAnnotations( // RemovePassthrough< sdk: SDKTypes.Annotations>, // spec: SpecTypes.Annotations // ) { // sdk = spec; // spec = sdk; // } // This file is .gitignore'd, and fetched by `npm run fetch:spec-types` (called by `npm run test`) const SPEC_TYPES_FILE = 'src/spec.types.ts'; const THIS_SOURCE_FILE = 'src/spec.types.test.ts'; describe('Spec Types', () => { const specTypesContent = require('fs').readFileSync(SPEC_TYPES_FILE, 'utf-8'); const typeNames = [...specTypesContent.matchAll(/export\s+interface\s+(\w+)\b/g)].map(m => m[1]); const testContent = require('fs').readFileSync(THIS_SOURCE_FILE, 'utf-8'); it('should define some expected types', () => { expect(typeNames).toContain('JSONRPCNotification'); expect(typeNames).toContain('ElicitResult'); }); for (const typeName of typeNames) { it(`${typeName} should have a compatibility test`, () => { expect(testContent).toContain(`function check${typeName}(`); }); } });