@ai-sdk/provider-utils 4.0.13 → 4.0.15

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,22 @@
1
1
  # @ai-sdk/provider-utils
2
2
 
3
+ ## 4.0.15
4
+
5
+ ### Patch Changes
6
+
7
+ - 4024a3a: security: prevent unbounded memory growth in download functions
8
+
9
+ The `download()` and `downloadBlob()` functions now enforce a default 2 GiB size limit when downloading from user-provided URLs. Downloads that exceed this limit are aborted with a `DownloadError` instead of consuming unbounded memory and crashing the process. The `abortSignal` parameter is now passed through to `fetch()` in all download call sites.
10
+
11
+ Added `download` option to `transcribe()` and `experimental_generateVideo()` for providing a custom download function. Use the new `createDownload({ maxBytes })` factory to configure download size limits.
12
+
13
+ ## 4.0.14
14
+
15
+ ### Patch Changes
16
+
17
+ - Updated dependencies [7168375]
18
+ - @ai-sdk/provider@3.0.8
19
+
3
20
  ## 4.0.13
4
21
 
5
22
  ### Patch Changes
package/dist/index.d.mts CHANGED
@@ -139,11 +139,17 @@ declare function convertToFormData<T extends Record<string, unknown>>(input: T,
139
139
  * Download a file from a URL and return it as a Blob.
140
140
  *
141
141
  * @param url - The URL to download from.
142
+ * @param options - Optional settings for the download.
143
+ * @param options.maxBytes - Maximum allowed download size in bytes. Defaults to 100 MiB.
144
+ * @param options.abortSignal - An optional abort signal to cancel the download.
142
145
  * @returns A Promise that resolves to the downloaded Blob.
143
146
  *
144
- * @throws DownloadError if the download fails.
147
+ * @throws DownloadError if the download fails or exceeds maxBytes.
145
148
  */
146
- declare function downloadBlob(url: string): Promise<Blob>;
149
+ declare function downloadBlob(url: string, options?: {
150
+ maxBytes?: number;
151
+ abortSignal?: AbortSignal;
152
+ }): Promise<Blob>;
147
153
 
148
154
  declare const symbol: unique symbol;
149
155
  declare class DownloadError extends AISDKError {
@@ -161,6 +167,37 @@ declare class DownloadError extends AISDKError {
161
167
  static isInstance(error: unknown): error is DownloadError;
162
168
  }
163
169
 
170
+ /**
171
+ * Default maximum download size: 2 GiB.
172
+ *
173
+ * `fetch().arrayBuffer()` has ~2x peak memory overhead (undici buffers the
174
+ * body internally, then creates the JS ArrayBuffer), so very large downloads
175
+ * risk exceeding the default V8 heap limit on 64-bit systems and terminating
176
+ * the process with an out-of-memory error.
177
+ *
178
+ * Setting this limit converts an unrecoverable OOM crash into a catchable
179
+ * `DownloadError`.
180
+ */
181
+ declare const DEFAULT_MAX_DOWNLOAD_SIZE: number;
182
+ /**
183
+ * Reads a fetch Response body with a size limit to prevent memory exhaustion.
184
+ *
185
+ * Checks the Content-Length header for early rejection, then reads the body
186
+ * incrementally via ReadableStream and aborts with a DownloadError when the
187
+ * limit is exceeded.
188
+ *
189
+ * @param response - The fetch Response to read.
190
+ * @param url - The URL being downloaded (used in error messages).
191
+ * @param maxBytes - Maximum allowed bytes. Defaults to DEFAULT_MAX_DOWNLOAD_SIZE.
192
+ * @returns A Uint8Array containing the response body.
193
+ * @throws DownloadError if the response exceeds maxBytes.
194
+ */
195
+ declare function readResponseWithSizeLimit({ response, url, maxBytes, }: {
196
+ response: Response;
197
+ url: string;
198
+ maxBytes?: number;
199
+ }): Promise<Uint8Array>;
200
+
164
201
  /**
165
202
  * Fetch function type (standardizes the version of fetch used).
166
203
  */
@@ -1369,4 +1406,4 @@ interface ToolResult<NAME extends string, INPUT, OUTPUT> {
1369
1406
  */
1370
1407
  type ToolCallOptions = ToolExecutionOptions;
1371
1408
 
1372
- export { type AssistantContent, type AssistantModelMessage, 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, generateId, getErrorMessage, getFromApi, getRuntimeEnvironmentUserAgent, injectJsonInstructionIntoMessages, isAbortError, isNonNullable, isParsableJson, isUrlSupported, jsonSchema, lazySchema, loadApiKey, loadOptionalSetting, loadSetting, mediaTypeToExtension, normalizeHeaders, parseJSON, parseJsonEventStream, parseProviderOptions, postFormDataToApi, postJsonToApi, postToApi, removeUndefinedEntries, resolve, safeParseJSON, safeValidateTypes, tool, validateTypes, withUserAgentSuffix, withoutTrailingSlash, zodSchema };
1409
+ 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, generateId, getErrorMessage, getFromApi, getRuntimeEnvironmentUserAgent, injectJsonInstructionIntoMessages, isAbortError, isNonNullable, isParsableJson, isUrlSupported, jsonSchema, lazySchema, loadApiKey, loadOptionalSetting, loadSetting, mediaTypeToExtension, normalizeHeaders, parseJSON, parseJsonEventStream, parseProviderOptions, postFormDataToApi, postJsonToApi, postToApi, readResponseWithSizeLimit, removeUndefinedEntries, resolve, safeParseJSON, safeValidateTypes, tool, validateTypes, withUserAgentSuffix, withoutTrailingSlash, zodSchema };
package/dist/index.d.ts CHANGED
@@ -139,11 +139,17 @@ declare function convertToFormData<T extends Record<string, unknown>>(input: T,
139
139
  * Download a file from a URL and return it as a Blob.
140
140
  *
141
141
  * @param url - The URL to download from.
142
+ * @param options - Optional settings for the download.
143
+ * @param options.maxBytes - Maximum allowed download size in bytes. Defaults to 100 MiB.
144
+ * @param options.abortSignal - An optional abort signal to cancel the download.
142
145
  * @returns A Promise that resolves to the downloaded Blob.
143
146
  *
144
- * @throws DownloadError if the download fails.
147
+ * @throws DownloadError if the download fails or exceeds maxBytes.
145
148
  */
146
- declare function downloadBlob(url: string): Promise<Blob>;
149
+ declare function downloadBlob(url: string, options?: {
150
+ maxBytes?: number;
151
+ abortSignal?: AbortSignal;
152
+ }): Promise<Blob>;
147
153
 
148
154
  declare const symbol: unique symbol;
149
155
  declare class DownloadError extends AISDKError {
@@ -161,6 +167,37 @@ declare class DownloadError extends AISDKError {
161
167
  static isInstance(error: unknown): error is DownloadError;
162
168
  }
163
169
 
170
+ /**
171
+ * Default maximum download size: 2 GiB.
172
+ *
173
+ * `fetch().arrayBuffer()` has ~2x peak memory overhead (undici buffers the
174
+ * body internally, then creates the JS ArrayBuffer), so very large downloads
175
+ * risk exceeding the default V8 heap limit on 64-bit systems and terminating
176
+ * the process with an out-of-memory error.
177
+ *
178
+ * Setting this limit converts an unrecoverable OOM crash into a catchable
179
+ * `DownloadError`.
180
+ */
181
+ declare const DEFAULT_MAX_DOWNLOAD_SIZE: number;
182
+ /**
183
+ * Reads a fetch Response body with a size limit to prevent memory exhaustion.
184
+ *
185
+ * Checks the Content-Length header for early rejection, then reads the body
186
+ * incrementally via ReadableStream and aborts with a DownloadError when the
187
+ * limit is exceeded.
188
+ *
189
+ * @param response - The fetch Response to read.
190
+ * @param url - The URL being downloaded (used in error messages).
191
+ * @param maxBytes - Maximum allowed bytes. Defaults to DEFAULT_MAX_DOWNLOAD_SIZE.
192
+ * @returns A Uint8Array containing the response body.
193
+ * @throws DownloadError if the response exceeds maxBytes.
194
+ */
195
+ declare function readResponseWithSizeLimit({ response, url, maxBytes, }: {
196
+ response: Response;
197
+ url: string;
198
+ maxBytes?: number;
199
+ }): Promise<Uint8Array>;
200
+
164
201
  /**
165
202
  * Fetch function type (standardizes the version of fetch used).
166
203
  */
@@ -1369,4 +1406,4 @@ interface ToolResult<NAME extends string, INPUT, OUTPUT> {
1369
1406
  */
1370
1407
  type ToolCallOptions = ToolExecutionOptions;
1371
1408
 
1372
- export { type AssistantContent, type AssistantModelMessage, 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, generateId, getErrorMessage, getFromApi, getRuntimeEnvironmentUserAgent, injectJsonInstructionIntoMessages, isAbortError, isNonNullable, isParsableJson, isUrlSupported, jsonSchema, lazySchema, loadApiKey, loadOptionalSetting, loadSetting, mediaTypeToExtension, normalizeHeaders, parseJSON, parseJsonEventStream, parseProviderOptions, postFormDataToApi, postJsonToApi, postToApi, removeUndefinedEntries, resolve, safeParseJSON, safeValidateTypes, tool, validateTypes, withUserAgentSuffix, withoutTrailingSlash, zodSchema };
1409
+ 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, generateId, getErrorMessage, getFromApi, getRuntimeEnvironmentUserAgent, injectJsonInstructionIntoMessages, isAbortError, isNonNullable, isParsableJson, isUrlSupported, jsonSchema, lazySchema, loadApiKey, loadOptionalSetting, loadSetting, mediaTypeToExtension, normalizeHeaders, parseJSON, parseJsonEventStream, parseProviderOptions, postFormDataToApi, postJsonToApi, postToApi, readResponseWithSizeLimit, removeUndefinedEntries, resolve, safeParseJSON, safeValidateTypes, tool, validateTypes, withUserAgentSuffix, withoutTrailingSlash, zodSchema };
package/dist/index.js CHANGED
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var src_exports = {};
32
32
  __export(src_exports, {
33
+ DEFAULT_MAX_DOWNLOAD_SIZE: () => DEFAULT_MAX_DOWNLOAD_SIZE,
33
34
  DelayedPromise: () => DelayedPromise,
34
35
  DownloadError: () => DownloadError,
35
36
  EventSourceParserStream: () => import_stream2.EventSourceParserStream,
@@ -78,6 +79,7 @@ __export(src_exports, {
78
79
  postFormDataToApi: () => postFormDataToApi,
79
80
  postJsonToApi: () => postJsonToApi,
80
81
  postToApi: () => postToApi,
82
+ readResponseWithSizeLimit: () => readResponseWithSizeLimit,
81
83
  removeUndefinedEntries: () => removeUndefinedEntries,
82
84
  resolve: () => resolve,
83
85
  safeParseJSON: () => safeParseJSON,
@@ -320,10 +322,68 @@ var DownloadError = class extends (_b = import_provider.AISDKError, _a = symbol,
320
322
  }
321
323
  };
322
324
 
325
+ // src/read-response-with-size-limit.ts
326
+ var DEFAULT_MAX_DOWNLOAD_SIZE = 2 * 1024 * 1024 * 1024;
327
+ async function readResponseWithSizeLimit({
328
+ response,
329
+ url,
330
+ maxBytes = DEFAULT_MAX_DOWNLOAD_SIZE
331
+ }) {
332
+ const contentLength = response.headers.get("content-length");
333
+ if (contentLength != null) {
334
+ const length = parseInt(contentLength, 10);
335
+ if (!isNaN(length) && length > maxBytes) {
336
+ throw new DownloadError({
337
+ url,
338
+ message: `Download of ${url} exceeded maximum size of ${maxBytes} bytes (Content-Length: ${length}).`
339
+ });
340
+ }
341
+ }
342
+ const body = response.body;
343
+ if (body == null) {
344
+ return new Uint8Array(0);
345
+ }
346
+ const reader = body.getReader();
347
+ const chunks = [];
348
+ let totalBytes = 0;
349
+ try {
350
+ while (true) {
351
+ const { done, value } = await reader.read();
352
+ if (done) {
353
+ break;
354
+ }
355
+ totalBytes += value.length;
356
+ if (totalBytes > maxBytes) {
357
+ throw new DownloadError({
358
+ url,
359
+ message: `Download of ${url} exceeded maximum size of ${maxBytes} bytes.`
360
+ });
361
+ }
362
+ chunks.push(value);
363
+ }
364
+ } finally {
365
+ try {
366
+ await reader.cancel();
367
+ } finally {
368
+ reader.releaseLock();
369
+ }
370
+ }
371
+ const result = new Uint8Array(totalBytes);
372
+ let offset = 0;
373
+ for (const chunk of chunks) {
374
+ result.set(chunk, offset);
375
+ offset += chunk.length;
376
+ }
377
+ return result;
378
+ }
379
+
323
380
  // src/download-blob.ts
324
- async function downloadBlob(url) {
381
+ async function downloadBlob(url, options) {
382
+ var _a2, _b2;
325
383
  try {
326
- const response = await fetch(url);
384
+ const response = await fetch(url, {
385
+ signal: options == null ? void 0 : options.abortSignal
386
+ });
327
387
  if (!response.ok) {
328
388
  throw new DownloadError({
329
389
  url,
@@ -331,7 +391,13 @@ async function downloadBlob(url) {
331
391
  statusText: response.statusText
332
392
  });
333
393
  }
334
- return await response.blob();
394
+ const data = await readResponseWithSizeLimit({
395
+ response,
396
+ url,
397
+ maxBytes: (_a2 = options == null ? void 0 : options.maxBytes) != null ? _a2 : DEFAULT_MAX_DOWNLOAD_SIZE
398
+ });
399
+ const contentType = (_b2 = response.headers.get("content-type")) != null ? _b2 : void 0;
400
+ return new Blob([data], contentType ? { type: contentType } : void 0);
335
401
  } catch (error) {
336
402
  if (DownloadError.isInstance(error)) {
337
403
  throw error;
@@ -502,7 +568,7 @@ function withUserAgentSuffix(headers, ...userAgentSuffixParts) {
502
568
  }
503
569
 
504
570
  // src/version.ts
505
- var VERSION = true ? "4.0.13" : "0.0.0-test";
571
+ var VERSION = true ? "4.0.15" : "0.0.0-test";
506
572
 
507
573
  // src/get-from-api.ts
508
574
  var getOriginalFetch = () => globalThis.fetch;
@@ -2603,6 +2669,7 @@ async function* executeTool({
2603
2669
  var import_stream2 = require("eventsource-parser/stream");
2604
2670
  // Annotate the CommonJS export names for ESM import in node:
2605
2671
  0 && (module.exports = {
2672
+ DEFAULT_MAX_DOWNLOAD_SIZE,
2606
2673
  DelayedPromise,
2607
2674
  DownloadError,
2608
2675
  EventSourceParserStream,
@@ -2651,6 +2718,7 @@ var import_stream2 = require("eventsource-parser/stream");
2651
2718
  postFormDataToApi,
2652
2719
  postJsonToApi,
2653
2720
  postToApi,
2721
+ readResponseWithSizeLimit,
2654
2722
  removeUndefinedEntries,
2655
2723
  resolve,
2656
2724
  safeParseJSON,