@surfjs/zod 0.2.0
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 +140 -0
- package/dist/index.cjs +155 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +96 -0
- package/dist/index.d.ts +96 -0
- package/dist/index.js +150 -0
- package/dist/index.js.map +1 -0
- package/package.json +61 -0
package/README.md
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# @surfjs/zod
|
|
2
|
+
|
|
3
|
+
Zod schema integration for [Surf.js](https://surf.codes) — define commands with Zod instead of raw `ParamSchema`.
|
|
4
|
+
|
|
5
|
+
## Why?
|
|
6
|
+
|
|
7
|
+
Surf commands use a `ParamSchema` format to define parameters. This works, but if you're already using Zod in your project, you'd rather write schemas once and get both validation and TypeScript inference from a single source of truth.
|
|
8
|
+
|
|
9
|
+
`@surfjs/zod` lets you do exactly that.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install @surfjs/zod zod
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
### Before: Raw ParamSchema
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import { createSurf } from '@surfjs/core';
|
|
23
|
+
|
|
24
|
+
const surf = createSurf({
|
|
25
|
+
name: 'my-store',
|
|
26
|
+
commands: {
|
|
27
|
+
search: {
|
|
28
|
+
description: 'Search products',
|
|
29
|
+
params: {
|
|
30
|
+
query: { type: 'string', required: true, description: 'Search query' },
|
|
31
|
+
limit: { type: 'number', required: false, default: 20 },
|
|
32
|
+
category: {
|
|
33
|
+
type: 'string',
|
|
34
|
+
required: false,
|
|
35
|
+
enum: ['electronics', 'clothing', 'books'],
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
// params is Record<string, unknown> — no inference
|
|
39
|
+
run: async (params) => {
|
|
40
|
+
const query = params.query as string;
|
|
41
|
+
const limit = (params.limit as number) ?? 20;
|
|
42
|
+
return { results: [] };
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### After: defineZodCommand
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
import { z } from 'zod';
|
|
53
|
+
import { createSurf } from '@surfjs/core';
|
|
54
|
+
import { defineZodCommand } from '@surfjs/zod';
|
|
55
|
+
|
|
56
|
+
const surf = createSurf({
|
|
57
|
+
name: 'my-store',
|
|
58
|
+
commands: {
|
|
59
|
+
search: defineZodCommand({
|
|
60
|
+
description: 'Search products',
|
|
61
|
+
params: z.object({
|
|
62
|
+
query: z.string().describe('Search query'),
|
|
63
|
+
limit: z.number().int().min(1).max(100).optional().default(20),
|
|
64
|
+
category: z.enum(['electronics', 'clothing', 'books']).optional(),
|
|
65
|
+
}),
|
|
66
|
+
// params are fully typed: { query: string; limit: number; category?: 'electronics' | 'clothing' | 'books' }
|
|
67
|
+
run: async ({ query, limit, category }) => {
|
|
68
|
+
return { results: [] };
|
|
69
|
+
},
|
|
70
|
+
}),
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## API
|
|
76
|
+
|
|
77
|
+
### `defineZodCommand(config)`
|
|
78
|
+
|
|
79
|
+
Defines a Surf command using a Zod object schema for parameters. Returns a standard `CommandDefinition` that can be used anywhere Surf expects one.
|
|
80
|
+
|
|
81
|
+
The Zod schema is converted to Surf's `ParamSchema` format at runtime, so the manifest, DevUI, and agents all see native Surf types.
|
|
82
|
+
|
|
83
|
+
### `zodToSurfParams(schema)`
|
|
84
|
+
|
|
85
|
+
Lower-level utility that converts a `z.object({...})` schema to `Record<string, ParamSchema>`. Useful if you want the conversion without the full command definition.
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
import { z } from 'zod';
|
|
89
|
+
import { zodToSurfParams } from '@surfjs/zod';
|
|
90
|
+
|
|
91
|
+
const params = zodToSurfParams(
|
|
92
|
+
z.object({
|
|
93
|
+
name: z.string(),
|
|
94
|
+
age: z.number().optional(),
|
|
95
|
+
}),
|
|
96
|
+
);
|
|
97
|
+
// { name: { type: 'string', required: true }, age: { type: 'number', required: false } }
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### `zodValidator(schema)`
|
|
101
|
+
|
|
102
|
+
Middleware that validates incoming params against a Zod schema at runtime. Use this for stricter validation (min/max, regex, custom refinements) beyond what Surf's built-in validation supports.
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
import { z } from 'zod';
|
|
106
|
+
import { zodValidator } from '@surfjs/zod';
|
|
107
|
+
|
|
108
|
+
const schema = z.object({
|
|
109
|
+
email: z.string().email(),
|
|
110
|
+
age: z.number().int().min(0).max(150),
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
const surf = createSurf({
|
|
114
|
+
name: 'my-app',
|
|
115
|
+
middleware: [zodValidator(schema)],
|
|
116
|
+
commands: { ... },
|
|
117
|
+
});
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### `convertZodType(zodType)`
|
|
121
|
+
|
|
122
|
+
Convert a single Zod type to a Surf `ParamSchema`. Used internally by `zodToSurfParams` but exported for advanced use cases.
|
|
123
|
+
|
|
124
|
+
## Type Mapping
|
|
125
|
+
|
|
126
|
+
| Zod Type | Surf ParamSchema |
|
|
127
|
+
|---|---|
|
|
128
|
+
| `z.string()` | `{ type: 'string' }` |
|
|
129
|
+
| `z.number()` | `{ type: 'number' }` |
|
|
130
|
+
| `z.boolean()` | `{ type: 'boolean' }` |
|
|
131
|
+
| `z.enum([...])` | `{ type: 'string', enum: [...] }` |
|
|
132
|
+
| `z.object({})` | `{ type: 'object', properties: {...} }` |
|
|
133
|
+
| `z.array(item)` | `{ type: 'array', items: ... }` |
|
|
134
|
+
| `.optional()` | `required: false` |
|
|
135
|
+
| `.default(val)` | `default: val` |
|
|
136
|
+
| `.describe(text)` | `description: text` |
|
|
137
|
+
|
|
138
|
+
## License
|
|
139
|
+
|
|
140
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var zod = require('zod');
|
|
4
|
+
|
|
5
|
+
// src/convert.ts
|
|
6
|
+
function convertZodType(zodType) {
|
|
7
|
+
const description = zodType.description;
|
|
8
|
+
const base = convertZodTypeInner(zodType);
|
|
9
|
+
if (description) {
|
|
10
|
+
base.description = description;
|
|
11
|
+
}
|
|
12
|
+
return base;
|
|
13
|
+
}
|
|
14
|
+
function convertZodTypeInner(zodType) {
|
|
15
|
+
if (zodType instanceof zod.ZodEffects) {
|
|
16
|
+
return convertZodTypeInner(zodType._def.schema);
|
|
17
|
+
}
|
|
18
|
+
if (zodType instanceof zod.ZodDefault) {
|
|
19
|
+
const inner = convertZodTypeInner(zodType._def.innerType);
|
|
20
|
+
inner.default = zodType._def.defaultValue();
|
|
21
|
+
return inner;
|
|
22
|
+
}
|
|
23
|
+
if (zodType instanceof zod.ZodOptional) {
|
|
24
|
+
const inner = convertZodTypeInner(zodType._def.innerType);
|
|
25
|
+
inner.required = false;
|
|
26
|
+
return inner;
|
|
27
|
+
}
|
|
28
|
+
if (zodType instanceof zod.ZodNullable) {
|
|
29
|
+
const inner = convertZodTypeInner(zodType._def.innerType);
|
|
30
|
+
inner.required = false;
|
|
31
|
+
return inner;
|
|
32
|
+
}
|
|
33
|
+
if (zodType instanceof zod.ZodString) {
|
|
34
|
+
return { type: "string" };
|
|
35
|
+
}
|
|
36
|
+
if (zodType instanceof zod.ZodNumber) {
|
|
37
|
+
return { type: "number" };
|
|
38
|
+
}
|
|
39
|
+
if (zodType instanceof zod.ZodBoolean) {
|
|
40
|
+
return { type: "boolean" };
|
|
41
|
+
}
|
|
42
|
+
if (zodType instanceof zod.ZodLiteral) {
|
|
43
|
+
const value = zodType._def.value;
|
|
44
|
+
if (typeof value === "string") {
|
|
45
|
+
return { type: "string", enum: [value] };
|
|
46
|
+
}
|
|
47
|
+
if (typeof value === "number") {
|
|
48
|
+
return { type: "number" };
|
|
49
|
+
}
|
|
50
|
+
if (typeof value === "boolean") {
|
|
51
|
+
return { type: "boolean" };
|
|
52
|
+
}
|
|
53
|
+
return { type: "string" };
|
|
54
|
+
}
|
|
55
|
+
if (zodType instanceof zod.ZodEnum) {
|
|
56
|
+
const values = zodType._def.values;
|
|
57
|
+
return { type: "string", enum: values };
|
|
58
|
+
}
|
|
59
|
+
if (zodType instanceof zod.ZodNativeEnum) {
|
|
60
|
+
const enumObj = zodType._def.values;
|
|
61
|
+
const values = Object.values(enumObj).filter(
|
|
62
|
+
(v) => typeof v === "string"
|
|
63
|
+
);
|
|
64
|
+
if (values.length > 0) {
|
|
65
|
+
return { type: "string", enum: values };
|
|
66
|
+
}
|
|
67
|
+
return { type: "string" };
|
|
68
|
+
}
|
|
69
|
+
if (zodType instanceof zod.ZodObject) {
|
|
70
|
+
const shape = zodType._def.shape();
|
|
71
|
+
const properties = {};
|
|
72
|
+
for (const [key, value] of Object.entries(shape)) {
|
|
73
|
+
if (value) {
|
|
74
|
+
const converted = convertZodType(value);
|
|
75
|
+
if (converted.required === void 0) {
|
|
76
|
+
converted.required = true;
|
|
77
|
+
}
|
|
78
|
+
properties[key] = converted;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return { type: "object", properties };
|
|
82
|
+
}
|
|
83
|
+
if (zodType instanceof zod.ZodArray) {
|
|
84
|
+
const itemSchema = convertZodType(zodType._def.type);
|
|
85
|
+
return { type: "array", items: itemSchema };
|
|
86
|
+
}
|
|
87
|
+
if (zodType instanceof zod.ZodUnion) {
|
|
88
|
+
const options = zodType._def.options;
|
|
89
|
+
if (options.length > 0 && options[0]) {
|
|
90
|
+
return convertZodTypeInner(options[0]);
|
|
91
|
+
}
|
|
92
|
+
return { type: "string" };
|
|
93
|
+
}
|
|
94
|
+
return { type: "string" };
|
|
95
|
+
}
|
|
96
|
+
function zodToSurfParams(schema) {
|
|
97
|
+
const shape = schema._def.shape();
|
|
98
|
+
const result = {};
|
|
99
|
+
for (const [key, value] of Object.entries(shape)) {
|
|
100
|
+
if (value) {
|
|
101
|
+
const converted = convertZodType(value);
|
|
102
|
+
if (converted.required === void 0) {
|
|
103
|
+
converted.required = true;
|
|
104
|
+
}
|
|
105
|
+
result[key] = converted;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return result;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// src/validate.ts
|
|
112
|
+
function zodValidator(schema) {
|
|
113
|
+
return async (ctx, next) => {
|
|
114
|
+
const parseResult = schema.safeParse(ctx.params);
|
|
115
|
+
if (!parseResult.success) {
|
|
116
|
+
const issues = parseResult.error.issues;
|
|
117
|
+
const message = issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`).join("; ");
|
|
118
|
+
ctx.error = {
|
|
119
|
+
ok: false,
|
|
120
|
+
error: {
|
|
121
|
+
code: "INVALID_PARAMS",
|
|
122
|
+
message: `Zod validation failed: ${message}`,
|
|
123
|
+
details: {
|
|
124
|
+
issues: issues.map((issue) => ({
|
|
125
|
+
path: issue.path,
|
|
126
|
+
message: issue.message,
|
|
127
|
+
code: issue.code
|
|
128
|
+
}))
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
ctx.params = parseResult.data;
|
|
135
|
+
await next();
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// src/index.ts
|
|
140
|
+
function defineZodCommand(config) {
|
|
141
|
+
const { params: zodSchema, run, ...rest } = config;
|
|
142
|
+
const surfParams = zodToSurfParams(zodSchema);
|
|
143
|
+
return {
|
|
144
|
+
...rest,
|
|
145
|
+
params: surfParams,
|
|
146
|
+
run
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
exports.convertZodType = convertZodType;
|
|
151
|
+
exports.defineZodCommand = defineZodCommand;
|
|
152
|
+
exports.zodToSurfParams = zodToSurfParams;
|
|
153
|
+
exports.zodValidator = zodValidator;
|
|
154
|
+
//# sourceMappingURL=index.cjs.map
|
|
155
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/convert.ts","../src/validate.ts","../src/index.ts"],"names":["ZodEffects","ZodDefault","ZodOptional","ZodNullable","ZodString","ZodNumber","ZodBoolean","ZodLiteral","ZodEnum","ZodNativeEnum","ZodObject","ZodArray","ZodUnion"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { ParamSchema } from '@surfjs/core';\nimport {\n type ZodTypeAny,\n ZodString,\n ZodNumber,\n ZodBoolean,\n ZodEnum,\n ZodObject,\n ZodArray,\n ZodOptional,\n ZodDefault,\n ZodNullable,\n ZodEffects,\n ZodLiteral,\n ZodUnion,\n ZodNativeEnum,\n} from 'zod';\n\n/**\n * Convert a single Zod type to a Surf ParamSchema.\n * Recursively handles nested objects, arrays, optionals, defaults, etc.\n */\nexport function convertZodType(zodType: ZodTypeAny): ParamSchema {\n const description = zodType.description;\n const base = convertZodTypeInner(zodType);\n\n if (description) {\n base.description = description;\n }\n\n return base;\n}\n\nfunction convertZodTypeInner(zodType: ZodTypeAny): ParamSchema {\n // Unwrap ZodEffects (refinements, transforms, preprocess)\n if (zodType instanceof ZodEffects) {\n return convertZodTypeInner(zodType._def.schema as ZodTypeAny);\n }\n\n // ZodDefault — extract default value, recurse into inner type\n if (zodType instanceof ZodDefault) {\n const inner = convertZodTypeInner(zodType._def.innerType as ZodTypeAny);\n inner.default = zodType._def.defaultValue();\n return inner;\n }\n\n // ZodOptional — mark as not required, recurse\n if (zodType instanceof ZodOptional) {\n const inner = convertZodTypeInner(zodType._def.innerType as ZodTypeAny);\n inner.required = false;\n return inner;\n }\n\n // ZodNullable — treat like optional for Surf's purposes\n if (zodType instanceof ZodNullable) {\n const inner = convertZodTypeInner(zodType._def.innerType as ZodTypeAny);\n inner.required = false;\n return inner;\n }\n\n // Primitives\n if (zodType instanceof ZodString) {\n return { type: 'string' };\n }\n\n if (zodType instanceof ZodNumber) {\n return { type: 'number' };\n }\n\n if (zodType instanceof ZodBoolean) {\n return { type: 'boolean' };\n }\n\n // ZodLiteral — infer type from value\n if (zodType instanceof ZodLiteral) {\n const value = zodType._def.value as unknown;\n if (typeof value === 'string') {\n return { type: 'string', enum: [value] };\n }\n if (typeof value === 'number') {\n return { type: 'number' };\n }\n if (typeof value === 'boolean') {\n return { type: 'boolean' };\n }\n return { type: 'string' };\n }\n\n // ZodEnum — string enum\n if (zodType instanceof ZodEnum) {\n const values = zodType._def.values as readonly string[];\n return { type: 'string', enum: values };\n }\n\n // ZodNativeEnum — JS enum\n if (zodType instanceof ZodNativeEnum) {\n const enumObj = zodType._def.values as Record<string, string | number>;\n const values = Object.values(enumObj).filter(\n (v): v is string => typeof v === 'string',\n );\n if (values.length > 0) {\n return { type: 'string', enum: values };\n }\n return { type: 'string' };\n }\n\n // ZodObject — recursive conversion\n if (zodType instanceof ZodObject) {\n const shape = zodType._def.shape() as Record<string, ZodTypeAny>;\n const properties: Record<string, ParamSchema> = {};\n\n for (const [key, value] of Object.entries(shape)) {\n if (value) {\n const converted = convertZodType(value);\n // In Zod, fields are required by default unless wrapped in .optional()\n if (converted.required === undefined) {\n converted.required = true;\n }\n properties[key] = converted;\n }\n }\n\n return { type: 'object', properties };\n }\n\n // ZodArray — convert item type\n if (zodType instanceof ZodArray) {\n const itemSchema = convertZodType(zodType._def.type as ZodTypeAny);\n return { type: 'array', items: itemSchema };\n }\n\n // ZodUnion — use first variant as a best-effort conversion\n if (zodType instanceof ZodUnion) {\n const options = zodType._def.options as ZodTypeAny[];\n if (options.length > 0 && options[0]) {\n return convertZodTypeInner(options[0]);\n }\n return { type: 'string' };\n }\n\n // Fallback for unsupported types\n return { type: 'string' };\n}\n\n/**\n * Convert a Zod object schema to Surf's `Record<string, ParamSchema>` format.\n * This is the primary conversion function used by `defineZodCommand`.\n *\n * @param schema - A `z.object({...})` schema defining command parameters\n * @returns A record of parameter names to their Surf ParamSchema definitions\n */\nexport function zodToSurfParams(\n schema: ZodObject<Record<string, ZodTypeAny>>,\n): Record<string, ParamSchema> {\n const shape = schema._def.shape() as Record<string, ZodTypeAny>;\n const result: Record<string, ParamSchema> = {};\n\n for (const [key, value] of Object.entries(shape)) {\n if (value) {\n const converted = convertZodType(value);\n // Top-level params: required by default unless explicitly optional\n if (converted.required === undefined) {\n converted.required = true;\n }\n result[key] = converted;\n }\n }\n\n return result;\n}\n","import type { ZodObject, ZodTypeAny } from 'zod';\nimport type { MiddlewareContext, SurfMiddleware } from '@surfjs/core';\n\n/**\n * Create a Surf middleware that validates command params against a Zod schema.\n * Use this for runtime validation in addition to (or instead of) Surf's built-in validation.\n *\n * @param schema - A `z.object({...})` schema to validate incoming params against\n * @returns A SurfMiddleware function\n *\n * @example\n * ```ts\n * import { z } from 'zod';\n * import { zodValidator } from '@surfjs/zod';\n *\n * const schema = z.object({\n * query: z.string().min(1),\n * limit: z.number().int().min(1).max(100).optional(),\n * });\n *\n * // Use as middleware in a Surf config\n * middleware: [zodValidator(schema)]\n * ```\n */\nexport function zodValidator(\n schema: ZodObject<Record<string, ZodTypeAny>>,\n): SurfMiddleware {\n return async (ctx: MiddlewareContext, next: () => Promise<void>) => {\n const parseResult = schema.safeParse(ctx.params);\n\n if (!parseResult.success) {\n const issues = parseResult.error.issues;\n const message = issues\n .map((issue) => `${issue.path.join('.')}: ${issue.message}`)\n .join('; ');\n\n ctx.error = {\n ok: false,\n error: {\n code: 'INVALID_PARAMS',\n message: `Zod validation failed: ${message}`,\n details: {\n issues: issues.map((issue) => ({\n path: issue.path,\n message: issue.message,\n code: issue.code,\n })),\n },\n },\n };\n return;\n }\n\n // Replace params with parsed (and potentially transformed/defaulted) values\n ctx.params = parseResult.data as Record<string, unknown>;\n await next();\n };\n}\n","import type { ZodObject, ZodTypeAny, infer as ZodInfer } from 'zod';\nimport type {\n CommandDefinition,\n CommandHints,\n CommandExample,\n ExecutionContext,\n PaginationConfig,\n ParamSchema,\n RateLimitConfig,\n TypeRef,\n} from '@surfjs/core';\nimport { zodToSurfParams } from './convert.js';\n\nexport { zodToSurfParams, convertZodType } from './convert.js';\nexport { zodValidator } from './validate.js';\n\n/**\n * Configuration for defining a Surf command using a Zod schema.\n * The `params` field accepts a `z.object({...})` instead of raw `ParamSchema`.\n */\nexport interface ZodCommandConfig<\n S extends ZodObject<Record<string, ZodTypeAny>>,\n R = unknown,\n> {\n /** Human-readable description of what this command does (shown to agents). */\n description: string;\n /** Zod object schema defining the command's parameters. */\n params: S;\n /** Return type schema for manifest documentation. */\n returns?: ParamSchema | TypeRef;\n /** Tags for grouping/filtering commands. */\n tags?: string[];\n /** Authentication requirement for this command. */\n auth?: 'none' | 'required' | 'optional' | 'hidden';\n /** Behavioral hints for agent optimization. */\n hints?: CommandHints;\n /** Enable SSE streaming for this command. */\n stream?: boolean;\n /** Per-command rate limiting. */\n rateLimit?: RateLimitConfig;\n /** Example request/response pairs shown in manifest. */\n examples?: CommandExample[];\n /** Enable pagination for this command. */\n paginated?: boolean | PaginationConfig;\n /** The command handler — receives fully-typed params inferred from the Zod schema. */\n run: (params: ZodInfer<S>, ctx: ExecutionContext) => R | Promise<R>;\n}\n\n/**\n * Define a Surf command using a Zod schema for parameters.\n *\n * Converts the Zod schema to Surf's native `ParamSchema` format at runtime,\n * while providing full TypeScript inference from the Zod schema for the handler.\n *\n * @example\n * ```ts\n * import { z } from 'zod';\n * import { defineZodCommand } from '@surfjs/zod';\n *\n * const search = defineZodCommand({\n * description: 'Search products',\n * params: z.object({\n * query: z.string().describe('Search query'),\n * limit: z.number().int().min(1).max(100).optional().default(20),\n * category: z.enum(['electronics', 'clothing', 'books']).optional(),\n * }),\n * run: async ({ query, limit, category }) => {\n * // params are fully typed!\n * return { results: [] };\n * },\n * });\n * ```\n */\nexport function defineZodCommand<\n S extends ZodObject<Record<string, ZodTypeAny>>,\n R = unknown,\n>(config: ZodCommandConfig<S, R>): CommandDefinition {\n const { params: zodSchema, run, ...rest } = config;\n const surfParams = zodToSurfParams(zodSchema);\n\n return {\n ...rest,\n params: surfParams,\n run: run as CommandDefinition['run'],\n };\n}\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { ZodTypeAny, ZodObject, infer } from 'zod';
|
|
2
|
+
import { ParamSchema, SurfMiddleware, TypeRef, CommandHints, RateLimitConfig, CommandExample, PaginationConfig, ExecutionContext, CommandDefinition } from '@surfjs/core';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Convert a single Zod type to a Surf ParamSchema.
|
|
6
|
+
* Recursively handles nested objects, arrays, optionals, defaults, etc.
|
|
7
|
+
*/
|
|
8
|
+
declare function convertZodType(zodType: ZodTypeAny): ParamSchema;
|
|
9
|
+
/**
|
|
10
|
+
* Convert a Zod object schema to Surf's `Record<string, ParamSchema>` format.
|
|
11
|
+
* This is the primary conversion function used by `defineZodCommand`.
|
|
12
|
+
*
|
|
13
|
+
* @param schema - A `z.object({...})` schema defining command parameters
|
|
14
|
+
* @returns A record of parameter names to their Surf ParamSchema definitions
|
|
15
|
+
*/
|
|
16
|
+
declare function zodToSurfParams(schema: ZodObject<Record<string, ZodTypeAny>>): Record<string, ParamSchema>;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Create a Surf middleware that validates command params against a Zod schema.
|
|
20
|
+
* Use this for runtime validation in addition to (or instead of) Surf's built-in validation.
|
|
21
|
+
*
|
|
22
|
+
* @param schema - A `z.object({...})` schema to validate incoming params against
|
|
23
|
+
* @returns A SurfMiddleware function
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```ts
|
|
27
|
+
* import { z } from 'zod';
|
|
28
|
+
* import { zodValidator } from '@surfjs/zod';
|
|
29
|
+
*
|
|
30
|
+
* const schema = z.object({
|
|
31
|
+
* query: z.string().min(1),
|
|
32
|
+
* limit: z.number().int().min(1).max(100).optional(),
|
|
33
|
+
* });
|
|
34
|
+
*
|
|
35
|
+
* // Use as middleware in a Surf config
|
|
36
|
+
* middleware: [zodValidator(schema)]
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
declare function zodValidator(schema: ZodObject<Record<string, ZodTypeAny>>): SurfMiddleware;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Configuration for defining a Surf command using a Zod schema.
|
|
43
|
+
* The `params` field accepts a `z.object({...})` instead of raw `ParamSchema`.
|
|
44
|
+
*/
|
|
45
|
+
interface ZodCommandConfig<S extends ZodObject<Record<string, ZodTypeAny>>, R = unknown> {
|
|
46
|
+
/** Human-readable description of what this command does (shown to agents). */
|
|
47
|
+
description: string;
|
|
48
|
+
/** Zod object schema defining the command's parameters. */
|
|
49
|
+
params: S;
|
|
50
|
+
/** Return type schema for manifest documentation. */
|
|
51
|
+
returns?: ParamSchema | TypeRef;
|
|
52
|
+
/** Tags for grouping/filtering commands. */
|
|
53
|
+
tags?: string[];
|
|
54
|
+
/** Authentication requirement for this command. */
|
|
55
|
+
auth?: 'none' | 'required' | 'optional' | 'hidden';
|
|
56
|
+
/** Behavioral hints for agent optimization. */
|
|
57
|
+
hints?: CommandHints;
|
|
58
|
+
/** Enable SSE streaming for this command. */
|
|
59
|
+
stream?: boolean;
|
|
60
|
+
/** Per-command rate limiting. */
|
|
61
|
+
rateLimit?: RateLimitConfig;
|
|
62
|
+
/** Example request/response pairs shown in manifest. */
|
|
63
|
+
examples?: CommandExample[];
|
|
64
|
+
/** Enable pagination for this command. */
|
|
65
|
+
paginated?: boolean | PaginationConfig;
|
|
66
|
+
/** The command handler — receives fully-typed params inferred from the Zod schema. */
|
|
67
|
+
run: (params: infer<S>, ctx: ExecutionContext) => R | Promise<R>;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Define a Surf command using a Zod schema for parameters.
|
|
71
|
+
*
|
|
72
|
+
* Converts the Zod schema to Surf's native `ParamSchema` format at runtime,
|
|
73
|
+
* while providing full TypeScript inference from the Zod schema for the handler.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```ts
|
|
77
|
+
* import { z } from 'zod';
|
|
78
|
+
* import { defineZodCommand } from '@surfjs/zod';
|
|
79
|
+
*
|
|
80
|
+
* const search = defineZodCommand({
|
|
81
|
+
* description: 'Search products',
|
|
82
|
+
* params: z.object({
|
|
83
|
+
* query: z.string().describe('Search query'),
|
|
84
|
+
* limit: z.number().int().min(1).max(100).optional().default(20),
|
|
85
|
+
* category: z.enum(['electronics', 'clothing', 'books']).optional(),
|
|
86
|
+
* }),
|
|
87
|
+
* run: async ({ query, limit, category }) => {
|
|
88
|
+
* // params are fully typed!
|
|
89
|
+
* return { results: [] };
|
|
90
|
+
* },
|
|
91
|
+
* });
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
declare function defineZodCommand<S extends ZodObject<Record<string, ZodTypeAny>>, R = unknown>(config: ZodCommandConfig<S, R>): CommandDefinition;
|
|
95
|
+
|
|
96
|
+
export { type ZodCommandConfig, convertZodType, defineZodCommand, zodToSurfParams, zodValidator };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { ZodTypeAny, ZodObject, infer } from 'zod';
|
|
2
|
+
import { ParamSchema, SurfMiddleware, TypeRef, CommandHints, RateLimitConfig, CommandExample, PaginationConfig, ExecutionContext, CommandDefinition } from '@surfjs/core';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Convert a single Zod type to a Surf ParamSchema.
|
|
6
|
+
* Recursively handles nested objects, arrays, optionals, defaults, etc.
|
|
7
|
+
*/
|
|
8
|
+
declare function convertZodType(zodType: ZodTypeAny): ParamSchema;
|
|
9
|
+
/**
|
|
10
|
+
* Convert a Zod object schema to Surf's `Record<string, ParamSchema>` format.
|
|
11
|
+
* This is the primary conversion function used by `defineZodCommand`.
|
|
12
|
+
*
|
|
13
|
+
* @param schema - A `z.object({...})` schema defining command parameters
|
|
14
|
+
* @returns A record of parameter names to their Surf ParamSchema definitions
|
|
15
|
+
*/
|
|
16
|
+
declare function zodToSurfParams(schema: ZodObject<Record<string, ZodTypeAny>>): Record<string, ParamSchema>;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Create a Surf middleware that validates command params against a Zod schema.
|
|
20
|
+
* Use this for runtime validation in addition to (or instead of) Surf's built-in validation.
|
|
21
|
+
*
|
|
22
|
+
* @param schema - A `z.object({...})` schema to validate incoming params against
|
|
23
|
+
* @returns A SurfMiddleware function
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```ts
|
|
27
|
+
* import { z } from 'zod';
|
|
28
|
+
* import { zodValidator } from '@surfjs/zod';
|
|
29
|
+
*
|
|
30
|
+
* const schema = z.object({
|
|
31
|
+
* query: z.string().min(1),
|
|
32
|
+
* limit: z.number().int().min(1).max(100).optional(),
|
|
33
|
+
* });
|
|
34
|
+
*
|
|
35
|
+
* // Use as middleware in a Surf config
|
|
36
|
+
* middleware: [zodValidator(schema)]
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
declare function zodValidator(schema: ZodObject<Record<string, ZodTypeAny>>): SurfMiddleware;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Configuration for defining a Surf command using a Zod schema.
|
|
43
|
+
* The `params` field accepts a `z.object({...})` instead of raw `ParamSchema`.
|
|
44
|
+
*/
|
|
45
|
+
interface ZodCommandConfig<S extends ZodObject<Record<string, ZodTypeAny>>, R = unknown> {
|
|
46
|
+
/** Human-readable description of what this command does (shown to agents). */
|
|
47
|
+
description: string;
|
|
48
|
+
/** Zod object schema defining the command's parameters. */
|
|
49
|
+
params: S;
|
|
50
|
+
/** Return type schema for manifest documentation. */
|
|
51
|
+
returns?: ParamSchema | TypeRef;
|
|
52
|
+
/** Tags for grouping/filtering commands. */
|
|
53
|
+
tags?: string[];
|
|
54
|
+
/** Authentication requirement for this command. */
|
|
55
|
+
auth?: 'none' | 'required' | 'optional' | 'hidden';
|
|
56
|
+
/** Behavioral hints for agent optimization. */
|
|
57
|
+
hints?: CommandHints;
|
|
58
|
+
/** Enable SSE streaming for this command. */
|
|
59
|
+
stream?: boolean;
|
|
60
|
+
/** Per-command rate limiting. */
|
|
61
|
+
rateLimit?: RateLimitConfig;
|
|
62
|
+
/** Example request/response pairs shown in manifest. */
|
|
63
|
+
examples?: CommandExample[];
|
|
64
|
+
/** Enable pagination for this command. */
|
|
65
|
+
paginated?: boolean | PaginationConfig;
|
|
66
|
+
/** The command handler — receives fully-typed params inferred from the Zod schema. */
|
|
67
|
+
run: (params: infer<S>, ctx: ExecutionContext) => R | Promise<R>;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Define a Surf command using a Zod schema for parameters.
|
|
71
|
+
*
|
|
72
|
+
* Converts the Zod schema to Surf's native `ParamSchema` format at runtime,
|
|
73
|
+
* while providing full TypeScript inference from the Zod schema for the handler.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```ts
|
|
77
|
+
* import { z } from 'zod';
|
|
78
|
+
* import { defineZodCommand } from '@surfjs/zod';
|
|
79
|
+
*
|
|
80
|
+
* const search = defineZodCommand({
|
|
81
|
+
* description: 'Search products',
|
|
82
|
+
* params: z.object({
|
|
83
|
+
* query: z.string().describe('Search query'),
|
|
84
|
+
* limit: z.number().int().min(1).max(100).optional().default(20),
|
|
85
|
+
* category: z.enum(['electronics', 'clothing', 'books']).optional(),
|
|
86
|
+
* }),
|
|
87
|
+
* run: async ({ query, limit, category }) => {
|
|
88
|
+
* // params are fully typed!
|
|
89
|
+
* return { results: [] };
|
|
90
|
+
* },
|
|
91
|
+
* });
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
declare function defineZodCommand<S extends ZodObject<Record<string, ZodTypeAny>>, R = unknown>(config: ZodCommandConfig<S, R>): CommandDefinition;
|
|
95
|
+
|
|
96
|
+
export { type ZodCommandConfig, convertZodType, defineZodCommand, zodToSurfParams, zodValidator };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { ZodEffects, ZodDefault, ZodOptional, ZodNullable, ZodString, ZodNumber, ZodBoolean, ZodLiteral, ZodEnum, ZodNativeEnum, ZodObject, ZodArray, ZodUnion } from 'zod';
|
|
2
|
+
|
|
3
|
+
// src/convert.ts
|
|
4
|
+
function convertZodType(zodType) {
|
|
5
|
+
const description = zodType.description;
|
|
6
|
+
const base = convertZodTypeInner(zodType);
|
|
7
|
+
if (description) {
|
|
8
|
+
base.description = description;
|
|
9
|
+
}
|
|
10
|
+
return base;
|
|
11
|
+
}
|
|
12
|
+
function convertZodTypeInner(zodType) {
|
|
13
|
+
if (zodType instanceof ZodEffects) {
|
|
14
|
+
return convertZodTypeInner(zodType._def.schema);
|
|
15
|
+
}
|
|
16
|
+
if (zodType instanceof ZodDefault) {
|
|
17
|
+
const inner = convertZodTypeInner(zodType._def.innerType);
|
|
18
|
+
inner.default = zodType._def.defaultValue();
|
|
19
|
+
return inner;
|
|
20
|
+
}
|
|
21
|
+
if (zodType instanceof ZodOptional) {
|
|
22
|
+
const inner = convertZodTypeInner(zodType._def.innerType);
|
|
23
|
+
inner.required = false;
|
|
24
|
+
return inner;
|
|
25
|
+
}
|
|
26
|
+
if (zodType instanceof ZodNullable) {
|
|
27
|
+
const inner = convertZodTypeInner(zodType._def.innerType);
|
|
28
|
+
inner.required = false;
|
|
29
|
+
return inner;
|
|
30
|
+
}
|
|
31
|
+
if (zodType instanceof ZodString) {
|
|
32
|
+
return { type: "string" };
|
|
33
|
+
}
|
|
34
|
+
if (zodType instanceof ZodNumber) {
|
|
35
|
+
return { type: "number" };
|
|
36
|
+
}
|
|
37
|
+
if (zodType instanceof ZodBoolean) {
|
|
38
|
+
return { type: "boolean" };
|
|
39
|
+
}
|
|
40
|
+
if (zodType instanceof ZodLiteral) {
|
|
41
|
+
const value = zodType._def.value;
|
|
42
|
+
if (typeof value === "string") {
|
|
43
|
+
return { type: "string", enum: [value] };
|
|
44
|
+
}
|
|
45
|
+
if (typeof value === "number") {
|
|
46
|
+
return { type: "number" };
|
|
47
|
+
}
|
|
48
|
+
if (typeof value === "boolean") {
|
|
49
|
+
return { type: "boolean" };
|
|
50
|
+
}
|
|
51
|
+
return { type: "string" };
|
|
52
|
+
}
|
|
53
|
+
if (zodType instanceof ZodEnum) {
|
|
54
|
+
const values = zodType._def.values;
|
|
55
|
+
return { type: "string", enum: values };
|
|
56
|
+
}
|
|
57
|
+
if (zodType instanceof ZodNativeEnum) {
|
|
58
|
+
const enumObj = zodType._def.values;
|
|
59
|
+
const values = Object.values(enumObj).filter(
|
|
60
|
+
(v) => typeof v === "string"
|
|
61
|
+
);
|
|
62
|
+
if (values.length > 0) {
|
|
63
|
+
return { type: "string", enum: values };
|
|
64
|
+
}
|
|
65
|
+
return { type: "string" };
|
|
66
|
+
}
|
|
67
|
+
if (zodType instanceof ZodObject) {
|
|
68
|
+
const shape = zodType._def.shape();
|
|
69
|
+
const properties = {};
|
|
70
|
+
for (const [key, value] of Object.entries(shape)) {
|
|
71
|
+
if (value) {
|
|
72
|
+
const converted = convertZodType(value);
|
|
73
|
+
if (converted.required === void 0) {
|
|
74
|
+
converted.required = true;
|
|
75
|
+
}
|
|
76
|
+
properties[key] = converted;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return { type: "object", properties };
|
|
80
|
+
}
|
|
81
|
+
if (zodType instanceof ZodArray) {
|
|
82
|
+
const itemSchema = convertZodType(zodType._def.type);
|
|
83
|
+
return { type: "array", items: itemSchema };
|
|
84
|
+
}
|
|
85
|
+
if (zodType instanceof ZodUnion) {
|
|
86
|
+
const options = zodType._def.options;
|
|
87
|
+
if (options.length > 0 && options[0]) {
|
|
88
|
+
return convertZodTypeInner(options[0]);
|
|
89
|
+
}
|
|
90
|
+
return { type: "string" };
|
|
91
|
+
}
|
|
92
|
+
return { type: "string" };
|
|
93
|
+
}
|
|
94
|
+
function zodToSurfParams(schema) {
|
|
95
|
+
const shape = schema._def.shape();
|
|
96
|
+
const result = {};
|
|
97
|
+
for (const [key, value] of Object.entries(shape)) {
|
|
98
|
+
if (value) {
|
|
99
|
+
const converted = convertZodType(value);
|
|
100
|
+
if (converted.required === void 0) {
|
|
101
|
+
converted.required = true;
|
|
102
|
+
}
|
|
103
|
+
result[key] = converted;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return result;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// src/validate.ts
|
|
110
|
+
function zodValidator(schema) {
|
|
111
|
+
return async (ctx, next) => {
|
|
112
|
+
const parseResult = schema.safeParse(ctx.params);
|
|
113
|
+
if (!parseResult.success) {
|
|
114
|
+
const issues = parseResult.error.issues;
|
|
115
|
+
const message = issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`).join("; ");
|
|
116
|
+
ctx.error = {
|
|
117
|
+
ok: false,
|
|
118
|
+
error: {
|
|
119
|
+
code: "INVALID_PARAMS",
|
|
120
|
+
message: `Zod validation failed: ${message}`,
|
|
121
|
+
details: {
|
|
122
|
+
issues: issues.map((issue) => ({
|
|
123
|
+
path: issue.path,
|
|
124
|
+
message: issue.message,
|
|
125
|
+
code: issue.code
|
|
126
|
+
}))
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
ctx.params = parseResult.data;
|
|
133
|
+
await next();
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// src/index.ts
|
|
138
|
+
function defineZodCommand(config) {
|
|
139
|
+
const { params: zodSchema, run, ...rest } = config;
|
|
140
|
+
const surfParams = zodToSurfParams(zodSchema);
|
|
141
|
+
return {
|
|
142
|
+
...rest,
|
|
143
|
+
params: surfParams,
|
|
144
|
+
run
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export { convertZodType, defineZodCommand, zodToSurfParams, zodValidator };
|
|
149
|
+
//# sourceMappingURL=index.js.map
|
|
150
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/convert.ts","../src/validate.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { ParamSchema } from '@surfjs/core';\nimport {\n type ZodTypeAny,\n ZodString,\n ZodNumber,\n ZodBoolean,\n ZodEnum,\n ZodObject,\n ZodArray,\n ZodOptional,\n ZodDefault,\n ZodNullable,\n ZodEffects,\n ZodLiteral,\n ZodUnion,\n ZodNativeEnum,\n} from 'zod';\n\n/**\n * Convert a single Zod type to a Surf ParamSchema.\n * Recursively handles nested objects, arrays, optionals, defaults, etc.\n */\nexport function convertZodType(zodType: ZodTypeAny): ParamSchema {\n const description = zodType.description;\n const base = convertZodTypeInner(zodType);\n\n if (description) {\n base.description = description;\n }\n\n return base;\n}\n\nfunction convertZodTypeInner(zodType: ZodTypeAny): ParamSchema {\n // Unwrap ZodEffects (refinements, transforms, preprocess)\n if (zodType instanceof ZodEffects) {\n return convertZodTypeInner(zodType._def.schema as ZodTypeAny);\n }\n\n // ZodDefault — extract default value, recurse into inner type\n if (zodType instanceof ZodDefault) {\n const inner = convertZodTypeInner(zodType._def.innerType as ZodTypeAny);\n inner.default = zodType._def.defaultValue();\n return inner;\n }\n\n // ZodOptional — mark as not required, recurse\n if (zodType instanceof ZodOptional) {\n const inner = convertZodTypeInner(zodType._def.innerType as ZodTypeAny);\n inner.required = false;\n return inner;\n }\n\n // ZodNullable — treat like optional for Surf's purposes\n if (zodType instanceof ZodNullable) {\n const inner = convertZodTypeInner(zodType._def.innerType as ZodTypeAny);\n inner.required = false;\n return inner;\n }\n\n // Primitives\n if (zodType instanceof ZodString) {\n return { type: 'string' };\n }\n\n if (zodType instanceof ZodNumber) {\n return { type: 'number' };\n }\n\n if (zodType instanceof ZodBoolean) {\n return { type: 'boolean' };\n }\n\n // ZodLiteral — infer type from value\n if (zodType instanceof ZodLiteral) {\n const value = zodType._def.value as unknown;\n if (typeof value === 'string') {\n return { type: 'string', enum: [value] };\n }\n if (typeof value === 'number') {\n return { type: 'number' };\n }\n if (typeof value === 'boolean') {\n return { type: 'boolean' };\n }\n return { type: 'string' };\n }\n\n // ZodEnum — string enum\n if (zodType instanceof ZodEnum) {\n const values = zodType._def.values as readonly string[];\n return { type: 'string', enum: values };\n }\n\n // ZodNativeEnum — JS enum\n if (zodType instanceof ZodNativeEnum) {\n const enumObj = zodType._def.values as Record<string, string | number>;\n const values = Object.values(enumObj).filter(\n (v): v is string => typeof v === 'string',\n );\n if (values.length > 0) {\n return { type: 'string', enum: values };\n }\n return { type: 'string' };\n }\n\n // ZodObject — recursive conversion\n if (zodType instanceof ZodObject) {\n const shape = zodType._def.shape() as Record<string, ZodTypeAny>;\n const properties: Record<string, ParamSchema> = {};\n\n for (const [key, value] of Object.entries(shape)) {\n if (value) {\n const converted = convertZodType(value);\n // In Zod, fields are required by default unless wrapped in .optional()\n if (converted.required === undefined) {\n converted.required = true;\n }\n properties[key] = converted;\n }\n }\n\n return { type: 'object', properties };\n }\n\n // ZodArray — convert item type\n if (zodType instanceof ZodArray) {\n const itemSchema = convertZodType(zodType._def.type as ZodTypeAny);\n return { type: 'array', items: itemSchema };\n }\n\n // ZodUnion — use first variant as a best-effort conversion\n if (zodType instanceof ZodUnion) {\n const options = zodType._def.options as ZodTypeAny[];\n if (options.length > 0 && options[0]) {\n return convertZodTypeInner(options[0]);\n }\n return { type: 'string' };\n }\n\n // Fallback for unsupported types\n return { type: 'string' };\n}\n\n/**\n * Convert a Zod object schema to Surf's `Record<string, ParamSchema>` format.\n * This is the primary conversion function used by `defineZodCommand`.\n *\n * @param schema - A `z.object({...})` schema defining command parameters\n * @returns A record of parameter names to their Surf ParamSchema definitions\n */\nexport function zodToSurfParams(\n schema: ZodObject<Record<string, ZodTypeAny>>,\n): Record<string, ParamSchema> {\n const shape = schema._def.shape() as Record<string, ZodTypeAny>;\n const result: Record<string, ParamSchema> = {};\n\n for (const [key, value] of Object.entries(shape)) {\n if (value) {\n const converted = convertZodType(value);\n // Top-level params: required by default unless explicitly optional\n if (converted.required === undefined) {\n converted.required = true;\n }\n result[key] = converted;\n }\n }\n\n return result;\n}\n","import type { ZodObject, ZodTypeAny } from 'zod';\nimport type { MiddlewareContext, SurfMiddleware } from '@surfjs/core';\n\n/**\n * Create a Surf middleware that validates command params against a Zod schema.\n * Use this for runtime validation in addition to (or instead of) Surf's built-in validation.\n *\n * @param schema - A `z.object({...})` schema to validate incoming params against\n * @returns A SurfMiddleware function\n *\n * @example\n * ```ts\n * import { z } from 'zod';\n * import { zodValidator } from '@surfjs/zod';\n *\n * const schema = z.object({\n * query: z.string().min(1),\n * limit: z.number().int().min(1).max(100).optional(),\n * });\n *\n * // Use as middleware in a Surf config\n * middleware: [zodValidator(schema)]\n * ```\n */\nexport function zodValidator(\n schema: ZodObject<Record<string, ZodTypeAny>>,\n): SurfMiddleware {\n return async (ctx: MiddlewareContext, next: () => Promise<void>) => {\n const parseResult = schema.safeParse(ctx.params);\n\n if (!parseResult.success) {\n const issues = parseResult.error.issues;\n const message = issues\n .map((issue) => `${issue.path.join('.')}: ${issue.message}`)\n .join('; ');\n\n ctx.error = {\n ok: false,\n error: {\n code: 'INVALID_PARAMS',\n message: `Zod validation failed: ${message}`,\n details: {\n issues: issues.map((issue) => ({\n path: issue.path,\n message: issue.message,\n code: issue.code,\n })),\n },\n },\n };\n return;\n }\n\n // Replace params with parsed (and potentially transformed/defaulted) values\n ctx.params = parseResult.data as Record<string, unknown>;\n await next();\n };\n}\n","import type { ZodObject, ZodTypeAny, infer as ZodInfer } from 'zod';\nimport type {\n CommandDefinition,\n CommandHints,\n CommandExample,\n ExecutionContext,\n PaginationConfig,\n ParamSchema,\n RateLimitConfig,\n TypeRef,\n} from '@surfjs/core';\nimport { zodToSurfParams } from './convert.js';\n\nexport { zodToSurfParams, convertZodType } from './convert.js';\nexport { zodValidator } from './validate.js';\n\n/**\n * Configuration for defining a Surf command using a Zod schema.\n * The `params` field accepts a `z.object({...})` instead of raw `ParamSchema`.\n */\nexport interface ZodCommandConfig<\n S extends ZodObject<Record<string, ZodTypeAny>>,\n R = unknown,\n> {\n /** Human-readable description of what this command does (shown to agents). */\n description: string;\n /** Zod object schema defining the command's parameters. */\n params: S;\n /** Return type schema for manifest documentation. */\n returns?: ParamSchema | TypeRef;\n /** Tags for grouping/filtering commands. */\n tags?: string[];\n /** Authentication requirement for this command. */\n auth?: 'none' | 'required' | 'optional' | 'hidden';\n /** Behavioral hints for agent optimization. */\n hints?: CommandHints;\n /** Enable SSE streaming for this command. */\n stream?: boolean;\n /** Per-command rate limiting. */\n rateLimit?: RateLimitConfig;\n /** Example request/response pairs shown in manifest. */\n examples?: CommandExample[];\n /** Enable pagination for this command. */\n paginated?: boolean | PaginationConfig;\n /** The command handler — receives fully-typed params inferred from the Zod schema. */\n run: (params: ZodInfer<S>, ctx: ExecutionContext) => R | Promise<R>;\n}\n\n/**\n * Define a Surf command using a Zod schema for parameters.\n *\n * Converts the Zod schema to Surf's native `ParamSchema` format at runtime,\n * while providing full TypeScript inference from the Zod schema for the handler.\n *\n * @example\n * ```ts\n * import { z } from 'zod';\n * import { defineZodCommand } from '@surfjs/zod';\n *\n * const search = defineZodCommand({\n * description: 'Search products',\n * params: z.object({\n * query: z.string().describe('Search query'),\n * limit: z.number().int().min(1).max(100).optional().default(20),\n * category: z.enum(['electronics', 'clothing', 'books']).optional(),\n * }),\n * run: async ({ query, limit, category }) => {\n * // params are fully typed!\n * return { results: [] };\n * },\n * });\n * ```\n */\nexport function defineZodCommand<\n S extends ZodObject<Record<string, ZodTypeAny>>,\n R = unknown,\n>(config: ZodCommandConfig<S, R>): CommandDefinition {\n const { params: zodSchema, run, ...rest } = config;\n const surfParams = zodToSurfParams(zodSchema);\n\n return {\n ...rest,\n params: surfParams,\n run: run as CommandDefinition['run'],\n };\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@surfjs/zod",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Zod schema integration for Surf.js — define commands with Zod instead of raw ParamSchema",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/index.d.cts",
|
|
17
|
+
"default": "./dist/index.cjs"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist"
|
|
23
|
+
],
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsup",
|
|
26
|
+
"dev": "tsup --watch",
|
|
27
|
+
"typecheck": "tsc --noEmit"
|
|
28
|
+
},
|
|
29
|
+
"peerDependencies": {
|
|
30
|
+
"@surfjs/core": ">=0.2.0",
|
|
31
|
+
"zod": ">=3.0.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@surfjs/core": "workspace:*",
|
|
35
|
+
"tsup": "^8.5.1",
|
|
36
|
+
"typescript": "^5.8.0",
|
|
37
|
+
"zod": "^3.24.0"
|
|
38
|
+
},
|
|
39
|
+
"license": "MIT",
|
|
40
|
+
"keywords": [
|
|
41
|
+
"surf",
|
|
42
|
+
"zod",
|
|
43
|
+
"schema",
|
|
44
|
+
"validation",
|
|
45
|
+
"ai",
|
|
46
|
+
"agents",
|
|
47
|
+
"protocol"
|
|
48
|
+
],
|
|
49
|
+
"repository": {
|
|
50
|
+
"type": "git",
|
|
51
|
+
"url": "https://github.com/hauselabs/surf.git",
|
|
52
|
+
"directory": "packages/zod"
|
|
53
|
+
},
|
|
54
|
+
"homepage": "https://surf.codes",
|
|
55
|
+
"bugs": {
|
|
56
|
+
"url": "https://github.com/hauselabs/surf/issues"
|
|
57
|
+
},
|
|
58
|
+
"publishConfig": {
|
|
59
|
+
"access": "public"
|
|
60
|
+
}
|
|
61
|
+
}
|