@ai-sdk/provider-utils 5.0.11 → 5.0.12

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,15 @@
1
1
  # @ai-sdk/provider-utils
2
2
 
3
+ ## 5.0.12
4
+
5
+ ### Patch Changes
6
+
7
+ - 02ffdcb: fix(provider-utils): bound media-type sniffing decode for ID3-prefixed input
8
+
9
+ Media-type detection stripped ID3 tags before the ~18-byte prefix cap, decoding the entire base64 attachment (plus a full-size copy) whenever the data began with `ID3`/`SUQz`. This turned the intended O(1) sniff into an O(N) decode of the whole attachment. Detection now decodes at most a bounded prefix and skips the ID3 tag within that bound, keeping cost O(1) in input size on all paths (image, audio, and combined).
10
+
11
+ - 76cb673: fix: detect MP4 audio from its ftyp box during transcription
12
+
3
13
  ## 5.0.11
4
14
 
5
15
  ### Patch Changes
package/dist/index.js CHANGED
@@ -427,7 +427,7 @@ var documentMediaTypeSignatures = [
427
427
  // %PDF
428
428
  }
429
429
  ];
430
- var audioMediaTypeSignatures = [
430
+ var audioMediaTypeSignaturesWithoutMp4 = [
431
431
  {
432
432
  mediaType: "audio/mpeg",
433
433
  bytesPrefix: [255, 251]
@@ -489,15 +489,28 @@ var audioMediaTypeSignatures = [
489
489
  mediaType: "audio/aac",
490
490
  bytesPrefix: [64, 21, 0, 0]
491
491
  },
492
- {
493
- mediaType: "audio/mp4",
494
- bytesPrefix: [102, 116, 121, 112]
495
- },
496
492
  {
497
493
  mediaType: "audio/webm",
498
494
  bytesPrefix: [26, 69, 223, 163]
499
495
  }
500
496
  ];
497
+ var audioMediaTypeSignatures = [
498
+ ...audioMediaTypeSignaturesWithoutMp4,
499
+ {
500
+ mediaType: "audio/mp4",
501
+ bytesPrefix: [
502
+ 0,
503
+ 0,
504
+ 0,
505
+ null,
506
+ 102,
507
+ 116,
508
+ 121,
509
+ 112
510
+ // ftyp
511
+ ]
512
+ }
513
+ ];
501
514
  var videoMediaTypeSignatures = [
502
515
  {
503
516
  mediaType: "video/mp4",
@@ -540,25 +553,37 @@ var videoMediaTypeSignatures = [
540
553
  // RIFF (AVI)
541
554
  }
542
555
  ];
543
- var stripID3 = (data) => {
544
- const bytes = typeof data === "string" ? convertBase64ToUint8Array(data) : data;
556
+ var DEFAULT_SNIFF_BYTES = 18;
557
+ var MAX_SIGNATURE_BYTES = 12;
558
+ var MAX_ID3_TAG_BYTES = 128 * 1024;
559
+ var ID3_SCAN_BYTES = MAX_ID3_TAG_BYTES + MAX_SIGNATURE_BYTES;
560
+ function decodePrefix(data, maxBytes) {
561
+ if (typeof data !== "string") {
562
+ return data.length > maxBytes ? data.subarray(0, maxBytes) : data;
563
+ }
564
+ const maxChars = Math.ceil(maxBytes / 3) * 4;
565
+ const bytes = convertBase64ToUint8Array(
566
+ data.substring(0, Math.min(data.length, maxChars))
567
+ );
568
+ return bytes.length > maxBytes ? bytes.subarray(0, maxBytes) : bytes;
569
+ }
570
+ function hasID3(bytes) {
571
+ return bytes.length > 10 && bytes[0] === 73 && // 'I'
572
+ bytes[1] === 68 && // 'D'
573
+ bytes[2] === 51;
574
+ }
575
+ var stripID3 = (bytes) => {
545
576
  const id3Size = (bytes[6] & 127) << 21 | (bytes[7] & 127) << 14 | (bytes[8] & 127) << 7 | bytes[9] & 127;
546
- return bytes.slice(id3Size + 10);
577
+ return bytes.subarray(id3Size + 10);
547
578
  };
548
- function stripID3TagsIfPresent(data) {
549
- const hasId3 = typeof data === "string" && data.startsWith("SUQz") || typeof data !== "string" && data.length > 10 && data[0] === 73 && // 'I'
550
- data[1] === 68 && // 'D'
551
- data[2] === 51;
552
- return hasId3 ? stripID3(data) : data;
553
- }
554
579
  function detectMediaTypeBySignatures({
555
580
  data,
556
581
  signatures
557
582
  }) {
558
- const processedData = stripID3TagsIfPresent(data);
559
- const bytes = typeof processedData === "string" ? convertBase64ToUint8Array(
560
- processedData.substring(0, Math.min(processedData.length, 24))
561
- ) : processedData;
583
+ let bytes = decodePrefix(data, DEFAULT_SNIFF_BYTES);
584
+ if (hasID3(bytes)) {
585
+ bytes = stripID3(decodePrefix(data, ID3_SCAN_BYTES));
586
+ }
562
587
  for (const signature of signatures) {
563
588
  if (bytes.length >= signature.bytesPrefix.length && signature.bytesPrefix.every(
564
589
  (byte, index) => byte === null || bytes[index] === byte
@@ -584,7 +609,9 @@ function detectMediaType({
584
609
  signatures: [
585
610
  ...imageMediaTypeSignatures,
586
611
  ...documentMediaTypeSignatures,
587
- ...audioMediaTypeSignatures,
612
+ // MP4 containers cannot be distinguished as audio or video by ftyp alone.
613
+ // Preserve the generic detection result as video/mp4.
614
+ ...audioMediaTypeSignaturesWithoutMp4,
588
615
  ...videoMediaTypeSignatures
589
616
  ]
590
617
  });
@@ -1153,7 +1180,7 @@ function withUserAgentSuffix(headers, ...userAgentSuffixParts) {
1153
1180
  }
1154
1181
 
1155
1182
  // src/version.ts
1156
- var VERSION = true ? "5.0.11" : "0.0.0-test";
1183
+ var VERSION = true ? "5.0.12" : "0.0.0-test";
1157
1184
 
1158
1185
  // src/get-from-api.ts
1159
1186
  var getOriginalFetch = () => globalThis.fetch;