@ai-sdk/provider-utils 3.0.25 → 3.0.26
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 +21 -0
- package/dist/index.d.mts +59 -1
- package/dist/index.d.ts +59 -1
- package/dist/index.js +209 -108
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +206 -108
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -154,6 +154,191 @@ var DownloadError = class extends (_b = AISDKError, _a = symbol, _b) {
|
|
|
154
154
|
}
|
|
155
155
|
};
|
|
156
156
|
|
|
157
|
+
// src/is-browser-runtime.ts
|
|
158
|
+
function isBrowserRuntime(globalThisAny = globalThis) {
|
|
159
|
+
return globalThisAny.window != null;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// src/validate-download-url.ts
|
|
163
|
+
function validateDownloadUrl(url) {
|
|
164
|
+
let parsed;
|
|
165
|
+
try {
|
|
166
|
+
parsed = new URL(url);
|
|
167
|
+
} catch (e) {
|
|
168
|
+
throw new DownloadError({
|
|
169
|
+
url,
|
|
170
|
+
message: `Invalid URL: ${url}`
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
if (parsed.protocol === "data:") {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
177
|
+
throw new DownloadError({
|
|
178
|
+
url,
|
|
179
|
+
message: `URL scheme must be http, https, or data, got ${parsed.protocol}`
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
const hostname = parsed.hostname.toLowerCase().replace(/\.+$/, "");
|
|
183
|
+
if (!hostname) {
|
|
184
|
+
throw new DownloadError({
|
|
185
|
+
url,
|
|
186
|
+
message: `URL must have a hostname`
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
if (hostname === "localhost" || hostname.endsWith(".local") || hostname.endsWith(".localhost")) {
|
|
190
|
+
throw new DownloadError({
|
|
191
|
+
url,
|
|
192
|
+
message: `URL with hostname ${hostname} is not allowed`
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
if (hostname.startsWith("[") && hostname.endsWith("]")) {
|
|
196
|
+
const ipv6 = hostname.slice(1, -1);
|
|
197
|
+
if (isPrivateIPv6(ipv6)) {
|
|
198
|
+
throw new DownloadError({
|
|
199
|
+
url,
|
|
200
|
+
message: `URL with IPv6 address ${hostname} is not allowed`
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
if (isIPv4(hostname)) {
|
|
206
|
+
if (isPrivateIPv4(hostname)) {
|
|
207
|
+
throw new DownloadError({
|
|
208
|
+
url,
|
|
209
|
+
message: `URL with IP address ${hostname} is not allowed`
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
function isIPv4(hostname) {
|
|
216
|
+
const parts = hostname.split(".");
|
|
217
|
+
if (parts.length !== 4) return false;
|
|
218
|
+
return parts.every((part) => {
|
|
219
|
+
const num = Number(part);
|
|
220
|
+
return Number.isInteger(num) && num >= 0 && num <= 255 && String(num) === part;
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
function isPrivateIPv4(ip) {
|
|
224
|
+
const parts = ip.split(".").map(Number);
|
|
225
|
+
const [a, b, c] = parts;
|
|
226
|
+
if (a === 0) return true;
|
|
227
|
+
if (a === 10) return true;
|
|
228
|
+
if (a === 100 && b >= 64 && b <= 127) return true;
|
|
229
|
+
if (a === 127) return true;
|
|
230
|
+
if (a === 169 && b === 254) return true;
|
|
231
|
+
if (a === 172 && b >= 16 && b <= 31) return true;
|
|
232
|
+
if (a === 192 && b === 0 && c === 0) return true;
|
|
233
|
+
if (a === 192 && b === 168) return true;
|
|
234
|
+
if (a === 198 && (b === 18 || b === 19)) return true;
|
|
235
|
+
if (a >= 240) return true;
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
function parseIPv6(ip) {
|
|
239
|
+
let address = ip.toLowerCase();
|
|
240
|
+
const zoneIndex = address.indexOf("%");
|
|
241
|
+
if (zoneIndex !== -1) {
|
|
242
|
+
address = address.slice(0, zoneIndex);
|
|
243
|
+
}
|
|
244
|
+
const halves = address.split("::");
|
|
245
|
+
if (halves.length > 2) return null;
|
|
246
|
+
const toGroups = (segment) => {
|
|
247
|
+
if (segment === "") return [];
|
|
248
|
+
const groups = [];
|
|
249
|
+
const parts = segment.split(":");
|
|
250
|
+
for (let i = 0; i < parts.length; i++) {
|
|
251
|
+
const part = parts[i];
|
|
252
|
+
if (part.includes(".")) {
|
|
253
|
+
if (i !== parts.length - 1 || !isIPv4(part)) return null;
|
|
254
|
+
const [a, b, c, d] = part.split(".").map(Number);
|
|
255
|
+
groups.push(a << 8 | b, c << 8 | d);
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
if (!/^[0-9a-f]{1,4}$/.test(part)) return null;
|
|
259
|
+
groups.push(parseInt(part, 16));
|
|
260
|
+
}
|
|
261
|
+
return groups;
|
|
262
|
+
};
|
|
263
|
+
const head = toGroups(halves[0]);
|
|
264
|
+
if (head === null) return null;
|
|
265
|
+
if (halves.length === 2) {
|
|
266
|
+
const tail = toGroups(halves[1]);
|
|
267
|
+
if (tail === null) return null;
|
|
268
|
+
const fill = 8 - head.length - tail.length;
|
|
269
|
+
if (fill < 0) return null;
|
|
270
|
+
return [...head, ...new Array(fill).fill(0), ...tail];
|
|
271
|
+
}
|
|
272
|
+
return head.length === 8 ? head : null;
|
|
273
|
+
}
|
|
274
|
+
function isPrivateIPv6(ip) {
|
|
275
|
+
const groups = parseIPv6(ip);
|
|
276
|
+
if (groups === null) return true;
|
|
277
|
+
const topZero = (count) => groups.slice(0, count).every((group) => group === 0);
|
|
278
|
+
if (topZero(7) && (groups[7] === 0 || groups[7] === 1)) return true;
|
|
279
|
+
if ((groups[0] & 65024) === 64512) return true;
|
|
280
|
+
if ((groups[0] & 65472) === 65152) return true;
|
|
281
|
+
if ((groups[0] & 65472) === 65216) return true;
|
|
282
|
+
if ((groups[0] & 65280) === 65280) return true;
|
|
283
|
+
const embedsIPv4 = (
|
|
284
|
+
// ::/96 — IPv4-compatible (deprecated)
|
|
285
|
+
topZero(6) || // ::ffff:0:0/96 — IPv4-mapped (ffff in group 5)
|
|
286
|
+
topZero(5) && groups[5] === 65535 || // ::ffff:0:0/96 — IPv4-translated form (ffff in group 4, group 5 zero)
|
|
287
|
+
topZero(4) && groups[4] === 65535 && groups[5] === 0 || // 64:ff9b::/96 — NAT64 well-known prefix
|
|
288
|
+
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
|
|
289
|
+
groups[0] === 100 && groups[1] === 65435 && groups[2] === 1
|
|
290
|
+
);
|
|
291
|
+
if (embedsIPv4) {
|
|
292
|
+
const a = groups[6] >> 8 & 255;
|
|
293
|
+
const b = groups[6] & 255;
|
|
294
|
+
const c = groups[7] >> 8 & 255;
|
|
295
|
+
const d = groups[7] & 255;
|
|
296
|
+
return isPrivateIPv4(`${a}.${b}.${c}.${d}`);
|
|
297
|
+
}
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// src/fetch-with-validated-redirects.ts
|
|
302
|
+
var MAX_DOWNLOAD_REDIRECTS = 10;
|
|
303
|
+
async function fetchWithValidatedRedirects({
|
|
304
|
+
url,
|
|
305
|
+
headers,
|
|
306
|
+
abortSignal,
|
|
307
|
+
maxRedirects = MAX_DOWNLOAD_REDIRECTS
|
|
308
|
+
}) {
|
|
309
|
+
const baseInit = { signal: abortSignal };
|
|
310
|
+
if (headers !== void 0) {
|
|
311
|
+
baseInit.headers = headers;
|
|
312
|
+
}
|
|
313
|
+
let currentUrl = url;
|
|
314
|
+
for (let redirectCount = 0; redirectCount <= maxRedirects; redirectCount++) {
|
|
315
|
+
validateDownloadUrl(currentUrl);
|
|
316
|
+
const response = await fetch(currentUrl, {
|
|
317
|
+
...baseInit,
|
|
318
|
+
redirect: "manual"
|
|
319
|
+
});
|
|
320
|
+
if (response.type === "opaqueredirect") {
|
|
321
|
+
if (!isBrowserRuntime()) {
|
|
322
|
+
throw new DownloadError({
|
|
323
|
+
url,
|
|
324
|
+
message: `Redirect from ${currentUrl} could not be validated and was blocked`
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
return await fetch(currentUrl, { ...baseInit, redirect: "follow" });
|
|
328
|
+
}
|
|
329
|
+
const location = response.headers.get("location");
|
|
330
|
+
if (response.status >= 300 && response.status < 400 && location) {
|
|
331
|
+
currentUrl = new URL(location, currentUrl).toString();
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
return response;
|
|
335
|
+
}
|
|
336
|
+
throw new DownloadError({
|
|
337
|
+
url,
|
|
338
|
+
message: `Too many redirects (max ${maxRedirects})`
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
|
|
157
342
|
// src/read-response-with-size-limit.ts
|
|
158
343
|
var DEFAULT_MAX_DOWNLOAD_SIZE = 2 * 1024 * 1024 * 1024;
|
|
159
344
|
async function readResponseWithSizeLimit({
|
|
@@ -343,7 +528,7 @@ function withUserAgentSuffix(headers, ...userAgentSuffixParts) {
|
|
|
343
528
|
}
|
|
344
529
|
|
|
345
530
|
// src/version.ts
|
|
346
|
-
var VERSION = true ? "3.0.
|
|
531
|
+
var VERSION = true ? "3.0.26" : "0.0.0-test";
|
|
347
532
|
|
|
348
533
|
// src/get-from-api.ts
|
|
349
534
|
var getOriginalFetch = () => globalThis.fetch;
|
|
@@ -353,10 +538,10 @@ var getFromApi = async ({
|
|
|
353
538
|
successfulResponseHandler,
|
|
354
539
|
failedResponseHandler,
|
|
355
540
|
abortSignal,
|
|
356
|
-
fetch = getOriginalFetch()
|
|
541
|
+
fetch: fetch2 = getOriginalFetch()
|
|
357
542
|
}) => {
|
|
358
543
|
try {
|
|
359
|
-
const response = await
|
|
544
|
+
const response = await fetch2(url, {
|
|
360
545
|
method: "GET",
|
|
361
546
|
headers: withUserAgentSuffix(
|
|
362
547
|
headers,
|
|
@@ -454,6 +639,15 @@ function injectJsonInstructionIntoMessages({
|
|
|
454
639
|
];
|
|
455
640
|
}
|
|
456
641
|
|
|
642
|
+
// src/is-same-origin.ts
|
|
643
|
+
function isSameOrigin(url, baseUrl) {
|
|
644
|
+
try {
|
|
645
|
+
return new URL(url).origin === new URL(baseUrl).origin;
|
|
646
|
+
} catch (e) {
|
|
647
|
+
return false;
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
|
|
457
651
|
// src/is-url-supported.ts
|
|
458
652
|
function isUrlSupported({
|
|
459
653
|
mediaType,
|
|
@@ -798,7 +992,7 @@ var postJsonToApi = async ({
|
|
|
798
992
|
failedResponseHandler,
|
|
799
993
|
successfulResponseHandler,
|
|
800
994
|
abortSignal,
|
|
801
|
-
fetch
|
|
995
|
+
fetch: fetch2
|
|
802
996
|
}) => postToApi({
|
|
803
997
|
url,
|
|
804
998
|
headers: {
|
|
@@ -812,7 +1006,7 @@ var postJsonToApi = async ({
|
|
|
812
1006
|
failedResponseHandler,
|
|
813
1007
|
successfulResponseHandler,
|
|
814
1008
|
abortSignal,
|
|
815
|
-
fetch
|
|
1009
|
+
fetch: fetch2
|
|
816
1010
|
});
|
|
817
1011
|
var postFormDataToApi = async ({
|
|
818
1012
|
url,
|
|
@@ -821,7 +1015,7 @@ var postFormDataToApi = async ({
|
|
|
821
1015
|
failedResponseHandler,
|
|
822
1016
|
successfulResponseHandler,
|
|
823
1017
|
abortSignal,
|
|
824
|
-
fetch
|
|
1018
|
+
fetch: fetch2
|
|
825
1019
|
}) => postToApi({
|
|
826
1020
|
url,
|
|
827
1021
|
headers,
|
|
@@ -832,7 +1026,7 @@ var postFormDataToApi = async ({
|
|
|
832
1026
|
failedResponseHandler,
|
|
833
1027
|
successfulResponseHandler,
|
|
834
1028
|
abortSignal,
|
|
835
|
-
fetch
|
|
1029
|
+
fetch: fetch2
|
|
836
1030
|
});
|
|
837
1031
|
var postToApi = async ({
|
|
838
1032
|
url,
|
|
@@ -841,10 +1035,10 @@ var postToApi = async ({
|
|
|
841
1035
|
successfulResponseHandler,
|
|
842
1036
|
failedResponseHandler,
|
|
843
1037
|
abortSignal,
|
|
844
|
-
fetch = getOriginalFetch2()
|
|
1038
|
+
fetch: fetch2 = getOriginalFetch2()
|
|
845
1039
|
}) => {
|
|
846
1040
|
try {
|
|
847
|
-
const response = await
|
|
1041
|
+
const response = await fetch2(url, {
|
|
848
1042
|
method: "POST",
|
|
849
1043
|
headers: withUserAgentSuffix(
|
|
850
1044
|
headers,
|
|
@@ -2468,105 +2662,6 @@ function convertToBase64(value) {
|
|
|
2468
2662
|
return value instanceof Uint8Array ? convertUint8ArrayToBase64(value) : value;
|
|
2469
2663
|
}
|
|
2470
2664
|
|
|
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
2665
|
// src/without-trailing-slash.ts
|
|
2571
2666
|
function withoutTrailingSlash(url) {
|
|
2572
2667
|
return url == null ? void 0 : url.replace(/\/$/, "");
|
|
@@ -2627,13 +2722,16 @@ export {
|
|
|
2627
2722
|
dynamicTool,
|
|
2628
2723
|
executeTool,
|
|
2629
2724
|
extractResponseHeaders,
|
|
2725
|
+
fetchWithValidatedRedirects,
|
|
2630
2726
|
generateId,
|
|
2631
2727
|
getErrorMessage,
|
|
2632
2728
|
getFromApi,
|
|
2633
2729
|
getRuntimeEnvironmentUserAgent,
|
|
2634
2730
|
injectJsonInstructionIntoMessages,
|
|
2635
2731
|
isAbortError,
|
|
2732
|
+
isBrowserRuntime,
|
|
2636
2733
|
isParsableJson,
|
|
2734
|
+
isSameOrigin,
|
|
2637
2735
|
isUrlSupported,
|
|
2638
2736
|
isValidator,
|
|
2639
2737
|
jsonSchema,
|