+26
-14
@@ -122,13 +122,25 @@ "use strict"; | ||
| ]; | ||
| var stripID3 = (data) => { | ||
| const bytes = typeof data === "string" ? (0, import_provider_utils.convertBase64ToUint8Array)(data) : data; | ||
| var DEFAULT_SNIFF_BYTES = 18; | ||
| var MAX_SIGNATURE_BYTES = 12; | ||
| var MAX_ID3_TAG_BYTES = 128 * 1024; | ||
| var ID3_SCAN_BYTES = MAX_ID3_TAG_BYTES + MAX_SIGNATURE_BYTES; | ||
| function decodePrefix(data, maxBytes) { | ||
| if (typeof data !== "string") { | ||
| return data.length > maxBytes ? data.subarray(0, maxBytes) : data; | ||
| } | ||
| const maxChars = Math.ceil(maxBytes / 3) * 4; | ||
| const bytes = (0, import_provider_utils.convertBase64ToUint8Array)( | ||
| data.substring(0, Math.min(data.length, maxChars)) | ||
| ); | ||
| return bytes.length > maxBytes ? bytes.subarray(0, maxBytes) : bytes; | ||
| } | ||
| function hasID3(bytes) { | ||
| return bytes.length > 10 && bytes[0] === 73 && // 'I' | ||
| bytes[1] === 68 && // 'D' | ||
| bytes[2] === 51; | ||
| } | ||
| var stripID3 = (bytes) => { | ||
| const id3Size = (bytes[6] & 127) << 21 | (bytes[7] & 127) << 14 | (bytes[8] & 127) << 7 | bytes[9] & 127; | ||
| return bytes.slice(id3Size + 10); | ||
| return bytes.subarray(id3Size + 10); | ||
| }; | ||
| function stripID3TagsIfPresent(data) { | ||
| const hasId3 = typeof data === "string" && data.startsWith("SUQz") || typeof data !== "string" && data.length > 10 && data[0] === 73 && // 'I' | ||
| data[1] === 68 && // 'D' | ||
| data[2] === 51; | ||
| return hasId3 ? stripID3(data) : data; | ||
| } | ||
| function detectMediaType({ | ||
@@ -138,6 +150,6 @@ data, | ||
| }) { | ||
| const processedData = stripID3TagsIfPresent(data); | ||
| const bytes = typeof processedData === "string" ? (0, import_provider_utils.convertBase64ToUint8Array)( | ||
| processedData.substring(0, Math.min(processedData.length, 24)) | ||
| ) : processedData; | ||
| let bytes = decodePrefix(data, DEFAULT_SNIFF_BYTES); | ||
| if (hasID3(bytes)) { | ||
| bytes = stripID3(decodePrefix(data, ID3_SCAN_BYTES)); | ||
| } | ||
| for (const signature of signatures) { | ||
@@ -157,3 +169,3 @@ if (bytes.length >= signature.bytesPrefix.length && signature.bytesPrefix.every( | ||
| // src/version.ts | ||
| var VERSION = true ? "6.0.233" : "0.0.0-test"; | ||
| var VERSION = true ? "6.0.234" : "0.0.0-test"; | ||
@@ -160,0 +172,0 @@ // src/util/download/download.ts |
+26
-14
@@ -94,13 +94,25 @@ // internal/index.ts | ||
| ]; | ||
| var stripID3 = (data) => { | ||
| const bytes = typeof data === "string" ? convertBase64ToUint8Array(data) : data; | ||
| var DEFAULT_SNIFF_BYTES = 18; | ||
| var MAX_SIGNATURE_BYTES = 12; | ||
| var MAX_ID3_TAG_BYTES = 128 * 1024; | ||
| var ID3_SCAN_BYTES = MAX_ID3_TAG_BYTES + MAX_SIGNATURE_BYTES; | ||
| function decodePrefix(data, maxBytes) { | ||
| if (typeof data !== "string") { | ||
| return data.length > maxBytes ? data.subarray(0, maxBytes) : data; | ||
| } | ||
| const maxChars = Math.ceil(maxBytes / 3) * 4; | ||
| const bytes = convertBase64ToUint8Array( | ||
| data.substring(0, Math.min(data.length, maxChars)) | ||
| ); | ||
| return bytes.length > maxBytes ? bytes.subarray(0, maxBytes) : bytes; | ||
| } | ||
| function hasID3(bytes) { | ||
| return bytes.length > 10 && bytes[0] === 73 && // 'I' | ||
| bytes[1] === 68 && // 'D' | ||
| bytes[2] === 51; | ||
| } | ||
| var stripID3 = (bytes) => { | ||
| const id3Size = (bytes[6] & 127) << 21 | (bytes[7] & 127) << 14 | (bytes[8] & 127) << 7 | bytes[9] & 127; | ||
| return bytes.slice(id3Size + 10); | ||
| return bytes.subarray(id3Size + 10); | ||
| }; | ||
| function stripID3TagsIfPresent(data) { | ||
| const hasId3 = typeof data === "string" && data.startsWith("SUQz") || typeof data !== "string" && data.length > 10 && data[0] === 73 && // 'I' | ||
| data[1] === 68 && // 'D' | ||
| data[2] === 51; | ||
| return hasId3 ? stripID3(data) : data; | ||
| } | ||
| function detectMediaType({ | ||
@@ -110,6 +122,6 @@ data, | ||
| }) { | ||
| const processedData = stripID3TagsIfPresent(data); | ||
| const bytes = typeof processedData === "string" ? convertBase64ToUint8Array( | ||
| processedData.substring(0, Math.min(processedData.length, 24)) | ||
| ) : processedData; | ||
| let bytes = decodePrefix(data, DEFAULT_SNIFF_BYTES); | ||
| if (hasID3(bytes)) { | ||
| bytes = stripID3(decodePrefix(data, ID3_SCAN_BYTES)); | ||
| } | ||
| for (const signature of signatures) { | ||
@@ -137,3 +149,3 @@ if (bytes.length >= signature.bytesPrefix.length && signature.bytesPrefix.every( | ||
| // src/version.ts | ||
| var VERSION = true ? "6.0.233" : "0.0.0-test"; | ||
| var VERSION = true ? "6.0.234" : "0.0.0-test"; | ||
@@ -140,0 +152,0 @@ // src/util/download/download.ts |
+4
-4
| { | ||
| "name": "ai", | ||
| "version": "6.0.233", | ||
| "version": "6.0.234", | ||
| "description": "AI SDK by Vercel - build apps like ChatGPT, Claude, Gemini, and more with a single interface for any model using the Vercel AI Gateway or go direct to OpenAI, Anthropic, Google, or any other model provider.", | ||
@@ -48,3 +48,3 @@ "license": "Apache-2.0", | ||
| "@opentelemetry/api": "^1.9.0", | ||
| "@ai-sdk/gateway": "3.0.155", | ||
| "@ai-sdk/gateway": "3.0.156", | ||
| "@ai-sdk/provider": "3.0.14", | ||
@@ -62,4 +62,4 @@ "@ai-sdk/provider-utils": "4.0.40" | ||
| "zod": "3.25.76", | ||
| "@ai-sdk/test-server": "1.0.6", | ||
| "@vercel/ai-tsconfig": "0.0.0" | ||
| "@vercel/ai-tsconfig": "0.0.0", | ||
| "@ai-sdk/test-server": "1.0.6" | ||
| }, | ||
@@ -66,0 +66,0 @@ "peerDependencies": { |
@@ -59,3 +59,3 @@ import type { ServerResponse } from 'node:http'; | ||
| >): Promise<void> { | ||
| pipeUIMessageStreamToResponse({ | ||
| return pipeUIMessageStreamToResponse({ | ||
| response, | ||
@@ -62,0 +62,0 @@ headers, |
@@ -88,3 +88,6 @@ import type { ServerResponse } from 'http'; | ||
| */ | ||
| pipeTextStreamToResponse(response: ServerResponse, init?: ResponseInit): void; | ||
| pipeTextStreamToResponse( | ||
| response: ServerResponse, | ||
| init?: ResponseInit, | ||
| ): Promise<void>; | ||
@@ -91,0 +94,0 @@ /** |
@@ -957,3 +957,3 @@ import type { | ||
| pipeTextStreamToResponse(response: ServerResponse, init?: ResponseInit) { | ||
| pipeTextStreamToResponse({ | ||
| return pipeTextStreamToResponse({ | ||
| response, | ||
@@ -960,0 +960,0 @@ textStream: this.textStream, |
@@ -345,3 +345,3 @@ import type { JSONObject } from '@ai-sdk/provider'; | ||
| options?: UIMessageStreamResponseInit & UIMessageStreamOptions<UI_MESSAGE>, | ||
| ): void; | ||
| ): Promise<void>; | ||
@@ -356,3 +356,6 @@ /** | ||
| */ | ||
| pipeTextStreamToResponse(response: ServerResponse, init?: ResponseInit): void; | ||
| pipeTextStreamToResponse( | ||
| response: ServerResponse, | ||
| init?: ResponseInit, | ||
| ): Promise<void>; | ||
@@ -359,0 +362,0 @@ /** |
@@ -16,2 +16,3 @@ import type { ServerResponse } from 'node:http'; | ||
| * @param options.textStream - The text stream to pipe. | ||
| * @returns A promise that resolves when the stream has been written. | ||
| */ | ||
@@ -27,4 +28,4 @@ export function pipeTextStreamToResponse({ | ||
| textStream: ReadableStream<string>; | ||
| } & ResponseInit): void { | ||
| writeToServerResponse({ | ||
| } & ResponseInit): Promise<void> { | ||
| return writeToServerResponse({ | ||
| response, | ||
@@ -31,0 +32,0 @@ status, |
@@ -19,2 +19,3 @@ import type { ServerResponse } from 'node:http'; | ||
| * @param options.consumeSseStream - Optional callback to consume a copy of the SSE stream independently. | ||
| * @returns A promise that resolves when the stream has been written. | ||
| */ | ||
@@ -31,3 +32,3 @@ export function pipeUIMessageStreamToResponse({ | ||
| stream: ReadableStream<UIMessageChunk>; | ||
| } & UIMessageStreamResponseInit): void { | ||
| } & UIMessageStreamResponseInit): Promise<void> { | ||
| let sseStream = stream.pipeThrough(new JsonToSseTransformStream()); | ||
@@ -44,3 +45,3 @@ | ||
| writeToServerResponse({ | ||
| return writeToServerResponse({ | ||
| response, | ||
@@ -47,0 +48,0 @@ status, |
@@ -171,5 +171,42 @@ import { convertBase64ToUint8Array } from '@ai-sdk/provider-utils'; | ||
| const stripID3 = (data: Uint8Array | string) => { | ||
| const bytes = | ||
| typeof data === 'string' ? convertBase64ToUint8Array(data) : data; | ||
| const DEFAULT_SNIFF_BYTES = 18; | ||
| // Longest signature prefix in the tables above (e.g. image/avif = 12 bytes). | ||
| const MAX_SIGNATURE_BYTES = 12; | ||
| // Largest ID3v2 tag (10-byte header + body) skipped to reach the audio frame. | ||
| // Covers typical tags including embedded cover art while keeping the decode | ||
| // bounded and O(1) in the attachment size. Exported for boundary tests. | ||
| export const MAX_ID3_TAG_BYTES = 128 * 1024; | ||
| // Total prefix decoded when an ID3 tag is present: the tag plus room for the | ||
| // trailing signature, so a tag right at the size limit stays detectable. | ||
| const ID3_SCAN_BYTES = MAX_ID3_TAG_BYTES + MAX_SIGNATURE_BYTES; | ||
| // Decode/view exactly the first `maxBytes` bytes from the front of the input. | ||
| // The base64 and raw-byte paths yield the same length, so detection does not | ||
| // depend on the input's representation. | ||
| function decodePrefix(data: Uint8Array | string, maxBytes: number): Uint8Array { | ||
| if (typeof data !== 'string') { | ||
| return data.length > maxBytes ? data.subarray(0, maxBytes) : data; | ||
| } | ||
| // base64: 4 chars -> 3 bytes. Decode whole 4-char groups, then trim the 0-2 | ||
| // extra bytes so the result matches the raw-byte path exactly. | ||
| const maxChars = Math.ceil(maxBytes / 3) * 4; | ||
| const bytes = convertBase64ToUint8Array( | ||
| data.substring(0, Math.min(data.length, maxChars)), | ||
| ); | ||
| return bytes.length > maxBytes ? bytes.subarray(0, maxBytes) : bytes; | ||
| } | ||
| function hasID3(bytes: Uint8Array): boolean { | ||
| return ( | ||
| bytes.length > 10 && | ||
| bytes[0] === 0x49 && // 'I' | ||
| bytes[1] === 0x44 && // 'D' | ||
| bytes[2] === 0x33 // '3' | ||
| ); | ||
| } | ||
| const stripID3 = (bytes: Uint8Array): Uint8Array => { | ||
| const id3Size = | ||
@@ -180,19 +217,5 @@ ((bytes[6] & 0x7f) << 21) | | ||
| (bytes[9] & 0x7f); | ||
| // The raw MP3 starts here | ||
| return bytes.slice(id3Size + 10); | ||
| return bytes.subarray(id3Size + 10); | ||
| }; | ||
| function stripID3TagsIfPresent(data: Uint8Array | string): Uint8Array | string { | ||
| const hasId3 = | ||
| (typeof data === 'string' && data.startsWith('SUQz')) || | ||
| (typeof data !== 'string' && | ||
| data.length > 10 && | ||
| data[0] === 0x49 && // 'I' | ||
| data[1] === 0x44 && // 'D' | ||
| data[2] === 0x33); // '3' | ||
| return hasId3 ? stripID3(data) : data; | ||
| } | ||
| /** | ||
@@ -215,11 +238,9 @@ * Detect the media IANA media type of a file using a list of signatures. | ||
| }): (typeof signatures)[number]['mediaType'] | undefined { | ||
| const processedData = stripID3TagsIfPresent(data); | ||
| let bytes = decodePrefix(data, DEFAULT_SNIFF_BYTES); | ||
| // Convert the first ~18 bytes (24 base64 chars) for consistent detection logic: | ||
| const bytes = | ||
| typeof processedData === 'string' | ||
| ? convertBase64ToUint8Array( | ||
| processedData.substring(0, Math.min(processedData.length, 24)), | ||
| ) | ||
| : processedData; | ||
| // ID3v2-tagged MP3s carry the audio frame after the tag; scan a bounded | ||
| // prefix past it rather than decoding the whole input. | ||
| if (hasID3(bytes)) { | ||
| bytes = stripID3(decodePrefix(data, ID3_SCAN_BYTES)); | ||
| } | ||
@@ -226,0 +247,0 @@ for (const signature of signatures) { |
@@ -18,3 +18,3 @@ import type { ServerResponse } from 'node:http'; | ||
| stream: ReadableStream<Uint8Array>; | ||
| }): void { | ||
| }): Promise<void> { | ||
| const statusCode = status ?? 200; | ||
@@ -49,3 +49,3 @@ if (statusText !== undefined) { | ||
| read(); | ||
| return read(); | ||
| } |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
6777573
0.14%64146
0.12%+ Added
- Removed
Updated