@ai-sdk/provider-utils 3.0.25 → 3.0.27
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 +29 -0
- package/dist/index.d.mts +73 -1
- package/dist/index.d.ts +73 -1
- package/dist/index.js +222 -108
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +218 -108
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -154,6 +154,201 @@ var DownloadError = class extends (_b = AISDKError, _a = symbol, _b) {
|
|
|
154
154
|
}
|
|
155
155
|
};
|
|
156
156
|
|
|
157
|
+
// src/cancel-response-body.ts
|
|
158
|
+
async function cancelResponseBody(response) {
|
|
159
|
+
var _a2;
|
|
160
|
+
try {
|
|
161
|
+
await ((_a2 = response.body) == null ? void 0 : _a2.cancel());
|
|
162
|
+
} catch (e) {
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// src/is-browser-runtime.ts
|
|
167
|
+
function isBrowserRuntime(globalThisAny = globalThis) {
|
|
168
|
+
return globalThisAny.window != null;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// src/validate-download-url.ts
|
|
172
|
+
function validateDownloadUrl(url) {
|
|
173
|
+
let parsed;
|
|
174
|
+
try {
|
|
175
|
+
parsed = new URL(url);
|
|
176
|
+
} catch (e) {
|
|
177
|
+
throw new DownloadError({
|
|
178
|
+
url,
|
|
179
|
+
message: `Invalid URL: ${url}`
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
if (parsed.protocol === "data:") {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
186
|
+
throw new DownloadError({
|
|
187
|
+
url,
|
|
188
|
+
message: `URL scheme must be http, https, or data, got ${parsed.protocol}`
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
const hostname = parsed.hostname.toLowerCase().replace(/\.+$/, "");
|
|
192
|
+
if (!hostname) {
|
|
193
|
+
throw new DownloadError({
|
|
194
|
+
url,
|
|
195
|
+
message: `URL must have a hostname`
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
if (hostname === "localhost" || hostname.endsWith(".local") || hostname.endsWith(".localhost")) {
|
|
199
|
+
throw new DownloadError({
|
|
200
|
+
url,
|
|
201
|
+
message: `URL with hostname ${hostname} is not allowed`
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
if (hostname.startsWith("[") && hostname.endsWith("]")) {
|
|
205
|
+
const ipv6 = hostname.slice(1, -1);
|
|
206
|
+
if (isPrivateIPv6(ipv6)) {
|
|
207
|
+
throw new DownloadError({
|
|
208
|
+
url,
|
|
209
|
+
message: `URL with IPv6 address ${hostname} is not allowed`
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
if (isIPv4(hostname)) {
|
|
215
|
+
if (isPrivateIPv4(hostname)) {
|
|
216
|
+
throw new DownloadError({
|
|
217
|
+
url,
|
|
218
|
+
message: `URL with IP address ${hostname} is not allowed`
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
function isIPv4(hostname) {
|
|
225
|
+
const parts = hostname.split(".");
|
|
226
|
+
if (parts.length !== 4) return false;
|
|
227
|
+
return parts.every((part) => {
|
|
228
|
+
const num = Number(part);
|
|
229
|
+
return Number.isInteger(num) && num >= 0 && num <= 255 && String(num) === part;
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
function isPrivateIPv4(ip) {
|
|
233
|
+
const parts = ip.split(".").map(Number);
|
|
234
|
+
const [a, b, c] = parts;
|
|
235
|
+
if (a === 0) return true;
|
|
236
|
+
if (a === 10) return true;
|
|
237
|
+
if (a === 100 && b >= 64 && b <= 127) return true;
|
|
238
|
+
if (a === 127) return true;
|
|
239
|
+
if (a === 169 && b === 254) return true;
|
|
240
|
+
if (a === 172 && b >= 16 && b <= 31) return true;
|
|
241
|
+
if (a === 192 && b === 0 && c === 0) return true;
|
|
242
|
+
if (a === 192 && b === 168) return true;
|
|
243
|
+
if (a === 198 && (b === 18 || b === 19)) return true;
|
|
244
|
+
if (a >= 240) return true;
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
function parseIPv6(ip) {
|
|
248
|
+
let address = ip.toLowerCase();
|
|
249
|
+
const zoneIndex = address.indexOf("%");
|
|
250
|
+
if (zoneIndex !== -1) {
|
|
251
|
+
address = address.slice(0, zoneIndex);
|
|
252
|
+
}
|
|
253
|
+
const halves = address.split("::");
|
|
254
|
+
if (halves.length > 2) return null;
|
|
255
|
+
const toGroups = (segment) => {
|
|
256
|
+
if (segment === "") return [];
|
|
257
|
+
const groups = [];
|
|
258
|
+
const parts = segment.split(":");
|
|
259
|
+
for (let i = 0; i < parts.length; i++) {
|
|
260
|
+
const part = parts[i];
|
|
261
|
+
if (part.includes(".")) {
|
|
262
|
+
if (i !== parts.length - 1 || !isIPv4(part)) return null;
|
|
263
|
+
const [a, b, c, d] = part.split(".").map(Number);
|
|
264
|
+
groups.push(a << 8 | b, c << 8 | d);
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
if (!/^[0-9a-f]{1,4}$/.test(part)) return null;
|
|
268
|
+
groups.push(parseInt(part, 16));
|
|
269
|
+
}
|
|
270
|
+
return groups;
|
|
271
|
+
};
|
|
272
|
+
const head = toGroups(halves[0]);
|
|
273
|
+
if (head === null) return null;
|
|
274
|
+
if (halves.length === 2) {
|
|
275
|
+
const tail = toGroups(halves[1]);
|
|
276
|
+
if (tail === null) return null;
|
|
277
|
+
const fill = 8 - head.length - tail.length;
|
|
278
|
+
if (fill < 0) return null;
|
|
279
|
+
return [...head, ...new Array(fill).fill(0), ...tail];
|
|
280
|
+
}
|
|
281
|
+
return head.length === 8 ? head : null;
|
|
282
|
+
}
|
|
283
|
+
function isPrivateIPv6(ip) {
|
|
284
|
+
const groups = parseIPv6(ip);
|
|
285
|
+
if (groups === null) return true;
|
|
286
|
+
const topZero = (count) => groups.slice(0, count).every((group) => group === 0);
|
|
287
|
+
if (topZero(7) && (groups[7] === 0 || groups[7] === 1)) return true;
|
|
288
|
+
if ((groups[0] & 65024) === 64512) return true;
|
|
289
|
+
if ((groups[0] & 65472) === 65152) return true;
|
|
290
|
+
if ((groups[0] & 65472) === 65216) return true;
|
|
291
|
+
if ((groups[0] & 65280) === 65280) return true;
|
|
292
|
+
const embedsIPv4 = (
|
|
293
|
+
// ::/96 — IPv4-compatible (deprecated)
|
|
294
|
+
topZero(6) || // ::ffff:0:0/96 — IPv4-mapped (ffff in group 5)
|
|
295
|
+
topZero(5) && groups[5] === 65535 || // ::ffff:0:0/96 — IPv4-translated form (ffff in group 4, group 5 zero)
|
|
296
|
+
topZero(4) && groups[4] === 65535 && groups[5] === 0 || // 64:ff9b::/96 — NAT64 well-known prefix
|
|
297
|
+
groups[0] === 100 && groups[1] === 65435 && groups[2] === 0 && groups[3] === 0 && groups[4] === 0 && groups[5] === 0 || // 64:ff9b:1::/48 — NAT64 local-use prefix
|
|
298
|
+
groups[0] === 100 && groups[1] === 65435 && groups[2] === 1
|
|
299
|
+
);
|
|
300
|
+
if (embedsIPv4) {
|
|
301
|
+
const a = groups[6] >> 8 & 255;
|
|
302
|
+
const b = groups[6] & 255;
|
|
303
|
+
const c = groups[7] >> 8 & 255;
|
|
304
|
+
const d = groups[7] & 255;
|
|
305
|
+
return isPrivateIPv4(`${a}.${b}.${c}.${d}`);
|
|
306
|
+
}
|
|
307
|
+
return false;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// src/fetch-with-validated-redirects.ts
|
|
311
|
+
var MAX_DOWNLOAD_REDIRECTS = 10;
|
|
312
|
+
async function fetchWithValidatedRedirects({
|
|
313
|
+
url,
|
|
314
|
+
headers,
|
|
315
|
+
abortSignal,
|
|
316
|
+
maxRedirects = MAX_DOWNLOAD_REDIRECTS
|
|
317
|
+
}) {
|
|
318
|
+
const baseInit = { signal: abortSignal };
|
|
319
|
+
if (headers !== void 0) {
|
|
320
|
+
baseInit.headers = headers;
|
|
321
|
+
}
|
|
322
|
+
let currentUrl = url;
|
|
323
|
+
for (let redirectCount = 0; redirectCount <= maxRedirects; redirectCount++) {
|
|
324
|
+
validateDownloadUrl(currentUrl);
|
|
325
|
+
const response = await fetch(currentUrl, {
|
|
326
|
+
...baseInit,
|
|
327
|
+
redirect: "manual"
|
|
328
|
+
});
|
|
329
|
+
if (response.type === "opaqueredirect") {
|
|
330
|
+
if (!isBrowserRuntime()) {
|
|
331
|
+
throw new DownloadError({
|
|
332
|
+
url,
|
|
333
|
+
message: `Redirect from ${currentUrl} could not be validated and was blocked`
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
return await fetch(currentUrl, { ...baseInit, redirect: "follow" });
|
|
337
|
+
}
|
|
338
|
+
const location = response.headers.get("location");
|
|
339
|
+
if (response.status >= 300 && response.status < 400 && location) {
|
|
340
|
+
await cancelResponseBody(response);
|
|
341
|
+
currentUrl = new URL(location, currentUrl).toString();
|
|
342
|
+
continue;
|
|
343
|
+
}
|
|
344
|
+
return response;
|
|
345
|
+
}
|
|
346
|
+
throw new DownloadError({
|
|
347
|
+
url,
|
|
348
|
+
message: `Too many redirects (max ${maxRedirects})`
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
|
|
157
352
|
// src/read-response-with-size-limit.ts
|
|
158
353
|
var DEFAULT_MAX_DOWNLOAD_SIZE = 2 * 1024 * 1024 * 1024;
|
|
159
354
|
async function readResponseWithSizeLimit({
|
|
@@ -165,6 +360,7 @@ async function readResponseWithSizeLimit({
|
|
|
165
360
|
if (contentLength != null) {
|
|
166
361
|
const length = parseInt(contentLength, 10);
|
|
167
362
|
if (!isNaN(length) && length > maxBytes) {
|
|
363
|
+
await cancelResponseBody(response);
|
|
168
364
|
throw new DownloadError({
|
|
169
365
|
url,
|
|
170
366
|
message: `Download of ${url} exceeded maximum size of ${maxBytes} bytes (Content-Length: ${length}).`
|
|
@@ -343,7 +539,7 @@ function withUserAgentSuffix(headers, ...userAgentSuffixParts) {
|
|
|
343
539
|
}
|
|
344
540
|
|
|
345
541
|
// src/version.ts
|
|
346
|
-
var VERSION = true ? "3.0.
|
|
542
|
+
var VERSION = true ? "3.0.27" : "0.0.0-test";
|
|
347
543
|
|
|
348
544
|
// src/get-from-api.ts
|
|
349
545
|
var getOriginalFetch = () => globalThis.fetch;
|
|
@@ -353,10 +549,10 @@ var getFromApi = async ({
|
|
|
353
549
|
successfulResponseHandler,
|
|
354
550
|
failedResponseHandler,
|
|
355
551
|
abortSignal,
|
|
356
|
-
fetch = getOriginalFetch()
|
|
552
|
+
fetch: fetch2 = getOriginalFetch()
|
|
357
553
|
}) => {
|
|
358
554
|
try {
|
|
359
|
-
const response = await
|
|
555
|
+
const response = await fetch2(url, {
|
|
360
556
|
method: "GET",
|
|
361
557
|
headers: withUserAgentSuffix(
|
|
362
558
|
headers,
|
|
@@ -454,6 +650,15 @@ function injectJsonInstructionIntoMessages({
|
|
|
454
650
|
];
|
|
455
651
|
}
|
|
456
652
|
|
|
653
|
+
// src/is-same-origin.ts
|
|
654
|
+
function isSameOrigin(url, baseUrl) {
|
|
655
|
+
try {
|
|
656
|
+
return new URL(url).origin === new URL(baseUrl).origin;
|
|
657
|
+
} catch (e) {
|
|
658
|
+
return false;
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
|
|
457
662
|
// src/is-url-supported.ts
|
|
458
663
|
function isUrlSupported({
|
|
459
664
|
mediaType,
|
|
@@ -798,7 +1003,7 @@ var postJsonToApi = async ({
|
|
|
798
1003
|
failedResponseHandler,
|
|
799
1004
|
successfulResponseHandler,
|
|
800
1005
|
abortSignal,
|
|
801
|
-
fetch
|
|
1006
|
+
fetch: fetch2
|
|
802
1007
|
}) => postToApi({
|
|
803
1008
|
url,
|
|
804
1009
|
headers: {
|
|
@@ -812,7 +1017,7 @@ var postJsonToApi = async ({
|
|
|
812
1017
|
failedResponseHandler,
|
|
813
1018
|
successfulResponseHandler,
|
|
814
1019
|
abortSignal,
|
|
815
|
-
fetch
|
|
1020
|
+
fetch: fetch2
|
|
816
1021
|
});
|
|
817
1022
|
var postFormDataToApi = async ({
|
|
818
1023
|
url,
|
|
@@ -821,7 +1026,7 @@ var postFormDataToApi = async ({
|
|
|
821
1026
|
failedResponseHandler,
|
|
822
1027
|
successfulResponseHandler,
|
|
823
1028
|
abortSignal,
|
|
824
|
-
fetch
|
|
1029
|
+
fetch: fetch2
|
|
825
1030
|
}) => postToApi({
|
|
826
1031
|
url,
|
|
827
1032
|
headers,
|
|
@@ -832,7 +1037,7 @@ var postFormDataToApi = async ({
|
|
|
832
1037
|
failedResponseHandler,
|
|
833
1038
|
successfulResponseHandler,
|
|
834
1039
|
abortSignal,
|
|
835
|
-
fetch
|
|
1040
|
+
fetch: fetch2
|
|
836
1041
|
});
|
|
837
1042
|
var postToApi = async ({
|
|
838
1043
|
url,
|
|
@@ -841,10 +1046,10 @@ var postToApi = async ({
|
|
|
841
1046
|
successfulResponseHandler,
|
|
842
1047
|
failedResponseHandler,
|
|
843
1048
|
abortSignal,
|
|
844
|
-
fetch = getOriginalFetch2()
|
|
1049
|
+
fetch: fetch2 = getOriginalFetch2()
|
|
845
1050
|
}) => {
|
|
846
1051
|
try {
|
|
847
|
-
const response = await
|
|
1052
|
+
const response = await fetch2(url, {
|
|
848
1053
|
method: "POST",
|
|
849
1054
|
headers: withUserAgentSuffix(
|
|
850
1055
|
headers,
|
|
@@ -2468,105 +2673,6 @@ function convertToBase64(value) {
|
|
|
2468
2673
|
return value instanceof Uint8Array ? convertUint8ArrayToBase64(value) : value;
|
|
2469
2674
|
}
|
|
2470
2675
|
|
|
2471
|
-
// src/validate-download-url.ts
|
|
2472
|
-
function validateDownloadUrl(url) {
|
|
2473
|
-
let parsed;
|
|
2474
|
-
try {
|
|
2475
|
-
parsed = new URL(url);
|
|
2476
|
-
} catch (e) {
|
|
2477
|
-
throw new DownloadError({
|
|
2478
|
-
url,
|
|
2479
|
-
message: `Invalid URL: ${url}`
|
|
2480
|
-
});
|
|
2481
|
-
}
|
|
2482
|
-
if (parsed.protocol === "data:") {
|
|
2483
|
-
return;
|
|
2484
|
-
}
|
|
2485
|
-
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
2486
|
-
throw new DownloadError({
|
|
2487
|
-
url,
|
|
2488
|
-
message: `URL scheme must be http, https, or data, got ${parsed.protocol}`
|
|
2489
|
-
});
|
|
2490
|
-
}
|
|
2491
|
-
const hostname = parsed.hostname;
|
|
2492
|
-
if (!hostname) {
|
|
2493
|
-
throw new DownloadError({
|
|
2494
|
-
url,
|
|
2495
|
-
message: `URL must have a hostname`
|
|
2496
|
-
});
|
|
2497
|
-
}
|
|
2498
|
-
if (hostname === "localhost" || hostname.endsWith(".local") || hostname.endsWith(".localhost")) {
|
|
2499
|
-
throw new DownloadError({
|
|
2500
|
-
url,
|
|
2501
|
-
message: `URL with hostname ${hostname} is not allowed`
|
|
2502
|
-
});
|
|
2503
|
-
}
|
|
2504
|
-
if (hostname.startsWith("[") && hostname.endsWith("]")) {
|
|
2505
|
-
const ipv6 = hostname.slice(1, -1);
|
|
2506
|
-
if (isPrivateIPv6(ipv6)) {
|
|
2507
|
-
throw new DownloadError({
|
|
2508
|
-
url,
|
|
2509
|
-
message: `URL with IPv6 address ${hostname} is not allowed`
|
|
2510
|
-
});
|
|
2511
|
-
}
|
|
2512
|
-
return;
|
|
2513
|
-
}
|
|
2514
|
-
if (isIPv4(hostname)) {
|
|
2515
|
-
if (isPrivateIPv4(hostname)) {
|
|
2516
|
-
throw new DownloadError({
|
|
2517
|
-
url,
|
|
2518
|
-
message: `URL with IP address ${hostname} is not allowed`
|
|
2519
|
-
});
|
|
2520
|
-
}
|
|
2521
|
-
return;
|
|
2522
|
-
}
|
|
2523
|
-
}
|
|
2524
|
-
function isIPv4(hostname) {
|
|
2525
|
-
const parts = hostname.split(".");
|
|
2526
|
-
if (parts.length !== 4) return false;
|
|
2527
|
-
return parts.every((part) => {
|
|
2528
|
-
const num = Number(part);
|
|
2529
|
-
return Number.isInteger(num) && num >= 0 && num <= 255 && String(num) === part;
|
|
2530
|
-
});
|
|
2531
|
-
}
|
|
2532
|
-
function isPrivateIPv4(ip) {
|
|
2533
|
-
const parts = ip.split(".").map(Number);
|
|
2534
|
-
const [a, b] = parts;
|
|
2535
|
-
if (a === 0) return true;
|
|
2536
|
-
if (a === 10) return true;
|
|
2537
|
-
if (a === 127) return true;
|
|
2538
|
-
if (a === 169 && b === 254) return true;
|
|
2539
|
-
if (a === 172 && b >= 16 && b <= 31) return true;
|
|
2540
|
-
if (a === 192 && b === 168) return true;
|
|
2541
|
-
return false;
|
|
2542
|
-
}
|
|
2543
|
-
function isPrivateIPv6(ip) {
|
|
2544
|
-
const normalized = ip.toLowerCase();
|
|
2545
|
-
if (normalized === "::1") return true;
|
|
2546
|
-
if (normalized === "::") return true;
|
|
2547
|
-
if (normalized.startsWith("::ffff:")) {
|
|
2548
|
-
const mappedPart = normalized.slice(7);
|
|
2549
|
-
if (isIPv4(mappedPart)) {
|
|
2550
|
-
return isPrivateIPv4(mappedPart);
|
|
2551
|
-
}
|
|
2552
|
-
const hexParts = mappedPart.split(":");
|
|
2553
|
-
if (hexParts.length === 2) {
|
|
2554
|
-
const high = parseInt(hexParts[0], 16);
|
|
2555
|
-
const low = parseInt(hexParts[1], 16);
|
|
2556
|
-
if (!isNaN(high) && !isNaN(low)) {
|
|
2557
|
-
const a = high >> 8 & 255;
|
|
2558
|
-
const b = high & 255;
|
|
2559
|
-
const c = low >> 8 & 255;
|
|
2560
|
-
const d = low & 255;
|
|
2561
|
-
return isPrivateIPv4(`${a}.${b}.${c}.${d}`);
|
|
2562
|
-
}
|
|
2563
|
-
}
|
|
2564
|
-
}
|
|
2565
|
-
if (normalized.startsWith("fc") || normalized.startsWith("fd")) return true;
|
|
2566
|
-
if (normalized.startsWith("fe80")) return true;
|
|
2567
|
-
return false;
|
|
2568
|
-
}
|
|
2569
|
-
|
|
2570
2676
|
// src/without-trailing-slash.ts
|
|
2571
2677
|
function withoutTrailingSlash(url) {
|
|
2572
2678
|
return url == null ? void 0 : url.replace(/\/$/, "");
|
|
@@ -2609,6 +2715,7 @@ export {
|
|
|
2609
2715
|
VERSION,
|
|
2610
2716
|
asSchema,
|
|
2611
2717
|
asValidator,
|
|
2718
|
+
cancelResponseBody,
|
|
2612
2719
|
combineHeaders,
|
|
2613
2720
|
convertAsyncIteratorToReadableStream,
|
|
2614
2721
|
convertBase64ToUint8Array,
|
|
@@ -2627,13 +2734,16 @@ export {
|
|
|
2627
2734
|
dynamicTool,
|
|
2628
2735
|
executeTool,
|
|
2629
2736
|
extractResponseHeaders,
|
|
2737
|
+
fetchWithValidatedRedirects,
|
|
2630
2738
|
generateId,
|
|
2631
2739
|
getErrorMessage,
|
|
2632
2740
|
getFromApi,
|
|
2633
2741
|
getRuntimeEnvironmentUserAgent,
|
|
2634
2742
|
injectJsonInstructionIntoMessages,
|
|
2635
2743
|
isAbortError,
|
|
2744
|
+
isBrowserRuntime,
|
|
2636
2745
|
isParsableJson,
|
|
2746
|
+
isSameOrigin,
|
|
2637
2747
|
isUrlSupported,
|
|
2638
2748
|
isValidator,
|
|
2639
2749
|
jsonSchema,
|