@ai-sdk/provider-utils 4.0.29 → 4.0.30

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,13 @@
1
1
  # @ai-sdk/provider-utils
2
2
 
3
+ ## 4.0.30
4
+
5
+ ### Patch Changes
6
+
7
+ - 779f5cd: fix(provider-utils): cancel response body on download rejection to prevent socket leak
8
+
9
+ 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`, `download`, and `downloadBlob`, and `fetchWithValidatedRedirects` cancels each redirect hop's body before following or rejecting the next hop.
10
+
3
11
  ## 4.0.29
4
12
 
5
13
  ### Patch Changes
package/dist/index.d.mts CHANGED
@@ -1332,6 +1332,20 @@ declare function createProviderToolFactoryWithOutputSchema<INPUT, OUTPUT, ARGS e
1332
1332
  supportsDeferredResults?: boolean;
1333
1333
  }): ProviderToolFactoryWithOutputSchema<INPUT, OUTPUT, ARGS>;
1334
1334
 
1335
+ /**
1336
+ * Cancels a response body to release the underlying connection.
1337
+ *
1338
+ * When a fetch Response is rejected without consuming its body (e.g. a failed
1339
+ * status code, an open-redirect rejection, or a Content-Length that exceeds the
1340
+ * size limit), the underlying TCP socket is not returned to the connection pool
1341
+ * and may stay open until the process runs out of file descriptors. Cancelling
1342
+ * the body avoids this leak.
1343
+ *
1344
+ * Errors thrown while cancelling are ignored: the body may already be locked,
1345
+ * disturbed, or absent, none of which should mask the original rejection.
1346
+ */
1347
+ declare function cancelResponseBody(response: Response): Promise<void>;
1348
+
1335
1349
  /**
1336
1350
  * Removes entries from a record where the value is null or undefined.
1337
1351
  * @param record - The input object whose entries may be null or undefined.
@@ -1504,4 +1518,4 @@ interface ToolResult<NAME extends string, INPUT, OUTPUT> {
1504
1518
  */
1505
1519
  type ToolCallOptions = ToolExecutionOptions;
1506
1520
 
1507
- export { type AssistantContent, type AssistantModelMessage, DEFAULT_MAX_DOWNLOAD_SIZE, type DataContent, DelayedPromise, DownloadError, type FetchFunction, type FilePart, type FlexibleSchema, type IdGenerator, type ImagePart, type InferSchema, type InferToolInput, type InferToolOutput, type LazySchema, type MaybePromiseLike, type ModelMessage, type ParseResult, type ProviderOptions, type ProviderToolFactory, type ProviderToolFactoryWithOutputSchema, type ReasoningPart, type Resolvable, type ResponseHandler, type Schema, type SystemModelMessage, type TextPart, type Tool, type ToolApprovalRequest, type ToolApprovalResponse, type ToolCall, type ToolCallOptions, type ToolCallPart, type ToolContent, type ToolExecuteFunction, type ToolExecutionOptions, type ToolModelMessage, type ToolNameMapping, type ToolNeedsApprovalFunction, type ToolResult, type ToolResultOutput, type ToolResultPart, type UserContent, type UserModelMessage, VERSION, type ValidationResult, asSchema, combineHeaders, convertAsyncIteratorToReadableStream, convertBase64ToUint8Array, convertImageModelFileToDataUri, convertToBase64, convertToFormData, convertUint8ArrayToBase64, createBinaryResponseHandler, createEventSourceResponseHandler, createIdGenerator, createJsonErrorResponseHandler, createJsonResponseHandler, createProviderToolFactory, createProviderToolFactoryWithOutputSchema, createStatusCodeErrorResponseHandler, createToolNameMapping, delay, downloadBlob, dynamicTool, executeTool, extractResponseHeaders, fetchWithValidatedRedirects, generateId, getErrorMessage, getFromApi, getRuntimeEnvironmentUserAgent, injectJsonInstructionIntoMessages, isAbortError, isBrowserRuntime, isNonNullable, isParsableJson, isSameOrigin, isUrlSupported, jsonSchema, lazySchema, loadApiKey, loadOptionalSetting, loadSetting, mediaTypeToExtension, normalizeHeaders, parseJSON, parseJsonEventStream, parseProviderOptions, postFormDataToApi, postJsonToApi, postToApi, readResponseWithSizeLimit, removeUndefinedEntries, resolve, safeParseJSON, safeValidateTypes, stripFileExtension, tool, validateDownloadUrl, validateTypes, withUserAgentSuffix, withoutTrailingSlash, zodSchema };
1521
+ export { type AssistantContent, type AssistantModelMessage, DEFAULT_MAX_DOWNLOAD_SIZE, type DataContent, DelayedPromise, DownloadError, type FetchFunction, type FilePart, type FlexibleSchema, type IdGenerator, type ImagePart, type InferSchema, type InferToolInput, type InferToolOutput, type LazySchema, type MaybePromiseLike, type ModelMessage, type ParseResult, type ProviderOptions, type ProviderToolFactory, type ProviderToolFactoryWithOutputSchema, type ReasoningPart, type Resolvable, type ResponseHandler, type Schema, type SystemModelMessage, type TextPart, type Tool, type ToolApprovalRequest, type ToolApprovalResponse, type ToolCall, type ToolCallOptions, type ToolCallPart, type ToolContent, type ToolExecuteFunction, type ToolExecutionOptions, type ToolModelMessage, type ToolNameMapping, type ToolNeedsApprovalFunction, type ToolResult, type ToolResultOutput, type ToolResultPart, type UserContent, type UserModelMessage, VERSION, type ValidationResult, asSchema, cancelResponseBody, combineHeaders, convertAsyncIteratorToReadableStream, convertBase64ToUint8Array, convertImageModelFileToDataUri, convertToBase64, convertToFormData, convertUint8ArrayToBase64, createBinaryResponseHandler, createEventSourceResponseHandler, createIdGenerator, createJsonErrorResponseHandler, createJsonResponseHandler, createProviderToolFactory, createProviderToolFactoryWithOutputSchema, createStatusCodeErrorResponseHandler, createToolNameMapping, delay, downloadBlob, dynamicTool, executeTool, extractResponseHeaders, fetchWithValidatedRedirects, generateId, getErrorMessage, getFromApi, getRuntimeEnvironmentUserAgent, injectJsonInstructionIntoMessages, isAbortError, isBrowserRuntime, isNonNullable, isParsableJson, isSameOrigin, isUrlSupported, jsonSchema, lazySchema, loadApiKey, loadOptionalSetting, loadSetting, mediaTypeToExtension, normalizeHeaders, parseJSON, parseJsonEventStream, parseProviderOptions, postFormDataToApi, postJsonToApi, postToApi, readResponseWithSizeLimit, removeUndefinedEntries, resolve, safeParseJSON, safeValidateTypes, stripFileExtension, tool, validateDownloadUrl, validateTypes, withUserAgentSuffix, withoutTrailingSlash, zodSchema };
package/dist/index.d.ts CHANGED
@@ -1332,6 +1332,20 @@ declare function createProviderToolFactoryWithOutputSchema<INPUT, OUTPUT, ARGS e
1332
1332
  supportsDeferredResults?: boolean;
1333
1333
  }): ProviderToolFactoryWithOutputSchema<INPUT, OUTPUT, ARGS>;
1334
1334
 
1335
+ /**
1336
+ * Cancels a response body to release the underlying connection.
1337
+ *
1338
+ * When a fetch Response is rejected without consuming its body (e.g. a failed
1339
+ * status code, an open-redirect rejection, or a Content-Length that exceeds the
1340
+ * size limit), the underlying TCP socket is not returned to the connection pool
1341
+ * and may stay open until the process runs out of file descriptors. Cancelling
1342
+ * the body avoids this leak.
1343
+ *
1344
+ * Errors thrown while cancelling are ignored: the body may already be locked,
1345
+ * disturbed, or absent, none of which should mask the original rejection.
1346
+ */
1347
+ declare function cancelResponseBody(response: Response): Promise<void>;
1348
+
1335
1349
  /**
1336
1350
  * Removes entries from a record where the value is null or undefined.
1337
1351
  * @param record - The input object whose entries may be null or undefined.
@@ -1504,4 +1518,4 @@ interface ToolResult<NAME extends string, INPUT, OUTPUT> {
1504
1518
  */
1505
1519
  type ToolCallOptions = ToolExecutionOptions;
1506
1520
 
1507
- export { type AssistantContent, type AssistantModelMessage, DEFAULT_MAX_DOWNLOAD_SIZE, type DataContent, DelayedPromise, DownloadError, type FetchFunction, type FilePart, type FlexibleSchema, type IdGenerator, type ImagePart, type InferSchema, type InferToolInput, type InferToolOutput, type LazySchema, type MaybePromiseLike, type ModelMessage, type ParseResult, type ProviderOptions, type ProviderToolFactory, type ProviderToolFactoryWithOutputSchema, type ReasoningPart, type Resolvable, type ResponseHandler, type Schema, type SystemModelMessage, type TextPart, type Tool, type ToolApprovalRequest, type ToolApprovalResponse, type ToolCall, type ToolCallOptions, type ToolCallPart, type ToolContent, type ToolExecuteFunction, type ToolExecutionOptions, type ToolModelMessage, type ToolNameMapping, type ToolNeedsApprovalFunction, type ToolResult, type ToolResultOutput, type ToolResultPart, type UserContent, type UserModelMessage, VERSION, type ValidationResult, asSchema, combineHeaders, convertAsyncIteratorToReadableStream, convertBase64ToUint8Array, convertImageModelFileToDataUri, convertToBase64, convertToFormData, convertUint8ArrayToBase64, createBinaryResponseHandler, createEventSourceResponseHandler, createIdGenerator, createJsonErrorResponseHandler, createJsonResponseHandler, createProviderToolFactory, createProviderToolFactoryWithOutputSchema, createStatusCodeErrorResponseHandler, createToolNameMapping, delay, downloadBlob, dynamicTool, executeTool, extractResponseHeaders, fetchWithValidatedRedirects, generateId, getErrorMessage, getFromApi, getRuntimeEnvironmentUserAgent, injectJsonInstructionIntoMessages, isAbortError, isBrowserRuntime, isNonNullable, isParsableJson, isSameOrigin, isUrlSupported, jsonSchema, lazySchema, loadApiKey, loadOptionalSetting, loadSetting, mediaTypeToExtension, normalizeHeaders, parseJSON, parseJsonEventStream, parseProviderOptions, postFormDataToApi, postJsonToApi, postToApi, readResponseWithSizeLimit, removeUndefinedEntries, resolve, safeParseJSON, safeValidateTypes, stripFileExtension, tool, validateDownloadUrl, validateTypes, withUserAgentSuffix, withoutTrailingSlash, zodSchema };
1521
+ export { type AssistantContent, type AssistantModelMessage, DEFAULT_MAX_DOWNLOAD_SIZE, type DataContent, DelayedPromise, DownloadError, type FetchFunction, type FilePart, type FlexibleSchema, type IdGenerator, type ImagePart, type InferSchema, type InferToolInput, type InferToolOutput, type LazySchema, type MaybePromiseLike, type ModelMessage, type ParseResult, type ProviderOptions, type ProviderToolFactory, type ProviderToolFactoryWithOutputSchema, type ReasoningPart, type Resolvable, type ResponseHandler, type Schema, type SystemModelMessage, type TextPart, type Tool, type ToolApprovalRequest, type ToolApprovalResponse, type ToolCall, type ToolCallOptions, type ToolCallPart, type ToolContent, type ToolExecuteFunction, type ToolExecutionOptions, type ToolModelMessage, type ToolNameMapping, type ToolNeedsApprovalFunction, type ToolResult, type ToolResultOutput, type ToolResultPart, type UserContent, type UserModelMessage, VERSION, type ValidationResult, asSchema, cancelResponseBody, combineHeaders, convertAsyncIteratorToReadableStream, convertBase64ToUint8Array, convertImageModelFileToDataUri, convertToBase64, convertToFormData, convertUint8ArrayToBase64, createBinaryResponseHandler, createEventSourceResponseHandler, createIdGenerator, createJsonErrorResponseHandler, createJsonResponseHandler, createProviderToolFactory, createProviderToolFactoryWithOutputSchema, createStatusCodeErrorResponseHandler, createToolNameMapping, delay, downloadBlob, dynamicTool, executeTool, extractResponseHeaders, fetchWithValidatedRedirects, generateId, getErrorMessage, getFromApi, getRuntimeEnvironmentUserAgent, injectJsonInstructionIntoMessages, isAbortError, isBrowserRuntime, isNonNullable, isParsableJson, isSameOrigin, isUrlSupported, jsonSchema, lazySchema, loadApiKey, loadOptionalSetting, loadSetting, mediaTypeToExtension, normalizeHeaders, parseJSON, parseJsonEventStream, parseProviderOptions, postFormDataToApi, postJsonToApi, postToApi, readResponseWithSizeLimit, removeUndefinedEntries, resolve, safeParseJSON, safeValidateTypes, stripFileExtension, tool, validateDownloadUrl, validateTypes, withUserAgentSuffix, withoutTrailingSlash, zodSchema };
package/dist/index.js CHANGED
@@ -36,6 +36,7 @@ __export(index_exports, {
36
36
  EventSourceParserStream: () => import_stream2.EventSourceParserStream,
37
37
  VERSION: () => VERSION,
38
38
  asSchema: () => asSchema,
39
+ cancelResponseBody: () => cancelResponseBody,
39
40
  combineHeaders: () => combineHeaders,
40
41
  convertAsyncIteratorToReadableStream: () => convertAsyncIteratorToReadableStream,
41
42
  convertBase64ToUint8Array: () => convertBase64ToUint8Array,
@@ -307,6 +308,15 @@ function convertToFormData(input, options = {}) {
307
308
  return formData;
308
309
  }
309
310
 
311
+ // src/cancel-response-body.ts
312
+ async function cancelResponseBody(response) {
313
+ var _a2;
314
+ try {
315
+ await ((_a2 = response.body) == null ? void 0 : _a2.cancel());
316
+ } catch (e) {
317
+ }
318
+ }
319
+
310
320
  // src/download-error.ts
311
321
  var import_provider = require("@ai-sdk/provider");
312
322
  var name = "AI_DownloadError";
@@ -506,6 +516,7 @@ async function fetchWithValidatedRedirects({
506
516
  }
507
517
  const location = response.headers.get("location");
508
518
  if (response.status >= 300 && response.status < 400 && location) {
519
+ await cancelResponseBody(response);
509
520
  currentUrl = new URL(location, currentUrl).toString();
510
521
  continue;
511
522
  }
@@ -528,6 +539,7 @@ async function readResponseWithSizeLimit({
528
539
  if (contentLength != null) {
529
540
  const length = parseInt(contentLength, 10);
530
541
  if (!isNaN(length) && length > maxBytes) {
542
+ await cancelResponseBody(response);
531
543
  throw new DownloadError({
532
544
  url,
533
545
  message: `Download of ${url} exceeded maximum size of ${maxBytes} bytes (Content-Length: ${length}).`
@@ -581,6 +593,7 @@ async function downloadBlob(url, options) {
581
593
  abortSignal: options == null ? void 0 : options.abortSignal
582
594
  });
583
595
  if (!response.ok) {
596
+ await cancelResponseBody(response);
584
597
  throw new DownloadError({
585
598
  url,
586
599
  statusCode: response.status,
@@ -764,7 +777,7 @@ function withUserAgentSuffix(headers, ...userAgentSuffixParts) {
764
777
  }
765
778
 
766
779
  // src/version.ts
767
- var VERSION = true ? "4.0.29" : "0.0.0-test";
780
+ var VERSION = true ? "4.0.30" : "0.0.0-test";
768
781
 
769
782
  // src/get-from-api.ts
770
783
  var getOriginalFetch = () => globalThis.fetch;
@@ -2886,6 +2899,7 @@ var import_stream2 = require("eventsource-parser/stream");
2886
2899
  EventSourceParserStream,
2887
2900
  VERSION,
2888
2901
  asSchema,
2902
+ cancelResponseBody,
2889
2903
  combineHeaders,
2890
2904
  convertAsyncIteratorToReadableStream,
2891
2905
  convertBase64ToUint8Array,