v2 backwards compat: specTypeSchema exported - synchronous StandardSchemaV1 (#2047)
This commit is contained in:
parent
2c0c481cb9
commit
22595b9685
5 changed files with 41 additions and 19 deletions
|
|
@ -140,7 +140,7 @@ export { InMemoryTaskMessageQueue, InMemoryTaskStore } from '../../experimental/
|
|||
// Validator types and classes
|
||||
export type { SpecTypeName, SpecTypes } from '../../types/specTypeSchema.js';
|
||||
export { isSpecType, specTypeSchemas } from '../../types/specTypeSchema.js';
|
||||
export type { StandardSchemaV1, StandardSchemaWithJSON } from '../../util/standardSchema.js';
|
||||
export type { StandardSchemaV1, StandardSchemaV1Sync, StandardSchemaWithJSON } from '../../util/standardSchema.js';
|
||||
export { AjvJsonSchemaValidator } from '../../validators/ajvProvider.js';
|
||||
export type { CfWorkerSchemaDraft } from '../../validators/cfWorkerProvider.js';
|
||||
// fromJsonSchema is intentionally NOT exported here — the server and client packages
|
||||
|
|
|
|||
|
|
@ -13,9 +13,9 @@ declare const untrusted: unknown;
|
|||
declare const value: unknown;
|
||||
declare const mixed: unknown[];
|
||||
|
||||
async function specTypeSchemas_basicUsage() {
|
||||
function specTypeSchemas_basicUsage() {
|
||||
//#region specTypeSchemas_basicUsage
|
||||
const result = await specTypeSchemas.CallToolResult['~standard'].validate(untrusted);
|
||||
const result = specTypeSchemas.CallToolResult['~standard'].validate(untrusted);
|
||||
if (result.issues === undefined) {
|
||||
// result.value is CallToolResult
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import {
|
|||
OpenIdProviderDiscoveryMetadataSchema,
|
||||
OpenIdProviderMetadataSchema
|
||||
} from '../shared/auth.js';
|
||||
import type { StandardSchemaV1 } from '../util/standardSchema.js';
|
||||
import type { StandardSchemaV1, StandardSchemaV1Sync } from '../util/standardSchema.js';
|
||||
import * as schemas from './schemas.js';
|
||||
|
||||
/**
|
||||
|
|
@ -235,7 +235,7 @@ type SpecTypeInputs = {
|
|||
[K in SchemaKey as StripSchemaSuffix<K>]: SchemaFor<K> extends z.ZodType ? z.input<SchemaFor<K>> : never;
|
||||
};
|
||||
|
||||
type SchemaRecord = { readonly [K in SpecTypeName]: StandardSchemaV1<SpecTypeInputs[K], SpecTypes[K]> };
|
||||
type SchemaRecord = { readonly [K in SpecTypeName]: StandardSchemaV1Sync<SpecTypeInputs[K], SpecTypes[K]> };
|
||||
type GuardRecord = { readonly [K in SpecTypeName]: (value: unknown) => value is SpecTypeInputs[K] };
|
||||
|
||||
const _specTypeSchemas: Record<string, StandardSchemaV1> = {};
|
||||
|
|
@ -265,7 +265,7 @@ for (const [key, schema] of Object.entries(authSchemas)) {
|
|||
*
|
||||
* @example
|
||||
* ```ts source="./specTypeSchema.examples.ts#specTypeSchemas_basicUsage"
|
||||
* const result = await specTypeSchemas.CallToolResult['~standard'].validate(untrusted);
|
||||
* const result = specTypeSchemas.CallToolResult['~standard'].validate(untrusted);
|
||||
* if (result.issues === undefined) {
|
||||
* // result.value is CallToolResult
|
||||
* }
|
||||
|
|
|
|||
|
|
@ -114,6 +114,28 @@ export namespace StandardSchemaWithJSON {
|
|||
export type InferOutput<Schema extends StandardTypedV1> = StandardTypedV1.InferOutput<Schema>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Narrowing of {@linkcode StandardSchemaV1} whose `validate` is guaranteed synchronous.
|
||||
*
|
||||
* The Zod schemas backing `specTypeSchemas` contain no async refinements or transforms,
|
||||
* so every entry satisfies this interface. Consumers can call `validate()` and access
|
||||
* `.issues` / `.value` on the result without `await`.
|
||||
*
|
||||
* `StandardSchemaV1Sync` is assignable to `StandardSchemaV1` — it is a strict subtype.
|
||||
*/
|
||||
export interface StandardSchemaV1Sync<Input = unknown, Output = Input> extends StandardSchemaV1<Input, Output> {
|
||||
readonly '~standard': StandardSchemaV1Sync.Props<Input, Output>;
|
||||
}
|
||||
|
||||
export namespace StandardSchemaV1Sync {
|
||||
export interface Props<Input = unknown, Output = Input> extends StandardSchemaV1.Props<Input, Output> {
|
||||
readonly validate: (value: unknown, options?: StandardSchemaV1.Options | undefined) => StandardSchemaV1.Result<Output>;
|
||||
}
|
||||
|
||||
export type InferInput<Schema extends StandardTypedV1> = StandardTypedV1.InferInput<Schema>;
|
||||
export type InferOutput<Schema extends StandardTypedV1> = StandardTypedV1.InferOutput<Schema>;
|
||||
}
|
||||
|
||||
// Type guards
|
||||
|
||||
export function isStandardJSONSchema(schema: unknown): schema is StandardJSONSchemaV1 {
|
||||
|
|
|
|||
|
|
@ -16,14 +16,14 @@ import type {
|
|||
} from '../../src/types/types.js';
|
||||
|
||||
describe('specTypeSchemas', () => {
|
||||
it('returns a StandardSchemaV1 validator that accepts valid values', () => {
|
||||
it('returns a StandardSchemaV1Sync validator that accepts valid values', () => {
|
||||
const result = specTypeSchemas.Implementation['~standard'].validate({ name: 'x', version: '1.0.0' });
|
||||
expect((result as { issues?: unknown }).issues).toBeUndefined();
|
||||
expect(result.issues).toBeUndefined();
|
||||
});
|
||||
|
||||
it('returns a validator that rejects invalid values with issues', () => {
|
||||
const result = specTypeSchemas.Implementation['~standard'].validate({ name: 'x' });
|
||||
expect((result as { issues?: readonly unknown[] }).issues?.length).toBeGreaterThan(0);
|
||||
expect(result.issues?.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('rejects unknown names at compile time and is undefined at runtime', () => {
|
||||
|
|
@ -33,14 +33,14 @@ describe('specTypeSchemas', () => {
|
|||
|
||||
it('covers JSON-RPC envelope types', () => {
|
||||
const ok = specTypeSchemas.JSONRPCRequest['~standard'].validate({ jsonrpc: '2.0', id: 1, method: 'ping' });
|
||||
expect((ok as { issues?: unknown }).issues).toBeUndefined();
|
||||
expect(ok.issues).toBeUndefined();
|
||||
});
|
||||
|
||||
it('covers OAuth types from shared/auth.ts', () => {
|
||||
const ok = specTypeSchemas.OAuthTokens['~standard'].validate({ access_token: 'x', token_type: 'Bearer' });
|
||||
expect((ok as { issues?: unknown }).issues).toBeUndefined();
|
||||
expect(ok.issues).toBeUndefined();
|
||||
const bad = specTypeSchemas.OAuthTokens['~standard'].validate({ token_type: 'Bearer' });
|
||||
expect((bad as { issues?: readonly unknown[] }).issues?.length).toBeGreaterThan(0);
|
||||
expect(bad.issues?.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue