@ai-sdk/provider-utils 5.0.0-canary.47 → 5.0.0

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.js CHANGED
@@ -489,6 +489,15 @@ function isFullMediaType(mediaType) {
489
489
  return subtype.length > 0 && subtype !== "*";
490
490
  }
491
491
 
492
+ // src/cancel-response-body.ts
493
+ async function cancelResponseBody(response) {
494
+ var _a2;
495
+ try {
496
+ await ((_a2 = response.body) == null ? void 0 : _a2.cancel());
497
+ } catch (e) {
498
+ }
499
+ }
500
+
492
501
  // src/download-error.ts
493
502
  import { AISDKError } from "@ai-sdk/provider";
494
503
  var name = "AI_DownloadError";
@@ -514,59 +523,9 @@ var DownloadError = class extends (_b = AISDKError, _a = symbol, _b) {
514
523
  }
515
524
  };
516
525
 
517
- // src/read-response-with-size-limit.ts
518
- var DEFAULT_MAX_DOWNLOAD_SIZE = 2 * 1024 * 1024 * 1024;
519
- async function readResponseWithSizeLimit({
520
- response,
521
- url,
522
- maxBytes = DEFAULT_MAX_DOWNLOAD_SIZE
523
- }) {
524
- const contentLength = response.headers.get("content-length");
525
- if (contentLength != null) {
526
- const length = parseInt(contentLength, 10);
527
- if (!isNaN(length) && length > maxBytes) {
528
- throw new DownloadError({
529
- url,
530
- message: `Download of ${url} exceeded maximum size of ${maxBytes} bytes (Content-Length: ${length}).`
531
- });
532
- }
533
- }
534
- const body = response.body;
535
- if (body == null) {
536
- return new Uint8Array(0);
537
- }
538
- const reader = body.getReader();
539
- const chunks = [];
540
- let totalBytes = 0;
541
- try {
542
- while (true) {
543
- const { done, value } = await reader.read();
544
- if (done) {
545
- break;
546
- }
547
- totalBytes += value.length;
548
- if (totalBytes > maxBytes) {
549
- throw new DownloadError({
550
- url,
551
- message: `Download of ${url} exceeded maximum size of ${maxBytes} bytes.`
552
- });
553
- }
554
- chunks.push(value);
555
- }
556
- } finally {
557
- try {
558
- await reader.cancel();
559
- } finally {
560
- reader.releaseLock();
561
- }
562
- }
563
- const result = new Uint8Array(totalBytes);
564
- let offset = 0;
565
- for (const chunk of chunks) {
566
- result.set(chunk, offset);
567
- offset += chunk.length;
568
- }
569
- return result;
526
+ // src/is-browser-runtime.ts
527
+ function isBrowserRuntime(globalThisAny = globalThis) {
528
+ return globalThisAny.window != null;
570
529
  }
571
530
 
572
531
  // src/validate-download-url.ts
@@ -589,7 +548,7 @@ function validateDownloadUrl(url) {
589
548
  message: `URL scheme must be http, https, or data, got ${parsed.protocol}`
590
549
  });
591
550
  }
