@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.
- package/CHANGELOG.md +14 -0
- package/dist/index.js +29 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +29 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -2
- package/src/handle-fetch-error.ts +33 -0
- package/src/__snapshots__/schema.test.ts.snap +0 -346
- package/src/add-additional-properties-to-json-schema.test.ts +0 -289
- package/src/convert-async-iterator-to-readable-stream.test.ts +0 -78
- package/src/convert-image-model-file-to-data-uri.test.ts +0 -85
- package/src/convert-to-form-data.test.ts +0 -167
- package/src/create-tool-name-mapping.test.ts +0 -163
- package/src/delay.test.ts +0 -212
- package/src/delayed-promise.test.ts +0 -132
- package/src/download-blob.test.ts +0 -145
- package/src/generate-id.test.ts +0 -31
- package/src/get-from-api.test.ts +0 -199
- package/src/get-runtime-environment-user-agent.test.ts +0 -47
- package/src/inject-json-instruction.test.ts +0 -404
- package/src/is-url-supported.test.ts +0 -282
- package/src/media-type-to-extension.test.ts +0 -26
- package/src/normalize-headers.test.ts +0 -64
- package/src/parse-json.test.ts +0 -191
- package/src/remove-undefined-entries.test.ts +0 -57
- package/src/resolve.test.ts +0 -125
- package/src/response-handler.test.ts +0 -89
- package/src/schema.test-d.ts +0 -11
- package/src/schema.test.ts +0 -502
- package/src/secure-json-parse.test.ts +0 -59
- package/src/to-json-schema/zod3-to-json-schema/parse-def.test.ts +0 -224
- package/src/to-json-schema/zod3-to-json-schema/parsers/array.test.ts +0 -98
- package/src/to-json-schema/zod3-to-json-schema/parsers/bigint.test.ts +0 -51
- package/src/to-json-schema/zod3-to-json-schema/parsers/branded.test.ts +0 -16
- package/src/to-json-schema/zod3-to-json-schema/parsers/catch.test.ts +0 -15
- package/src/to-json-schema/zod3-to-json-schema/parsers/date.test.ts +0 -97
- package/src/to-json-schema/zod3-to-json-schema/parsers/default.test.ts +0 -54
- package/src/to-json-schema/zod3-to-json-schema/parsers/effects.test.ts +0 -41
- package/src/to-json-schema/zod3-to-json-schema/parsers/intersection.test.ts +0 -92
- package/src/to-json-schema/zod3-to-json-schema/parsers/map.test.ts +0 -48
- package/src/to-json-schema/zod3-to-json-schema/parsers/native-enum.test.ts +0 -102
- package/src/to-json-schema/zod3-to-json-schema/parsers/nullable.test.ts +0 -67
- package/src/to-json-schema/zod3-to-json-schema/parsers/number.test.ts +0 -65
- package/src/to-json-schema/zod3-to-json-schema/parsers/object.test.ts +0 -149
- package/src/to-json-schema/zod3-to-json-schema/parsers/optional.test.ts +0 -147
- package/src/to-json-schema/zod3-to-json-schema/parsers/pipe.test.ts +0 -35
- package/src/to-json-schema/zod3-to-json-schema/parsers/promise.test.ts +0 -15
- package/src/to-json-schema/zod3-to-json-schema/parsers/readonly.test.ts +0 -20
- package/src/to-json-schema/zod3-to-json-schema/parsers/record.test.ts +0 -108
- package/src/to-json-schema/zod3-to-json-schema/parsers/set.test.ts +0 -20
- package/src/to-json-schema/zod3-to-json-schema/parsers/string.test.ts +0 -438
- package/src/to-json-schema/zod3-to-json-schema/parsers/tuple.test.ts +0 -33
- package/src/to-json-schema/zod3-to-json-schema/parsers/union.test.ts +0 -226
- package/src/to-json-schema/zod3-to-json-schema/refs.test.ts +0 -919
- package/src/to-json-schema/zod3-to-json-schema/zod3-to-json-schema.test.ts +0 -862
- package/src/types/tool.test-d.ts +0 -228
- package/src/validate-types.test.ts +0 -105
- package/src/with-user-agent-suffix.test.ts +0 -84
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import { DelayedPromise } from './delayed-promise';
|
|
2
|
-
import { delay } from '@ai-sdk/provider-utils';
|
|
3
|
-
import { describe, it, expect } from 'vitest';
|
|
4
|
-
|
|
5
|
-
describe('DelayedPromise', () => {
|
|
6
|
-
it('should resolve when accessed after resolution', async () => {
|
|
7
|
-
const dp = new DelayedPromise<string>();
|
|
8
|
-
dp.resolve('success');
|
|
9
|
-
expect(await dp.promise).toBe('success');
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
it('should reject when accessed after rejection', async () => {
|
|
13
|
-
const dp = new DelayedPromise<string>();
|
|
14
|
-
const error = new Error('failure');
|
|
15
|
-
dp.reject(error);
|
|
16
|
-
await expect(dp.promise).rejects.toThrow('failure');
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it('should resolve when accessed before resolution', async () => {
|
|
20
|
-
const dp = new DelayedPromise<string>();
|
|
21
|
-
const promise = dp.promise;
|
|
22
|
-
dp.resolve('success');
|
|
23
|
-
expect(await promise).toBe('success');
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it('should reject when accessed before rejection', async () => {
|
|
27
|
-
const dp = new DelayedPromise<string>();
|
|
28
|
-
const promise = dp.promise;
|
|
29
|
-
const error = new Error('failure');
|
|
30
|
-
dp.reject(error);
|
|
31
|
-
await expect(promise).rejects.toThrow('failure');
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it('should maintain the resolved state after multiple accesses', async () => {
|
|
35
|
-
const dp = new DelayedPromise<string>();
|
|
36
|
-
dp.resolve('success');
|
|
37
|
-
expect(await dp.promise).toBe('success');
|
|
38
|
-
expect(await dp.promise).toBe('success');
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('should maintain the rejected state after multiple accesses', async () => {
|
|
42
|
-
const dp = new DelayedPromise<string>();
|
|
43
|
-
const error = new Error('failure');
|
|
44
|
-
dp.reject(error);
|
|
45
|
-
await expect(dp.promise).rejects.toThrow('failure');
|
|
46
|
-
await expect(dp.promise).rejects.toThrow('failure');
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('should block until resolved when accessed before resolution', async () => {
|
|
50
|
-
const dp = new DelayedPromise<string>();
|
|
51
|
-
let resolved = false;
|
|
52
|
-
|
|
53
|
-
// Access the promise before resolving
|
|
54
|
-
const promise = dp.promise.then(value => {
|
|
55
|
-
resolved = true;
|
|
56
|
-
return value;
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
// Promise should not be resolved yet
|
|
60
|
-
expect(resolved).toBe(false);
|
|
61
|
-
|
|
62
|
-
// Wait a bit to ensure it's truly blocking
|
|
63
|
-
await delay(10);
|
|
64
|
-
expect(resolved).toBe(false);
|
|
65
|
-
|
|
66
|
-
// Now resolve it
|
|
67
|
-
dp.resolve('delayed-success');
|
|
68
|
-
|
|
69
|
-
// Should now resolve
|
|
70
|
-
const result = await promise;
|
|
71
|
-
expect(result).toBe('delayed-success');
|
|
72
|
-
expect(resolved).toBe(true);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
it('should block until rejected when accessed before rejection', async () => {
|
|
76
|
-
const dp = new DelayedPromise<string>();
|
|
77
|
-
let rejected = false;
|
|
78
|
-
|
|
79
|
-
// Access the promise before rejecting
|
|
80
|
-
const promise = dp.promise.catch(error => {
|
|
81
|
-
rejected = true;
|
|
82
|
-
throw error;
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
// Promise should not be rejected yet
|
|
86
|
-
expect(rejected).toBe(false);
|
|
87
|
-
|
|
88
|
-
// Wait a bit to ensure it's truly blocking
|
|
89
|
-
await delay(10);
|
|
90
|
-
expect(rejected).toBe(false);
|
|
91
|
-
|
|
92
|
-
// Now reject it
|
|
93
|
-
const error = new Error('delayed-failure');
|
|
94
|
-
dp.reject(error);
|
|
95
|
-
|
|
96
|
-
// Should now reject
|
|
97
|
-
await expect(promise).rejects.toThrow('delayed-failure');
|
|
98
|
-
expect(rejected).toBe(true);
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
it('should resolve all pending promises when resolved after access', async () => {
|
|
102
|
-
const dp = new DelayedPromise<string>();
|
|
103
|
-
const results: string[] = [];
|
|
104
|
-
|
|
105
|
-
// Access the promise multiple times before resolution
|
|
106
|
-
const promise1 = dp.promise.then(value => {
|
|
107
|
-
results.push(`first: ${value}`);
|
|
108
|
-
return value;
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
const promise2 = dp.promise.then(value => {
|
|
112
|
-
results.push(`second: ${value}`);
|
|
113
|
-
return value;
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
// Neither should be resolved yet
|
|
117
|
-
expect(results).toHaveLength(0);
|
|
118
|
-
|
|
119
|
-
// Wait to ensure they're blocking
|
|
120
|
-
await delay(10);
|
|
121
|
-
expect(results).toHaveLength(0);
|
|
122
|
-
|
|
123
|
-
// Resolve the promise
|
|
124
|
-
dp.resolve('success');
|
|
125
|
-
|
|
126
|
-
// Both should resolve
|
|
127
|
-
await Promise.all([promise1, promise2]);
|
|
128
|
-
expect(results).toHaveLength(2);
|
|
129
|
-
expect(results).toContain('first: success');
|
|
130
|
-
expect(results).toContain('second: success');
|
|
131
|
-
});
|
|
132
|
-
});
|
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
import { downloadBlob } from './download-blob';
|
|
3
|
-
import { DownloadError } from './download-error';
|
|
4
|
-
|
|
5
|
-
describe('downloadBlob()', () => {
|
|
6
|
-
const originalFetch = globalThis.fetch;
|
|
7
|
-
|
|
8
|
-
beforeEach(() => {
|
|
9
|
-
vi.resetAllMocks();
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
afterEach(() => {
|
|
13
|
-
globalThis.fetch = originalFetch;
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
it('should download a blob successfully', async () => {
|
|
17
|
-
const mockBlob = new Blob(['test content'], { type: 'image/png' });
|
|
18
|
-
globalThis.fetch = vi.fn().mockResolvedValue({
|
|
19
|
-
ok: true,
|
|
20
|
-
blob: () => Promise.resolve(mockBlob),
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
const result = await downloadBlob('https://example.com/image.png');
|
|
24
|
-
|
|
25
|
-
expect(result).toBe(mockBlob);
|
|
26
|
-
expect(fetch).toHaveBeenCalledWith('https://example.com/image.png');
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it('should throw DownloadError on non-ok response', async () => {
|
|
30
|
-
globalThis.fetch = vi.fn().mockResolvedValue({
|
|
31
|
-
ok: false,
|
|
32
|
-
status: 404,
|
|
33
|
-
statusText: 'Not Found',
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
await expect(
|
|
37
|
-
downloadBlob('https://example.com/not-found.png'),
|
|
38
|
-
).rejects.toThrow(DownloadError);
|
|
39
|
-
|
|
40
|
-
try {
|
|
41
|
-
await downloadBlob('https://example.com/not-found.png');
|
|
42
|
-
} catch (error) {
|
|
43
|
-
expect(DownloadError.isInstance(error)).toBe(true);
|
|
44
|
-
if (DownloadError.isInstance(error)) {
|
|
45
|
-
expect(error.url).toBe('https://example.com/not-found.png');
|
|
46
|
-
expect(error.statusCode).toBe(404);
|
|
47
|
-
expect(error.statusText).toBe('Not Found');
|
|
48
|
-
expect(error.message).toBe(
|
|
49
|
-
'Failed to download https://example.com/not-found.png: 404 Not Found',
|
|
50
|
-
);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('should throw DownloadError on network error', async () => {
|
|
56
|
-
const networkError = new Error('Network error');
|
|
57
|
-
globalThis.fetch = vi.fn().mockRejectedValue(networkError);
|
|
58
|
-
|
|
59
|
-
await expect(
|
|
60
|
-
downloadBlob('https://example.com/network-error.png'),
|
|
61
|
-
).rejects.toThrow(DownloadError);
|
|
62
|
-
|
|
63
|
-
try {
|
|
64
|
-
await downloadBlob('https://example.com/network-error.png');
|
|
65
|
-
} catch (error) {
|
|
66
|
-
expect(DownloadError.isInstance(error)).toBe(true);
|
|
67
|
-
if (DownloadError.isInstance(error)) {
|
|
68
|
-
expect(error.url).toBe('https://example.com/network-error.png');
|
|
69
|
-
expect(error.cause).toBe(networkError);
|
|
70
|
-
expect(error.message).toContain('Network error');
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
it('should re-throw DownloadError without wrapping', async () => {
|
|
76
|
-
const originalError = new DownloadError({
|
|
77
|
-
url: 'https://example.com/original.png',
|
|
78
|
-
statusCode: 500,
|
|
79
|
-
statusText: 'Internal Server Error',
|
|
80
|
-
});
|
|
81
|
-
globalThis.fetch = vi.fn().mockRejectedValue(originalError);
|
|
82
|
-
|
|
83
|
-
try {
|
|
84
|
-
await downloadBlob('https://example.com/test.png');
|
|
85
|
-
} catch (error) {
|
|
86
|
-
expect(error).toBe(originalError);
|
|
87
|
-
expect(DownloadError.isInstance(error)).toBe(true);
|
|
88
|
-
if (DownloadError.isInstance(error)) {
|
|
89
|
-
expect(error.url).toBe('https://example.com/original.png');
|
|
90
|
-
expect(error.statusCode).toBe(500);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
});
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
describe('DownloadError', () => {
|
|
97
|
-
it('should create error with status code and text', () => {
|
|
98
|
-
const error = new DownloadError({
|
|
99
|
-
url: 'https://example.com/test.png',
|
|
100
|
-
statusCode: 403,
|
|
101
|
-
statusText: 'Forbidden',
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
expect(error.name).toBe('AI_DownloadError');
|
|
105
|
-
expect(error.url).toBe('https://example.com/test.png');
|
|
106
|
-
expect(error.statusCode).toBe(403);
|
|
107
|
-
expect(error.statusText).toBe('Forbidden');
|
|
108
|
-
expect(error.message).toBe(
|
|
109
|
-
'Failed to download https://example.com/test.png: 403 Forbidden',
|
|
110
|
-
);
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
it('should create error with cause', () => {
|
|
114
|
-
const cause = new Error('Connection refused');
|
|
115
|
-
const error = new DownloadError({
|
|
116
|
-
url: 'https://example.com/test.png',
|
|
117
|
-
cause,
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
expect(error.url).toBe('https://example.com/test.png');
|
|
121
|
-
expect(error.cause).toBe(cause);
|
|
122
|
-
expect(error.message).toContain('Connection refused');
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
it('should create error with custom message', () => {
|
|
126
|
-
const error = new DownloadError({
|
|
127
|
-
url: 'https://example.com/test.png',
|
|
128
|
-
message: 'Custom error message',
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
expect(error.message).toBe('Custom error message');
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
it('should identify DownloadError instances correctly', () => {
|
|
135
|
-
const downloadError = new DownloadError({
|
|
136
|
-
url: 'https://example.com/test.png',
|
|
137
|
-
});
|
|
138
|
-
const regularError = new Error('Not a download error');
|
|
139
|
-
|
|
140
|
-
expect(DownloadError.isInstance(downloadError)).toBe(true);
|
|
141
|
-
expect(DownloadError.isInstance(regularError)).toBe(false);
|
|
142
|
-
expect(DownloadError.isInstance(null)).toBe(false);
|
|
143
|
-
expect(DownloadError.isInstance(undefined)).toBe(false);
|
|
144
|
-
});
|
|
145
|
-
});
|
package/src/generate-id.test.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { InvalidArgumentError } from '@ai-sdk/provider';
|
|
2
|
-
import { expect, it } from 'vitest';
|
|
3
|
-
import { createIdGenerator, generateId } from './generate-id';
|
|
4
|
-
import { describe } from 'vitest';
|
|
5
|
-
|
|
6
|
-
describe('createIdGenerator', () => {
|
|
7
|
-
it('should generate an ID with the correct length', () => {
|
|
8
|
-
const idGenerator = createIdGenerator({ size: 10 });
|
|
9
|
-
expect(idGenerator()).toHaveLength(10);
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
it('should generate an ID with the correct default length', () => {
|
|
13
|
-
const idGenerator = createIdGenerator();
|
|
14
|
-
expect(idGenerator()).toHaveLength(16);
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
it('should throw an error if the separator is part of the alphabet', () => {
|
|
18
|
-
expect(() => createIdGenerator({ separator: 'a', prefix: 'b' })).toThrow(
|
|
19
|
-
InvalidArgumentError,
|
|
20
|
-
);
|
|
21
|
-
});
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
describe('generateId', () => {
|
|
25
|
-
it('should generate unique IDs', () => {
|
|
26
|
-
const id1 = generateId();
|
|
27
|
-
const id2 = generateId();
|
|
28
|
-
|
|
29
|
-
expect(id1).not.toBe(id2);
|
|
30
|
-
});
|
|
31
|
-
});
|
package/src/get-from-api.test.ts
DELETED
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
import { APICallError } from '@ai-sdk/provider';
|
|
2
|
-
import { describe, it, expect, vi } from 'vitest';
|
|
3
|
-
import { getFromApi } from './get-from-api';
|
|
4
|
-
import {
|
|
5
|
-
createJsonResponseHandler,
|
|
6
|
-
createStatusCodeErrorResponseHandler,
|
|
7
|
-
} from './response-handler';
|
|
8
|
-
import { z } from 'zod/v4';
|
|
9
|
-
import { getRuntimeEnvironmentUserAgent } from './get-runtime-environment-user-agent';
|
|
10
|
-
import { withUserAgentSuffix } from './with-user-agent-suffix';
|
|
11
|
-
|
|
12
|
-
vi.mock('./get-runtime-environment-user-agent', async () => {
|
|
13
|
-
const actual = await vi.importActual('./get-runtime-environment-user-agent');
|
|
14
|
-
return {
|
|
15
|
-
...actual,
|
|
16
|
-
getRuntimeEnvironmentUserAgent: () => 'runtime/test-env',
|
|
17
|
-
};
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
describe('getFromApi', () => {
|
|
21
|
-
const mockSuccessResponse = {
|
|
22
|
-
name: 'test',
|
|
23
|
-
value: 123,
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
const mockResponseSchema = z.object({
|
|
27
|
-
name: z.string(),
|
|
28
|
-
value: z.number(),
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
const mockHeaders = {
|
|
32
|
-
'Content-Type': 'application/json',
|
|
33
|
-
Authorization: 'Bearer test',
|
|
34
|
-
'user-agent': 'runtime/test-env',
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
it('should successfully fetch and parse data', async () => {
|
|
38
|
-
const mockFetch = vi.fn().mockResolvedValue(
|
|
39
|
-
new Response(JSON.stringify(mockSuccessResponse), {
|
|
40
|
-
status: 200,
|
|
41
|
-
headers: withUserAgentSuffix(
|
|
42
|
-
mockHeaders,
|
|
43
|
-
getRuntimeEnvironmentUserAgent(),
|
|
44
|
-
),
|
|
45
|
-
}),
|
|
46
|
-
);
|
|
47
|
-
|
|
48
|
-
const result = await getFromApi({
|
|
49
|
-
url: 'https://api.test.com/data',
|
|
50
|
-
headers: { Authorization: 'Bearer test' },
|
|
51
|
-
successfulResponseHandler: createJsonResponseHandler(mockResponseSchema),
|
|
52
|
-
failedResponseHandler: createStatusCodeErrorResponseHandler(),
|
|
53
|
-
fetch: mockFetch,
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
expect(result.value).toEqual(mockSuccessResponse);
|
|
57
|
-
expect(mockFetch).toHaveBeenCalledWith(
|
|
58
|
-
'https://api.test.com/data',
|
|
59
|
-
expect.objectContaining({
|
|
60
|
-
method: 'GET',
|
|
61
|
-
headers: {
|
|
62
|
-
authorization: 'Bearer test',
|
|
63
|
-
'user-agent': 'ai-sdk/provider-utils/0.0.0-test runtime/test-env',
|
|
64
|
-
},
|
|
65
|
-
}),
|
|
66
|
-
);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it('should handle API errors', async () => {
|
|
70
|
-
const errorResponse = { error: 'Not Found' };
|
|
71
|
-
const mockFetch = vi.fn().mockResolvedValue(
|
|
72
|
-
new Response(JSON.stringify(errorResponse), {
|
|
73
|
-
status: 404,
|
|
74
|
-
statusText: 'Not Found',
|
|
75
|
-
headers: mockHeaders,
|
|
76
|
-
}),
|
|
77
|
-
);
|
|
78
|
-
|
|
79
|
-
await expect(
|
|
80
|
-
getFromApi({
|
|
81
|
-
url: 'https://api.test.com/data',
|
|
82
|
-
successfulResponseHandler:
|
|
83
|
-
createJsonResponseHandler(mockResponseSchema),
|
|
84
|
-
failedResponseHandler: createStatusCodeErrorResponseHandler(),
|
|
85
|
-
fetch: mockFetch,
|
|
86
|
-
}),
|
|
87
|
-
).rejects.toThrow(APICallError);
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
it('should handle network errors', async () => {
|
|
91
|
-
const mockFetch = vi.fn().mockRejectedValue(
|
|
92
|
-
Object.assign(new TypeError('fetch failed'), {
|
|
93
|
-
cause: new Error('Failed to connect'),
|
|
94
|
-
}),
|
|
95
|
-
);
|
|
96
|
-
|
|
97
|
-
await expect(
|
|
98
|
-
getFromApi({
|
|
99
|
-
url: 'https://api.test.com/data',
|
|
100
|
-
successfulResponseHandler:
|
|
101
|
-
createJsonResponseHandler(mockResponseSchema),
|
|
102
|
-
failedResponseHandler: createStatusCodeErrorResponseHandler(),
|
|
103
|
-
fetch: mockFetch,
|
|
104
|
-
}),
|
|
105
|
-
).rejects.toThrow('Cannot connect to API: Failed to connect');
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
it('should handle abort signals', async () => {
|
|
109
|
-
const abortController = new AbortController();
|
|
110
|
-
const mockFetch = vi.fn().mockImplementation(() => {
|
|
111
|
-
abortController.abort();
|
|
112
|
-
return Promise.reject(new DOMException('Aborted', 'AbortError'));
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
await expect(
|
|
116
|
-
getFromApi({
|
|
117
|
-
url: 'https://api.test.com/data',
|
|
118
|
-
successfulResponseHandler:
|
|
119
|
-
createJsonResponseHandler(mockResponseSchema),
|
|
120
|
-
failedResponseHandler: createStatusCodeErrorResponseHandler(),
|
|
121
|
-
fetch: mockFetch,
|
|
122
|
-
abortSignal: abortController.signal,
|
|
123
|
-
}),
|
|
124
|
-
).rejects.toThrow('Aborted');
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
it('should remove undefined header entries', async () => {
|
|
128
|
-
const mockFetch = vi.fn().mockResolvedValue(
|
|
129
|
-
new Response(JSON.stringify(mockSuccessResponse), {
|
|
130
|
-
status: 200,
|
|
131
|
-
headers: mockHeaders,
|
|
132
|
-
}),
|
|
133
|
-
);
|
|
134
|
-
|
|
135
|
-
await getFromApi({
|
|
136
|
-
url: 'https://api.test.com/data',
|
|
137
|
-
headers: {
|
|
138
|
-
Authorization: 'Bearer test',
|
|
139
|
-
'X-Custom-Header': undefined,
|
|
140
|
-
},
|
|
141
|
-
successfulResponseHandler: createJsonResponseHandler(mockResponseSchema),
|
|
142
|
-
failedResponseHandler: createStatusCodeErrorResponseHandler(),
|
|
143
|
-
fetch: mockFetch,
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
expect(mockFetch).toHaveBeenCalledWith(
|
|
147
|
-
'https://api.test.com/data',
|
|
148
|
-
expect.objectContaining({
|
|
149
|
-
headers: {
|
|
150
|
-
authorization: 'Bearer test',
|
|
151
|
-
'user-agent': 'ai-sdk/provider-utils/0.0.0-test runtime/test-env',
|
|
152
|
-
},
|
|
153
|
-
}),
|
|
154
|
-
);
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
it('should handle errors in response handlers', async () => {
|
|
158
|
-
const mockFetch = vi.fn().mockResolvedValue(
|
|
159
|
-
new Response('invalid json', {
|
|
160
|
-
status: 200,
|
|
161
|
-
headers: mockHeaders,
|
|
162
|
-
}),
|
|
163
|
-
);
|
|
164
|
-
|
|
165
|
-
await expect(
|
|
166
|
-
getFromApi({
|
|
167
|
-
url: 'https://api.test.com/data',
|
|
168
|
-
successfulResponseHandler:
|
|
169
|
-
createJsonResponseHandler(mockResponseSchema),
|
|
170
|
-
failedResponseHandler: createStatusCodeErrorResponseHandler(),
|
|
171
|
-
fetch: mockFetch,
|
|
172
|
-
}),
|
|
173
|
-
).rejects.toThrow(APICallError);
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
it('should use default fetch when not provided', async () => {
|
|
177
|
-
const originalFetch = global.fetch;
|
|
178
|
-
const mockFetch = vi.fn().mockResolvedValue(
|
|
179
|
-
new Response(JSON.stringify(mockSuccessResponse), {
|
|
180
|
-
status: 200,
|
|
181
|
-
headers: mockHeaders,
|
|
182
|
-
}),
|
|
183
|
-
);
|
|
184
|
-
global.fetch = mockFetch;
|
|
185
|
-
|
|
186
|
-
try {
|
|
187
|
-
await getFromApi({
|
|
188
|
-
url: 'https://api.test.com/data',
|
|
189
|
-
successfulResponseHandler:
|
|
190
|
-
createJsonResponseHandler(mockResponseSchema),
|
|
191
|
-
failedResponseHandler: createStatusCodeErrorResponseHandler(),
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
expect(mockFetch).toHaveBeenCalled();
|
|
195
|
-
} finally {
|
|
196
|
-
global.fetch = originalFetch;
|
|
197
|
-
}
|
|
198
|
-
});
|
|
199
|
-
});
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
-
|
|
3
|
-
// Stabilize provider utils version used inside UA string construction
|
|
4
|
-
vi.mock('./version', () => ({
|
|
5
|
-
VERSION: '0.0.0-test',
|
|
6
|
-
}));
|
|
7
|
-
|
|
8
|
-
import { getRuntimeEnvironmentUserAgent } from './get-runtime-environment-user-agent';
|
|
9
|
-
|
|
10
|
-
describe('getRuntimeEnvironmentUserAgent', () => {
|
|
11
|
-
it('should return the correct user agent for browsers', () => {
|
|
12
|
-
expect(
|
|
13
|
-
getRuntimeEnvironmentUserAgent({
|
|
14
|
-
window: true,
|
|
15
|
-
}),
|
|
16
|
-
).toBe('runtime/browser');
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it('should return the correct user agent for test', () => {
|
|
20
|
-
expect(
|
|
21
|
-
getRuntimeEnvironmentUserAgent({
|
|
22
|
-
navigator: {
|
|
23
|
-
userAgent: 'test',
|
|
24
|
-
},
|
|
25
|
-
}),
|
|
26
|
-
).toBe('runtime/test');
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it('should return the correct user agent for Edge Runtime', () => {
|
|
30
|
-
expect(
|
|
31
|
-
getRuntimeEnvironmentUserAgent({
|
|
32
|
-
EdgeRuntime: true,
|
|
33
|
-
}),
|
|
34
|
-
).toBe('runtime/vercel-edge');
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('should return the correct user agent for Node.js', () => {
|
|
38
|
-
expect(
|
|
39
|
-
getRuntimeEnvironmentUserAgent({
|
|
40
|
-
process: {
|
|
41
|
-
versions: { node: 'test' },
|
|
42
|
-
version: 'test',
|
|
43
|
-
},
|
|
44
|
-
}),
|
|
45
|
-
).toBe('runtime/node.js/test');
|
|
46
|
-
});
|
|
47
|
-
});
|