@ai-sdk/provider-utils 4.0.60 → 4.0.61
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 +8 -0
- package/dist/index.d.mts +53 -11
- package/dist/index.d.ts +53 -11
- package/dist/index.js +77 -20
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +77 -20
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/fetch-with-validated-redirects.ts +65 -28
- package/src/get-from-api.ts +65 -10
- package/src/sanitize-request-headers.ts +53 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# @ai-sdk/provider-utils
|
|
2
2
|
|
|
3
|
+
## 4.0.61
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 5aa3086: feat(openai-compatible): support URL-based image responses
|
|
8
|
+
|
|
9
|
+
Add opt-in URL validation and credential origin handling to `getFromApi` for URL-based image responses. Validate redirect targets, strip unsafe request headers, and drop credentials on cross-origin redirects while preserving existing unvalidated requests.
|
|
10
|
+
|
|
3
11
|
## 4.0.60
|
|
4
12
|
|
|
5
13
|
### Patch Changes
|
package/dist/index.d.mts
CHANGED
|
@@ -250,24 +250,34 @@ declare function fetchWithValidatedEndpoint({ url, init, fetch: customFetch, tru
|
|
|
250
250
|
redirect?: 'error' | 'manual';
|
|
251
251
|
}): Promise<Response>;
|
|
252
252
|
/**
|
|
253
|
-
* Fetches a URL while enforcing the
|
|
253
|
+
* Fetches a URL while enforcing the download guard on every hop.
|
|
254
254
|
*
|
|
255
255
|
* Redirects are followed manually (`redirect: 'manual'`) so each hop is
|
|
256
256
|
* validated with {@link validateDownloadUrl} *before* it is requested. Relying
|
|
257
257
|
* on the default `redirect: 'follow'` would issue the request to a redirect
|
|
258
258
|
* target (e.g. an internal address) before we ever see its URL, defeating the
|
|
259
|
-
*
|
|
259
|
+
* guard.
|
|
260
|
+
*
|
|
261
|
+
* Request headers are also protected: {@link sanitizeRequestHeaders} strips
|
|
262
|
+
* proxy/metadata/cookie/hop-by-hop headers before the first request, and all
|
|
263
|
+
* caller headers except `User-Agent` are dropped on a cross-origin redirect.
|
|
264
|
+
* Credentials and custom headers are preserved on the first hop for backwards
|
|
265
|
+
* compatibility. The caller must ensure that the initial URL may receive them.
|
|
266
|
+
* The fetch spec only strips `Authorization` on cross-origin redirects because
|
|
267
|
+
* in a browser, CORS preflighting protects custom headers; there is no CORS on
|
|
268
|
+
* the server, so provider API keys carried in custom headers (e.g. `x-key`)
|
|
269
|
+
* must be dropped here as well.
|
|
260
270
|
*
|
|
261
271
|
* A `redirect: 'manual'` request yields an unreadable opaque response in the
|
|
262
272
|
* browser (and in other spec-compliant fetch implementations), so the redirect
|
|
263
273
|
* target cannot be validated here. In a real browser this is safe to follow
|
|
264
|
-
* natively because
|
|
265
|
-
* cannot reach a server's internal network or
|
|
266
|
-
* runtime we cannot validate the hop, so we fail
|
|
267
|
-
* blindly and bypass the
|
|
274
|
+
* natively because reaching an internal network is not possible (fetch is
|
|
275
|
+
* constrained by CORS and cannot reach a server's internal network or
|
|
276
|
+
* cloud-metadata). On any other runtime we cannot validate the hop, so we fail
|
|
277
|
+
* closed rather than follow it blindly and bypass the guard.
|
|
268
278
|
*
|
|
269
279
|
* A hop that is same-origin with `trustedOrigin` (the developer-configured
|
|
270
|
-
* endpoint) skips target validation: that origin is exactly what an
|
|
280
|
+
* provider endpoint) skips target validation: that origin is exactly what an
|
|
271
281
|
* unvalidated, config-derived request would fetch anyway, and validating it
|
|
272
282
|
* would break legitimate self-hosted / localhost deployments whose response
|
|
273
283
|
* URLs point back at the configured host. Hops on any other origin are always
|
|
@@ -278,7 +288,8 @@ declare function fetchWithValidatedEndpoint({ url, init, fetch: customFetch, tru
|
|
|
278
288
|
*
|
|
279
289
|
* On Node.js, the default fetch resolves every hostname through a validating
|
|
280
290
|
* lookup hook and passes those exact addresses to the connector, preventing
|
|
281
|
-
* hostname-to-private-IP and DNS-rebinding bypasses.
|
|
291
|
+
* hostname-to-private-IP and DNS-rebinding bypasses. An injected fetch is
|
|
292
|
+
* responsible for equivalent connect-time validation. Other runtimes should
|
|
282
293
|
* constrain egress at the network layer when handling untrusted URLs.
|
|
283
294
|
*
|
|
284
295
|
* @throws DownloadError if a hop is unsafe, the redirect limit is exceeded, or
|
|
@@ -291,8 +302,8 @@ declare function fetchWithValidatedRedirects({ url, headers, abortSignal, maxRed
|
|
|
291
302
|
maxRedirects?: number;
|
|
292
303
|
fetch?: FetchFunction;
|
|
293
304
|
/**
|
|
294
|
-
* A developer-configured origin
|
|
295
|
-
* never be derived from response data.
|
|
305
|
+
* A developer-configured origin (e.g. the provider's `baseURL`) whose hops
|
|
306
|
+
* skip target validation. Must never be derived from response data.
|
|
296
307
|
*/
|
|
297
308
|
trustedOrigin?: string;
|
|
298
309
|
}): Promise<Response>;
|
|
@@ -467,13 +478,44 @@ declare const createJsonResponseHandler: <T>(responseSchema: FlexibleSchema<T>)
|
|
|
467
478
|
declare const createBinaryResponseHandler: () => ResponseHandler<Uint8Array>;
|
|
468
479
|
declare const createStatusCodeErrorResponseHandler: () => ResponseHandler<APICallError>;
|
|
469
480
|
|
|
470
|
-
declare const getFromApi: <T>({ url, headers, successfulResponseHandler, failedResponseHandler, abortSignal, fetch, }: {
|
|
481
|
+
declare const getFromApi: <T>({ url, headers, successfulResponseHandler, failedResponseHandler, abortSignal, fetch, validateUrl, credentialedOrigin, trustedOrigin, }: {
|
|
471
482
|
url: string;
|
|
472
483
|
headers?: Record<string, string | undefined>;
|
|
473
484
|
failedResponseHandler: ResponseHandler<Error>;
|
|
474
485
|
successfulResponseHandler: ResponseHandler<T>;
|
|
475
486
|
abortSignal?: AbortSignal;
|
|
476
487
|
fetch?: FetchFunction;
|
|
488
|
+
/**
|
|
489
|
+
* Set `true` when `url` is untrusted (e.g. taken from a provider response
|
|
490
|
+
* body): it is routed through {@link fetchWithValidatedRedirects}, which
|
|
491
|
+
* rejects private/loopback/link-local targets and re-validates redirect
|
|
492
|
+
* hops; blocked URLs throw `DownloadError`. Set `false` only for URLs built
|
|
493
|
+
* from a developer-configured endpoint.
|
|
494
|
+
*
|
|
495
|
+
* Optional for backwards compatibility with existing callers; omitting it
|
|
496
|
+
* behaves like `false` (no validation).
|
|
497
|
+
*/
|
|
498
|
+
validateUrl?: boolean;
|
|
499
|
+
/**
|
|
500
|
+
* When set, `headers` are sent only if `url` is same-origin with this origin
|
|
501
|
+
* (the user-agent suffix is always kept). Pass the provider's configured
|
|
502
|
+
* base URL alongside `validateUrl: true` so credentials never ride a request
|
|
503
|
+
* to a response-supplied host on a different origin (e.g. a CDN). Redirects
|
|
504
|
+
* that later cross origin drop all caller headers regardless (see
|
|
505
|
+
* {@link fetchWithValidatedRedirects}).
|
|
506
|
+
*/
|
|
507
|
+
credentialedOrigin?: string;
|
|
508
|
+
/**
|
|
509
|
+
* A developer-configured origin (e.g. the provider's `baseURL`) that is
|
|
510
|
+
* exempt from URL validation when `validateUrl` is `true`. A response URL
|
|
511
|
+
* (or redirect hop) that is same-origin with it is fetched without target
|
|
512
|
+
* validation — it points at exactly the host a config-derived
|
|
513
|
+
* `validateUrl: false` request would fetch anyway, so blocking it would
|
|
514
|
+
* only break legitimate self-hosted / localhost deployments whose response
|
|
515
|
+
* URLs point back at the configured host. Hops on any other origin are
|
|
516
|
+
* still validated. Must never be derived from response data.
|
|
517
|
+
*/
|
|
518
|
+
trustedOrigin?: string;
|
|
477
519
|
}) => Promise<{
|
|
478
520
|
value: T;
|
|
479
521
|
rawValue?: unknown;
|
package/dist/index.d.ts
CHANGED
|
@@ -250,24 +250,34 @@ declare function fetchWithValidatedEndpoint({ url, init, fetch: customFetch, tru
|
|
|
250
250
|
redirect?: 'error' | 'manual';
|
|
251
251
|
}): Promise<Response>;
|
|
252
252
|
/**
|
|
253
|
-
* Fetches a URL while enforcing the
|
|
253
|
+
* Fetches a URL while enforcing the download guard on every hop.
|
|
254
254
|
*
|
|
255
255
|
* Redirects are followed manually (`redirect: 'manual'`) so each hop is
|
|
256
256
|
* validated with {@link validateDownloadUrl} *before* it is requested. Relying
|
|
257
257
|
* on the default `redirect: 'follow'` would issue the request to a redirect
|
|
258
258
|
* target (e.g. an internal address) before we ever see its URL, defeating the
|
|
259
|
-
*
|
|
259
|
+
* guard.
|
|
260
|
+
*
|
|
261
|
+
* Request headers are also protected: {@link sanitizeRequestHeaders} strips
|
|
262
|
+
* proxy/metadata/cookie/hop-by-hop headers before the first request, and all
|
|
263
|
+
* caller headers except `User-Agent` are dropped on a cross-origin redirect.
|
|
264
|
+
* Credentials and custom headers are preserved on the first hop for backwards
|
|
265
|
+
* compatibility. The caller must ensure that the initial URL may receive them.
|
|
266
|
+
* The fetch spec only strips `Authorization` on cross-origin redirects because
|
|
267
|
+
* in a browser, CORS preflighting protects custom headers; there is no CORS on
|
|
268
|
+
* the server, so provider API keys carried in custom headers (e.g. `x-key`)
|
|
269
|
+
* must be dropped here as well.
|
|
260
270
|
*
|
|
261
271
|
* A `redirect: 'manual'` request yields an unreadable opaque response in the
|
|
262
272
|
* browser (and in other spec-compliant fetch implementations), so the redirect
|
|
263
273
|
* target cannot be validated here. In a real browser this is safe to follow
|
|
264
|
-
* natively because
|
|
265
|
-
* cannot reach a server's internal network or
|
|
266
|
-
* runtime we cannot validate the hop, so we fail
|
|
267
|
-
* blindly and bypass the
|
|
274
|
+
* natively because reaching an internal network is not possible (fetch is
|
|
275
|
+
* constrained by CORS and cannot reach a server's internal network or
|
|
276
|
+
* cloud-metadata). On any other runtime we cannot validate the hop, so we fail
|
|
277
|
+
* closed rather than follow it blindly and bypass the guard.
|
|
268
278
|
*
|
|
269
279
|
* A hop that is same-origin with `trustedOrigin` (the developer-configured
|
|
270
|
-
* endpoint) skips target validation: that origin is exactly what an
|
|
280
|
+
* provider endpoint) skips target validation: that origin is exactly what an
|
|
271
281
|
* unvalidated, config-derived request would fetch anyway, and validating it
|
|
272
282
|
* would break legitimate self-hosted / localhost deployments whose response
|
|
273
283
|
* URLs point back at the configured host. Hops on any other origin are always
|
|
@@ -278,7 +288,8 @@ declare function fetchWithValidatedEndpoint({ url, init, fetch: customFetch, tru
|
|
|
278
288
|
*
|
|
279
289
|
* On Node.js, the default fetch resolves every hostname through a validating
|
|
280
290
|
* lookup hook and passes those exact addresses to the connector, preventing
|
|
281
|
-
* hostname-to-private-IP and DNS-rebinding bypasses.
|
|
291
|
+
* hostname-to-private-IP and DNS-rebinding bypasses. An injected fetch is
|
|
292
|
+
* responsible for equivalent connect-time validation. Other runtimes should
|
|
282
293
|
* constrain egress at the network layer when handling untrusted URLs.
|
|
283
294
|
*
|
|
284
295
|
* @throws DownloadError if a hop is unsafe, the redirect limit is exceeded, or
|
|
@@ -291,8 +302,8 @@ declare function fetchWithValidatedRedirects({ url, headers, abortSignal, maxRed
|
|
|
291
302
|
maxRedirects?: number;
|
|
292
303
|
fetch?: FetchFunction;
|
|
293
304
|
/**
|
|
294
|
-
* A developer-configured origin
|
|
295
|
-
* never be derived from response data.
|
|
305
|
+
* A developer-configured origin (e.g. the provider's `baseURL`) whose hops
|
|
306
|
+
* skip target validation. Must never be derived from response data.
|
|
296
307
|
*/
|
|
297
308
|
trustedOrigin?: string;
|
|
298
309
|
}): Promise<Response>;
|
|
@@ -467,13 +478,44 @@ declare const createJsonResponseHandler: <T>(responseSchema: FlexibleSchema<T>)
|
|
|
467
478
|
declare const createBinaryResponseHandler: () => ResponseHandler<Uint8Array>;
|
|
468
479
|
declare const createStatusCodeErrorResponseHandler: () => ResponseHandler<APICallError>;
|
|
469
480
|
|
|
470
|
-
declare const getFromApi: <T>({ url, headers, successfulResponseHandler, failedResponseHandler, abortSignal, fetch, }: {
|
|
481
|
+
declare const getFromApi: <T>({ url, headers, successfulResponseHandler, failedResponseHandler, abortSignal, fetch, validateUrl, credentialedOrigin, trustedOrigin, }: {
|
|
471
482
|
url: string;
|
|
472
483
|
headers?: Record<string, string | undefined>;
|
|
473
484
|
failedResponseHandler: ResponseHandler<Error>;
|
|
474
485
|
successfulResponseHandler: ResponseHandler<T>;
|
|
475
486
|
abortSignal?: AbortSignal;
|
|
476
487
|
fetch?: FetchFunction;
|
|
488
|
+
/**
|
|
489
|
+
* Set `true` when `url` is untrusted (e.g. taken from a provider response
|
|
490
|
+
* body): it is routed through {@link fetchWithValidatedRedirects}, which
|
|
491
|
+
* rejects private/loopback/link-local targets and re-validates redirect
|
|
492
|
+
* hops; blocked URLs throw `DownloadError`. Set `false` only for URLs built
|
|
493
|
+
* from a developer-configured endpoint.
|
|
494
|
+
*
|
|
495
|
+
* Optional for backwards compatibility with existing callers; omitting it
|
|
496
|
+
* behaves like `false` (no validation).
|
|
497
|
+
*/
|
|
498
|
+
validateUrl?: boolean;
|
|
499
|
+
/**
|
|
500
|
+
* When set, `headers` are sent only if `url` is same-origin with this origin
|
|
501
|
+
* (the user-agent suffix is always kept). Pass the provider's configured
|
|
502
|
+
* base URL alongside `validateUrl: true` so credentials never ride a request
|
|
503
|
+
* to a response-supplied host on a different origin (e.g. a CDN). Redirects
|
|
504
|
+
* that later cross origin drop all caller headers regardless (see
|
|
505
|
+
* {@link fetchWithValidatedRedirects}).
|
|
506
|
+
*/
|
|
507
|
+
credentialedOrigin?: string;
|
|
508
|
+
/**
|
|
509
|
+
* A developer-configured origin (e.g. the provider's `baseURL`) that is
|
|
510
|
+
* exempt from URL validation when `validateUrl` is `true`. A response URL
|
|
511
|
+
* (or redirect hop) that is same-origin with it is fetched without target
|
|
512
|
+
* validation — it points at exactly the host a config-derived
|
|
513
|
+
* `validateUrl: false` request would fetch anyway, so blocking it would
|
|
514
|
+
* only break legitimate self-hosted / localhost deployments whose response
|
|
515
|
+
* URLs point back at the configured host. Hops on any other origin are
|
|
516
|
+
* still validated. Must never be derived from response data.
|
|
517
|
+
*/
|
|
518
|
+
trustedOrigin?: string;
|
|
477
519
|
}) => Promise<{
|
|
478
520
|
value: T;
|
|
479
521
|
rawValue?: unknown;
|
package/dist/index.js
CHANGED
|
@@ -605,8 +605,45 @@ function getCurrentModulePath() {
|
|
|
605
605
|
}
|
|
606
606
|
}
|
|
607
607
|
|
|
608
|
+
// src/sanitize-request-headers.ts
|
|
609
|
+
var BLOCKED_REQUEST_HEADERS = [
|
|
610
|
+
// Hop-by-hop / transport (RFC 7230 §6.1)
|
|
611
|
+
"connection",
|
|
612
|
+
"keep-alive",
|
|
613
|
+
"te",
|
|
614
|
+
"trailer",
|
|
615
|
+
"transfer-encoding",
|
|
616
|
+
"upgrade",
|
|
617
|
+
// Host / virtual-host routing
|
|
618
|
+
"host",
|
|
619
|
+
// Proxy / origin spoofing
|
|
620
|
+
"forwarded",
|
|
621
|
+
"proxy-authorization",
|
|
622
|
+
"via",
|
|
623
|
+
"x-forwarded-for",
|
|
624
|
+
"x-forwarded-host",
|
|
625
|
+
"x-forwarded-proto",
|
|
626
|
+
"x-real-ip",
|
|
627
|
+
// Cloud metadata (GCP, AWS IMDSv1/v2, Azure, Alibaba, DigitalOcean)
|
|
628
|
+
"metadata",
|
|
629
|
+
"metadata-flavor",
|
|
630
|
+
"x-aws-ec2-metadata-token",
|
|
631
|
+
"x-metadata-token",
|
|
632
|
+
// Session / cookie
|
|
633
|
+
"cookie",
|
|
634
|
+
"set-cookie"
|
|
635
|
+
];
|
|
636
|
+
function sanitizeRequestHeaders(input) {
|
|
637
|
+
const headers = new Headers(input);
|
|
638
|
+
for (const name2 of BLOCKED_REQUEST_HEADERS) {
|
|
639
|
+
headers.delete(name2);
|
|
640
|
+
}
|
|
641
|
+
return headers;
|
|
642
|
+
}
|
|
643
|
+
|
|
608
644
|
// src/fetch-with-validated-redirects.ts
|
|
609
645
|
var MAX_DOWNLOAD_REDIRECTS = 10;
|
|
646
|
+
var REDIRECT_STATUS_CODES = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
|
|
610
647
|
async function getValidatedFetch(customFetch) {
|
|
611
648
|
return customFetch == null || customFetch === globalThis.fetch ? await getDefaultDownloadFetch() : customFetch;
|
|
612
649
|
}
|
|
@@ -637,10 +674,14 @@ async function fetchWithValidatedRedirects({
|
|
|
637
674
|
trustedOrigin
|
|
638
675
|
}) {
|
|
639
676
|
var _a2;
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
677
|
+
let currentHeaders = headers === void 0 ? void 0 : sanitizeRequestHeaders(headers);
|
|
678
|
+
const perHopInit = (redirect) => {
|
|
679
|
+
const init = { signal: abortSignal, redirect };
|
|
680
|
+
if (currentHeaders !== void 0) {
|
|
681
|
+
init.headers = new Headers(currentHeaders);
|
|
682
|
+
}
|
|
683
|
+
return init;
|
|
684
|
+
};
|
|
644
685
|
let currentUrl = url;
|
|
645
686
|
for (let redirectCount = 0; redirectCount <= maxRedirects; redirectCount++) {
|
|
646
687
|
const isTrustedHop = trustedOrigin !== void 0 && isSameOrigin(currentUrl, trustedOrigin);
|
|
@@ -648,10 +689,7 @@ async function fetchWithValidatedRedirects({
|
|
|
648
689
|
validateDownloadUrl(currentUrl);
|
|
649
690
|
}
|
|
650
691
|
const fetch = isTrustedHop && customFetch != null ? customFetch : isTrustedHop ? globalThis.fetch : await getValidatedFetch(customFetch);
|
|
651
|
-
const response = await fetch(currentUrl,
|
|
652
|
-
...baseInit,
|
|
653
|
-
redirect: "manual"
|
|
654
|
-
});
|
|
692
|
+
const response = await fetch(currentUrl, perHopInit("manual"));
|
|
655
693
|
if (response.type === "opaqueredirect") {
|
|
656
694
|
if (!isBrowserRuntime()) {
|
|
657
695
|
throw new DownloadError({
|
|
@@ -659,12 +697,19 @@ async function fetchWithValidatedRedirects({
|
|
|
659
697
|
message: `Redirect from ${currentUrl} could not be validated and was blocked`
|
|
660
698
|
});
|
|
661
699
|
}
|
|
662
|
-
return await fetch(currentUrl,
|
|
700
|
+
return await fetch(currentUrl, perHopInit("follow"));
|
|
663
701
|
}
|
|
664
702
|
const location = (_a2 = response.headers) == null ? void 0 : _a2.get("location");
|
|
665
|
-
if (
|
|
666
|
-
|
|
667
|
-
|
|
703
|
+
if (REDIRECT_STATUS_CODES.has(response.status) && location) {
|
|
704
|
+
void cancelResponseBody(response);
|
|
705
|
+
const nextUrl = new URL(location, currentUrl).toString();
|
|
706
|
+
if (currentHeaders !== void 0 && !isSameOrigin(nextUrl, currentUrl)) {
|
|
707
|
+
const userAgent = currentHeaders.get("user-agent");
|
|
708
|
+
currentHeaders = new Headers(
|
|
709
|
+
userAgent == null ? void 0 : { "user-agent": userAgent }
|
|
710
|
+
);
|
|
711
|
+
}
|
|
712
|
+
currentUrl = nextUrl;
|
|
668
713
|
continue;
|
|
669
714
|
}
|
|
670
715
|
return response;
|
|
@@ -954,7 +999,7 @@ function withUserAgentSuffix(headers, ...userAgentSuffixParts) {
|
|
|
954
999
|
}
|
|
955
1000
|
|
|
956
1001
|
// src/version.ts
|
|
957
|
-
var VERSION = true ? "4.0.
|
|
1002
|
+
var VERSION = true ? "4.0.61" : "0.0.0-test";
|
|
958
1003
|
|
|
959
1004
|
// src/get-from-api.ts
|
|
960
1005
|
var getOriginalFetch = () => globalThis.fetch;
|
|
@@ -964,16 +1009,28 @@ var getFromApi = async ({
|
|
|
964
1009
|
successfulResponseHandler,
|
|
965
1010
|
failedResponseHandler,
|
|
966
1011
|
abortSignal,
|
|
967
|
-
fetch
|
|
1012
|
+
fetch,
|
|
1013
|
+
validateUrl,
|
|
1014
|
+
credentialedOrigin,
|
|
1015
|
+
trustedOrigin
|
|
968
1016
|
}) => {
|
|
969
1017
|
try {
|
|
970
|
-
const
|
|
1018
|
+
const requestFetch = fetch != null ? fetch : getOriginalFetch();
|
|
1019
|
+
const outgoingHeaders = credentialedOrigin !== void 0 && !isSameOrigin(url, credentialedOrigin) ? {} : headers;
|
|
1020
|
+
const requestHeaders = withUserAgentSuffix(
|
|
1021
|
+
outgoingHeaders,
|
|
1022
|
+
`ai-sdk/provider-utils/${VERSION}`,
|
|
1023
|
+
getRuntimeEnvironmentUserAgent()
|
|
1024
|
+
);
|
|
1025
|
+
const response = validateUrl ? await fetchWithValidatedRedirects({
|
|
1026
|
+
url,
|
|
1027
|
+
headers: requestHeaders,
|
|
1028
|
+
abortSignal,
|
|
1029
|
+
fetch,
|
|
1030
|
+
trustedOrigin
|
|
1031
|
+
}) : await requestFetch(url, {
|
|
971
1032
|
method: "GET",
|
|
972
|
-
headers:
|
|
973
|
-
headers,
|
|
974
|
-
`ai-sdk/provider-utils/${VERSION}`,
|
|
975
|
-
getRuntimeEnvironmentUserAgent()
|
|
976
|
-
),
|
|
1033
|
+
headers: requestHeaders,
|
|
977
1034
|
signal: abortSignal
|
|
978
1035
|
});
|
|
979
1036
|
const responseHeaders = extractResponseHeaders(response);
|