592
- const hostname = parsed.hostname;
551
+ const hostname = parsed.hostname.toLowerCase().replace(/\.+$/, "");
593
552
  if (!hostname) {
594
553
  throw new DownloadError({
595
554
  url,
@@ -632,54 +591,190 @@ function isIPv4(hostname) {
632
591
  }
633
592
  function isPrivateIPv4(ip) {
634
593
  const parts = ip.split(".").map(Number);
635
- const [a, b] = parts;
594
+ const [a, b, c] = parts;
636
595
  if (a === 0) return true;
637
596
  if (a === 10) return true;
597
+ if (a === 100 && b >= 64 && b <= 127) return true;
638
598
  if (a === 127) return true;
639
599
  if (a === 169 && b === 254) return true;
640
600
  if (a === 172 && b >= 16 && b <= 31) return true;
601
+ if (a === 192 && b === 0 && c === 0) return true;
641
602
  if (a === 192 && b === 168) return true;
603
+ if (a === 198 && (b === 18 || b === 19)) return true;
604
+ if (a >= 240) return true;
642
605
  return false;
643
606
  }
644
- function isPrivateIPv6(ip) {
645
- const normalized = ip.toLowerCase();
646
- if (normalized === "::1") return true;
647
- if (normalized === "::") return true;
648
- if (normalized.startsWith("::ffff:")) {
649
- const mappedPart = normalized.slice(7);
650
- if (isIPv4(mappedPart)) {
651
- return isPrivateIPv4(mappedPart);
652
- }
653
- const hexParts = mappedPart.split(":");
654
- if (hexParts.length === 2) {
655
- const high = parseInt(hexParts[0], 16);
656
- const low = parseInt(hexParts[1], 16);
657
- if (!isNaN(high) && !isNaN(low)) {
658
- const a = high >> 8 & 255;
659
- const b = high & 255;
660
- const c = low >> 8 & 255;
661
- const d = low & 255;
662
- return isPrivateIPv4(`${a}.${b}.${c}.${d}`);
607
+ function parseIPv6(ip) {
608
+ let address = ip.toLowerCase();
609
+ const zoneIndex = address.indexOf("%");
610
+ if (zoneIndex !== -1) {
611
+ address = address.slice(0, zoneIndex);
612
+ }
613
+ const halves = address.split("::");
614
+ if (halves.length > 2) return null;
615
+ const toGroups = (segment) => {
616
+ if (segment === "") return [];
617
+ const groups = [];
618
+ const parts = segment.split(":");
619
+ for (let i = 0; i < parts.length; i++) {
620
+ const part = parts[i];
621
+ if (part.includes(".")) {
622
+ if (i !== parts.length - 1 || !isIPv4(part)) return null;
623
+ const [a, b, c, d] = part.split(".").map(Number);
624
+ groups.push(a << 8 | b, c << 8 | d);
625
+ continue;
663
626
  }
627
+ if (!/^[0-9a-f]{1,4}$/.test(part)) return null;
628
+ groups.push(parseInt(part, 16));
664
629
  }
630
+ return groups;
631
+ };
632
+ const head = toGroups(halves[0]);
633
+ if (head === null) return null;
634
+ if (halves.length === 2) {
635
+ const tail = toGroups(halves[1]);
636
+ if (tail === null) return null;
637
+ const fill = 8 - head.length - tail.length;
638
+ if (fill < 0) return null;
639
+ return [...head, ...new Array(fill).fill(0), ...tail];
640
+ }
641
+ return head.length === 8 ? head : null;
642
+ }
643
+ function isPrivateIPv6(ip) {
644
+ const groups = parseIPv6(ip);
645
+ if (groups === null) return true;
646
+ const topZero = (count) => groups.slice(0, count).every((group) => group === 0);
647
+ if (topZero(7) && (groups[7] === 0 || groups[7] === 1)) return true;
648
+ if ((groups[0] & 65024) === 64512) return true;
649
+ if ((groups[0] & 65472) === 65152) return true;
650
+ if ((groups[0] & 65472) === 65216) return true;
651
+ if ((groups[0] & 65280) === 65280) return true;
652
+ const embedsIPv4 = (
653
+ // ::/96 — IPv4-compatible (deprecated)
654
+ topZero(6) || // ::ffff:0:0/96 — IPv4-mapped (ffff in group 5)
655
+ topZero(5) && groups[5] === 65535 || // ::ffff:0:0/96 — IPv4-translated form (ffff in group 4, group 5 zero)
656
+ topZero(4) && groups[4] === 65535 && groups[5] === 0 || // 64:ff9b::/96 — NAT64 well-known prefix
657
+ 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
658
+ groups[0] === 100 && groups[1] === 65435 && groups[2] === 1
659
+ );
660
+ if (embedsIPv4) {
661
+ const a = groups[6] >> 8 & 255;
662
+ const b = groups[6] & 255;
663
+ const c = groups[7] >> 8 & 255;
664
+ const d = groups[7] & 255;
665
+ return isPrivateIPv4(`${a}.${b}.${c}.${d}`);
665
666
  }
666
- if (normalized.startsWith("fc") || normalized.startsWith("fd")) return true;
667
- if (normalized.startsWith("fe80")) return true;
668
667
  return false;
669
668
  }
670
669
 
670
+ // src/fetch-with-validated-redirects.ts
671
+ var MAX_DOWNLOAD_REDIRECTS = 10;
672
+ async function fetchWithValidatedRedirects({
673
+ url,
674
+ headers,
675
+ abortSignal,
676
+ maxRedirects = MAX_DOWNLOAD_REDIRECTS
677
+ }) {
678
+ const baseInit = { signal: abortSignal };
679
+ if (headers !== void 0) {
680
+ baseInit.headers = headers;
681
+ }
682
+ let currentUrl = url;
683
+ for (let redirectCount = 0; redirectCount <= maxRedirects; redirectCount++) {
684
+ validateDownloadUrl(currentUrl);
685
+ const response = await fetch(currentUrl, {
686
+ ...baseInit,
687
+ redirect: "manual"
688
+ });
689
+ if (response.type === "opaqueredirect") {
690
+ if (!isBrowserRuntime()) {
691
+ throw new DownloadError({
692
+ url,
693
+ message: `Redirect from ${currentUrl} could not be validated and was blocked`
694
+ });
695
+ }
696
+ return await fetch(currentUrl, { ...baseInit, redirect: "follow" });
697
+ }
698
+ const location = response.headers.get("location");
699
+ if (response.status >= 300 && response.status < 400 && location) {
700
+ await cancelResponseBody(response);
701
+ currentUrl = new URL(location, currentUrl).toString();
702
+ continue;
703
+ }
704
+ return response;
705
+ }
706
+ throw new DownloadError({
707
+ url,
708
+ message: `Too many redirects (max ${maxRedirects})`
709
+ });
710
+ }
711
+
712
+ // src/read-response-with-size-limit.ts
713
+ var DEFAULT_MAX_DOWNLOAD_SIZE = 2 * 1024 * 1024 * 1024;
714
+ async function readResponseWithSizeLimit({
715
+ response,
716
+ url,
717
+ maxBytes = DEFAULT_MAX_DOWNLOAD_SIZE
718
+ }) {
719
+ const contentLength = response.headers.get("content-length");
720
+ if (contentLength != null) {
721
+ const length = parseInt(contentLength, 10);
722
+ if (!isNaN(length) && length > maxBytes) {
723
+ await cancelResponseBody(response);
724
+ throw new DownloadError({
725
+ url,
726
+ message: `Download of ${url} exceeded maximum size of ${maxBytes} bytes (Content-Length: ${length}).`
727
+ });
728
+ }
729
+ }
730
+ const body = response.body;
731
+ if (body == null) {
732
+ return new Uint8Array(0);
733
+ }
734
+ const reader = body.getReader();
735
+ const chunks = [];
736
+ let totalBytes = 0;
737
+ try {
738
+ while (true) {
739
+ const { done, value } = await reader.read();
740
+ if (done) {
741
+ break;
742
+ }
743
+ totalBytes += value.length;
744
+ if (totalBytes > maxBytes) {
745
+ throw new DownloadError({
746
+ url,
747
+ message: `Download of ${url} exceeded maximum size of ${maxBytes} bytes.`
748
+ });
749
+ }
750
+ chunks.push(value);
751
+ }
752
+ } finally {
753
+ try {
754
+ await reader.cancel();
755
+ } finally {
756
+ reader.releaseLock();
757
+ }
758
+ }
759
+ const result = new Uint8Array(totalBytes);
760
+ let offset = 0;
761
+ for (const chunk of chunks) {
762
+ result.set(chunk, offset);
763
+ offset += chunk.length;
764
+ }
765
+ return result;
766
+ }
767
+
671
768
  // src/download-blob.ts
672
769
  async function downloadBlob(url, options) {
673
770
  var _a2, _b2;
674
- validateDownloadUrl(url);
675
771
  try {
676
- const response = await fetch(url, {
677
- signal: options == null ? void 0 : options.abortSignal
772
+ const response = await fetchWithValidatedRedirects({
773
+ url,
774
+ abortSignal: options == null ? void 0 : options.abortSignal
678
775
  });
679
- if (response.redirected) {
680
- validateDownloadUrl(response.url);
681
- }
682
776
  if (!response.ok) {
777
+ await cancelResponseBody(response);
683
778
  throw new DownloadError({
684
779
  url,
685
780
  statusCode: response.status,
@@ -876,7 +971,7 @@ function withUserAgentSuffix(headers, ...userAgentSuffixParts) {
876
971
  }
877
972
 
878
973
  // src/version.ts
879
- var VERSION = true ? "5.0.0-canary.47" : "0.0.0-test";
974
+ var VERSION = true ? "5.0.0" : "0.0.0-test";
880
975
 
881
976
  // src/get-from-api.ts
882
977
  var getOriginalFetch = () => globalThis.fetch;
@@ -993,6 +1088,15 @@ function isBuffer(value) {
993
1088
  return (_b2 = (_a2 = globalThis.Buffer) == null ? void 0 : _a2.isBuffer(value)) != null ? _b2 : false;
994
1089
  }
995
1090
 
1091
+ // src/is-same-origin.ts
1092
+ function isSameOrigin(url, baseUrl) {
1093
+ try {
1094
+ return new URL(url).origin === new URL(baseUrl).origin;
1095
+ } catch (e) {
1096
+ return false;
1097
+ }
1098
+ }
1099
+
996
1100
  // src/is-non-nullable.ts
997
1101
  function isNonNullable(value) {
998
1102
  return value != null;
@@ -3342,6 +3446,7 @@ export {
3342
3446
  WORKFLOW_SERIALIZE,
3343
3447
  asArray,
3344
3448
  asSchema,
3449
+ cancelResponseBody,
3345
3450
  combineHeaders,
3346
3451
  convertAsyncIteratorToReadableStream,
3347
3452
  convertBase64ToUint8Array,
@@ -3367,6 +3472,7 @@ export {
3367
3472
  executeTool,
3368
3473
  extractLines,
3369
3474
  extractResponseHeaders,
3475
+ fetchWithValidatedRedirects,
3370
3476
  filterNullable,
3371
3477
  generateId,
3372
3478
  getErrorMessage,
@@ -3375,6 +3481,7 @@ export {
3375
3481
  getTopLevelMediaType,
3376
3482
  injectJsonInstructionIntoMessages,
3377
3483
  isAbortError,
3484
+ isBrowserRuntime,
3378
3485
  isBuffer,
3379
3486
  isCustomReasoning,
3380
3487
  isExecutableTool,
@@ -3382,6 +3489,7 @@ export {
3382
3489
  isNonNullable,
3383
3490
  isParsableJson,
3384
3491
  isProviderReference,
3492
+ isSameOrigin,
3385
3493
  isUrlSupported,
3386
3494
  jsonSchema,
3387
3495
  lazySchema,