@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/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.25" : "0.0.0-test";
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 fetch(url, {
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 fetch(url, {
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,