feat(devframe): accept Standard Schema for RPC args/return schemas - #155
feat(devframe): accept Standard Schema for RPC args/return schemas#155dvcolomban wants to merge 1 commit into
Conversation
Consumers using zod (or any other Standard Schema vendor) instead of valibot can now declare RPC args/returns directly, with the same compile-time inference behavior as today. RpcArgsSchema/RpcReturnSchema widen from valibot's GenericSchema to StandardSchemaV1 — a structural superset, so existing valibot-based code is unaffected. JSON Schema generation for agent-exposed tools now prefers a schema's own ~standard.jsonSchema converter (e.g. zod 4) before falling back to @valibot/to-json-schema, then to the existing generic object fallback.
✅ Deploy Preview for devfra ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
There was a problem hiding this comment.
Pull request overview
This PR widens devframe’s RPC schema typing from valibot-only (GenericSchema) to the Standard Schema v1 type (@standard-schema/spec), allowing RPC args/returns to be declared with any Standard-Schema-compliant validator (e.g. zod v4) while improving MCP JSON Schema generation for agent tools.
Changes:
- Switch
RpcArgsSchema/RpcReturnSchematoStandardSchemaV1and update type inference helpers accordingly. - Update MCP adapter JSON Schema generation to prefer
~standard.jsonSchemawhen available, with a fallback chain. - Add tests proving vendor-agnostic Standard Schema inference and covering the JSON Schema dispatch/fallback behavior.
Reviewed changes
Copilot reviewed 8 out of 9 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| pnpm-workspace.yaml | Adds @standard-schema/spec to the workspace dependency catalog. |
| pnpm-lock.yaml | Locks @standard-schema/spec and wires it into packages/devframe. |
| packages/devframe/package.json | Adds @standard-schema/spec as a dependency for exported/public types. |
| packages/devframe/src/rpc/types.ts | Widens RPC schema types to Standard Schema and updates docs/comments. |
| packages/devframe/src/rpc/utils.ts | Updates args/return type inference to use StandardSchemaV1.InferInput. |
| packages/devframe/src/rpc/types.test.ts | Adds a minimal Standard Schema implementation to assert vendor-agnostic inference. |
| packages/devframe/src/adapters/mcp/to-json-schema.ts | Updates schema conversion to accept Standard Schema and prefer ~standard.jsonSchema. |
| packages/devframe/src/adapters/mcp/build-server.ts | Updates MCP server schema extraction to use the renamed converter functions and Standard Schema types. |
| packages/devframe/src/adapters/mcp/tests/to-json-schema.test.ts | Adds coverage for ~standard.jsonSchema dispatch and fallback behavior. |
Files not reviewed (1)
- pnpm-lock.yaml: Generated file
Suppressed comments (1)
packages/devframe/src/adapters/mcp/to-json-schema.ts:67
safeToJsonSchema()always callsstandard.jsonSchema.input(...). To support correct JSON Schema generation for both RPC args (input) and returns (output), this helper should accept which side to convert and default to input so existing arg call sites remain unchanged.
function safeToJsonSchema(schema: StandardSchemaV1): unknown {
const standard = schema['~standard'] as StandardSchemaProps
try {
if (standard.jsonSchema)
return standard.jsonSchema.input({ target: 'draft-2020-12' })
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| export function returnToJsonSchema(schema: StandardSchemaV1 | undefined): unknown { | ||
| if (!schema) | ||
| return undefined | ||
| try { | ||
| return toJsonSchema(schema as any) | ||
| } | ||
| catch { | ||
| return FALLBACK_OBJECT_SCHEMA | ||
| } | ||
| return safeToJsonSchema(schema) | ||
| } |
There was a problem hiding this comment.
I kept it identical to match the typing of valibot and prevent any breaking changes but if we want to cleanly support validation I can switch to output
Summary
RpcArgsSchema/RpcReturnSchemafrom valibot'sGenericSchematoStandardSchemaV1(@standard-schema/spec), so RPC functions can declareargs/returnswith any Standard-Schema-compliant validator — not just valibot. zod 4 is the immediate motivating case: some consumers already use zod elsewhere in their stack and shouldn't have to pull in valibot just to satisfy devframe's RPC types.GenericSchema's~standardshape is a structural subtype ofStandardSchemaV1(verified against valibot's own type declarations), so this is a pure widening — every existing valibot-based RPC definition keeps inferring identically, with zero runtime behavior change.adapters/mcp) now prefer a schema's own~standard.jsonSchemaconverter (part of the Standard Schema spec, implemented by zod 4) when generating JSON Schema for MCP, before falling back to@valibot/to-json-schema, then to the existing generic-object fallback. So a zod-typed RPC function now exposes a real JSON Schema to agents instead of silently degrading to{ type: 'object', additionalProperties: true }.@standard-schema/specis type-only.adapters/flags.ts(CLI flags) is untouched; it introspects valibot's internal shape and is out of scope here.Test plan
pnpm lintpnpm typecheck(all 20 workspace packages)pnpm buildpnpm test(905/905, full suite)rpc/types.test.ts(hand-rolled~standardimplementation, proving the code path is vendor-agnostic rather than zod-shaped)to-json-schema.test.tscases covering the~standard.jsonSchemaconverter dispatch and its fallback chain