@ai-sdk/provider-utils 3.0.26 → 3.0.28

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 CHANGED
@@ -1,5 +1,19 @@
1
1
  # @ai-sdk/provider-utils
2
2
 
3
+ ## 3.0.28
4
+
5
+ ### Patch Changes
6
+
7
+ - b85c4fb: Limit JSON response body reads in response handlers to prevent unbounded memory use.
8
+
9
+ ## 3.0.27
10
+
11
+ ### Patch Changes
12
+
13
+ - 9169261: fix(provider-utils): cancel response body on download rejection to prevent socket leak
14
+
15
+ When a download was rejected early — because the `Content-Length` header exceeded the size limit, the response status was not ok, or a redirect resolved to a blocked URL — the fetch response body was left unconsumed and uncancelled. With WHATWG Fetch/undici this leaves the underlying TCP socket open instead of returning it to the connection pool, allowing an attacker-controlled origin to exhaust file descriptors and cause a denial of service. The body is now cancelled on all early-rejection paths in `readResponseWithSizeLimit` and `download`, and `fetchWithValidatedRedirects` cancels each redirect hop's body before following or rejecting the next hop.
16
+
3
17
  ## 3.0.26
4
18
 
5
19
  ### Patch Changes
package/dist/index.d.mts CHANGED
@@ -907,6 +907,20 @@ declare function createProviderDefinedToolFactoryWithOutputSchema<INPUT, OUTPUT,
907
907
  outputSchema: FlexibleSchema<OUTPUT>;
908
908
  }): ProviderDefinedToolFactoryWithOutputSchema<INPUT, OUTPUT, ARGS>;
909
909
 
