@ai-sdk/provider-utils 4.0.8 → 4.0.10

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.
Files changed (58) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/index.js +29 -1
  3. package/dist/index.js.map +1 -1
  4. package/dist/index.mjs +29 -1
  5. package/dist/index.mjs.map +1 -1
  6. package/package.json +6 -2
  7. package/src/handle-fetch-error.ts +33 -0
  8. package/src/__snapshots__/schema.test.ts.snap +0 -346
  9. package/src/add-additional-properties-to-json-schema.test.ts +0 -289
  10. package/src/convert-async-iterator-to-readable-stream.test.ts +0 -78
  11. package/src/convert-image-model-file-to-data-uri.test.ts +0 -85
  12. package/src/convert-to-form-data.test.ts +0 -167
  13. package/src/create-tool-name-mapping.test.ts +0 -163
  14. package/src/delay.test.ts +0 -212
  15. package/src/delayed-promise.test.ts +0 -132
  16. package/src/download-blob.test.ts +0 -145
  17. package/src/generate-id.test.ts +0 -31
  18. package/src/get-from-api.test.ts +0 -199
  19. package/src/get-runtime-environment-user-agent.test.ts +0 -47
  20. package/src/inject-json-instruction.test.ts +0 -404
  21. package/src/is-url-supported.test.ts +0 -282
  22. package/src/media-type-to-extension.test.ts +0 -26
  23. package/src/normalize-headers.test.ts +0 -64
  24. package/src/parse-json.test.ts +0 -191
  25. package/src/remove-undefined-entries.test.ts +0 -57
  26. package/src/resolve.test.ts +0 -125
  27. package/src/response-handler.test.ts +0 -89
  28. package/src/schema.test-d.ts +0 -11
  29. package/src/schema.test.ts +0 -502
  30. package/src/secure-json-parse.test.ts +0 -59
  31. package/src/to-json-schema/zod3-to-json-schema/parse-def.test.ts +0 -224
  32. package/src/to-json-schema/zod3-to-json-schema/parsers/array.test.ts +0 -98
  33. package/src/to-json-schema/zod3-to-json-schema/parsers/bigint.test.ts +0 -51
  34. package/src/to-json-schema/zod3-to-json-schema/parsers/branded.test.ts +0 -16
  35. package/src/to-json-schema/zod3-to-json-schema/parsers/catch.test.ts +0 -15
  36. package/src/to-json-schema/zod3-to-json-schema/parsers/date.test.ts +0 -97
  37. package/src/to-json-schema/zod3-to-json-schema/parsers/default.test.ts +0 -54
  38. package/src/to-json-schema/zod3-to-json-schema/parsers/effects.test.ts +0 -41
  39. package/src/to-json-schema/zod3-to-json-schema/parsers/intersection.test.ts +0 -92
  40. package/src/to-json-schema/zod3-to-json-schema/parsers/map.test.ts +0 -48
  41. package/src/to-json-schema/zod3-to-json-schema/parsers/native-enum.test.ts +0 -102
  42. package/src/to-json-schema/zod3-to-json-schema/parsers/nullable.test.ts +0 -67
  43. package/src/to-json-schema/zod3-to-json-schema/parsers/number.test.ts +0 -65
  44. package/src/to-json-schema/zod3-to-json-schema/parsers/object.test.ts +0 -149
  45. package/src/to-json-schema/zod3-to-json-schema/parsers/optional.test.ts +0 -147
  46. package/src/to-json-schema/zod3-to-json-schema/parsers/pipe.test.ts +0 -35
  47. package/src/to-json-schema/zod3-to-json-schema/parsers/promise.test.ts +0 -15
  48. package/src/to-json-schema/zod3-to-json-schema/parsers/readonly.test.ts +0 -20
  49. package/src/to-json-schema/zod3-to-json-schema/parsers/record.test.ts +0 -108
  50. package/src/to-json-schema/zod3-to-json-schema/parsers/set.test.ts +0 -20
  51. package/src/to-json-schema/zod3-to-json-schema/parsers/string.test.ts +0 -438
  52. package/src/to-json-schema/zod3-to-json-schema/parsers/tuple.test.ts +0 -33
  53. package/src/to-json-schema/zod3-to-json-schema/parsers/union.test.ts +0 -226
  54. package/src/to-json-schema/zod3-to-json-schema/refs.test.ts +0 -919
  55. package/src/to-json-schema/zod3-to-json-schema/zod3-to-json-schema.test.ts +0 -862
  56. package/src/types/tool.test-d.ts +0 -228
  57. package/src/validate-types.test.ts +0 -105
  58. package/src/with-user-agent-suffix.test.ts +0 -84
