@ai-sdk/provider-utils 4.0.18 → 4.0.20

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
@@ -288,13 +288,113 @@ async function readResponseWithSizeLimit({
288
288
  return result;
289
289
  }
290
290
 
291
+ // src/validate-download-url.ts
292
+ function validateDownloadUrl(url) {
293
+ let parsed;
294
+ try {
295
+ parsed = new URL(url);
296
+ } catch (e) {
297
+ throw new DownloadError({
298
+ url,
299
+ message: `Invalid URL: ${url}`
300
+ });
301
+ }
302
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
303
+ throw new DownloadError({
304
+ url,
305
+ message: `URL scheme must be http or https, got ${parsed.protocol}`
306
+ });
307
+ }
308
+ const hostname = parsed.hostname;
309
+ if (!hostname) {
310
+ throw new DownloadError({
311
+ url,
312
+ message: `URL must have a hostname`
313
+ });
314
+ }
315
+ if (hostname === "localhost" || hostname.endsWith(".local") || hostname.endsWith(".localhost")) {
316
+ throw new DownloadError({
317
+ url,
318
+ message: `URL with hostname ${hostname} is not allowed`
319
+ });
320
+ }
321
+ if (hostname.startsWith("[") && hostname.endsWith("]")) {
322
+ const ipv6 = hostname.slice(1, -1);
323
+ if (isPrivateIPv6(ipv6)) {
324
+ throw new DownloadError({
325
+ url,
326
+ message: `URL with IPv6 address ${hostname} is not allowed`
327
+ });
328
+ }
329
+ return;
330
+ }
331
+ if (isIPv4(hostname)) {
332
+ if (isPrivateIPv4(hostname)) {
333
+ throw new DownloadError({
334
+ url,
335
+ message: `URL with IP address ${hostname} is not allowed`
336
+ });
337
+ }
338
+ return;
339
+ }
340
+ }
341
+ function isIPv4(hostname) {
342
+ const parts = hostname.split(".");
343
+ if (parts.length !== 4) return false;
344
+ return parts.every((part) => {
345
+ const num = Number(part);
346
+ return Number.isInteger(num) && num >= 0 && num <= 255 && String(num) === part;
347
+ });
348
+ }
349
+ function isPrivateIPv4(ip) {
350
+ const parts = ip.split(".").map(Number);
351
+ const [a, b] = parts;
352
+ if (a === 0) return true;
353
+ if (a === 10) return true;
354
+ if (a === 127) return true;
355
+ if (a === 169 && b === 254) return true;
356
+ if (a === 172 && b >= 16 && b <= 31) return true;
357
+ if (a === 192 && b === 168) return true;
358
+ return false;
359
+ }
360
+ function isPrivateIPv6(ip) {
361
+ const normalized = ip.toLowerCase();
362
+ if (normalized === "::1") return true;
363
+ if (normalized === "::") return true;
364
+ if (normalized.startsWith("::ffff:")) {
365
+ const mappedPart = normalized.slice(7);
366
+ if (isIPv4(mappedPart)) {
367
+ return isPrivateIPv4(mappedPart);
368
+ }
369
+ const hexParts = mappedPart.split(":");
370
+ if (hexParts.length === 2) {
371
+ const high = parseInt(hexParts[0], 16);
372
+ const low = parseInt(hexParts[1], 16);
373
+ if (!isNaN(high) && !isNaN(low)) {
374
+ const a = high >> 8 & 255;
375
+ const b = high & 255;
376
+ const c = low >> 8 & 255;
377
+ const d = low & 255;
378
+ return isPrivateIPv4(`${a}.${b}.${c}.${d}`);
379
+ }
380
+ }
381
+ }
382
+ if (normalized.startsWith("fc") || normalized.startsWith("fd")) return true;
383
+ if (normalized.startsWith("fe80")) return true;
384
+ return false;
385
+ }
386
+
291
387
  // src/download-blob.ts
292
388
  async function downloadBlob(url, options) {
293
389
  var _a2, _b2;
390
+ validateDownloadUrl(url);
294
391
  try {
295
392
  const response = await fetch(url, {
296
393
  signal: options == null ? void 0 : options.abortSignal
297
394
  });
395
+ if (response.redirected) {
396
+ validateDownloadUrl(response.url);
397
+ }
298
398
  if (!response.ok) {
299
399
  throw new DownloadError({
300
400
  url,
@@ -479,7 +579,7 @@ function withUserAgentSuffix(headers, ...userAgentSuffixParts) {
479
579
  }
480
580
 
481
581
  // src/version.ts
482
- var VERSION = true ? "4.0.18" : "0.0.0-test";
582
+ var VERSION = true ? "4.0.20" : "0.0.0-test";
483
583
 
484
584
  // src/get-from-api.ts
485
585
  var getOriginalFetch = () => globalThis.fetch;
@@ -2650,6 +2750,7 @@ export {
2650
2750
  safeValidateTypes,
2651
2751
  stripFileExtension,
2652
2752
  tool,
2753
+ validateDownloadUrl,
2653
2754
  validateTypes,
2654
2755
  withUserAgentSuffix,
2655
2756
  withoutTrailingSlash,