910
+ /**
911
+ * Cancels a response body to release the underlying connection.
912
+ *
913
+ * When a fetch Response is rejected without consuming its body (e.g. a failed
914
+ * status code, an open-redirect rejection, or a Content-Length that exceeds the
915
+ * size limit), the underlying TCP socket is not returned to the connection pool
916
+ * and may stay open until the process runs out of file descriptors. Cancelling
917
+ * the body avoids this leak.
918
+ *
919
+ * Errors thrown while cancelling are ignored: the body may already be locked,
920
+ * disturbed, or absent, none of which should mask the original rejection.
921
+ */
922
+ declare function cancelResponseBody(response: Response): Promise<void>;
923
+
910
924
  /**
911
925
  * Removes entries from a record where the value is null or undefined.
912
926
  * @param record - The input object whose entries may be null or undefined.
@@ -1072,4 +1086,4 @@ interface ToolResult<NAME extends string, INPUT, OUTPUT> {
1072
1086
  dynamic?: boolean;
1073
1087
  }
1074
1088
 
1075
- export { type AssistantContent, type AssistantModelMessage, DEFAULT_MAX_DOWNLOAD_SIZE, type DataContent, DelayedPromise, DownloadError, type FetchFunction, type FilePart, type FlexibleSchema, type FlexibleValidator, type IdGenerator, type ImagePart, type InferSchema, type InferToolInput, type InferToolOutput, type InferValidator, type LazySchema, type LazyValidator, type ModelMessage, type ParseResult, type ProviderDefinedToolFactory, type ProviderDefinedToolFactoryWithOutputSchema, type ProviderOptions, type ReasoningPart, type Resolvable, type ResponseHandler, type Schema, type SystemModelMessage, type TextPart, type Tool, type ToolCall, type ToolCallOptions, type ToolCallPart, type ToolContent, type ToolExecuteFunction, type ToolModelMessage, type ToolResult, type ToolResultPart, type UserContent, type UserModelMessage, VERSION, type ValidationResult, type Validator, asSchema, asValidator, combineHeaders, convertAsyncIteratorToReadableStream, convertBase64ToUint8Array, convertToBase64, convertUint8ArrayToBase64, createBinaryResponseHandler, createEventSourceResponseHandler, createIdGenerator, createJsonErrorResponseHandler, createJsonResponseHandler, createJsonStreamResponseHandler, createProviderDefinedToolFactory, createProviderDefinedToolFactoryWithOutputSchema, createStatusCodeErrorResponseHandler, delay, dynamicTool, executeTool, extractResponseHeaders, fetchWithValidatedRedirects, generateId, getErrorMessage, getFromApi, getRuntimeEnvironmentUserAgent, injectJsonInstructionIntoMessages, isAbortError, isBrowserRuntime, isParsableJson, isSameOrigin, isUrlSupported, isValidator, jsonSchema, lazySchema, lazyValidator, loadApiKey, loadOptionalSetting, loadSetting, mediaTypeToExtension, normalizeHeaders, parseJSON, parseJsonEventStream, parseProviderOptions, postFormDataToApi, postJsonToApi, postToApi, readResponseWithSizeLimit, removeUndefinedEntries, resolve, safeParseJSON, safeValidateTypes, standardSchemaValidator, tool, validateDownloadUrl, validateTypes, validator, withUserAgentSuffix, withoutTrailingSlash, zodSchema };
1089
+ export { type AssistantContent, type AssistantModelMessage, DEFAULT_MAX_DOWNLOAD_SIZE, type DataContent, DelayedPromise, DownloadError, type FetchFunction, type FilePart, type FlexibleSchema, type FlexibleValidator, type IdGenerator, type ImagePart, type InferSchema, type InferToolInput, type InferToolOutput, type InferValidator, type LazySchema, type LazyValidator, type ModelMessage, type ParseResult, type ProviderDefinedToolFactory, type ProviderDefinedToolFactoryWithOutputSchema, type ProviderOptions, type ReasoningPart, type Resolvable, type ResponseHandler, type Schema, type SystemModelMessage, type TextPart, type Tool, type ToolCall, type ToolCallOptions, type ToolCallPart, type ToolContent, type ToolExecuteFunction, type ToolModelMessage, type ToolResult, type ToolResultPart, type UserContent, type UserModelMessage, VERSION, type ValidationResult, type Validator, asSchema, asValidator, cancelResponseBody, combineHeaders, convertAsyncIteratorToReadableStream, convertBase64ToUint8Array, convertToBase64, convertUint8ArrayToBase64, createBinaryResponseHandler, createEventSourceResponseHandler, createIdGenerator, createJsonErrorResponseHandler, createJsonResponseHandler, createJsonStreamResponseHandler, createProviderDefinedToolFactory, createProviderDefinedToolFactoryWithOutputSchema, createStatusCodeErrorResponseHandler, delay, dynamicTool, executeTool, extractResponseHeaders, fetchWithValidatedRedirects, generateId, getErrorMessage, getFromApi, getRuntimeEnvironmentUserAgent, injectJsonInstructionIntoMessages, isAbortError, isBrowserRuntime, isParsableJson, isSameOrigin, isUrlSupported, isValidator, jsonSchema, lazySchema, lazyValidator, loadApiKey, loadOptionalSetting, loadSetting, mediaTypeToExtension, normalizeHeaders, parseJSON, parseJsonEventStream, parseProviderOptions, postFormDataToApi, postJsonToApi, postToApi, readResponseWithSizeLimit, removeUndefinedEntries, resolve, safeParseJSON, safeValidateTypes, standardSchemaValidator, tool, validateDownloadUrl, validateTypes, validator, withUserAgentSuffix, withoutTrailingSlash, zodSchema };
package/dist/index.d.ts CHANGED
@@ -907,6 +907,20 @@ declare function createProviderDefinedToolFactoryWithOutputSchema<INPUT, OUTPUT,
907
907
  outputSchema: FlexibleSchema<OUTPUT>;
908
908
  }): ProviderDefinedToolFactoryWithOutputSchema<INPUT, OUTPUT, ARGS>;
909
909
 
910
+ /**
911
+ * Cancels a response body to release the underlying connection.
912
+ *
913
+ * When a fetch Response is rejected without consuming its body (e.g. a failed
914
+ * status code, an open-redirect rejection, or a Content-Length that exceeds the
915
+ * size limit), the underlying TCP socket is not returned to the connection pool
916
+ * and may stay open until the process runs out of file descriptors. Cancelling
917
+ * the body avoids this leak.
918
+ *
919
+ * Errors thrown while cancelling are ignored: the body may already be locked,
920
+ * disturbed, or absent, none of which should mask the original rejection.
921
+ */
922
+ declare function cancelResponseBody(response: Response): Promise<void>;
923
+
910
924
  /**
911
925
  * Removes entries from a record where the value is null or undefined.
912
926
  * @param record - The input object whose entries may be null or undefined.
@@ -1072,4 +1086,4 @@ interface ToolResult<NAME extends string, INPUT, OUTPUT> {
1072
1086
  dynamic?: boolean;
1073
1087
  }
1074
1088
 
1075
- export { type AssistantContent, type AssistantModelMessage, DEFAULT_MAX_DOWNLOAD_SIZE, type DataContent, DelayedPromise, DownloadError, type FetchFunction, type FilePart, type FlexibleSchema, type FlexibleValidator, type IdGenerator, type ImagePart, type InferSchema, type InferToolInput, type InferToolOutput, type InferValidator, type LazySchema, type LazyValidator, type ModelMessage, type ParseResult, type ProviderDefinedToolFactory, type ProviderDefinedToolFactoryWithOutputSchema, type ProviderOptions, type ReasoningPart, type Resolvable, type ResponseHandler, type Schema, type SystemModelMessage, type TextPart, type Tool, type ToolCall, type ToolCallOptions, type ToolCallPart, type ToolContent, type ToolExecuteFunction, type ToolModelMessage, type ToolResult, type ToolResultPart, type UserContent, type UserModelMessage, VERSION, type ValidationResult, type Validator, asSchema, asValidator, combineHeaders, convertAsyncIteratorToReadableStream, convertBase64ToUint8Array, convertToBase64, convertUint8ArrayToBase64, createBinaryResponseHandler, createEventSourceResponseHandler, createIdGenerator, createJsonErrorResponseHandler, createJsonResponseHandler, createJsonStreamResponseHandler, createProviderDefinedToolFactory, createProviderDefinedToolFactoryWithOutputSchema, createStatusCodeErrorResponseHandler, delay, dynamicTool, executeTool, extractResponseHeaders, fetchWithValidatedRedirects, generateId, getErrorMessage, getFromApi, getRuntimeEnvironmentUserAgent, injectJsonInstructionIntoMessages, isAbortError, isBrowserRuntime, isParsableJson, isSameOrigin, isUrlSupported, isValidator, jsonSchema, lazySchema, lazyValidator, loadApiKey, loadOptionalSetting, loadSetting, mediaTypeToExtension, normalizeHeaders, parseJSON, parseJsonEventStream, parseProviderOptions, postFormDataToApi, postJsonToApi, postToApi, readResponseWithSizeLimit, removeUndefinedEntries, resolve, safeParseJSON, safeValidateTypes, standardSchemaValidator, tool, validateDownloadUrl, validateTypes, validator, withUserAgentSuffix, withoutTrailingSlash, zodSchema };
1089
+ export { type AssistantContent, type AssistantModelMessage, DEFAULT_MAX_DOWNLOAD_SIZE, type DataContent, DelayedPromise, DownloadError, type FetchFunction, type FilePart, type FlexibleSchema, type FlexibleValidator, type IdGenerator, type ImagePart, type InferSchema, type InferToolInput, type InferToolOutput, type InferValidator, type LazySchema, type LazyValidator, type ModelMessage, type ParseResult, type ProviderDefinedToolFactory, type ProviderDefinedToolFactoryWithOutputSchema, type ProviderOptions, type ReasoningPart, type Resolvable, type ResponseHandler, type Schema, type SystemModelMessage, type TextPart, type Tool, type ToolCall, type ToolCallOptions, type ToolCallPart, type ToolContent, type ToolExecuteFunction, type ToolModelMessage, type ToolResult, type ToolResultPart, type UserContent, type UserModelMessage, VERSION, type ValidationResult, type Validator, asSchema, asValidator, cancelResponseBody, combineHeaders, convertAsyncIteratorToReadableStream, convertBase64ToUint8Array, convertToBase64, convertUint8ArrayToBase64, createBinaryResponseHandler, createEventSourceResponseHandler, createIdGenerator, createJsonErrorResponseHandler, createJsonResponseHandler, createJsonStreamResponseHandler, createProviderDefinedToolFactory, createProviderDefinedToolFactoryWithOutputSchema, createStatusCodeErrorResponseHandler, delay, dynamicTool, executeTool, extractResponseHeaders, fetchWithValidatedRedirects, generateId, getErrorMessage, getFromApi, getRuntimeEnvironmentUserAgent, injectJsonInstructionIntoMessages, isAbortError, isBrowserRuntime, isParsableJson, isSameOrigin, isUrlSupported, isValidator, jsonSchema, lazySchema, lazyValidator, loadApiKey, loadOptionalSetting, loadSetting, mediaTypeToExtension, normalizeHeaders, parseJSON, parseJsonEventStream, parseProviderOptions, postFormDataToApi, postJsonToApi, postToApi, readResponseWithSizeLimit, removeUndefinedEntries, resolve, safeParseJSON, safeValidateTypes, standardSchemaValidator, tool, validateDownloadUrl, validateTypes, validator, withUserAgentSuffix, withoutTrailingSlash, zodSchema };
package/dist/index.js CHANGED
@@ -38,6 +38,7 @@ __export(index_exports, {
38
38
  VERSION: () => VERSION,
39
39
  asSchema: () => asSchema,
40
40
  asValidator: () => asValidator,
41
+ cancelResponseBody: () => cancelResponseBody,
41
42
  combineHeaders: () => combineHeaders,
42
43
  convertAsyncIteratorToReadableStream: () => convertAsyncIteratorToReadableStream,
43
44
  convertBase64ToUint8Array: () => convertBase64ToUint8Array,
@@ -254,6 +255,15 @@ var DownloadError = class extends (_b = import_provider.AISDKError, _a = symbol,
254
255
  }
255
256
  };
256
257
 
258
+ // src/cancel-response-body.ts
259
+ async function cancelResponseBody(response) {
260
+ var _a2;
261
+ try {
262
+ await ((_a2 = response.body) == null ? void 0 : _a2.cancel());
263
+ } catch (e) {
264
+ }
265
+ }
266
+
257
267
  // src/is-browser-runtime.ts
258
268
  function isBrowserRuntime(globalThisAny = globalThis) {
259
269
  return globalThisAny.window != null;
@@ -428,6 +438,7 @@ async function fetchWithValidatedRedirects({
428
438
  }
429
439
  const location = response.headers.get("location");
430
440
  if (response.status >= 300 && response.status < 400 && location) {
441
+ await cancelResponseBody(response);
431
442
  currentUrl = new URL(location, currentUrl).toString();
432
443
  continue;
433
444
  }
@@ -450,6 +461,7 @@ async function readResponseWithSizeLimit({
450
461
  if (contentLength != null) {
451
462
  const length = parseInt(contentLength, 10);
452
463
  if (!isNaN(length) && length > maxBytes) {
464
+ await cancelResponseBody(response);
453
465
  throw new DownloadError({
454
466
  url,
455
467
  message: `Download of ${url} exceeded maximum size of ${maxBytes} bytes (Content-Length: ${length}).`
@@ -628,7 +640,7 @@ function withUserAgentSuffix(headers, ...userAgentSuffixParts) {
628
640
  }
629
641
 
630
642
  // src/version.ts
631
- var VERSION = true ? "3.0.26" : "0.0.0-test";
643
+ var VERSION = true ? "3.0.28" : "0.0.0-test";
632
644
 
633
645
  // src/get-from-api.ts
634
646
  var getOriginalFetch = () => globalThis.fetch;
@@ -1274,12 +1286,24 @@ async function resolve(value) {
1274
1286
 
1275
1287
  // src/response-handler.ts
1276
1288
  var import_provider12 = require("@ai-sdk/provider");
1289
+ var textDecoder = new TextDecoder();
1290
+ async function readResponseBodyAsText({
1291
+ response,
1292
+ url
1293
+ }) {
1294
+ return textDecoder.decode(
1295
+ await readResponseWithSizeLimit({
1296
+ response,
1297
+ url
1298
+ })
1299
+ );
1300
+ }
1277
1301
  var createJsonErrorResponseHandler = ({
1278
1302
  errorSchema,
1279
1303
  errorToMessage,
1280
1304
  isRetryable
1281
1305
  }) => async ({ response, url, requestBodyValues }) => {
1282
- const responseBody = await response.text();
1306
+ const responseBody = await readResponseBodyAsText({ response, url });
1283
1307
  const responseHeaders = extractResponseHeaders(response);
1284
1308
  if (responseBody.trim() === "") {
1285
1309
  return {
@@ -1369,7 +1393,7 @@ var createJsonStreamResponseHandler = (chunkSchema) => async ({ response }) => {
1369
1393
  };
1370
1394
  };
1371
1395
  var createJsonResponseHandler = (responseSchema) => async ({ response, url, requestBodyValues }) => {
1372
- const responseBody = await response.text();
1396
+ const responseBody = await readResponseBodyAsText({ response, url });
1373
1397
  const parsedResult = await safeParseJSON({
1374
1398
  text: responseBody,
1375
1399
  schema: responseSchema
@@ -1424,7 +1448,7 @@ var createBinaryResponseHandler = () => async ({ response, url, requestBodyValue
1424
1448
  };
1425
1449
  var createStatusCodeErrorResponseHandler = () => async ({ response, url, requestBodyValues }) => {
1426
1450
  const responseHeaders = extractResponseHeaders(response);
1427
- const responseBody = await response.text();
1451
+ const responseBody = await readResponseBodyAsText({ response, url });
1428
1452
  return {
1429
1453
  responseHeaders,
1430
1454
  value: new import_provider12.APICallError({
@@ -2796,6 +2820,7 @@ var import_stream2 = require("eventsource-parser/stream");
2796
2820
  VERSION,
2797
2821
  asSchema,
2798
2822
  asValidator,
2823
+ cancelResponseBody,
2799
2824
  combineHeaders,
2800
2825
  convertAsyncIteratorToReadableStream,
2801
2826
  convertBase64ToUint8Array,