file-type 22.0.1 → 22.0.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "file-type",
3
- "version": "22.0.1",
3
+ "version": "22.0.2",
4
4
  "description": "Detect the file type of a file, stream, or data",
5
5
  "license": "MIT",
6
6
  "repository": "sindresorhus/file-type",
package/readme.md CHANGED
@@ -306,6 +306,9 @@ They allow support for uncommon file types, non-binary formats, or customized de
306
306
  Detectors can be added via the constructor options or by directly modifying `FileTypeParser#detectors`.
307
307
  Detectors provided through the constructor are executed before the default ones.
308
308
 
309
+ > [!NOTE]
310
+ > Not safe for concurrent use. Create a new instance per call if you need concurrency.
311
+
309
312
  ### Example adding a detector
310
313
 
311
314
  ```js
@@ -53,12 +53,17 @@ async function decompressDeflateRawWithLimit(data, {maximumLength = maximumZipEn
53
53
 
54
54
  totalLength += value.length;
55
55
  if (totalLength > maximumLength) {
56
- await reader.cancel();
56
+ await reader.cancel().catch(() => {});
57
57
  throw new Error(`ZIP entry decompressed data exceeds ${maximumLength} bytes`);
58
58
  }
59
59
 
60
60
  chunks.push(value);
61
61
  }
62
+ } catch (error) {
63
+ // A ZIP entry with a data descriptor has an unknown compressed size, so the buffered data can contain bytes that follow the deflate stream. Node.js 24 rejects those, unlike other versions. The data decompressed so far is still valid and enough for detection.
64
+ if (error.code !== 'ERR_TRAILING_JUNK_AFTER_STREAM_END') {
65
+ throw error;
66
+ }
62
67
  } finally {
63
68
  reader.releaseLock();
64
69
  }
package/source/index.d.ts CHANGED
@@ -238,6 +238,9 @@ This method can be handy to put in a stream pipeline, but it comes with a price.
238
238
  */
239
239
  export function fileTypeStream(webStream: AnyWebReadableStream<Uint8Array>, options?: StreamOptions & FileTypeOptions): Promise<AnyWebReadableByteStreamWithFileType>;
240
240
 
241
+ /**
242
+ Not safe for concurrent use. Create a new instance per call if you need concurrency.
243
+ */
241
244
  export declare class FileTypeParser {
242
245
  /**
243
246
  File type detectors.
package/source/index.js CHANGED
@@ -25,7 +25,7 @@ import {detectPng} from './detectors/png.js';
25
25
  import {detectAsf} from './detectors/asf.js';
26
26
 
27
27
  export const reasonableDetectionSizeInBytes = 4100; // A fair amount of file-types are detectable within this range.
28
- const maximumMpegOffsetTolerance = reasonableDetectionSizeInBytes - 2;
28
+ const maximumMpegOffsetTolerance = reasonableDetectionSizeInBytes - 4; // Keep room for the 4 bytes of the frame header at the deepest scanned offset.
29
29
  const maximumNestedGzipDetectionSizeInBytes = maximumUntrustedSkipSizeInBytes;
30
30
  const maximumNestedGzipProbeDepth = 1;
31
31
  const unknownSizeGzipProbeTimeoutInMilliseconds = 100;
@@ -1729,11 +1729,11 @@ export class FileTypeParser {
1729
1729
  };
1730
1730
  }
1731
1731
 
1732
- // Adjust buffer to `mpegOffsetTolerance`
1733
- await tokenizer.peekBuffer(this.buffer, {length: Math.min(2 + this.options.mpegOffsetTolerance, fileSize), mayBeLess: true});
1732
+ // Adjust buffer to `mpegOffsetTolerance`, plus the 4 bytes of the frame header itself
1733
+ await tokenizer.peekBuffer(this.buffer, {length: Math.min(4 + this.options.mpegOffsetTolerance, fileSize), mayBeLess: true});
1734
1734
 
1735
1735
  // Check MPEG 1 or 2 Layer 3 header, or 'layer 0' for ADTS (MPEG sync-word 0xFFE)
1736
- if (this.buffer.length >= (2 + this.options.mpegOffsetTolerance)) {
1736
+ if (this.buffer.length >= (4 + this.options.mpegOffsetTolerance)) {
1737
1737
  for (let depth = 0; depth <= this.options.mpegOffsetTolerance; ++depth) {
1738
1738
  const type = this.scanMpeg(depth);
1739
1739
  if (type) {
@@ -1865,22 +1865,34 @@ export class FileTypeParser {
1865
1865
  */
1866
1866
  scanMpeg(offset) {
1867
1867
  if (this.check([0xFF, 0xE0], {offset, mask: [0xFF, 0xE0]})) {
1868
+ // Both (ADTS) MPEG-2 and MPEG-4 are AAC
1868
1869
  if (this.check([0x10], {offset: offset + 1, mask: [0x16]})) {
1869
- // Check for (ADTS) MPEG-2
1870
- if (this.check([0x08], {offset: offset + 1, mask: [0x08]})) {
1871
- return {
1872
- ext: 'aac',
1873
- mime: 'audio/aac',
1874
- };
1875
- }
1876
-
1877
- // Must be (ADTS) MPEG-4
1878
1870
  return {
1879
1871
  ext: 'aac',
1880
1872
  mime: 'audio/aac',
1881
1873
  };
1882
1874
  }
1883
1875
 
1876
+ // An MPEG-1 Layer I header with CRC protection enabled is byte-identical to a UTF-16 LE BOM, so text files cannot be told apart from audio. `file(1)` disables MPEG-1 Layer I detection completely for this reason; we only drop the colliding variant.
1877
+ if (this.check([0xFF, 0xFE], {offset})) {
1878
+ return;
1879
+ }
1880
+
1881
+ // Reject the reserved MPEG version `01`
1882
+ if (this.check([0x08], {offset: offset + 1, mask: [0x18]})) {
1883
+ return;
1884
+ }
1885
+
1886
+ // Reject the `bad` (`1111`) bitrate index
1887
+ if (this.check([0xF0], {offset: offset + 2, mask: [0xF0]})) {
1888
+ return;
1889
+ }
1890
+
1891
+ // Reject the reserved sampling frequency `11`
1892
+ if (this.check([0x0C], {offset: offset + 2, mask: [0x0C]})) {
1893
+ return;
1894
+ }
1895
+
1884
1896
  // MPEG 1 or 2 Layer 3 header
1885
1897
  // Check for MPEG layer 3
1886
1898
  if (this.check([0x02], {offset: offset + 1, mask: [0x06]})) {