@output.ai/core 0.0.13 → 0.0.14
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/package.json +1 -2
- package/src/index.d.ts +74 -171
- package/src/index.js +2 -1
- package/src/interface/schema_utils.js +34 -0
- package/src/interface/schema_utils.spec.js +67 -0
- package/src/interface/step.js +14 -8
- package/src/interface/validations/static.js +11 -10
- package/src/interface/validations/static.spec.js +14 -15
- package/src/interface/workflow.js +12 -12
- package/src/interface/zod_integration.spec.js +646 -0
- package/src/interface/validations/ajv_provider.js +0 -3
- package/src/interface/validations/runtime.js +0 -69
- package/src/interface/validations/runtime.spec.js +0 -50
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@output.ai/core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.14",
|
|
4
4
|
"description": "The core module of the output framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -27,7 +27,6 @@
|
|
|
27
27
|
"@babel/types": "7.28.4",
|
|
28
28
|
"@temporalio/worker": "1.13.0",
|
|
29
29
|
"@temporalio/workflow": "1.13.0",
|
|
30
|
-
"ajv": "8.17.1",
|
|
31
30
|
"zod": "4.1.9"
|
|
32
31
|
},
|
|
33
32
|
"imports": {
|
package/src/index.d.ts
CHANGED
|
@@ -1,175 +1,100 @@
|
|
|
1
|
-
//
|
|
2
|
-
type
|
|
3
|
-
type EnumValues = readonly ( string | number | boolean | null )[];
|
|
1
|
+
// Import Zod types for dual schema support
|
|
2
|
+
import type { z } from 'zod';
|
|
4
3
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
enum?: EnumValues;
|
|
8
|
-
const?: string | number | boolean | null;
|
|
9
|
-
anyOf?: readonly JSONSchema[];
|
|
10
|
-
oneOf?: readonly JSONSchema[];
|
|
11
|
-
allOf?: readonly JSONSchema[];
|
|
12
|
-
// object
|
|
13
|
-
properties?: { [key: string]: JSONSchema };
|
|
14
|
-
required?: readonly string[];
|
|
15
|
-
additionalProperties?: boolean | JSONSchema;
|
|
16
|
-
// array
|
|
17
|
-
items?: JSONSchema | readonly JSONSchema[];
|
|
18
|
-
// ignore $ref & others for typing purposes
|
|
19
|
-
$ref?: string;
|
|
20
|
-
} & Record<string, unknown>;
|
|
4
|
+
// Re-export Zod for consumers to use
|
|
5
|
+
export { z } from 'zod';
|
|
21
6
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
: Record<never, never>;
|
|
37
|
-
|
|
38
|
-
type ObjectRequiredKeys<S extends JSONSchema> = S extends { required: readonly ( infer R )[] }
|
|
39
|
-
? Extract<R & string, keyof ObjectProps<S>>
|
|
40
|
-
: never;
|
|
41
|
-
|
|
42
|
-
type ObjectFrom<S extends JSONSchema> = Simplify<
|
|
43
|
-
Pick<ObjectProps<S>, ObjectRequiredKeys<S>> &
|
|
44
|
-
Partial<Omit<ObjectProps<S>, ObjectRequiredKeys<S>>>
|
|
45
|
-
>;
|
|
46
|
-
|
|
47
|
-
type ArrayFrom<S extends JSONSchema> = S extends { items: infer I }
|
|
48
|
-
? I extends readonly unknown[]
|
|
49
|
-
? FromSchema<I[number]>[]
|
|
50
|
-
: FromSchema<I>[]
|
|
51
|
-
: unknown[];
|
|
52
|
-
|
|
53
|
-
export type FromSchema<S extends JSONSchema> =
|
|
54
|
-
// combinators first
|
|
55
|
-
S extends { anyOf: infer A extends readonly JSONSchema[] } ? FromSchema<A[number]> :
|
|
56
|
-
S extends { oneOf: infer A extends readonly JSONSchema[] } ? FromSchema<A[number]> :
|
|
57
|
-
S extends { allOf: infer A extends readonly JSONSchema[] } ? UnionToIntersection<FromSchema<A[number]>> :
|
|
58
|
-
// enum/const
|
|
59
|
-
FromEnum<S> extends never ? ( FromConst<S> extends never ? (
|
|
60
|
-
// object (explicit or by presence of properties)
|
|
61
|
-
S extends { type: 'object' } | { properties: Record<string, JSONSchema> } ? ObjectFrom<S> :
|
|
62
|
-
// array
|
|
63
|
-
S extends { type: 'array' } ? ArrayFrom<S> :
|
|
64
|
-
// primitives
|
|
65
|
-
FromPrimitive<S> extends never ? unknown : FromPrimitive<S>
|
|
66
|
-
) : FromConst<S> ) : FromEnum<S>;
|
|
67
|
-
|
|
68
|
-
export type OutputFrom<O extends JSONSchema> = FromSchema<O>;
|
|
69
|
-
|
|
70
|
-
// Utility to strip readonly from inferred types
|
|
71
|
-
/** Recursively removes readonly modifiers from object and array types. */
|
|
72
|
-
type DeepMutable<T> =
|
|
73
|
-
T extends readonly ( infer U )[] ? DeepMutable<U>[] :
|
|
74
|
-
T extends object ? { -readonly [K in keyof T]: DeepMutable<T[K]> } :
|
|
75
|
-
T;
|
|
7
|
+
/**
|
|
8
|
+
* Type alias for any Zod schema type.
|
|
9
|
+
*
|
|
10
|
+
* Note: The use of `any` here is intentional and necessary. Zod's ZodType has three
|
|
11
|
+
* generic parameters (Output, Def, Input) that vary based on the specific schema type.
|
|
12
|
+
* When we want to accept ANY Zod schema (string, number, object, etc.), we must use
|
|
13
|
+
* `any` for these parameters. Using `unknown` would be too restrictive and would
|
|
14
|
+
* break Zod's type inference system.
|
|
15
|
+
*
|
|
16
|
+
* This is a common pattern in TypeScript when dealing with highly generic types,
|
|
17
|
+
* and Zod itself uses this pattern internally.
|
|
18
|
+
*/
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
20
|
+
type AnyZodSchema = z.ZodType<any, any, any>;
|
|
76
21
|
|
|
77
22
|
/*
|
|
78
|
-
* There
|
|
23
|
+
* There are 4 overloads of the "step" function:
|
|
79
24
|
* - with fn receiving input and returning output;
|
|
80
25
|
* - with fn receiving input and returning void;
|
|
81
|
-
* - with fn receiving void and returning
|
|
26
|
+
* - with fn receiving void and returning output;
|
|
82
27
|
* - with fn receiving void and returning void;
|
|
83
28
|
*/
|
|
84
29
|
|
|
85
30
|
/**
|
|
86
|
-
*
|
|
87
|
-
* @param {any} input - The input, defined by the inputSchema
|
|
88
|
-
* @returns {any} The output defined by the outputSchema
|
|
89
|
-
*/
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Creates logical unit of work, called "step", which will be invoked from workflows.
|
|
31
|
+
* Creates logical unit of work with Zod schemas for both input and output.
|
|
93
32
|
*
|
|
94
33
|
* @param {object} options - Step options
|
|
95
34
|
* @param {string} options.name - Human-readable step name (only letters, numbers and "_")
|
|
96
35
|
* @param {string} [options.description] - Description of the step
|
|
97
|
-
* @param {
|
|
98
|
-
* @param {
|
|
99
|
-
* @param {
|
|
100
|
-
* @returns {
|
|
36
|
+
* @param {z.ZodType} options.inputSchema - Zod schema for the fn input
|
|
37
|
+
* @param {z.ZodType} options.outputSchema - Zod schema for the fn output
|
|
38
|
+
* @param {function} options.fn - The function logic: `(input: z.infer<InputSchema>) => Promise<z.infer<OutputSchema>>`
|
|
39
|
+
* @returns {function} Function with signature: `(input: z.infer<InputSchema>) => Promise<z.infer<OutputSchema>>`
|
|
101
40
|
*/
|
|
102
41
|
export async function step<
|
|
103
|
-
|
|
104
|
-
|
|
42
|
+
InputSchema extends AnyZodSchema,
|
|
43
|
+
OutputSchema extends AnyZodSchema
|
|
105
44
|
>( options: {
|
|
106
45
|
name: string;
|
|
107
46
|
description?: string;
|
|
108
47
|
inputSchema: InputSchema;
|
|
109
48
|
outputSchema: OutputSchema;
|
|
110
|
-
fn: ( input:
|
|
111
|
-
} ): ( input:
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* @callback InputOnlyStepFn
|
|
115
|
-
* @param {any} input - The input, defined by the inputSchema
|
|
116
|
-
*/
|
|
49
|
+
fn: ( input: z.infer<InputSchema> ) => Promise<z.infer<OutputSchema>>;
|
|
50
|
+
} ): ( input: z.infer<InputSchema> ) => Promise<z.infer<OutputSchema>>;
|
|
117
51
|
|
|
118
52
|
/**
|
|
119
|
-
* Creates logical unit of work
|
|
53
|
+
* Creates logical unit of work with Zod schema for input only.
|
|
120
54
|
*
|
|
121
55
|
* @param {object} options - Step options
|
|
122
56
|
* @param {string} options.name - Human-readable step name (only letters, numbers and "_")
|
|
123
57
|
* @param {string} [options.description] - Description of the step
|
|
124
|
-
* @param {
|
|
125
|
-
* @param {
|
|
126
|
-
* @returns {
|
|
58
|
+
* @param {z.ZodType} options.inputSchema - Zod schema for the fn input
|
|
59
|
+
* @param {function} options.fn - The function logic: `(input: z.infer<InputSchema>) => Promise<void>`
|
|
60
|
+
* @returns {function} Function with signature: `(input: z.infer<InputSchema>) => Promise<void>`
|
|
127
61
|
*/
|
|
128
62
|
export async function step<
|
|
129
|
-
|
|
63
|
+
InputSchema extends AnyZodSchema
|
|
130
64
|
>( options: {
|
|
131
65
|
name: string;
|
|
132
66
|
description?: string;
|
|
133
67
|
inputSchema: InputSchema;
|
|
134
|
-
fn: ( input:
|
|
135
|
-
} ): ( input:
|
|
68
|
+
fn: ( input: z.infer<InputSchema> ) => Promise<void>;
|
|
69
|
+
} ): ( input: z.infer<InputSchema> ) => Promise<void>;
|
|
136
70
|
|
|
137
71
|
/**
|
|
138
|
-
*
|
|
139
|
-
* @returns {any} The output defined by the outputSchema
|
|
140
|
-
*/
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Creates logical unit of work, called "step", which will be invoked from workflows.
|
|
72
|
+
* Creates logical unit of work with Zod schema for output only.
|
|
144
73
|
*
|
|
145
74
|
* @param {object} options - Step options
|
|
146
75
|
* @param {string} options.name - Human-readable step name (only letters, numbers and "_")
|
|
147
76
|
* @param {string} [options.description] - Description of the step
|
|
148
|
-
* @param {
|
|
149
|
-
* @param {
|
|
150
|
-
* @returns {
|
|
77
|
+
* @param {z.ZodType} options.outputSchema - Zod schema for the fn output
|
|
78
|
+
* @param {function} options.fn - The function logic: `() => Promise<z.infer<OutputSchema>>`
|
|
79
|
+
* @returns {function} Function with signature: `() => Promise<z.infer<OutputSchema>>`
|
|
151
80
|
*/
|
|
152
81
|
export async function step<
|
|
153
|
-
|
|
82
|
+
OutputSchema extends AnyZodSchema
|
|
154
83
|
>( options: {
|
|
155
84
|
name: string;
|
|
156
85
|
description?: string;
|
|
157
86
|
outputSchema: OutputSchema;
|
|
158
|
-
fn: () => Promise<
|
|
159
|
-
} ): () => Promise<
|
|
87
|
+
fn: () => Promise<z.infer<OutputSchema>>;
|
|
88
|
+
} ): () => Promise<z.infer<OutputSchema>>;
|
|
160
89
|
|
|
161
90
|
/**
|
|
162
|
-
*
|
|
163
|
-
*/
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* Creates logical unit of work, called "step", which will be invoked from workflows.
|
|
91
|
+
* Creates logical unit of work without schemas.
|
|
167
92
|
*
|
|
168
93
|
* @param {object} options - Step options
|
|
169
94
|
* @param {string} options.name - Human-readable step name (only letters, numbers and "_")
|
|
170
95
|
* @param {string} [options.description] - Description of the step
|
|
171
|
-
* @param {
|
|
172
|
-
* @returns {
|
|
96
|
+
* @param {function} options.fn - The function logic: `() => Promise<void>`
|
|
97
|
+
* @returns {function} Function with signature: `() => Promise<void>`
|
|
173
98
|
*/
|
|
174
99
|
export async function step( options: {
|
|
175
100
|
name: string;
|
|
@@ -178,103 +103,81 @@ export async function step( options: {
|
|
|
178
103
|
} ): () => Promise<void>;
|
|
179
104
|
|
|
180
105
|
/*
|
|
181
|
-
* There
|
|
106
|
+
* There are 4 overloads of the "workflow" function:
|
|
182
107
|
* - with fn receiving input and returning output;
|
|
183
108
|
* - with fn receiving input and returning void;
|
|
184
|
-
* - with fn receiving void and returning
|
|
109
|
+
* - with fn receiving void and returning output;
|
|
185
110
|
* - with fn receiving void and returning void;
|
|
186
111
|
*/
|
|
187
112
|
|
|
188
113
|
/**
|
|
189
|
-
*
|
|
190
|
-
* @param {any} input - The input, defined by the inputSchema
|
|
191
|
-
* @returns {any} The output defined by the outputSchema
|
|
192
|
-
*/
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Creates a workflow orchestrator which can invoke steps.
|
|
114
|
+
* Creates a workflow orchestrator with Zod schemas for both input and output.
|
|
196
115
|
*
|
|
197
116
|
* @param {object} options - Workflow options
|
|
198
117
|
* @param {string} options.name - Unique workflow name
|
|
199
118
|
* @param {string} [options.description] - Description of the workflow
|
|
200
|
-
* @param {
|
|
201
|
-
* @param {
|
|
202
|
-
* @param {
|
|
203
|
-
* @returns {
|
|
119
|
+
* @param {z.ZodType} options.inputSchema - Zod schema for workflow input
|
|
120
|
+
* @param {z.ZodType} options.outputSchema - Zod schema for workflow output
|
|
121
|
+
* @param {function} options.fn - Workflow logic: `(input: z.infer<InputSchema>) => Promise<z.infer<OutputSchema>>`
|
|
122
|
+
* @returns {function} Callable workflow function: `(input: z.infer<InputSchema>) => Promise<z.infer<OutputSchema>>`
|
|
204
123
|
*/
|
|
205
124
|
export function workflow<
|
|
206
|
-
|
|
207
|
-
|
|
125
|
+
InputSchema extends AnyZodSchema,
|
|
126
|
+
OutputSchema extends AnyZodSchema
|
|
208
127
|
>( options : {
|
|
209
128
|
name: string,
|
|
210
129
|
description?: string,
|
|
211
130
|
inputSchema: InputSchema,
|
|
212
131
|
outputSchema: OutputSchema,
|
|
213
|
-
fn: ( input:
|
|
214
|
-
} ): ( input:
|
|
132
|
+
fn: ( input: z.infer<InputSchema> ) => Promise<z.infer<OutputSchema>>
|
|
133
|
+
} ): ( input: z.infer<InputSchema> ) => Promise<z.infer<OutputSchema>>;
|
|
215
134
|
|
|
216
135
|
/**
|
|
217
|
-
*
|
|
218
|
-
* @param {any} input - The input, defined by the inputSchema
|
|
219
|
-
*/
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* Creates a workflow orchestrator which can invoke steps.
|
|
136
|
+
* Creates a workflow orchestrator with Zod schema for input only.
|
|
223
137
|
*
|
|
224
138
|
* @param {object} options - Workflow options
|
|
225
139
|
* @param {string} options.name - Unique workflow name
|
|
226
140
|
* @param {string} [options.description] - Description of the workflow
|
|
227
|
-
* @param {
|
|
228
|
-
* @param {
|
|
229
|
-
* @returns {
|
|
141
|
+
* @param {z.ZodType} options.inputSchema - Zod schema for workflow input
|
|
142
|
+
* @param {function} options.fn - Workflow logic: `(input: z.infer<InputSchema>) => Promise<void>`
|
|
143
|
+
* @returns {function} Callable workflow function: `(input: z.infer<InputSchema>) => Promise<void>`
|
|
230
144
|
*/
|
|
231
145
|
export function workflow<
|
|
232
|
-
|
|
146
|
+
InputSchema extends AnyZodSchema
|
|
233
147
|
>( options : {
|
|
234
148
|
name: string,
|
|
235
149
|
description?: string,
|
|
236
150
|
inputSchema: InputSchema,
|
|
237
|
-
fn: ( input:
|
|
238
|
-
} ): ( input:
|
|
151
|
+
fn: ( input: z.infer<InputSchema> ) => Promise<void>
|
|
152
|
+
} ): ( input: z.infer<InputSchema> ) => Promise<void>;
|
|
239
153
|
|
|
240
154
|
/**
|
|
241
|
-
*
|
|
242
|
-
* @returns {any} The output defined by the outputSchema
|
|
243
|
-
*/
|
|
244
|
-
|
|
245
|
-
/**
|
|
246
|
-
* Creates a workflow orchestrator which can invoke steps.
|
|
155
|
+
* Creates a workflow orchestrator with Zod schema for output only.
|
|
247
156
|
*
|
|
248
157
|
* @param {object} options - Workflow options
|
|
249
158
|
* @param {string} options.name - Unique workflow name
|
|
250
159
|
* @param {string} [options.description] - Description of the workflow
|
|
251
|
-
* @param {
|
|
252
|
-
* @param {
|
|
253
|
-
* @returns {
|
|
160
|
+
* @param {z.ZodType} options.outputSchema - Zod schema for workflow output
|
|
161
|
+
* @param {function} options.fn - Workflow logic: `() => Promise<z.infer<OutputSchema>>`
|
|
162
|
+
* @returns {function} Callable workflow function: `() => Promise<z.infer<OutputSchema>>`
|
|
254
163
|
*/
|
|
255
164
|
export function workflow<
|
|
256
|
-
|
|
165
|
+
OutputSchema extends AnyZodSchema
|
|
257
166
|
>( options : {
|
|
258
167
|
name: string,
|
|
259
168
|
description?: string,
|
|
260
169
|
outputSchema: OutputSchema,
|
|
261
|
-
fn: () => Promise<
|
|
262
|
-
} ): () => Promise<
|
|
263
|
-
|
|
264
|
-
/**
|
|
265
|
-
* @callback VoidWorkflowFn
|
|
266
|
-
* @param {any} input - The input, defined by the inputSchema
|
|
267
|
-
* @returns {any} The output defined by the outputSchema
|
|
268
|
-
*/
|
|
170
|
+
fn: () => Promise<z.infer<OutputSchema>>
|
|
171
|
+
} ): () => Promise<z.infer<OutputSchema>>;
|
|
269
172
|
|
|
270
173
|
/**
|
|
271
|
-
* Creates a workflow orchestrator
|
|
174
|
+
* Creates a workflow orchestrator without schemas.
|
|
272
175
|
*
|
|
273
176
|
* @param {object} options - Workflow options
|
|
274
177
|
* @param {string} options.name - Unique workflow name
|
|
275
178
|
* @param {string} [options.description] - Description of the workflow
|
|
276
|
-
* @param {
|
|
277
|
-
* @returns {
|
|
179
|
+
* @param {function} options.fn - Workflow logic: `() => Promise<void>`
|
|
180
|
+
* @returns {function} Callable workflow function: `() => Promise<void>`
|
|
278
181
|
*/
|
|
279
182
|
export function workflow( options : {
|
|
280
183
|
name: string,
|
package/src/index.js
CHANGED
|
@@ -2,5 +2,6 @@ import { step } from './interface/step.js';
|
|
|
2
2
|
import { workflow } from './interface/workflow.js';
|
|
3
3
|
import { createWebhook } from './interface/webhook.js';
|
|
4
4
|
import { FatalError, ValidationError } from './errors.js';
|
|
5
|
+
import { z } from 'zod';
|
|
5
6
|
|
|
6
|
-
export { step, workflow, createWebhook, FatalError, ValidationError };
|
|
7
|
+
export { step, workflow, createWebhook, FatalError, ValidationError, z };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { ValidationError } from '#errors';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Detects if a schema is a Zod schema object
|
|
5
|
+
* @param {unknown} schema - The schema to check
|
|
6
|
+
* @returns {boolean} True if the schema is a Zod schema
|
|
7
|
+
*/
|
|
8
|
+
export function isZodSchema( schema ) {
|
|
9
|
+
return schema &&
|
|
10
|
+
typeof schema === 'object' &&
|
|
11
|
+
'_def' in schema &&
|
|
12
|
+
typeof schema.parse === 'function' &&
|
|
13
|
+
typeof schema.parseAsync === 'function';
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Validates data against a Zod schema using safeParse
|
|
18
|
+
* @param {unknown} schema - The Zod schema to validate against
|
|
19
|
+
* @param {unknown} data - The data to validate
|
|
20
|
+
* @param {string} context - Description of what's being validated (for error messages)
|
|
21
|
+
* @throws {ValidationError} If validation fails
|
|
22
|
+
* @returns {void}
|
|
23
|
+
*/
|
|
24
|
+
export function validateWithSchema( schema, data, context ) {
|
|
25
|
+
if ( !schema ) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const result = schema.safeParse( data );
|
|
30
|
+
if ( !result.success ) {
|
|
31
|
+
throw new ValidationError( `${context} validation failed: ${result.error.message}` );
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
// Import the actual implementations
|
|
5
|
+
import { isZodSchema } from './schema_utils.js';
|
|
6
|
+
|
|
7
|
+
describe( 'Schema Detection', () => {
|
|
8
|
+
describe( 'isZodSchema', () => {
|
|
9
|
+
it( 'should correctly identify Zod schemas', () => {
|
|
10
|
+
const zodSchema = z.object( {
|
|
11
|
+
name: z.string(),
|
|
12
|
+
age: z.number()
|
|
13
|
+
} );
|
|
14
|
+
|
|
15
|
+
expect( isZodSchema( zodSchema ) ).toBe( true );
|
|
16
|
+
} );
|
|
17
|
+
|
|
18
|
+
it( 'should correctly identify Zod string schema', () => {
|
|
19
|
+
const zodString = z.string();
|
|
20
|
+
expect( isZodSchema( zodString ) ).toBe( true );
|
|
21
|
+
} );
|
|
22
|
+
|
|
23
|
+
it( 'should correctly identify Zod array schema', () => {
|
|
24
|
+
const zodArray = z.array( z.number() );
|
|
25
|
+
expect( isZodSchema( zodArray ) ).toBe( true );
|
|
26
|
+
} );
|
|
27
|
+
|
|
28
|
+
it( 'should correctly identify Zod union schema', () => {
|
|
29
|
+
const zodUnion = z.union( [ z.string(), z.number() ] );
|
|
30
|
+
expect( isZodSchema( zodUnion ) ).toBe( true );
|
|
31
|
+
} );
|
|
32
|
+
|
|
33
|
+
it( 'should return false for JSON Schema objects', () => {
|
|
34
|
+
const jsonSchema = {
|
|
35
|
+
type: 'object',
|
|
36
|
+
properties: {
|
|
37
|
+
name: { type: 'string' },
|
|
38
|
+
age: { type: 'number' }
|
|
39
|
+
},
|
|
40
|
+
required: [ 'name' ]
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
expect( isZodSchema( jsonSchema ) ).toBe( false );
|
|
44
|
+
} );
|
|
45
|
+
|
|
46
|
+
it( 'should return false for plain objects', () => {
|
|
47
|
+
expect( isZodSchema( {} ) ).toBe( false );
|
|
48
|
+
expect( isZodSchema( { type: 'string' } ) ).toBe( false );
|
|
49
|
+
} );
|
|
50
|
+
|
|
51
|
+
it( 'should return false for null and undefined', () => {
|
|
52
|
+
expect( isZodSchema( null ) ).toBeFalsy();
|
|
53
|
+
expect( isZodSchema( undefined ) ).toBeFalsy();
|
|
54
|
+
} );
|
|
55
|
+
|
|
56
|
+
it( 'should return false for primitive values', () => {
|
|
57
|
+
expect( isZodSchema( 'string' ) ).toBe( false );
|
|
58
|
+
expect( isZodSchema( 123 ) ).toBe( false );
|
|
59
|
+
expect( isZodSchema( true ) ).toBe( false );
|
|
60
|
+
} );
|
|
61
|
+
|
|
62
|
+
it( 'should return false for arrays', () => {
|
|
63
|
+
expect( isZodSchema( [] ) ).toBe( false );
|
|
64
|
+
expect( isZodSchema( [ 1, 2, 3 ] ) ).toBe( false );
|
|
65
|
+
} );
|
|
66
|
+
} );
|
|
67
|
+
} );
|
package/src/interface/step.js
CHANGED
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
import { setMetadata } from './metadata.js';
|
|
2
2
|
import { validateStep } from './validations/static.js';
|
|
3
|
-
import {
|
|
3
|
+
import { validateWithSchema } from './schema_utils.js';
|
|
4
4
|
|
|
5
5
|
export function step( { name, description, inputSchema, outputSchema, fn } ) {
|
|
6
|
-
validateStep( {
|
|
6
|
+
validateStep( {
|
|
7
|
+
name,
|
|
8
|
+
description,
|
|
9
|
+
inputSchema,
|
|
10
|
+
outputSchema,
|
|
11
|
+
fn
|
|
12
|
+
} );
|
|
13
|
+
|
|
7
14
|
const wrapper = async input => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
}
|
|
15
|
+
validateWithSchema( inputSchema, input, `Step ${name} input` );
|
|
16
|
+
|
|
11
17
|
const output = await fn( input );
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
18
|
+
|
|
19
|
+
validateWithSchema( outputSchema, output, `Step ${name} output` );
|
|
20
|
+
|
|
15
21
|
return output;
|
|
16
22
|
};
|
|
17
23
|
|
|
@@ -1,26 +1,27 @@
|
|
|
1
|
-
import { ajv } from './ajv_provider.js';
|
|
2
1
|
import * as z from 'zod';
|
|
2
|
+
import { isZodSchema } from '../schema_utils.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Error is thrown when the definition of a step/workflow has problems
|
|
6
6
|
*/
|
|
7
7
|
export class StaticValidationError extends Error {};
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
ctx.addIssue( {
|
|
13
|
-
code: 'invalid_format',
|
|
14
|
-
message: ajv.errorsText( ajv.errors )
|
|
15
|
-
} );
|
|
9
|
+
const refineSchema = ( value, ctx ) => {
|
|
10
|
+
if ( !value || isZodSchema( value ) ) {
|
|
11
|
+
return;
|
|
16
12
|
}
|
|
13
|
+
|
|
14
|
+
ctx.addIssue( {
|
|
15
|
+
code: 'invalid_type',
|
|
16
|
+
message: 'Schema must be a Zod schema'
|
|
17
|
+
} );
|
|
17
18
|
};
|
|
18
19
|
|
|
19
20
|
const stepAndWorkflowSchema = z.object( {
|
|
20
21
|
name: z.string().regex( /^[a-z_][a-z0-9_]*$/i ),
|
|
21
22
|
description: z.string().optional(),
|
|
22
|
-
inputSchema: z.
|
|
23
|
-
outputSchema: z.
|
|
23
|
+
inputSchema: z.any().optional().superRefine( refineSchema ),
|
|
24
|
+
outputSchema: z.any().optional().superRefine( refineSchema ),
|
|
24
25
|
fn: z.function()
|
|
25
26
|
} );
|
|
26
27
|
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { z } from 'zod';
|
|
2
3
|
import { validateStep, validateWorkflow, validateCreateWebhook, StaticValidationError } from './static.js';
|
|
3
4
|
|
|
4
5
|
const validArgs = Object.freeze( {
|
|
5
6
|
name: 'valid_name',
|
|
6
7
|
description: 'desc',
|
|
7
|
-
inputSchema:
|
|
8
|
-
outputSchema:
|
|
8
|
+
inputSchema: z.object( {} ),
|
|
9
|
+
outputSchema: z.object( {} ),
|
|
9
10
|
fn: () => {}
|
|
10
11
|
} );
|
|
11
12
|
|
|
@@ -35,26 +36,24 @@ describe( 'interface/validator', () => {
|
|
|
35
36
|
expect( () => validateStep( { ...validArgs, description: 10 } ) ).toThrow( error );
|
|
36
37
|
} );
|
|
37
38
|
|
|
38
|
-
it( 'rejects non-
|
|
39
|
-
const error = new StaticValidationError( '✖
|
|
40
|
-
expect( () => validateStep( { ...validArgs, inputSchema: 'not-
|
|
39
|
+
it( 'rejects non-Zod inputSchema', () => {
|
|
40
|
+
const error = new StaticValidationError( '✖ Schema must be a Zod schema\n → at inputSchema' );
|
|
41
|
+
expect( () => validateStep( { ...validArgs, inputSchema: 'not-a-zod-schema' } ) ).toThrow( error );
|
|
41
42
|
} );
|
|
42
43
|
|
|
43
|
-
it( 'rejects
|
|
44
|
-
const error = new StaticValidationError( '✖
|
|
45
|
-
|
|
46
|
-
expect( () => validateStep( { ...validArgs, inputSchema: { type: 1 } } ) ).toThrow( error );
|
|
44
|
+
it( 'rejects JSON Schema inputSchema', () => {
|
|
45
|
+
const error = new StaticValidationError( '✖ Schema must be a Zod schema\n → at inputSchema' );
|
|
46
|
+
expect( () => validateStep( { ...validArgs, inputSchema: { type: 'object' } } ) ).toThrow( error );
|
|
47
47
|
} );
|
|
48
48
|
|
|
49
|
-
it( 'rejects non-
|
|
50
|
-
const error = new StaticValidationError( '✖
|
|
49
|
+
it( 'rejects non-Zod outputSchema', () => {
|
|
50
|
+
const error = new StaticValidationError( '✖ Schema must be a Zod schema\n → at outputSchema' );
|
|
51
51
|
expect( () => validateStep( { ...validArgs, outputSchema: 10 } ) ).toThrow( error );
|
|
52
52
|
} );
|
|
53
53
|
|
|
54
|
-
it( 'rejects
|
|
55
|
-
const error = new StaticValidationError( '✖
|
|
56
|
-
|
|
57
|
-
expect( () => validateStep( { ...validArgs, outputSchema: { type: 1 } } ) ).toThrow( error );
|
|
54
|
+
it( 'rejects JSON Schema outputSchema', () => {
|
|
55
|
+
const error = new StaticValidationError( '✖ Schema must be a Zod schema\n → at outputSchema' );
|
|
56
|
+
expect( () => validateStep( { ...validArgs, outputSchema: { type: 'string' } } ) ).toThrow( error );
|
|
58
57
|
} );
|
|
59
58
|
|
|
60
59
|
it( 'rejects missing fn', () => {
|