@@ -1,26 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { mediaTypeToExtension } from './media-type-to-extension';
3
-
4
- describe('mediaTypeToExtension()', () => {
5
- it.each([
6
- // most common
7
- ['audio/mpeg', 'mp3'],
8
- ['audio/mp3', 'mp3'],
9
- ['audio/wav', 'wav'],
10
- ['audio/x-wav', 'wav'],
11
- ['audio/webm', 'webm'],
12
- ['audio/ogg', 'ogg'],
13
- ['audio/opus', 'ogg'],
14
- ['audio/mp4', 'm4a'],
15
- ['audio/x-m4a', 'm4a'],
16
- ['audio/flac', 'flac'],
17
- ['audio/aac', 'aac'],
18
- // upper case
19
- ['AUDIO/MPEG', 'mp3'],
20
- ['AUDIO/MP3', 'mp3'],
21
- // invalid
22
- ['nope', ''],
23
- ])('should map %s to %s', (mediaType, expectedExtension) => {
24
- expect(mediaTypeToExtension(mediaType)).toBe(expectedExtension);
25
- });
26
- });
@@ -1,64 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
-
3
- import { normalizeHeaders } from './normalize-headers';
4
-
5
- describe('normalizeHeaders', () => {
6
- it('returns empty object for undefined', () => {
7
- expect(normalizeHeaders(undefined)).toEqual({});
8
- });
9
-
10
- it('converts Headers instance to record', () => {
11
- const headers = new Headers({
12
- Authorization: 'Bearer token',
13
- 'X-Feature': 'beta',
14
- });
15
-
16
- expect(normalizeHeaders(headers)).toEqual({
17
- authorization: 'Bearer token',
18
- 'x-feature': 'beta',
19
- });
20
- });
21
-
22
- it('converts tuple array', () => {
23
- const headers: HeadersInit = [
24
- ['Authorization', 'Bearer token'],
25
- ['X-Feature', 'beta'],
26
- ['X-Ignore', undefined as unknown as string],
27
- ];
28
-
29
- expect(normalizeHeaders(headers)).toEqual({
30
- authorization: 'Bearer token',
31
- 'x-feature': 'beta',
32
- });
33
- });
34
-
35
- it('converts plain record and filters nullish values', () => {
36
- expect(
37
- normalizeHeaders({
38
- Authorization: 'Bearer token',
39
- 'X-Feature': undefined,
40
- 'Content-Type': 'application/json',
41
- }),
42
- ).toEqual({
43
- authorization: 'Bearer token',
44
- 'content-type': 'application/json',
45
- });
46
- });
47
-
48
- it('handles empty Headers instance', () => {
49
- const headers = new Headers();
50
- expect(normalizeHeaders(headers)).toEqual({});
51
- });
52
-
53
- it('converts uppercase keys to lowercase', () => {
54
- expect(
55
- normalizeHeaders({
56
- 'CONTENT-TYPE': 'application/json',
57
- 'X-CUSTOM-HEADER': 'test-value',
58
- }),
59
- ).toEqual({
60
- 'content-type': 'application/json',
61
- 'x-custom-header': 'test-value',
62
- });
63
- });
64
- });
@@ -1,191 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { parseJSON, safeParseJSON, isParsableJson } from './parse-json';
3
- import { z } from 'zod/v4';
4
- import { JSONParseError, TypeValidationError } from '@ai-sdk/provider';
5
-
6
- describe('parseJSON', () => {
7
- it('should parse basic JSON without schema', async () => {
8
- const result = await parseJSON({ text: '{"foo": "bar"}' });
9
- expect(result).toEqual({ foo: 'bar' });
10
- });
11
-
12
- it('should parse JSON with schema validation', async () => {
13
- const schema = z.object({ foo: z.string() });
14
- const result = await parseJSON({ text: '{"foo": "bar"}', schema });
15
- expect(result).toEqual({ foo: 'bar' });
16
- });
17
-
18
- it('should throw JSONParseError for invalid JSON', async () => {
19
- await expect(() => parseJSON({ text: 'invalid json' })).rejects.toThrow(
20
- JSONParseError,
21
- );
22
- });
23
-
24
- it('should throw TypeValidationError for schema validation failures', async () => {
25
- const schema = z.object({ foo: z.number() });
26
- await expect(() =>
27
- parseJSON({ text: '{"foo": "bar"}', schema }),
28
- ).rejects.toThrow(TypeValidationError);
29
- });
30
- });
31
-
32
- describe('safeParseJSON', () => {
33
- it('should safely parse basic JSON without schema and include rawValue', async () => {
34
- const result = await safeParseJSON({ text: '{"foo": "bar"}' });
35
- expect(result).toEqual({
36
- success: true,
37
- value: { foo: 'bar' },
38
- rawValue: { foo: 'bar' },
39
- });
40
- });
41
-
42
- it('should preserve rawValue even after schema transformation', async () => {
43
- const schema = z.object({
44
- count: z.coerce.number(),
45
- });
46
- const result = await safeParseJSON({
47
- text: '{"count": "42"}',
48
- schema,
49
- });
50
-
51
- expect(result).toEqual({
52
- success: true,
53
- value: { count: 42 },
54
- rawValue: { count: '42' },
55
- });
56
- });
57
-
58
- it('should handle failed parsing with error details', async () => {
59
- const result = await safeParseJSON({ text: 'invalid json' });
60
- expect(result).toEqual({
61
- success: false,
62
- error: expect.any(JSONParseError),
63
- });
64
- });
65
-
66
- it('should handle schema validation failures', async () => {
67
- const schema = z.object({ age: z.number() });
68
- const result = await safeParseJSON({
69
- text: '{"age": "twenty"}',
70
- schema,
71
- });
72
-
73
- expect(result).toEqual({
74
- success: false,
75
- error: expect.any(TypeValidationError),
76
- rawValue: { age: 'twenty' },
77
- });
78
- });
79
-
80
- it('should handle nested objects and preserve raw values', async () => {
81
- const schema = z.object({
82
- user: z.object({
83
- id: z.string().transform(val => parseInt(val, 10)),
84
- name: z.string(),
85
- }),
86
- });
87
-
88
- const result = await safeParseJSON({
89
- text: '{"user": {"id": "123", "name": "John"}}',
90
- schema: schema as any,
91
- });
92
-
93
- expect(result).toEqual({
94
- success: true,
95
- value: { user: { id: 123, name: 'John' } },
96
- rawValue: { user: { id: '123', name: 'John' } },
97
- });
98
- });
99
-
100
- it('should handle arrays and preserve raw values', async () => {
101
- const schema = z.array(z.string().transform(val => val.toUpperCase()));
102
- const result = await safeParseJSON({
103
- text: '["hello", "world"]',
104
- schema,
105
- });
106
-
107
- expect(result).toEqual({
108
- success: true,
109
- value: ['HELLO', 'WORLD'],
110
- rawValue: ['hello', 'world'],
111
- });
112
- });
113
-
114
- it('should handle discriminated unions in schema', async () => {
115
- const schema = z.discriminatedUnion('type', [
116
- z.object({ type: z.literal('text'), content: z.string() }),
117
- z.object({ type: z.literal('number'), value: z.number() }),
118
- ]);
119
-
120
- const result = await safeParseJSON({
121
- text: '{"type": "text", "content": "hello"}',
122
- schema,
123
- });
124
-
125
- expect(result).toEqual({
126
- success: true,
127
- value: { type: 'text', content: 'hello' },
128
- rawValue: { type: 'text', content: 'hello' },
129
- });
130
- });
131
-
132
- it('should handle nullable fields in schema', async () => {
133
- const schema = z.object({
134
- id: z.string().nullish(),
135
- data: z.string(),
136
- });
137
-
138
- const result = await safeParseJSON({
139
- text: '{"id": null, "data": "test"}',
140
- schema,
141
- });
142
-
143
- expect(result).toEqual({
144
- success: true,
145
- value: { id: null, data: 'test' },
146
- rawValue: { id: null, data: 'test' },
147
- });
148
- });
149
-
150
- it('should handle union types in schema', async () => {
151
- const schema = z.object({
152
- value: z.union([z.string(), z.number()]),
153
- });
154
-
155
- const result1 = await safeParseJSON({
156
- text: '{"value": "test"}',
157
- schema,
158
- });
159
-
160
- const result2 = await safeParseJSON({
161
- text: '{"value": 123}',
162
- schema,
163
- });
164
-
165
- expect(result1).toEqual({
166
- success: true,
167
- value: { value: 'test' },
168
- rawValue: { value: 'test' },
169
- });
170
-
171
- expect(result2).toEqual({
172
- success: true,
173
- value: { value: 123 },
174
- rawValue: { value: 123 },
175
- });
176
- });
177
- });
178
-
179
- describe('isParsableJson', () => {
180
- it('should return true for valid JSON', () => {
181
- expect(isParsableJson('{"foo": "bar"}')).toBe(true);
182
- expect(isParsableJson('[1, 2, 3]')).toBe(true);
183
- expect(isParsableJson('"hello"')).toBe(true);
184
- });
185
-
186
- it('should return false for invalid JSON', () => {
187
- expect(isParsableJson('invalid')).toBe(false);
188
- expect(isParsableJson('{foo: "bar"}')).toBe(false);
189
- expect(isParsableJson('{"foo": }')).toBe(false);
190
- });
191
- });
@@ -1,57 +0,0 @@
1
- import { expect, it } from 'vitest';
2
- import { removeUndefinedEntries } from './remove-undefined-entries';
3
-
4
- it('should remove undefined entries from record', () => {
5
- const input = {
6
- a: 1,
7
- b: undefined,
8
- c: 'test',
9
- d: undefined,
10
- };
11
-
12
- expect(removeUndefinedEntries(input)).toEqual({
13
- a: 1,
14
- c: 'test',
15
- });
16
- });
17
-
18
- it('should handle empty object', () => {
19
- const input = {};
20
- expect(removeUndefinedEntries(input)).toEqual({});
21
- });
22
-
23
- it('should handle object with all undefined values', () => {
24
- const input = {
25
- a: undefined,
26
- b: undefined,
27
- };
28
- expect(removeUndefinedEntries(input)).toEqual({});
29
- });
30
-
31
- it('should remove null values', () => {
32
- // Both null and undefined will be removed.
33
- const input = {
34
- a: null,
35
- b: undefined,
36
- c: 'test',
37
- };
38
- expect(removeUndefinedEntries(input)).toEqual({
39
- c: 'test',
40
- });
41
- });
42
-
43
- it('should preserve falsy values except null and undefined', () => {
44
- // Only false, 0, and '' are preserved.
45
- const input = {
46
- a: false,
47
- b: 0,
48
- c: '',
49
- d: undefined,
50
- e: null,
51
- };
52
- expect(removeUndefinedEntries(input)).toEqual({
53
- a: false,
54
- b: 0,
55
- c: '',
56
- });
57
- });
@@ -1,125 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { resolve, Resolvable } from './resolve';
3
-
4
- describe('resolve', () => {
5
- // Test raw values
6
- it('should resolve raw values', async () => {
7
- const value: Resolvable<number> = 42;
8
- expect(await resolve(value)).toBe(42);
9
- });
10
-
11
- it('should resolve raw objects', async () => {
12
- const value: Resolvable<object> = { foo: 'bar' };
13
- expect(await resolve(value)).toEqual({ foo: 'bar' });
14
- });
15
-
16
- // Test promises
17
- it('should resolve promises', async () => {
18
- const value: Resolvable<string> = Promise.resolve('hello');
19
- expect(await resolve(value)).toBe('hello');
20
- });
21
-
22
- it('should resolve rejected promises', async () => {
23
- const value: Resolvable<string> = Promise.reject(new Error('test error'));
24
- await expect(resolve(value)).rejects.toThrow('test error');
25
- });
26
-
27
- // Test synchronous functions
28
- it('should resolve synchronous functions', async () => {
29
- const value: Resolvable<number> = () => 42;
30
- expect(await resolve(value)).toBe(42);
31
- });
32
-
33
- it('should resolve synchronous functions returning objects', async () => {
34
- const value: Resolvable<object> = () => ({ foo: 'bar' });
35
- expect(await resolve(value)).toEqual({ foo: 'bar' });
36
- });
37
-
38
- // Test async functions
39
- it('should resolve async functions', async () => {
40
- const value: Resolvable<string> = async () => 'hello';
41
- expect(await resolve(value)).toBe('hello');
42
- });
43
-
44
- it('should resolve async functions returning promises', async () => {
45
- const value: Resolvable<number> = () => Promise.resolve(42);
46
- expect(await resolve(value)).toBe(42);
47
- });
48
-
49
- it('should handle async function rejections', async () => {
50
- const value: Resolvable<string> = async () => {
51
- throw new Error('async error');
52
- };
53
- await expect(resolve(value)).rejects.toThrow('async error');
54
- });
55
-
56
- // Test edge cases
57
- it('should handle null', async () => {
58
- const value: Resolvable<null> = null;
59
- expect(await resolve(value)).toBe(null);
60
- });
61
-
62
- it('should handle undefined', async () => {
63
- const value: Resolvable<undefined> = undefined;
64
- expect(await resolve(value)).toBe(undefined);
65
- });
66
-
67
- // Test with complex objects
68
- it('should resolve nested objects', async () => {
69
- const value: Resolvable<{ nested: { value: number } }> = {
70
- nested: { value: 42 },
71
- };
72
- expect(await resolve(value)).toEqual({ nested: { value: 42 } });
73
- });
74
-
75
- // Test resolving objects as frequently used in headers as a common example
76
- describe('resolve headers', () => {
77
- it('should resolve header objects', async () => {
78
- const headers = { 'Content-Type': 'application/json' };
79
- expect(await resolve(headers)).toEqual(headers);
80
- });
81
-
82
- it('should resolve header functions', async () => {
83
- const headers = () => ({ Authorization: 'Bearer token' });
84
- expect(await resolve(headers)).toEqual({ Authorization: 'Bearer token' });
85
- });
86
-
87
- it('should resolve async header functions', async () => {
88
- const headers = async () => ({ 'X-Custom': 'value' });
89
- expect(await resolve(headers)).toEqual({ 'X-Custom': 'value' });
90
- });
91
-
92
- it('should resolve header promises', async () => {
93
- const headers = Promise.resolve({ Accept: 'application/json' });
94
- expect(await resolve(headers)).toEqual({ Accept: 'application/json' });
95
- });
96
-
97
- it('should call async header functions each time when resolved multiple times', async () => {
98
- let counter = 0;
99
- const headers = async () => ({ 'X-Request-Number': String(++counter) });
100
-
101
- // Resolve the same headers function multiple times
102
- expect(await resolve(headers)).toEqual({ 'X-Request-Number': '1' });
103
- expect(await resolve(headers)).toEqual({ 'X-Request-Number': '2' });
104
- expect(await resolve(headers)).toEqual({ 'X-Request-Number': '3' });
105
- });
106
- });
107
-
108
- // Test type inference
109
- it('should maintain type information', async () => {
110
- interface User {
111
- id: number;
112
- name: string;
113
- }
114
-
115
- const userPromise: Resolvable<User> = Promise.resolve({
116
- id: 1,
117
- name: 'Test User',
118
- });
119
-
120
- const result = await resolve(userPromise);
121
- // TypeScript should recognize result as User type
122
- expect(result.id).toBe(1);
123
- expect(result.name).toBe('Test User');
124
- });
125
- });
@@ -1,89 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { z } from 'zod/v4';
3
- import {
4
- createBinaryResponseHandler,
5
- createJsonResponseHandler,
6
- createStatusCodeErrorResponseHandler,
7
- } from './response-handler';
8
-
9
- describe('createJsonResponseHandler', () => {
10
- it('should return both parsed value and rawValue', async () => {
11
- const responseSchema = z.object({
12
- name: z.string(),
13
- age: z.number(),
14
- });
15
-
16
- const rawData = {
17
- name: 'John',
18
- age: 30,
19
- extraField: 'ignored',
20
- };
21
-
22
- const response = new Response(JSON.stringify(rawData));
23
- const handler = createJsonResponseHandler(responseSchema);
24
-
25
- const result = await handler({
26
- url: 'test-url',
27
- requestBodyValues: {},
28
- response,
29
- });
30
-
31
- expect(result.value).toEqual({
32
- name: 'John',
33
- age: 30,
34
- });
35
- expect(result.rawValue).toEqual(rawData);
36
- });
37
- });
38
-
39
- describe('createBinaryResponseHandler', () => {
40
- it('should handle binary response successfully', async () => {
41
- const binaryData = new Uint8Array([1, 2, 3, 4]);
42
- const response = new Response(binaryData);
43
- const handler = createBinaryResponseHandler();
44
-
45
- const result = await handler({
46
- url: 'test-url',
47
- requestBodyValues: {},
48
- response,
49
- });
50
-
51
- expect(result.value).toBeInstanceOf(Uint8Array);
52
- expect(result.value).toEqual(binaryData);
53
- });
54
-
55
- it('should throw APICallError when response body is null', async () => {
56
- const response = new Response(null);
57
- const handler = createBinaryResponseHandler();
58
-
59
- await expect(
60
- handler({
61
- url: 'test-url',
62
- requestBodyValues: {},
63
- response,
64
- }),
65
- ).rejects.toThrow('Response body is empty');
66
- });
67
- });
68
-
69
- describe('createStatusCodeErrorResponseHandler', () => {
70
- it('should create error with status text and response body', async () => {
71
- const response = new Response('Error message', {
72
- status: 404,
73
- statusText: 'Not Found',
74
- });
75
- const handler = createStatusCodeErrorResponseHandler();
76
-
77
- const result = await handler({
78
- url: 'test-url',
79
- requestBodyValues: { some: 'data' },
80
- response,
81
- });
82
-
83
- expect(result.value.message).toBe('Not Found');
84
- expect(result.value.statusCode).toBe(404);
85
- expect(result.value.responseBody).toBe('Error message');
86
- expect(result.value.url).toBe('test-url');
87
- expect(result.value.requestBodyValues).toEqual({ some: 'data' });
88
- });
89
- });
@@ -1,11 +0,0 @@
1
- import { describe, expectTypeOf, it } from 'vitest';
2
- import { InferSchema, StandardSchema } from './schema';
3
-
4
- describe('InferSchema type', () => {
5
- it('should work with StandardSchema', () => {
6
- type MySchema = StandardSchema<number>;
7
- type Result = InferSchema<MySchema>;
8
-
9
- expectTypeOf<Result>().toMatchTypeOf<number>();
10
- });
11
- });