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