file-type 22.0.0 → 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 +2 -1
- package/readme.md +3 -0
- package/source/detectors/zip.js +6 -1
- package/source/index.d.ts +3 -0
- package/source/index.js +32 -15
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "file-type",
|
|
3
|
-
"version": "22.0.
|
|
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",
|
|
@@ -241,6 +241,7 @@
|
|
|
241
241
|
"@types/node": "^25.5.0",
|
|
242
242
|
"ava": "^7.0.0",
|
|
243
243
|
"commonmark": "^0.31.2",
|
|
244
|
+
"esbuild": "^0.28.0",
|
|
244
245
|
"get-stream": "^9.0.1",
|
|
245
246
|
"tsd": "^0.33.0",
|
|
246
247
|
"xo": "^2.0.2"
|
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
|
package/source/detectors/zip.js
CHANGED
|
@@ -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 -
|
|
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;
|
|
@@ -62,6 +62,11 @@ function getKnownFileSizeOrMaximum(fileSize) {
|
|
|
62
62
|
return Math.max(0, fileSize);
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
// Keep the specifier non-literal at the call site so browser bundlers do not try to resolve Node-only imports.
|
|
66
|
+
function importAtRuntime(specifier) {
|
|
67
|
+
return import(specifier);
|
|
68
|
+
}
|
|
69
|
+
|
|
65
70
|
// Wrap stream in an identity TransformStream to avoid BYOB readers.
|
|
66
71
|
// Node.js has a bug where calling controller.close() inside a BYOB stream's
|
|
67
72
|
// pull() callback does not resolve pending reader.read() calls, causing
|
|
@@ -258,8 +263,8 @@ export class FileTypeParser {
|
|
|
258
263
|
this.options.signal?.throwIfAborted();
|
|
259
264
|
// TODO: Remove this when `strtok3.fromFile()` safely rejects non-regular filesystem objects without a pathname race.
|
|
260
265
|
const [{default: fsPromises}, {FileTokenizer}] = await Promise.all([
|
|
261
|
-
|
|
262
|
-
|
|
266
|
+
importAtRuntime('node:fs/promises'),
|
|
267
|
+
importAtRuntime('strtok3'),
|
|
263
268
|
]);
|
|
264
269
|
const fileHandle = await fsPromises.open(path, fsPromises.constants.O_RDONLY | fsPromises.constants.O_NONBLOCK);
|
|
265
270
|
const fileStat = await fileHandle.stat();
|
|
@@ -1724,11 +1729,11 @@ export class FileTypeParser {
|
|
|
1724
1729
|
};
|
|
1725
1730
|
}
|
|
1726
1731
|
|
|
1727
|
-
// Adjust buffer to `mpegOffsetTolerance
|
|
1728
|
-
await tokenizer.peekBuffer(this.buffer, {length: Math.min(
|
|
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});
|
|
1729
1734
|
|
|
1730
1735
|
// Check MPEG 1 or 2 Layer 3 header, or 'layer 0' for ADTS (MPEG sync-word 0xFFE)
|
|
1731
|
-
if (this.buffer.length >= (
|
|
1736
|
+
if (this.buffer.length >= (4 + this.options.mpegOffsetTolerance)) {
|
|
1732
1737
|
for (let depth = 0; depth <= this.options.mpegOffsetTolerance; ++depth) {
|
|
1733
1738
|
const type = this.scanMpeg(depth);
|
|
1734
1739
|
if (type) {
|
|
@@ -1860,22 +1865,34 @@ export class FileTypeParser {
|
|
|
1860
1865
|
*/
|
|
1861
1866
|
scanMpeg(offset) {
|
|
1862
1867
|
if (this.check([0xFF, 0xE0], {offset, mask: [0xFF, 0xE0]})) {
|
|
1868
|
+
// Both (ADTS) MPEG-2 and MPEG-4 are AAC
|
|
1863
1869
|
if (this.check([0x10], {offset: offset + 1, mask: [0x16]})) {
|
|
1864
|
-
// Check for (ADTS) MPEG-2
|
|
1865
|
-
if (this.check([0x08], {offset: offset + 1, mask: [0x08]})) {
|
|
1866
|
-
return {
|
|
1867
|
-
ext: 'aac',
|
|
1868
|
-
mime: 'audio/aac',
|
|
1869
|
-
};
|
|
1870
|
-
}
|
|
1871
|
-
|
|
1872
|
-
// Must be (ADTS) MPEG-4
|
|
1873
1870
|
return {
|
|
1874
1871
|
ext: 'aac',
|
|
1875
1872
|
mime: 'audio/aac',
|
|
1876
1873
|
};
|
|
1877
1874
|
}
|
|
1878
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
|
+
|
|
1879
1896
|
// MPEG 1 or 2 Layer 3 header
|
|
1880
1897
|
// Check for MPEG layer 3
|
|
1881
1898
|
if (this.check([0x02], {offset: offset + 1, mask: [0x06]})) {
|