@ai-sdk/provider-utils 4.0.60 → 4.0.62
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 +15 -0
- package/dist/index.d.mts +61 -12
- package/dist/index.d.ts +61 -12
- package/dist/index.js +86 -21
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +85 -21
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/encode-path-segment.ts +15 -0
- package/src/fetch-with-validated-redirects.ts +65 -28
- package/src/get-from-api.ts +65 -10
- package/src/index.ts +1 -0
- package/src/sanitize-request-headers.ts +53 -0
- package/src/validate-download-url.ts +3 -2
package/dist/index.mjs
CHANGED
|
@@ -284,7 +284,7 @@ function validateDownloadUrl(url) {
|
|
|
284
284
|
message: `URL must have a hostname`
|
|
285
285
|
});
|
|
286
286
|
}
|
|
287
|
-
if (hostname === "localhost" || hostname.endsWith(".local") || hostname.endsWith(".localhost")) {
|
|
287
|
+
if (hostname === "localhost" || hostname.endsWith(".local") || hostname.endsWith(".localhost") || hostname.endsWith(".internal")) {
|
|
288
288
|
throw new DownloadError({
|
|
289
289
|
url,
|
|
290
290
|
message: `URL with hostname ${hostname} is not allowed`
|
|
@@ -499,8 +499,45 @@ function getCurrentModulePath() {
|
|
|
499
499
|
}
|
|
500
500
|
}
|
|
501
501
|
|
|
502
|
+
// src/sanitize-request-headers.ts
|
|
503
|
+
var BLOCKED_REQUEST_HEADERS = [
|
|
504
|
+
// Hop-by-hop / transport (RFC 7230 §6.1)
|
|
505
|
+
"connection",
|
|
506
|
+
"keep-alive",
|
|
507
|
+
"te",
|
|
508
|
+
"trailer",
|
|
509
|
+
"transfer-encoding",
|
|
510
|
+
"upgrade",
|
|
511
|
+
// Host / virtual-host routing
|
|
512
|
+
"host",
|
|
513
|
+
// Proxy / origin spoofing
|
|
514
|
+
"forwarded",
|
|
515
|
+
"proxy-authorization",
|
|
516
|
+
"via",
|
|
517
|
+
"x-forwarded-for",
|
|
518
|
+
"x-forwarded-host",
|
|
519
|
+
"x-forwarded-proto",
|
|
520
|
+
"x-real-ip",
|
|
521
|
+
// Cloud metadata (GCP, AWS IMDSv1/v2, Azure, Alibaba, DigitalOcean)
|
|
522
|
+
"metadata",
|
|
523
|
+
"metadata-flavor",
|
|
524
|
+
"x-aws-ec2-metadata-token",
|
|
525
|
+
"x-metadata-token",
|
|
526
|
+
// Session / cookie
|
|
527
|
+
"cookie",
|
|
528
|
+
"set-cookie"
|
|
529
|
+
];
|
|
530
|
+
function sanitizeRequestHeaders(input) {
|
|
531
|
+
const headers = new Headers(input);
|
|
532
|
+
for (const name2 of BLOCKED_REQUEST_HEADERS) {
|
|
533
|
+
headers.delete(name2);
|
|
534
|
+
}
|
|
535
|
+
return headers;
|
|
536
|
+
}
|
|
537
|
+
|
|
502
538
|
// src/fetch-with-validated-redirects.ts
|
|
503
539
|
var MAX_DOWNLOAD_REDIRECTS = 10;
|
|
540
|
+
var REDIRECT_STATUS_CODES = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
|
|
504
541
|
async function getValidatedFetch(customFetch) {
|
|
505
542
|
return customFetch == null || customFetch === globalThis.fetch ? await getDefaultDownloadFetch() : customFetch;
|
|
506
543
|
}
|
|
@@ -531,10 +568,14 @@ async function fetchWithValidatedRedirects({
|
|
|
531
568
|
trustedOrigin
|
|
532
569
|
}) {
|
|
533
570
|
var _a2;
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
571
|
+
let currentHeaders = headers === void 0 ? void 0 : sanitizeRequestHeaders(headers);
|
|
572
|
+
const perHopInit = (redirect) => {
|
|
573
|
+
const init = { signal: abortSignal, redirect };
|
|
574
|
+
if (currentHeaders !== void 0) {
|
|
575
|
+
init.headers = new Headers(currentHeaders);
|
|
576
|
+
}
|
|
577
|
+
return init;
|
|
578
|
+
};
|
|
538
579
|
let currentUrl = url;
|
|
539
580
|
for (let redirectCount = 0; redirectCount <= maxRedirects; redirectCount++) {
|
|
540
581
|
const isTrustedHop = trustedOrigin !== void 0 && isSameOrigin(currentUrl, trustedOrigin);
|
|
@@ -542,10 +583,7 @@ async function fetchWithValidatedRedirects({
|
|
|
542
583
|
validateDownloadUrl(currentUrl);
|
|
543
584
|
}
|
|
544
585
|
const fetch = isTrustedHop && customFetch != null ? customFetch : isTrustedHop ? globalThis.fetch : await getValidatedFetch(customFetch);
|
|
545
|
-
const response = await fetch(currentUrl,
|
|
546
|
-
...baseInit,
|
|
547
|
-
redirect: "manual"
|
|
548
|
-
});
|
|
586
|
+
const response = await fetch(currentUrl, perHopInit("manual"));
|
|
549
587
|
if (response.type === "opaqueredirect") {
|
|
550
588
|
if (!isBrowserRuntime()) {
|
|
551
589
|
throw new DownloadError({
|
|
@@ -553,12 +591,19 @@ async function fetchWithValidatedRedirects({
|
|
|
553
591
|
message: `Redirect from ${currentUrl} could not be validated and was blocked`
|
|
554
592
|
});
|
|
555
593
|
}
|
|
556
|
-
return await fetch(currentUrl,
|
|
594
|
+
return await fetch(currentUrl, perHopInit("follow"));
|
|
557
595
|
}
|
|
558
596
|
const location = (_a2 = response.headers) == null ? void 0 : _a2.get("location");
|
|
559
|
-
if (
|
|
560
|
-
|
|
561
|
-
|
|
597
|
+
if (REDIRECT_STATUS_CODES.has(response.status) && location) {
|
|
598
|
+
void cancelResponseBody(response);
|
|
599
|
+
const nextUrl = new URL(location, currentUrl).toString();
|
|
600
|
+
if (currentHeaders !== void 0 && !isSameOrigin(nextUrl, currentUrl)) {
|
|
601
|
+
const userAgent = currentHeaders.get("user-agent");
|
|
602
|
+
currentHeaders = new Headers(
|
|
603
|
+
userAgent == null ? void 0 : { "user-agent": userAgent }
|
|
604
|
+
);
|
|
605
|
+
}
|
|
606
|
+
currentUrl = nextUrl;
|
|
562
607
|
continue;
|
|
563
608
|
}
|
|
564
609
|
return response;
|
|
@@ -694,6 +739,12 @@ var createIdGenerator = ({
|
|
|
694
739
|
};
|
|
695
740
|
var generateId = createIdGenerator();
|
|
696
741
|
|
|
742
|
+
// src/encode-path-segment.ts
|
|
743
|
+
function encodePathSegment(value) {
|
|
744
|
+
const encodedValue = encodeURIComponent(value);
|
|
745
|
+
return encodedValue === "." ? "%252E" : encodedValue === ".." ? "%252E%252E" : encodedValue;
|
|
746
|
+
}
|
|
747
|
+
|
|
697
748
|
// src/get-error-message.ts
|
|
698
749
|
function getErrorMessage(error) {
|
|
699
750
|
if (error == null) {
|
|
@@ -848,7 +899,7 @@ function withUserAgentSuffix(headers, ...userAgentSuffixParts) {
|
|
|
848
899
|
}
|
|
849
900
|
|
|
850
901
|
// src/version.ts
|
|
851
|
-
var VERSION = true ? "4.0.
|
|
902
|
+
var VERSION = true ? "4.0.62" : "0.0.0-test";
|
|
852
903
|
|
|
853
904
|
// src/get-from-api.ts
|
|
854
905
|
var getOriginalFetch = () => globalThis.fetch;
|
|
@@ -858,16 +909,28 @@ var getFromApi = async ({
|
|
|
858
909
|
successfulResponseHandler,
|
|
859
910
|
failedResponseHandler,
|
|
860
911
|
abortSignal,
|
|
861
|
-
fetch
|
|
912
|
+
fetch,
|
|
913
|
+
validateUrl,
|
|
914
|
+
credentialedOrigin,
|
|
915
|
+
trustedOrigin
|
|
862
916
|
}) => {
|
|
863
917
|
try {
|
|
864
|
-
const
|
|
918
|
+
const requestFetch = fetch != null ? fetch : getOriginalFetch();
|
|
919
|
+
const outgoingHeaders = credentialedOrigin !== void 0 && !isSameOrigin(url, credentialedOrigin) ? {} : headers;
|
|
920
|
+
const requestHeaders = withUserAgentSuffix(
|
|
921
|
+
outgoingHeaders,
|
|
922
|
+
`ai-sdk/provider-utils/${VERSION}`,
|
|
923
|
+
getRuntimeEnvironmentUserAgent()
|
|
924
|
+
);
|
|
925
|
+
const response = validateUrl ? await fetchWithValidatedRedirects({
|
|
926
|
+
url,
|
|
927
|
+
headers: requestHeaders,
|
|
928
|
+
abortSignal,
|
|
929
|
+
fetch,
|
|
930
|
+
trustedOrigin
|
|
931
|
+
}) : await requestFetch(url, {
|
|
865
932
|
method: "GET",
|
|
866
|
-
headers:
|
|
867
|
-
headers,
|
|
868
|
-
`ai-sdk/provider-utils/${VERSION}`,
|
|
869
|
-
getRuntimeEnvironmentUserAgent()
|
|
870
|
-
),
|
|
933
|
+
headers: requestHeaders,
|
|
871
934
|
signal: abortSignal
|
|
872
935
|
});
|
|
873
936
|
const responseHeaders = extractResponseHeaders(response);
|
|
@@ -3524,6 +3587,7 @@ export {
|
|
|
3524
3587
|
delay,
|
|
3525
3588
|
downloadBlob,
|
|
3526
3589
|
dynamicTool,
|
|
3590
|
+
encodePathSegment,
|
|
3527
3591
|
executeTool,
|
|
3528
3592
|
extractResponseHeaders,
|
|
3529
3593
|
fetchWithValidatedEndpoint,
|