@ai-sdk/provider-utils 4.0.5 → 4.0.6
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/CHANGELOG.md +8 -0
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +4 -2
- package/src/__snapshots__/schema.test.ts.snap +346 -0
- package/src/add-additional-properties-to-json-schema.test.ts +289 -0
- package/src/add-additional-properties-to-json-schema.ts +53 -0
- package/src/combine-headers.ts +11 -0
- package/src/convert-async-iterator-to-readable-stream.test.ts +78 -0
- package/src/convert-async-iterator-to-readable-stream.ts +47 -0
- package/src/convert-image-model-file-to-data-uri.test.ts +85 -0
- package/src/convert-image-model-file-to-data-uri.ts +19 -0
- package/src/convert-to-form-data.test.ts +167 -0
- package/src/convert-to-form-data.ts +61 -0
- package/src/create-tool-name-mapping.test.ts +163 -0
- package/src/create-tool-name-mapping.ts +66 -0
- package/src/delay.test.ts +212 -0
- package/src/delay.ts +47 -0
- package/src/delayed-promise.test.ts +132 -0
- package/src/delayed-promise.ts +61 -0
- package/src/download-blob.test.ts +145 -0
- package/src/download-blob.ts +31 -0
- package/src/download-error.ts +39 -0
- package/src/extract-response-headers.ts +9 -0
- package/src/fetch-function.ts +4 -0
- package/src/generate-id.test.ts +31 -0
- package/src/generate-id.ts +57 -0
- package/src/get-error-message.ts +15 -0
- package/src/get-from-api.test.ts +199 -0
- package/src/get-from-api.ts +97 -0
- package/src/get-runtime-environment-user-agent.test.ts +47 -0
- package/src/get-runtime-environment-user-agent.ts +24 -0
- package/src/handle-fetch-error.ts +39 -0
- package/src/index.ts +67 -0
- package/src/inject-json-instruction.test.ts +404 -0
- package/src/inject-json-instruction.ts +63 -0
- package/src/is-abort-error.ts +8 -0
- package/src/is-async-iterable.ts +3 -0
- package/src/is-non-nullable.ts +12 -0
- package/src/is-url-supported.test.ts +282 -0
- package/src/is-url-supported.ts +40 -0
- package/src/load-api-key.ts +45 -0
- package/src/load-optional-setting.ts +30 -0
- package/src/load-setting.ts +62 -0
- package/src/maybe-promise-like.ts +3 -0
- package/src/media-type-to-extension.test.ts +26 -0
- package/src/media-type-to-extension.ts +22 -0
- package/src/normalize-headers.test.ts +64 -0
- package/src/normalize-headers.ts +38 -0
- package/src/parse-json-event-stream.ts +33 -0
- package/src/parse-json.test.ts +191 -0
- package/src/parse-json.ts +122 -0
- package/src/parse-provider-options.ts +32 -0
- package/src/post-to-api.ts +166 -0
- package/src/provider-tool-factory.ts +125 -0
- package/src/remove-undefined-entries.test.ts +57 -0
- package/src/remove-undefined-entries.ts +12 -0
- package/src/resolve.test.ts +125 -0
- package/src/resolve.ts +17 -0
- package/src/response-handler.test.ts +89 -0
- package/src/response-handler.ts +187 -0
- package/src/schema.test-d.ts +11 -0
- package/src/schema.test.ts +502 -0
- package/src/schema.ts +267 -0
- package/src/secure-json-parse.test.ts +59 -0
- package/src/secure-json-parse.ts +92 -0
- package/src/test/convert-array-to-async-iterable.ts +9 -0
- package/src/test/convert-array-to-readable-stream.ts +15 -0
- package/src/test/convert-async-iterable-to-array.ts +9 -0
- package/src/test/convert-readable-stream-to-array.ts +14 -0
- package/src/test/convert-response-stream-to-array.ts +9 -0
- package/src/test/index.ts +7 -0
- package/src/test/is-node-version.ts +4 -0
- package/src/test/mock-id.ts +8 -0
- package/src/to-json-schema/zod3-to-json-schema/LICENSE +16 -0
- package/src/to-json-schema/zod3-to-json-schema/README.md +24 -0
- package/src/to-json-schema/zod3-to-json-schema/get-relative-path.ts +7 -0
- package/src/to-json-schema/zod3-to-json-schema/index.ts +1 -0
- package/src/to-json-schema/zod3-to-json-schema/options.ts +98 -0
- package/src/to-json-schema/zod3-to-json-schema/parse-def.test.ts +224 -0
- package/src/to-json-schema/zod3-to-json-schema/parse-def.ts +109 -0
- package/src/to-json-schema/zod3-to-json-schema/parse-types.ts +57 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/any.ts +5 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/array.test.ts +98 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/array.ts +38 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/bigint.test.ts +51 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/bigint.ts +44 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/boolean.ts +7 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/branded.test.ts +16 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/branded.ts +7 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/catch.test.ts +15 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/catch.ts +7 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/date.test.ts +97 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/date.ts +64 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/default.test.ts +54 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/default.ts +14 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/effects.test.ts +41 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/effects.ts +14 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/enum.ts +13 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/intersection.test.ts +92 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/intersection.ts +52 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/literal.ts +29 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/map.test.ts +48 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/map.ts +47 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/native-enum.test.ts +102 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/native-enum.ts +31 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/never.ts +9 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/null.ts +9 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/nullable.test.ts +67 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/nullable.ts +42 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/number.test.ts +65 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/number.ts +44 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/object.test.ts +149 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/object.ts +88 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/optional.test.ts +147 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/optional.ts +23 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/pipe.test.ts +35 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/pipeline.ts +29 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/promise.test.ts +15 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/promise.ts +11 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/readonly.test.ts +20 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/readonly.ts +7 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/record.test.ts +108 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/record.ts +71 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/set.test.ts +20 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/set.ts +35 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/string.test.ts +438 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/string.ts +426 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/tuple.test.ts +33 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/tuple.ts +61 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/undefined.ts +11 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/union.test.ts +226 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/union.ts +144 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/unknown.ts +7 -0
- package/src/to-json-schema/zod3-to-json-schema/refs.test.ts +919 -0
- package/src/to-json-schema/zod3-to-json-schema/refs.ts +39 -0
- package/src/to-json-schema/zod3-to-json-schema/select-parser.ts +115 -0
- package/src/to-json-schema/zod3-to-json-schema/zod3-to-json-schema.test.ts +862 -0
- package/src/to-json-schema/zod3-to-json-schema/zod3-to-json-schema.ts +93 -0
- package/src/types/assistant-model-message.ts +39 -0
- package/src/types/content-part.ts +379 -0
- package/src/types/data-content.ts +4 -0
- package/src/types/execute-tool.ts +27 -0
- package/src/types/index.ts +40 -0
- package/src/types/model-message.ts +14 -0
- package/src/types/provider-options.ts +9 -0
- package/src/types/system-model-message.ts +20 -0
- package/src/types/tool-approval-request.ts +16 -0
- package/src/types/tool-approval-response.ts +27 -0
- package/src/types/tool-call.ts +31 -0
- package/src/types/tool-model-message.ts +23 -0
- package/src/types/tool-result.ts +35 -0
- package/src/types/tool.test-d.ts +193 -0
- package/src/types/tool.ts +324 -0
- package/src/types/user-model-message.ts +22 -0
- package/src/uint8-utils.ts +26 -0
- package/src/validate-types.test.ts +105 -0
- package/src/validate-types.ts +81 -0
- package/src/version.ts +6 -0
- package/src/with-user-agent-suffix.test.ts +84 -0
- package/src/with-user-agent-suffix.ts +27 -0
- package/src/without-trailing-slash.ts +3 -0
- package/LICENSE +0 -13
package/src/schema.ts
ADDED
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import { JSONSchema7, TypeValidationError } from '@ai-sdk/provider';
|
|
2
|
+
import { StandardSchemaV1, StandardJSONSchemaV1 } from '@standard-schema/spec';
|
|
3
|
+
import * as z3 from 'zod/v3';
|
|
4
|
+
import * as z4 from 'zod/v4';
|
|
5
|
+
import { addAdditionalPropertiesToJsonSchema } from './add-additional-properties-to-json-schema';
|
|
6
|
+
import { zod3ToJsonSchema } from './to-json-schema/zod3-to-json-schema';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Used to mark schemas so we can support both Zod and custom schemas.
|
|
10
|
+
*/
|
|
11
|
+
const schemaSymbol = Symbol.for('vercel.ai.schema');
|
|
12
|
+
|
|
13
|
+
export type ValidationResult<OBJECT> =
|
|
14
|
+
| { success: true; value: OBJECT }
|
|
15
|
+
| { success: false; error: Error };
|
|
16
|
+
|
|
17
|
+
export type Schema<OBJECT = unknown> = {
|
|
18
|
+
/**
|
|
19
|
+
* Used to mark schemas so we can support both Zod and custom schemas.
|
|
20
|
+
*/
|
|
21
|
+
[schemaSymbol]: true;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Schema type for inference.
|
|
25
|
+
*/
|
|
26
|
+
_type: OBJECT;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Optional. Validates that the structure of a value matches this schema,
|
|
30
|
+
* and returns a typed version of the value if it does.
|
|
31
|
+
*/
|
|
32
|
+
readonly validate?: (
|
|
33
|
+
value: unknown,
|
|
34
|
+
) => ValidationResult<OBJECT> | PromiseLike<ValidationResult<OBJECT>>;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* The JSON Schema for the schema. It is passed to the providers.
|
|
38
|
+
*/
|
|
39
|
+
readonly jsonSchema: JSONSchema7 | PromiseLike<JSONSchema7>;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Creates a schema with deferred creation.
|
|
44
|
+
* This is important to reduce the startup time of the library
|
|
45
|
+
* and to avoid initializing unused validators.
|
|
46
|
+
*
|
|
47
|
+
* @param createValidator A function that creates a schema.
|
|
48
|
+
* @returns A function that returns a schema.
|
|
49
|
+
*/
|
|
50
|
+
export function lazySchema<SCHEMA>(
|
|
51
|
+
createSchema: () => Schema<SCHEMA>,
|
|
52
|
+
): LazySchema<SCHEMA> {
|
|
53
|
+
// cache the validator to avoid initializing it multiple times
|
|
54
|
+
let schema: Schema<SCHEMA> | undefined;
|
|
55
|
+
return () => {
|
|
56
|
+
if (schema == null) {
|
|
57
|
+
schema = createSchema();
|
|
58
|
+
}
|
|
59
|
+
return schema;
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export type LazySchema<SCHEMA> = () => Schema<SCHEMA>;
|
|
64
|
+
|
|
65
|
+
export type ZodSchema<SCHEMA = any> =
|
|
66
|
+
| z3.Schema<SCHEMA, z3.ZodTypeDef, any>
|
|
67
|
+
| z4.core.$ZodType<SCHEMA, any>;
|
|
68
|
+
|
|
69
|
+
export type StandardSchema<SCHEMA = any> = StandardSchemaV1<unknown, SCHEMA> &
|
|
70
|
+
StandardJSONSchemaV1<unknown, SCHEMA>;
|
|
71
|
+
|
|
72
|
+
export type FlexibleSchema<SCHEMA = any> =
|
|
73
|
+
| Schema<SCHEMA>
|
|
74
|
+
| LazySchema<SCHEMA>
|
|
75
|
+
| ZodSchema<SCHEMA>
|
|
76
|
+
| StandardSchema<SCHEMA>;
|
|
77
|
+
|
|
78
|
+
export type InferSchema<SCHEMA> =
|
|
79
|
+
SCHEMA extends ZodSchema<infer T>
|
|
80
|
+
? T
|
|
81
|
+
: SCHEMA extends StandardSchema<infer T>
|
|
82
|
+
? T
|
|
83
|
+
: SCHEMA extends LazySchema<infer T>
|
|
84
|
+
? T
|
|
85
|
+
: SCHEMA extends Schema<infer T>
|
|
86
|
+
? T
|
|
87
|
+
: never;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Create a schema using a JSON Schema.
|
|
91
|
+
*
|
|
92
|
+
* @param jsonSchema The JSON Schema for the schema.
|
|
93
|
+
* @param options.validate Optional. A validation function for the schema.
|
|
94
|
+
*/
|
|
95
|
+
export function jsonSchema<OBJECT = unknown>(
|
|
96
|
+
jsonSchema:
|
|
97
|
+
| JSONSchema7
|
|
98
|
+
| PromiseLike<JSONSchema7>
|
|
99
|
+
| (() => JSONSchema7 | PromiseLike<JSONSchema7>),
|
|
100
|
+
{
|
|
101
|
+
validate,
|
|
102
|
+
}: {
|
|
103
|
+
validate?: (
|
|
104
|
+
value: unknown,
|
|
105
|
+
) => ValidationResult<OBJECT> | PromiseLike<ValidationResult<OBJECT>>;
|
|
106
|
+
} = {},
|
|
107
|
+
): Schema<OBJECT> {
|
|
108
|
+
return {
|
|
109
|
+
[schemaSymbol]: true,
|
|
110
|
+
_type: undefined as OBJECT, // should never be used directly
|
|
111
|
+
get jsonSchema() {
|
|
112
|
+
if (typeof jsonSchema === 'function') {
|
|
113
|
+
jsonSchema = jsonSchema(); // cache the function results
|
|
114
|
+
}
|
|
115
|
+
return jsonSchema;
|
|
116
|
+
},
|
|
117
|
+
validate,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function isSchema(value: unknown): value is Schema {
|
|
122
|
+
return (
|
|
123
|
+
typeof value === 'object' &&
|
|
124
|
+
value !== null &&
|
|
125
|
+
schemaSymbol in value &&
|
|
126
|
+
value[schemaSymbol] === true &&
|
|
127
|
+
'jsonSchema' in value &&
|
|
128
|
+
'validate' in value
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function asSchema<OBJECT>(
|
|
133
|
+
schema: FlexibleSchema<OBJECT> | undefined,
|
|
134
|
+
): Schema<OBJECT> {
|
|
135
|
+
return schema == null
|
|
136
|
+
? jsonSchema({ properties: {}, additionalProperties: false })
|
|
137
|
+
: isSchema(schema)
|
|
138
|
+
? schema
|
|
139
|
+
: '~standard' in schema
|
|
140
|
+
? schema['~standard'].vendor === 'zod'
|
|
141
|
+
? zodSchema(schema as ZodSchema<OBJECT>)
|
|
142
|
+
: standardSchema(schema as StandardSchema<OBJECT>)
|
|
143
|
+
: schema();
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function standardSchema<OBJECT>(
|
|
147
|
+
standardSchema: StandardSchema<OBJECT>,
|
|
148
|
+
): Schema<OBJECT> {
|
|
149
|
+
return jsonSchema(
|
|
150
|
+
() =>
|
|
151
|
+
addAdditionalPropertiesToJsonSchema(
|
|
152
|
+
standardSchema['~standard'].jsonSchema.input({
|
|
153
|
+
target: 'draft-07',
|
|
154
|
+
}) as JSONSchema7,
|
|
155
|
+
),
|
|
156
|
+
{
|
|
157
|
+
validate: async value => {
|
|
158
|
+
const result = await standardSchema['~standard'].validate(value);
|
|
159
|
+
return 'value' in result
|
|
160
|
+
? { success: true, value: result.value }
|
|
161
|
+
: {
|
|
162
|
+
success: false,
|
|
163
|
+
error: new TypeValidationError({
|
|
164
|
+
value,
|
|
165
|
+
cause: result.issues,
|
|
166
|
+
}),
|
|
167
|
+
};
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export function zod3Schema<OBJECT>(
|
|
174
|
+
zodSchema: z3.Schema<OBJECT, z3.ZodTypeDef, any>,
|
|
175
|
+
options?: {
|
|
176
|
+
/**
|
|
177
|
+
* Enables support for references in the schema.
|
|
178
|
+
* This is required for recursive schemas, e.g. with `z.lazy`.
|
|
179
|
+
* However, not all language models and providers support such references.
|
|
180
|
+
* Defaults to `false`.
|
|
181
|
+
*/
|
|
182
|
+
useReferences?: boolean;
|
|
183
|
+
},
|
|
184
|
+
): Schema<OBJECT> {
|
|
185
|
+
// default to no references (to support openapi conversion for google)
|
|
186
|
+
const useReferences = options?.useReferences ?? false;
|
|
187
|
+
|
|
188
|
+
return jsonSchema(
|
|
189
|
+
// defer json schema creation to avoid unnecessary computation when only validation is needed
|
|
190
|
+
() =>
|
|
191
|
+
zod3ToJsonSchema(zodSchema, {
|
|
192
|
+
$refStrategy: useReferences ? 'root' : 'none',
|
|
193
|
+
}) as JSONSchema7,
|
|
194
|
+
{
|
|
195
|
+
validate: async value => {
|
|
196
|
+
const result = await zodSchema.safeParseAsync(value);
|
|
197
|
+
return result.success
|
|
198
|
+
? { success: true, value: result.data }
|
|
199
|
+
: { success: false, error: result.error };
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export function zod4Schema<OBJECT>(
|
|
206
|
+
zodSchema: z4.core.$ZodType<OBJECT, any>,
|
|
207
|
+
options?: {
|
|
208
|
+
/**
|
|
209
|
+
* Enables support for references in the schema.
|
|
210
|
+
* This is required for recursive schemas, e.g. with `z.lazy`.
|
|
211
|
+
* However, not all language models and providers support such references.
|
|
212
|
+
* Defaults to `false`.
|
|
213
|
+
*/
|
|
214
|
+
useReferences?: boolean;
|
|
215
|
+
},
|
|
216
|
+
): Schema<OBJECT> {
|
|
217
|
+
// default to no references (to support openapi conversion for google)
|
|
218
|
+
const useReferences = options?.useReferences ?? false;
|
|
219
|
+
|
|
220
|
+
return jsonSchema(
|
|
221
|
+
// defer json schema creation to avoid unnecessary computation when only validation is needed
|
|
222
|
+
() =>
|
|
223
|
+
addAdditionalPropertiesToJsonSchema(
|
|
224
|
+
z4.toJSONSchema(zodSchema, {
|
|
225
|
+
target: 'draft-7',
|
|
226
|
+
io: 'input',
|
|
227
|
+
reused: useReferences ? 'ref' : 'inline',
|
|
228
|
+
}) as JSONSchema7,
|
|
229
|
+
),
|
|
230
|
+
{
|
|
231
|
+
validate: async value => {
|
|
232
|
+
const result = await z4.safeParseAsync(zodSchema, value);
|
|
233
|
+
return result.success
|
|
234
|
+
? { success: true, value: result.data }
|
|
235
|
+
: { success: false, error: result.error };
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export function isZod4Schema(
|
|
242
|
+
zodSchema: z4.core.$ZodType<any, any> | z3.Schema<any, z3.ZodTypeDef, any>,
|
|
243
|
+
): zodSchema is z4.core.$ZodType<any, any> {
|
|
244
|
+
// https://zod.dev/library-authors?id=how-to-support-zod-3-and-zod-4-simultaneously
|
|
245
|
+
return '_zod' in zodSchema;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export function zodSchema<OBJECT>(
|
|
249
|
+
zodSchema:
|
|
250
|
+
| z4.core.$ZodType<OBJECT, any>
|
|
251
|
+
| z3.Schema<OBJECT, z3.ZodTypeDef, any>,
|
|
252
|
+
options?: {
|
|
253
|
+
/**
|
|
254
|
+
* Enables support for references in the schema.
|
|
255
|
+
* This is required for recursive schemas, e.g. with `z.lazy`.
|
|
256
|
+
* However, not all language models and providers support such references.
|
|
257
|
+
* Defaults to `false`.
|
|
258
|
+
*/
|
|
259
|
+
useReferences?: boolean;
|
|
260
|
+
},
|
|
261
|
+
): Schema<OBJECT> {
|
|
262
|
+
if (isZod4Schema(zodSchema)) {
|
|
263
|
+
return zod4Schema(zodSchema, options);
|
|
264
|
+
} else {
|
|
265
|
+
return zod3Schema(zodSchema, options);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// Licensed under BSD-3-Clause (this file only)
|
|
2
|
+
// Code adapted from https://github.com/fastify/secure-json-parse/blob/783fcb1b5434709466759847cec974381939673a/test/index.test.js
|
|
3
|
+
//
|
|
4
|
+
// Copyright (c) Vercel, Inc. (https://vercel.com)
|
|
5
|
+
// Copyright (c) 2019 The Fastify Team
|
|
6
|
+
// Copyright (c) 2019, Sideway Inc, and project contributors
|
|
7
|
+
// All rights reserved.
|
|
8
|
+
//
|
|
9
|
+
// The complete list of contributors can be found at:
|
|
10
|
+
// - https://github.com/hapijs/bourne/graphs/contributors
|
|
11
|
+
// - https://github.com/fastify/secure-json-parse/graphs/contributors
|
|
12
|
+
// - https://github.com/vercel/ai/commits/main/packages/provider-utils/src/secure-parse-json.test.ts
|
|
13
|
+
//
|
|
14
|
+
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
|
15
|
+
//
|
|
16
|
+
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
17
|
+
//
|
|
18
|
+
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
|
19
|
+
//
|
|
20
|
+
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
|
21
|
+
//
|
|
22
|
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
23
|
+
|
|
24
|
+
import { describe, it, expect } from 'vitest';
|
|
25
|
+
import { secureJsonParse } from './secure-json-parse';
|
|
26
|
+
|
|
27
|
+
describe('secureJsonParse', () => {
|
|
28
|
+
it('parses object string', () => {
|
|
29
|
+
expect(secureJsonParse('{"a": 5, "b": 6}')).toStrictEqual(
|
|
30
|
+
JSON.parse('{"a": 5, "b": 6}'),
|
|
31
|
+
);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('parses null string', () => {
|
|
35
|
+
expect(secureJsonParse('null')).toStrictEqual(JSON.parse('null'));
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('parses 0 string', () => {
|
|
39
|
+
expect(secureJsonParse('0')).toStrictEqual(JSON.parse('0'));
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('parses string string', () => {
|
|
43
|
+
expect(secureJsonParse('"X"')).toStrictEqual(JSON.parse('"X"'));
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('errors on constructor property', () => {
|
|
47
|
+
const text =
|
|
48
|
+
'{ "a": 5, "b": 6, "constructor": { "x": 7 }, "c": { "d": 0, "e": "text", "__proto__": { "y": 8 }, "f": { "g": 2 } } }';
|
|
49
|
+
|
|
50
|
+
expect(() => secureJsonParse(text)).toThrow(SyntaxError);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('errors on proto property', () => {
|
|
54
|
+
const text =
|
|
55
|
+
'{ "a": 5, "b": 6, "__proto__": { "x": 7 }, "c": { "d": 0, "e": "text", "__proto__": { "y": 8 }, "f": { "g": 2 } } }';
|
|
56
|
+
|
|
57
|
+
expect(() => secureJsonParse(text)).toThrow(SyntaxError);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// Licensed under BSD-3-Clause (this file only)
|
|
2
|
+
// Code adapted from https://github.com/fastify/secure-json-parse/blob/783fcb1b5434709466759847cec974381939673a/index.js
|
|
3
|
+
//
|
|
4
|
+
// Copyright (c) Vercel, Inc. (https://vercel.com)
|
|
5
|
+
// Copyright (c) 2019 The Fastify Team
|
|
6
|
+
// Copyright (c) 2019, Sideway Inc, and project contributors
|
|
7
|
+
// All rights reserved.
|
|
8
|
+
//
|
|
9
|
+
// The complete list of contributors can be found at:
|
|
10
|
+
// - https://github.com/hapijs/bourne/graphs/contributors
|
|
11
|
+
// - https://github.com/fastify/secure-json-parse/graphs/contributors
|
|
12
|
+
// - https://github.com/vercel/ai/commits/main/packages/provider-utils/src/secure-parse-json.ts
|
|
13
|
+
//
|
|
14
|
+
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
|
15
|
+
//
|
|
16
|
+
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
17
|
+
//
|
|
18
|
+
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
|
19
|
+
//
|
|
20
|
+
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
|
21
|
+
//
|
|
22
|
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
23
|
+
|
|
24
|
+
const suspectProtoRx = /"__proto__"\s*:/;
|
|
25
|
+
const suspectConstructorRx = /"constructor"\s*:/;
|
|
26
|
+
|
|
27
|
+
function _parse(text: string) {
|
|
28
|
+
// Parse normally
|
|
29
|
+
const obj = JSON.parse(text);
|
|
30
|
+
|
|
31
|
+
// Ignore null and non-objects
|
|
32
|
+
if (obj === null || typeof obj !== 'object') {
|
|
33
|
+
return obj;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (
|
|
37
|
+
suspectProtoRx.test(text) === false &&
|
|
38
|
+
suspectConstructorRx.test(text) === false
|
|
39
|
+
) {
|
|
40
|
+
return obj;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Scan result for proto keys
|
|
44
|
+
return filter(obj);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function filter(obj: any) {
|
|
48
|
+
let next = [obj];
|
|
49
|
+
|
|
50
|
+
while (next.length) {
|
|
51
|
+
const nodes = next;
|
|
52
|
+
next = [];
|
|
53
|
+
|
|
54
|
+
for (const node of nodes) {
|
|
55
|
+
if (Object.prototype.hasOwnProperty.call(node, '__proto__')) {
|
|
56
|
+
throw new SyntaxError('Object contains forbidden prototype property');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (
|
|
60
|
+
Object.prototype.hasOwnProperty.call(node, 'constructor') &&
|
|
61
|
+
Object.prototype.hasOwnProperty.call(node.constructor, 'prototype')
|
|
62
|
+
) {
|
|
63
|
+
throw new SyntaxError('Object contains forbidden prototype property');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
for (const key in node) {
|
|
67
|
+
const value = node[key];
|
|
68
|
+
if (value && typeof value === 'object') {
|
|
69
|
+
next.push(value);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return obj;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function secureJsonParse(text: string) {
|
|
78
|
+
const { stackTraceLimit } = Error;
|
|
79
|
+
try {
|
|
80
|
+
// Performance optimization, see https://github.com/fastify/secure-json-parse/pull/90
|
|
81
|
+
Error.stackTraceLimit = 0;
|
|
82
|
+
} catch (e) {
|
|
83
|
+
// Fallback in case Error is immutable (v8 readonly)
|
|
84
|
+
return _parse(text);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
return _parse(text);
|
|
89
|
+
} finally {
|
|
90
|
+
Error.stackTraceLimit = stackTraceLimit;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export function convertArrayToReadableStream<T>(
|
|
2
|
+
values: T[],
|
|
3
|
+
): ReadableStream<T> {
|
|
4
|
+
return new ReadableStream({
|
|
5
|
+
start(controller) {
|
|
6
|
+
try {
|
|
7
|
+
for (const value of values) {
|
|
8
|
+
controller.enqueue(value);
|
|
9
|
+
}
|
|
10
|
+
} finally {
|
|
11
|
+
controller.close();
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export async function convertReadableStreamToArray<T>(
|
|
2
|
+
stream: ReadableStream<T>,
|
|
3
|
+
): Promise<T[]> {
|
|
4
|
+
const reader = stream.getReader();
|
|
5
|
+
const result: T[] = [];
|
|
6
|
+
|
|
7
|
+
while (true) {
|
|
8
|
+
const { done, value } = await reader.read();
|
|
9
|
+
if (done) break;
|
|
10
|
+
result.push(value);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return result;
|
|
14
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { convertReadableStreamToArray } from './convert-readable-stream-to-array';
|
|
2
|
+
|
|
3
|
+
export async function convertResponseStreamToArray(
|
|
4
|
+
response: Response,
|
|
5
|
+
): Promise<string[]> {
|
|
6
|
+
return convertReadableStreamToArray(
|
|
7
|
+
response.body!.pipeThrough(new TextDecoderStream()),
|
|
8
|
+
);
|
|
9
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export * from './convert-array-to-async-iterable';
|
|
2
|
+
export * from './convert-array-to-readable-stream';
|
|
3
|
+
export * from './convert-async-iterable-to-array';
|
|
4
|
+
export * from './convert-readable-stream-to-array';
|
|
5
|
+
export * from './convert-response-stream-to-array';
|
|
6
|
+
export * from './is-node-version';
|
|
7
|
+
export * from './mock-id';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2020, Stefan Terdell
|
|
4
|
+
Copyright (c) 2025, Vercel Inc.
|
|
5
|
+
|
|
6
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
7
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
8
|
+
copyright notice and this permission notice appear in all copies.
|
|
9
|
+
|
|
10
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
11
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
12
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
13
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
14
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
15
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
16
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# `zod-to-json-schema`
|
|
2
|
+
|
|
3
|
+
Originally copied from https://github.com/StefanTerdell/zod-to-json-schema because its `peerDependency` on `"zod": "^3.24.1"` while `ai` needs to support `zod@4` if users already use it. We want to avoid having both `zod@3` and `zod@4` in the dependency tree of our users.
|
|
4
|
+
|
|
5
|
+
The code in this directory and sub-directories is released under the ISC license:
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
ISC License
|
|
9
|
+
|
|
10
|
+
Copyright (c) 2020, Stefan Terdell
|
|
11
|
+
Copyright (c) 2025, Vercel Inc.
|
|
12
|
+
|
|
13
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
14
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
15
|
+
copyright notice and this permission notice appear in all copies.
|
|
16
|
+
|
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
18
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
19
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
20
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
21
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
22
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
23
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
24
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { zod3ToJsonSchema } from './zod3-to-json-schema';
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { ZodSchema, ZodTypeDef } from 'zod/v3';
|
|
2
|
+
import { Refs, Seen } from './refs';
|
|
3
|
+
import { JsonSchema7Type } from './parse-types';
|
|
4
|
+
|
|
5
|
+
export type DateStrategy =
|
|
6
|
+
| 'format:date-time'
|
|
7
|
+
| 'format:date'
|
|
8
|
+
| 'string'
|
|
9
|
+
| 'integer';
|
|
10
|
+
|
|
11
|
+
export const ignoreOverride = Symbol(
|
|
12
|
+
'Let zodToJsonSchema decide on which parser to use',
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
export type OverrideCallback = (
|
|
16
|
+
def: ZodTypeDef,
|
|
17
|
+
refs: Refs,
|
|
18
|
+
seen: Seen | undefined,
|
|
19
|
+
forceResolution?: boolean,
|
|
20
|
+
) => JsonSchema7Type | undefined | typeof ignoreOverride;
|
|
21
|
+
|
|
22
|
+
export type PostProcessCallback = (
|
|
23
|
+
jsonSchema: JsonSchema7Type | undefined,
|
|
24
|
+
def: ZodTypeDef,
|
|
25
|
+
refs: Refs,
|
|
26
|
+
) => JsonSchema7Type | undefined;
|
|
27
|
+
|
|
28
|
+
export const jsonDescription: PostProcessCallback = (jsonSchema, def) => {
|
|
29
|
+
if (def.description) {
|
|
30
|
+
try {
|
|
31
|
+
return {
|
|
32
|
+
...jsonSchema,
|
|
33
|
+
...JSON.parse(def.description),
|
|
34
|
+
};
|
|
35
|
+
} catch {}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return jsonSchema;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export type Options = {
|
|
42
|
+
name: string | undefined;
|
|
43
|
+
$refStrategy: 'root' | 'relative' | 'none' | 'seen';
|
|
44
|
+
basePath: string[];
|
|
45
|
+
effectStrategy: 'input' | 'any';
|
|
46
|
+
pipeStrategy: 'input' | 'output' | 'all';
|
|
47
|
+
dateStrategy: DateStrategy | DateStrategy[];
|
|
48
|
+
mapStrategy: 'entries' | 'record';
|
|
49
|
+
removeAdditionalStrategy: 'passthrough' | 'strict';
|
|
50
|
+
allowedAdditionalProperties: true | undefined;
|
|
51
|
+
rejectedAdditionalProperties: false | undefined;
|
|
52
|
+
strictUnions: boolean;
|
|
53
|
+
definitionPath: string;
|
|
54
|
+
definitions: Record<string, ZodSchema>;
|
|
55
|
+
errorMessages: boolean;
|
|
56
|
+
patternStrategy: 'escape' | 'preserve';
|
|
57
|
+
applyRegexFlags: boolean;
|
|
58
|
+
emailStrategy: 'format:email' | 'format:idn-email' | 'pattern:zod';
|
|
59
|
+
base64Strategy: 'format:binary' | 'contentEncoding:base64' | 'pattern:zod';
|
|
60
|
+
nameStrategy: 'ref' | 'title';
|
|
61
|
+
override?: OverrideCallback;
|
|
62
|
+
postProcess?: PostProcessCallback;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const defaultOptions: Options = {
|
|
66
|
+
name: undefined,
|
|
67
|
+
$refStrategy: 'root',
|
|
68
|
+
basePath: ['#'],
|
|
69
|
+
effectStrategy: 'input',
|
|
70
|
+
pipeStrategy: 'all',
|
|
71
|
+
dateStrategy: 'format:date-time',
|
|
72
|
+
mapStrategy: 'entries',
|
|
73
|
+
removeAdditionalStrategy: 'passthrough',
|
|
74
|
+
allowedAdditionalProperties: true,
|
|
75
|
+
rejectedAdditionalProperties: false,
|
|
76
|
+
definitionPath: 'definitions',
|
|
77
|
+
strictUnions: false,
|
|
78
|
+
definitions: {},
|
|
79
|
+
errorMessages: false,
|
|
80
|
+
patternStrategy: 'escape',
|
|
81
|
+
applyRegexFlags: false,
|
|
82
|
+
emailStrategy: 'format:email',
|
|
83
|
+
base64Strategy: 'contentEncoding:base64',
|
|
84
|
+
nameStrategy: 'ref',
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export const getDefaultOptions = (
|
|
88
|
+
options: Partial<Options> | string | undefined,
|
|
89
|
+
) =>
|
|
90
|
+
(typeof options === 'string'
|
|
91
|
+
? {
|
|
92
|
+
...defaultOptions,
|
|
93
|
+
name: options,
|
|
94
|
+
}
|
|
95
|
+
: {
|
|
96
|
+
...defaultOptions,
|
|
97
|
+
...options,
|
|
98
|
+
}) as Options;
|