- API: `pnpm build` bundles dist/ into apps/api/.output (esbuild), with Linux musl native packages for sharp and argon2 kept alongside - docker/api.Dockerfile copies that output; no pnpm install on the server - add dist/migrate.js (prisma migrate deploy equivalent, same _prisma_migrations table and lock) so the Prisma CLI is not needed at runtime - pnpm-workspace: supportedArchitectures for linux/x64/musl - admin: apps/admin/.env.production sets VITE_SITE_URL for the production build - drop NPM_REGISTRY / SITE_URL build args from compose and .env.example - gitignore: anchor node_modules rules so pre-built node_modules are committed - README: describe the pre-built deploy flow Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
4508 lines
148 KiB
JavaScript
4508 lines
148 KiB
JavaScript
import { createRequire as __bundleCreateRequire } from "node:module"; const require = __bundleCreateRequire(import.meta.url);
|
|
import {
|
|
require_src
|
|
} from "./chunk-C4DYPKAN.js";
|
|
import "./chunk-A34KYKJP.js";
|
|
import {
|
|
__commonJS,
|
|
__esm,
|
|
__name,
|
|
__toESM
|
|
} from "./chunk-T6GW54FI.js";
|
|
|
|
// ../../node_modules/.pnpm/ieee754@1.2.1/node_modules/ieee754/index.js
|
|
var require_ieee754 = __commonJS({
|
|
"../../node_modules/.pnpm/ieee754@1.2.1/node_modules/ieee754/index.js"(exports) {
|
|
exports.read = function(buffer, offset, isLE, mLen, nBytes) {
|
|
var e, m;
|
|
var eLen = nBytes * 8 - mLen - 1;
|
|
var eMax = (1 << eLen) - 1;
|
|
var eBias = eMax >> 1;
|
|
var nBits = -7;
|
|
var i = isLE ? nBytes - 1 : 0;
|
|
var d = isLE ? -1 : 1;
|
|
var s = buffer[offset + i];
|
|
i += d;
|
|
e = s & (1 << -nBits) - 1;
|
|
s >>= -nBits;
|
|
nBits += eLen;
|
|
for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {
|
|
}
|
|
m = e & (1 << -nBits) - 1;
|
|
e >>= -nBits;
|
|
nBits += mLen;
|
|
for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {
|
|
}
|
|
if (e === 0) {
|
|
e = 1 - eBias;
|
|
} else if (e === eMax) {
|
|
return m ? NaN : (s ? -1 : 1) * Infinity;
|
|
} else {
|
|
m = m + Math.pow(2, mLen);
|
|
e = e - eBias;
|
|
}
|
|
return (s ? -1 : 1) * m * Math.pow(2, e - mLen);
|
|
};
|
|
exports.write = function(buffer, value, offset, isLE, mLen, nBytes) {
|
|
var e, m, c;
|
|
var eLen = nBytes * 8 - mLen - 1;
|
|
var eMax = (1 << eLen) - 1;
|
|
var eBias = eMax >> 1;
|
|
var rt = mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0;
|
|
var i = isLE ? 0 : nBytes - 1;
|
|
var d = isLE ? 1 : -1;
|
|
var s = value < 0 || value === 0 && 1 / value < 0 ? 1 : 0;
|
|
value = Math.abs(value);
|
|
if (isNaN(value) || value === Infinity) {
|
|
m = isNaN(value) ? 1 : 0;
|
|
e = eMax;
|
|
} else {
|
|
e = Math.floor(Math.log(value) / Math.LN2);
|
|
if (value * (c = Math.pow(2, -e)) < 1) {
|
|
e--;
|
|
c *= 2;
|
|
}
|
|
if (e + eBias >= 1) {
|
|
value += rt / c;
|
|
} else {
|
|
value += rt * Math.pow(2, 1 - eBias);
|
|
}
|
|
if (value * c >= 2) {
|
|
e++;
|
|
c /= 2;
|
|
}
|
|
if (e + eBias >= eMax) {
|
|
m = 0;
|
|
e = eMax;
|
|
} else if (e + eBias >= 1) {
|
|
m = (value * c - 1) * Math.pow(2, mLen);
|
|
e = e + eBias;
|
|
} else {
|
|
m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen);
|
|
e = 0;
|
|
}
|
|
}
|
|
for (; mLen >= 8; buffer[offset + i] = m & 255, i += d, m /= 256, mLen -= 8) {
|
|
}
|
|
e = e << mLen | m;
|
|
eLen += mLen;
|
|
for (; eLen > 0; buffer[offset + i] = e & 255, i += d, e /= 256, eLen -= 8) {
|
|
}
|
|
buffer[offset + i - d] |= s * 128;
|
|
};
|
|
}
|
|
});
|
|
|
|
// ../../node_modules/.pnpm/@borewit+text-codec@0.2.2/node_modules/@borewit/text-codec/lib/index.js
|
|
function utf8Decoder() {
|
|
if (typeof globalThis.TextDecoder === "undefined")
|
|
return void 0;
|
|
return _utf8Decoder !== null && _utf8Decoder !== void 0 ? _utf8Decoder : _utf8Decoder = new globalThis.TextDecoder("utf-8");
|
|
}
|
|
function textDecode(bytes, encoding = "utf-8") {
|
|
switch (encoding.toLowerCase()) {
|
|
case "utf-8":
|
|
case "utf8": {
|
|
const dec = utf8Decoder();
|
|
return dec ? dec.decode(bytes) : decodeUTF8(bytes);
|
|
}
|
|
case "utf-16le":
|
|
return decodeUTF16LE(bytes);
|
|
case "us-ascii":
|
|
case "ascii":
|
|
return decodeASCII(bytes);
|
|
case "latin1":
|
|
case "iso-8859-1":
|
|
return decodeLatin1(bytes);
|
|
case "windows-1252":
|
|
return decodeWindows1252(bytes);
|
|
default:
|
|
throw new RangeError(`Encoding '${encoding}' not supported`);
|
|
}
|
|
}
|
|
function flushChunk(parts, chunk) {
|
|
if (chunk.length === 0)
|
|
return;
|
|
parts.push(String.fromCharCode.apply(null, chunk));
|
|
chunk.length = 0;
|
|
}
|
|
function pushCodeUnit(parts, chunk, codeUnit) {
|
|
chunk.push(codeUnit);
|
|
if (chunk.length >= CHUNK)
|
|
flushChunk(parts, chunk);
|
|
}
|
|
function pushCodePoint(parts, chunk, cp) {
|
|
if (cp <= 65535) {
|
|
pushCodeUnit(parts, chunk, cp);
|
|
return;
|
|
}
|
|
cp -= 65536;
|
|
pushCodeUnit(parts, chunk, 55296 + (cp >> 10));
|
|
pushCodeUnit(parts, chunk, 56320 + (cp & 1023));
|
|
}
|
|
function decodeUTF8(bytes) {
|
|
const parts = [];
|
|
const chunk = [];
|
|
let i = 0;
|
|
if (bytes.length >= 3 && bytes[0] === 239 && bytes[1] === 187 && bytes[2] === 191) {
|
|
i = 3;
|
|
}
|
|
while (i < bytes.length) {
|
|
const b1 = bytes[i];
|
|
if (b1 <= 127) {
|
|
pushCodeUnit(parts, chunk, b1);
|
|
i++;
|
|
continue;
|
|
}
|
|
if (b1 < 194 || b1 > 244) {
|
|
pushCodeUnit(parts, chunk, REPLACEMENT);
|
|
i++;
|
|
continue;
|
|
}
|
|
if (b1 <= 223) {
|
|
if (i + 1 >= bytes.length) {
|
|
pushCodeUnit(parts, chunk, REPLACEMENT);
|
|
i++;
|
|
continue;
|
|
}
|
|
const b22 = bytes[i + 1];
|
|
if ((b22 & 192) !== 128) {
|
|
pushCodeUnit(parts, chunk, REPLACEMENT);
|
|
i++;
|
|
continue;
|
|
}
|
|
const cp2 = (b1 & 31) << 6 | b22 & 63;
|
|
pushCodeUnit(parts, chunk, cp2);
|
|
i += 2;
|
|
continue;
|
|
}
|
|
if (b1 <= 239) {
|
|
if (i + 2 >= bytes.length) {
|
|
pushCodeUnit(parts, chunk, REPLACEMENT);
|
|
i++;
|
|
continue;
|
|
}
|
|
const b22 = bytes[i + 1];
|
|
const b32 = bytes[i + 2];
|
|
const valid2 = (b22 & 192) === 128 && (b32 & 192) === 128 && !(b1 === 224 && b22 < 160) && // overlong
|
|
!(b1 === 237 && b22 >= 160);
|
|
if (!valid2) {
|
|
pushCodeUnit(parts, chunk, REPLACEMENT);
|
|
i++;
|
|
continue;
|
|
}
|
|
const cp2 = (b1 & 15) << 12 | (b22 & 63) << 6 | b32 & 63;
|
|
pushCodeUnit(parts, chunk, cp2);
|
|
i += 3;
|
|
continue;
|
|
}
|
|
if (i + 3 >= bytes.length) {
|
|
pushCodeUnit(parts, chunk, REPLACEMENT);
|
|
i++;
|
|
continue;
|
|
}
|
|
const b2 = bytes[i + 1];
|
|
const b3 = bytes[i + 2];
|
|
const b4 = bytes[i + 3];
|
|
const valid = (b2 & 192) === 128 && (b3 & 192) === 128 && (b4 & 192) === 128 && !(b1 === 240 && b2 < 144) && // overlong
|
|
!(b1 === 244 && b2 > 143);
|
|
if (!valid) {
|
|
pushCodeUnit(parts, chunk, REPLACEMENT);
|
|
i++;
|
|
continue;
|
|
}
|
|
const cp = (b1 & 7) << 18 | (b2 & 63) << 12 | (b3 & 63) << 6 | b4 & 63;
|
|
pushCodePoint(parts, chunk, cp);
|
|
i += 4;
|
|
}
|
|
flushChunk(parts, chunk);
|
|
return parts.join("");
|
|
}
|
|
function decodeUTF16LE(bytes) {
|
|
const parts = [];
|
|
const chunk = [];
|
|
const len = bytes.length;
|
|
let i = 0;
|
|
while (i + 1 < len) {
|
|
const u1 = bytes[i] | bytes[i + 1] << 8;
|
|
i += 2;
|
|
if (u1 >= 55296 && u1 <= 56319) {
|
|
if (i + 1 < len) {
|
|
const u2 = bytes[i] | bytes[i + 1] << 8;
|
|
if (u2 >= 56320 && u2 <= 57343) {
|
|
pushCodeUnit(parts, chunk, u1);
|
|
pushCodeUnit(parts, chunk, u2);
|
|
i += 2;
|
|
} else {
|
|
pushCodeUnit(parts, chunk, REPLACEMENT);
|
|
}
|
|
} else {
|
|
pushCodeUnit(parts, chunk, REPLACEMENT);
|
|
}
|
|
continue;
|
|
}
|
|
if (u1 >= 56320 && u1 <= 57343) {
|
|
pushCodeUnit(parts, chunk, REPLACEMENT);
|
|
continue;
|
|
}
|
|
pushCodeUnit(parts, chunk, u1);
|
|
}
|
|
if (i < len) {
|
|
pushCodeUnit(parts, chunk, REPLACEMENT);
|
|
}
|
|
flushChunk(parts, chunk);
|
|
return parts.join("");
|
|
}
|
|
function decodeASCII(bytes) {
|
|
const parts = [];
|
|
for (let i = 0; i < bytes.length; i += CHUNK) {
|
|
const end = Math.min(bytes.length, i + CHUNK);
|
|
const codes = new Array(end - i);
|
|
for (let j = i, k = 0; j < end; j++, k++) {
|
|
codes[k] = bytes[j] & 127;
|
|
}
|
|
parts.push(String.fromCharCode.apply(null, codes));
|
|
}
|
|
return parts.join("");
|
|
}
|
|
function decodeLatin1(bytes) {
|
|
const parts = [];
|
|
for (let i = 0; i < bytes.length; i += CHUNK) {
|
|
const end = Math.min(bytes.length, i + CHUNK);
|
|
const codes = new Array(end - i);
|
|
for (let j = i, k = 0; j < end; j++, k++) {
|
|
codes[k] = bytes[j];
|
|
}
|
|
parts.push(String.fromCharCode.apply(null, codes));
|
|
}
|
|
return parts.join("");
|
|
}
|
|
function decodeWindows1252(bytes) {
|
|
const parts = [];
|
|
let out = "";
|
|
for (let i = 0; i < bytes.length; i++) {
|
|
const b = bytes[i];
|
|
const extra = b >= 128 && b <= 159 ? WINDOWS_1252_EXTRA[b] : void 0;
|
|
out += extra !== null && extra !== void 0 ? extra : String.fromCharCode(b);
|
|
if (out.length >= CHUNK) {
|
|
parts.push(out);
|
|
out = "";
|
|
}
|
|
}
|
|
if (out)
|
|
parts.push(out);
|
|
return parts.join("");
|
|
}
|
|
var WINDOWS_1252_EXTRA, WINDOWS_1252_REVERSE, _utf8Decoder, CHUNK, REPLACEMENT;
|
|
var init_lib = __esm({
|
|
"../../node_modules/.pnpm/@borewit+text-codec@0.2.2/node_modules/@borewit/text-codec/lib/index.js"() {
|
|
WINDOWS_1252_EXTRA = {
|
|
128: "\u20AC",
|
|
130: "\u201A",
|
|
131: "\u0192",
|
|
132: "\u201E",
|
|
133: "\u2026",
|
|
134: "\u2020",
|
|
135: "\u2021",
|
|
136: "\u02C6",
|
|
137: "\u2030",
|
|
138: "\u0160",
|
|
139: "\u2039",
|
|
140: "\u0152",
|
|
142: "\u017D",
|
|
145: "\u2018",
|
|
146: "\u2019",
|
|
147: "\u201C",
|
|
148: "\u201D",
|
|
149: "\u2022",
|
|
150: "\u2013",
|
|
151: "\u2014",
|
|
152: "\u02DC",
|
|
153: "\u2122",
|
|
154: "\u0161",
|
|
155: "\u203A",
|
|
156: "\u0153",
|
|
158: "\u017E",
|
|
159: "\u0178"
|
|
};
|
|
WINDOWS_1252_REVERSE = {};
|
|
for (const [code, char] of Object.entries(WINDOWS_1252_EXTRA)) {
|
|
WINDOWS_1252_REVERSE[char] = Number.parseInt(code, 10);
|
|
}
|
|
__name(utf8Decoder, "utf8Decoder");
|
|
CHUNK = 32 * 1024;
|
|
REPLACEMENT = 65533;
|
|
__name(textDecode, "textDecode");
|
|
__name(flushChunk, "flushChunk");
|
|
__name(pushCodeUnit, "pushCodeUnit");
|
|
__name(pushCodePoint, "pushCodePoint");
|
|
__name(decodeUTF8, "decodeUTF8");
|
|
__name(decodeUTF16LE, "decodeUTF16LE");
|
|
__name(decodeASCII, "decodeASCII");
|
|
__name(decodeLatin1, "decodeLatin1");
|
|
__name(decodeWindows1252, "decodeWindows1252");
|
|
}
|
|
});
|
|
|
|
// ../../node_modules/.pnpm/token-types@6.1.2/node_modules/token-types/lib/index.js
|
|
function dv(array) {
|
|
return new DataView(array.buffer, array.byteOffset);
|
|
}
|
|
var ieee754, UINT8, UINT16_LE, UINT16_BE, UINT32_LE, UINT32_BE, INT32_BE, UINT64_LE, StringType;
|
|
var init_lib2 = __esm({
|
|
"../../node_modules/.pnpm/token-types@6.1.2/node_modules/token-types/lib/index.js"() {
|
|
ieee754 = __toESM(require_ieee754(), 1);
|
|
init_lib();
|
|
__name(dv, "dv");
|
|
UINT8 = {
|
|
len: 1,
|
|
get(array, offset) {
|
|
return dv(array).getUint8(offset);
|
|
},
|
|
put(array, offset, value) {
|
|
dv(array).setUint8(offset, value);
|
|
return offset + 1;
|
|
}
|
|
};
|
|
UINT16_LE = {
|
|
len: 2,
|
|
get(array, offset) {
|
|
return dv(array).getUint16(offset, true);
|
|
},
|
|
put(array, offset, value) {
|
|
dv(array).setUint16(offset, value, true);
|
|
return offset + 2;
|
|
}
|
|
};
|
|
UINT16_BE = {
|
|
len: 2,
|
|
get(array, offset) {
|
|
return dv(array).getUint16(offset);
|
|
},
|
|
put(array, offset, value) {
|
|
dv(array).setUint16(offset, value);
|
|
return offset + 2;
|
|
}
|
|
};
|
|
UINT32_LE = {
|
|
len: 4,
|
|
get(array, offset) {
|
|
return dv(array).getUint32(offset, true);
|
|
},
|
|
put(array, offset, value) {
|
|
dv(array).setUint32(offset, value, true);
|
|
return offset + 4;
|
|
}
|
|
};
|
|
UINT32_BE = {
|
|
len: 4,
|
|
get(array, offset) {
|
|
return dv(array).getUint32(offset);
|
|
},
|
|
put(array, offset, value) {
|
|
dv(array).setUint32(offset, value);
|
|
return offset + 4;
|
|
}
|
|
};
|
|
INT32_BE = {
|
|
len: 4,
|
|
get(array, offset) {
|
|
return dv(array).getInt32(offset);
|
|
},
|
|
put(array, offset, value) {
|
|
dv(array).setInt32(offset, value);
|
|
return offset + 4;
|
|
}
|
|
};
|
|
UINT64_LE = {
|
|
len: 8,
|
|
get(array, offset) {
|
|
return dv(array).getBigUint64(offset, true);
|
|
},
|
|
put(array, offset, value) {
|
|
dv(array).setBigUint64(offset, value, true);
|
|
return offset + 8;
|
|
}
|
|
};
|
|
StringType = class {
|
|
static {
|
|
__name(this, "StringType");
|
|
}
|
|
constructor(len, encoding) {
|
|
this.len = len;
|
|
this.encoding = encoding;
|
|
}
|
|
get(data, offset = 0) {
|
|
const bytes = data.subarray(offset, offset + this.len);
|
|
return textDecode(bytes, this.encoding);
|
|
}
|
|
};
|
|
}
|
|
});
|
|
|
|
// ../../node_modules/.pnpm/strtok3@10.6.2/node_modules/strtok3/lib/stream/Errors.js
|
|
var defaultMessages, EndOfStreamError, AbortError;
|
|
var init_Errors = __esm({
|
|
"../../node_modules/.pnpm/strtok3@10.6.2/node_modules/strtok3/lib/stream/Errors.js"() {
|
|
defaultMessages = "End-Of-Stream";
|
|
EndOfStreamError = class extends Error {
|
|
static {
|
|
__name(this, "EndOfStreamError");
|
|
}
|
|
constructor() {
|
|
super(defaultMessages);
|
|
this.name = "EndOfStreamError";
|
|
}
|
|
};
|
|
AbortError = class extends Error {
|
|
static {
|
|
__name(this, "AbortError");
|
|
}
|
|
constructor(message = "The operation was aborted") {
|
|
super(message);
|
|
this.name = "AbortError";
|
|
}
|
|
};
|
|
}
|
|
});
|
|
|
|
// ../../node_modules/.pnpm/strtok3@10.6.2/node_modules/strtok3/lib/AbortSignal.js
|
|
function throwIfAborted(signal) {
|
|
if (signal?.aborted) {
|
|
throw new AbortError();
|
|
}
|
|
}
|
|
var init_AbortSignal = __esm({
|
|
"../../node_modules/.pnpm/strtok3@10.6.2/node_modules/strtok3/lib/AbortSignal.js"() {
|
|
init_Errors();
|
|
__name(throwIfAborted, "throwIfAborted");
|
|
}
|
|
});
|
|
|
|
// ../../node_modules/.pnpm/strtok3@10.6.2/node_modules/strtok3/lib/BufferSizeError.js
|
|
function getMaxBufferSize(options) {
|
|
const limit = options?.maxBufferSize ?? Number.POSITIVE_INFINITY;
|
|
if (limit !== Number.POSITIVE_INFINITY && (!Number.isSafeInteger(limit) || limit <= 0)) {
|
|
throw new RangeError("maxBufferSize must be a positive safe integer or Infinity");
|
|
}
|
|
return limit;
|
|
}
|
|
var BufferSizeError;
|
|
var init_BufferSizeError = __esm({
|
|
"../../node_modules/.pnpm/strtok3@10.6.2/node_modules/strtok3/lib/BufferSizeError.js"() {
|
|
BufferSizeError = class extends RangeError {
|
|
static {
|
|
__name(this, "BufferSizeError");
|
|
}
|
|
/**
|
|
* Create an error describing an allocation that exceeds the configured limit.
|
|
* @param requestedSize - Requested buffer size in bytes
|
|
* @param maxBufferSize - Configured maximum buffer size in bytes
|
|
*/
|
|
constructor(requestedSize, maxBufferSize) {
|
|
super(`Requested buffer size ${requestedSize} exceeds maxBufferSize ${maxBufferSize}`);
|
|
this.requestedSize = requestedSize;
|
|
this.maxBufferSize = maxBufferSize;
|
|
this.name = "BufferSizeError";
|
|
}
|
|
};
|
|
__name(getMaxBufferSize, "getMaxBufferSize");
|
|
}
|
|
});
|
|
|
|
// ../../node_modules/.pnpm/strtok3@10.6.2/node_modules/strtok3/lib/stream/AbstractStreamReader.js
|
|
var AbstractStreamReader;
|
|
var init_AbstractStreamReader = __esm({
|
|
"../../node_modules/.pnpm/strtok3@10.6.2/node_modules/strtok3/lib/stream/AbstractStreamReader.js"() {
|
|
init_Errors();
|
|
AbstractStreamReader = class {
|
|
static {
|
|
__name(this, "AbstractStreamReader");
|
|
}
|
|
constructor() {
|
|
this.endOfStream = false;
|
|
this.interrupted = false;
|
|
this.peekQueue = [];
|
|
}
|
|
async peek(uint8Array, mayBeLess = false) {
|
|
const bytesRead = await this.read(uint8Array, mayBeLess);
|
|
this.peekQueue.push(uint8Array.subarray(0, bytesRead));
|
|
return bytesRead;
|
|
}
|
|
async read(buffer, mayBeLess = false) {
|
|
if (buffer.length === 0) {
|
|
return 0;
|
|
}
|
|
let bytesRead = this.readFromPeekBuffer(buffer);
|
|
if (!this.endOfStream) {
|
|
bytesRead += await this.readRemainderFromStream(buffer.subarray(bytesRead), mayBeLess);
|
|
}
|
|
if (bytesRead === 0 && !mayBeLess) {
|
|
throw new EndOfStreamError();
|
|
}
|
|
return bytesRead;
|
|
}
|
|
/**
|
|
* Read chunk from stream
|
|
* @param buffer - Target Uint8Array (or Buffer) to store data read from stream in
|
|
* @returns Number of bytes read
|
|
*/
|
|
readFromPeekBuffer(buffer) {
|
|
let remaining = buffer.length;
|
|
let bytesRead = 0;
|
|
while (this.peekQueue.length > 0 && remaining > 0) {
|
|
const peekData = this.peekQueue.pop();
|
|
if (!peekData) {
|
|
throw new Error("peekData should be defined");
|
|
}
|
|
const lenCopy = Math.min(peekData.length, remaining);
|
|
buffer.set(peekData.subarray(0, lenCopy), bytesRead);
|
|
bytesRead += lenCopy;
|
|
remaining -= lenCopy;
|
|
if (lenCopy < peekData.length) {
|
|
this.peekQueue.push(peekData.subarray(lenCopy));
|
|
}
|
|
}
|
|
return bytesRead;
|
|
}
|
|
async readRemainderFromStream(buffer, mayBeLess) {
|
|
let bytesRead = 0;
|
|
while (bytesRead < buffer.length && !this.endOfStream) {
|
|
if (this.interrupted) {
|
|
throw new AbortError();
|
|
}
|
|
const chunkLen = await this.readFromStream(buffer.subarray(bytesRead), mayBeLess);
|
|
if (chunkLen === 0) {
|
|
break;
|
|
}
|
|
bytesRead += chunkLen;
|
|
}
|
|
if (!mayBeLess && bytesRead < buffer.length) {
|
|
throw new EndOfStreamError();
|
|
}
|
|
return bytesRead;
|
|
}
|
|
};
|
|
}
|
|
});
|
|
|
|
// ../../node_modules/.pnpm/strtok3@10.6.2/node_modules/strtok3/lib/stream/Deferred.js
|
|
var init_Deferred = __esm({
|
|
"../../node_modules/.pnpm/strtok3@10.6.2/node_modules/strtok3/lib/stream/Deferred.js"() {
|
|
}
|
|
});
|
|
|
|
// ../../node_modules/.pnpm/strtok3@10.6.2/node_modules/strtok3/lib/stream/StreamReader.js
|
|
var init_StreamReader = __esm({
|
|
"../../node_modules/.pnpm/strtok3@10.6.2/node_modules/strtok3/lib/stream/StreamReader.js"() {
|
|
init_AbstractStreamReader();
|
|
init_Deferred();
|
|
init_Errors();
|
|
}
|
|
});
|
|
|
|
// ../../node_modules/.pnpm/strtok3@10.6.2/node_modules/strtok3/lib/stream/WebStreamReader.js
|
|
var WebStreamReader;
|
|
var init_WebStreamReader = __esm({
|
|
"../../node_modules/.pnpm/strtok3@10.6.2/node_modules/strtok3/lib/stream/WebStreamReader.js"() {
|
|
init_AbstractStreamReader();
|
|
WebStreamReader = class extends AbstractStreamReader {
|
|
static {
|
|
__name(this, "WebStreamReader");
|
|
}
|
|
constructor(reader) {
|
|
super();
|
|
this.reader = reader;
|
|
}
|
|
async abort() {
|
|
return this.close();
|
|
}
|
|
async close() {
|
|
this.reader.releaseLock();
|
|
}
|
|
};
|
|
}
|
|
});
|
|
|
|
// ../../node_modules/.pnpm/strtok3@10.6.2/node_modules/strtok3/lib/stream/WebStreamByobReader.js
|
|
var WebStreamByobReader;
|
|
var init_WebStreamByobReader = __esm({
|
|
"../../node_modules/.pnpm/strtok3@10.6.2/node_modules/strtok3/lib/stream/WebStreamByobReader.js"() {
|
|
init_WebStreamReader();
|
|
WebStreamByobReader = class extends WebStreamReader {
|
|
static {
|
|
__name(this, "WebStreamByobReader");
|
|
}
|
|
/**
|
|
* Read from stream
|
|
* @param buffer - Target Uint8Array (or Buffer) to store data read from stream in
|
|
* @param mayBeLess - If true, may fill the buffer partially
|
|
* @protected Bytes read
|
|
*/
|
|
async readFromStream(buffer, mayBeLess) {
|
|
if (buffer.length === 0) {
|
|
return 0;
|
|
}
|
|
const result = await this.reader.read(new Uint8Array(buffer.length), {
|
|
min: mayBeLess ? void 0 : buffer.length
|
|
});
|
|
if (result.done) {
|
|
this.endOfStream = result.done;
|
|
}
|
|
if (result.value) {
|
|
buffer.set(result.value);
|
|
return result.value.length;
|
|
}
|
|
return 0;
|
|
}
|
|
};
|
|
}
|
|
});
|
|
|
|
// ../../node_modules/.pnpm/strtok3@10.6.2/node_modules/strtok3/lib/stream/WebStreamDefaultReader.js
|
|
var WebStreamDefaultReader;
|
|
var init_WebStreamDefaultReader = __esm({
|
|
"../../node_modules/.pnpm/strtok3@10.6.2/node_modules/strtok3/lib/stream/WebStreamDefaultReader.js"() {
|
|
init_AbstractStreamReader();
|
|
init_Errors();
|
|
WebStreamDefaultReader = class extends AbstractStreamReader {
|
|
static {
|
|
__name(this, "WebStreamDefaultReader");
|
|
}
|
|
constructor(reader) {
|
|
super();
|
|
this.reader = reader;
|
|
this.buffer = null;
|
|
}
|
|
/**
|
|
* Copy chunk to target, and store the remainder in this.buffer
|
|
*/
|
|
writeChunk(target, chunk) {
|
|
const written = Math.min(chunk.length, target.length);
|
|
target.set(chunk.subarray(0, written));
|
|
if (written < chunk.length) {
|
|
this.buffer = chunk.subarray(written);
|
|
} else {
|
|
this.buffer = null;
|
|
}
|
|
return written;
|
|
}
|
|
/**
|
|
* Read from stream
|
|
* @param buffer - Target Uint8Array (or Buffer) to store data read from stream in
|
|
* @param mayBeLess - If true, may fill the buffer partially
|
|
* @protected Bytes read
|
|
*/
|
|
async readFromStream(buffer, mayBeLess) {
|
|
if (buffer.length === 0) {
|
|
return 0;
|
|
}
|
|
let totalBytesRead = 0;
|
|
if (this.buffer) {
|
|
totalBytesRead += this.writeChunk(buffer, this.buffer);
|
|
}
|
|
while (totalBytesRead < buffer.length && !this.endOfStream) {
|
|
const result = await this.reader.read();
|
|
if (result.done) {
|
|
this.endOfStream = true;
|
|
break;
|
|
}
|
|
if (result.value) {
|
|
totalBytesRead += this.writeChunk(buffer.subarray(totalBytesRead), result.value);
|
|
}
|
|
}
|
|
if (!mayBeLess && totalBytesRead === 0 && this.endOfStream) {
|
|
throw new EndOfStreamError();
|
|
}
|
|
return totalBytesRead;
|
|
}
|
|
abort() {
|
|
this.interrupted = true;
|
|
return this.reader.cancel();
|
|
}
|
|
async close() {
|
|
try {
|
|
await this.abort();
|
|
} finally {
|
|
this.reader.releaseLock();
|
|
}
|
|
}
|
|
};
|
|
}
|
|
});
|
|
|
|
// ../../node_modules/.pnpm/strtok3@10.6.2/node_modules/strtok3/lib/stream/WebStreamReaderFactory.js
|
|
function makeWebStreamReader(stream) {
|
|
try {
|
|
const reader = stream.getReader({ mode: "byob" });
|
|
if (reader instanceof ReadableStreamDefaultReader) {
|
|
return new WebStreamDefaultReader(reader);
|
|
}
|
|
return new WebStreamByobReader(reader);
|
|
} catch (error) {
|
|
if (error instanceof TypeError) {
|
|
return new WebStreamDefaultReader(stream.getReader());
|
|
}
|
|
throw error;
|
|
}
|
|
}
|
|
var init_WebStreamReaderFactory = __esm({
|
|
"../../node_modules/.pnpm/strtok3@10.6.2/node_modules/strtok3/lib/stream/WebStreamReaderFactory.js"() {
|
|
init_WebStreamByobReader();
|
|
init_WebStreamDefaultReader();
|
|
__name(makeWebStreamReader, "makeWebStreamReader");
|
|
}
|
|
});
|
|
|
|
// ../../node_modules/.pnpm/strtok3@10.6.2/node_modules/strtok3/lib/stream/index.js
|
|
var init_stream = __esm({
|
|
"../../node_modules/.pnpm/strtok3@10.6.2/node_modules/strtok3/lib/stream/index.js"() {
|
|
init_Errors();
|
|
init_StreamReader();
|
|
init_WebStreamByobReader();
|
|
init_WebStreamDefaultReader();
|
|
init_WebStreamReaderFactory();
|
|
}
|
|
});
|
|
|
|
// ../../node_modules/.pnpm/strtok3@10.6.2/node_modules/strtok3/lib/AbstractTokenizer.js
|
|
var AbstractTokenizer;
|
|
var init_AbstractTokenizer = __esm({
|
|
"../../node_modules/.pnpm/strtok3@10.6.2/node_modules/strtok3/lib/AbstractTokenizer.js"() {
|
|
init_AbortSignal();
|
|
init_BufferSizeError();
|
|
init_stream();
|
|
AbstractTokenizer = class {
|
|
static {
|
|
__name(this, "AbstractTokenizer");
|
|
}
|
|
/**
|
|
* Constructor
|
|
* @param options Tokenizer options
|
|
* @protected
|
|
*/
|
|
constructor(options) {
|
|
this.numBuffer = new Uint8Array(8);
|
|
this.position = 0;
|
|
this.maxBufferSize = getMaxBufferSize(options);
|
|
throwIfAborted(options?.abortSignal);
|
|
this.onClose = options?.onClose;
|
|
if (options?.abortSignal) {
|
|
this.addAbortListener(options.abortSignal, () => {
|
|
void this.abort().catch(() => {
|
|
});
|
|
});
|
|
}
|
|
}
|
|
addAbortListener(signal, listener) {
|
|
this.abortSignal = signal;
|
|
this.abortListener = listener;
|
|
signal.addEventListener("abort", listener, { once: true });
|
|
}
|
|
removeAbortListener() {
|
|
if (this.abortListener) {
|
|
this.abortSignal?.removeEventListener("abort", this.abortListener);
|
|
}
|
|
this.abortSignal = void 0;
|
|
this.abortListener = void 0;
|
|
}
|
|
/**
|
|
* Read a token from the tokenizer-stream
|
|
* @param token - The token to read
|
|
* @param position - If provided, the desired position in the tokenizer-stream
|
|
* @returns Promise with token data
|
|
*/
|
|
async readToken(token, position = this.position) {
|
|
this.validateTokenRead(token.len, position);
|
|
const uint8Array = new Uint8Array(token.len);
|
|
const len = await this.readBuffer(uint8Array, { position });
|
|
if (len < token.len) {
|
|
throw new EndOfStreamError();
|
|
}
|
|
return token.get(uint8Array, 0);
|
|
}
|
|
/**
|
|
* Peek a token from the tokenizer-stream.
|
|
* @param token - Token to peek from the tokenizer-stream.
|
|
* @param position - Offset where to begin reading within the file. If position is null, data will be read from the current file position.
|
|
* @returns Promise with token data
|
|
*/
|
|
async peekToken(token, position = this.position) {
|
|
const peekPosition = position ?? this.position;
|
|
this.validateTokenRead(token.len, peekPosition, true);
|
|
const uint8Array = new Uint8Array(token.len);
|
|
const len = await this.peekBuffer(uint8Array, { position: peekPosition });
|
|
if (len < token.len) {
|
|
throw new EndOfStreamError();
|
|
}
|
|
return token.get(uint8Array, 0);
|
|
}
|
|
/**
|
|
* Read a numeric token from the stream
|
|
* @param token - Numeric token
|
|
* @returns Promise with number
|
|
*/
|
|
async readNumber(token) {
|
|
const len = await this.readBuffer(this.numBuffer, { length: token.len });
|
|
if (len < token.len) {
|
|
throw new EndOfStreamError();
|
|
}
|
|
return token.get(this.numBuffer, 0);
|
|
}
|
|
/**
|
|
* Read a numeric token from the stream
|
|
* @param token - Numeric token
|
|
* @returns Promise with number
|
|
*/
|
|
async peekNumber(token) {
|
|
const len = await this.peekBuffer(this.numBuffer, { length: token.len });
|
|
if (len < token.len) {
|
|
throw new EndOfStreamError();
|
|
}
|
|
return token.get(this.numBuffer, 0);
|
|
}
|
|
/**
|
|
* Ignore number of bytes, advances the pointer in under tokenizer-stream.
|
|
* @param length - Number of bytes to ignore. Must be ≥ 0.
|
|
* @return resolves the number of bytes ignored, equals length if this available, otherwise the number of bytes available
|
|
*/
|
|
async ignore(length) {
|
|
if (length < 0) {
|
|
throw new RangeError("ignore length must be \u2265 0 bytes");
|
|
}
|
|
this.validateLength(length, "ignore length");
|
|
this.validateLength(this.position + length, "end position");
|
|
if (this.fileInfo.size !== void 0) {
|
|
const bytesLeft = this.fileInfo.size - this.position;
|
|
if (length > bytesLeft) {
|
|
this.position += bytesLeft;
|
|
return bytesLeft;
|
|
}
|
|
}
|
|
this.position += length;
|
|
return length;
|
|
}
|
|
async close() {
|
|
this.removeAbortListener();
|
|
await this.abort();
|
|
await this.onClose?.();
|
|
}
|
|
/**
|
|
* Validate a byte length or position before using it in buffer calculations.
|
|
* @param value - Value that must be a non-negative safe integer
|
|
* @param name - Label used in the validation error
|
|
* @throws RangeError if the value is negative or not a safe integer
|
|
*/
|
|
validateLength(value, name) {
|
|
if (!Number.isSafeInteger(value) || value < 0) {
|
|
throw new RangeError(`${name} must be a non-negative safe integer`);
|
|
}
|
|
}
|
|
/**
|
|
* Validate a requested buffer size against the configured allocation limit.
|
|
* @param length - Requested buffer size in bytes
|
|
* @throws RangeError if the length is negative or not a safe integer
|
|
* @throws BufferSizeError if the length exceeds maxBufferSize
|
|
*/
|
|
validateBufferSize(length) {
|
|
this.validateLength(length, "buffer length");
|
|
if (length > this.maxBufferSize) {
|
|
throw new BufferSizeError(length, this.maxBufferSize);
|
|
}
|
|
}
|
|
/**
|
|
* Validate a token request before allocating a buffer or consuming input.
|
|
* @param length - Token length in bytes
|
|
* @param position - Byte offset where the token starts
|
|
* @param peek - Whether to include skipped stream bytes in the lookahead limit
|
|
* @throws RangeError if a length or position is negative or not a safe integer
|
|
* @throws BufferSizeError if the token buffer or stream lookahead exceeds maxBufferSize
|
|
* @throws Error if a stream request starts before the current position
|
|
* @throws EndOfStreamError if the token extends beyond the known input size
|
|
*/
|
|
validateTokenRead(length, position, peek = false) {
|
|
this.validateBufferSize(length);
|
|
this.validateLength(position, "position");
|
|
this.validateLength(position + length, "end position");
|
|
if (!this.supportsRandomAccess() && position < this.position) {
|
|
throw new Error("`options.position` must be equal or greater than `tokenizer.position`");
|
|
}
|
|
if (peek && !this.supportsRandomAccess()) {
|
|
this.validateBufferSize(length + position - this.position);
|
|
}
|
|
if (this.fileInfo.size !== void 0 && length > this.fileInfo.size - position) {
|
|
throw new EndOfStreamError();
|
|
}
|
|
}
|
|
/**
|
|
* Apply defaults and validate buffer read or peek options.
|
|
* @param uint8Array - Target buffer whose length is the default read length
|
|
* @param options - Requested length, position and partial-read behavior
|
|
* @returns Validated options with an explicit length, position and mayBeLess flag
|
|
* @throws RangeError if a length or position is invalid, or the length exceeds the target buffer
|
|
* @throws Error if a stream request starts before the current position
|
|
*/
|
|
normalizeOptions(uint8Array, options) {
|
|
const length = options?.length ?? uint8Array.length;
|
|
const position = options?.position ?? this.position;
|
|
this.validateLength(length, "length");
|
|
this.validateLength(position, "position");
|
|
this.validateLength(position + length, "end position");
|
|
if (length > uint8Array.length) {
|
|
throw new RangeError("length must not exceed the target buffer length");
|
|
}
|
|
if (!this.supportsRandomAccess() && position < this.position) {
|
|
throw new Error("`options.position` must be equal or greater than `tokenizer.position`");
|
|
}
|
|
return { length, position, mayBeLess: options?.mayBeLess ?? false };
|
|
}
|
|
abort() {
|
|
this.removeAbortListener();
|
|
return Promise.resolve();
|
|
}
|
|
};
|
|
}
|
|
});
|
|
|
|
// ../../node_modules/.pnpm/strtok3@10.6.2/node_modules/strtok3/lib/BlobTokenizer.js
|
|
var BlobTokenizer;
|
|
var init_BlobTokenizer = __esm({
|
|
"../../node_modules/.pnpm/strtok3@10.6.2/node_modules/strtok3/lib/BlobTokenizer.js"() {
|
|
init_AbstractTokenizer();
|
|
init_stream();
|
|
BlobTokenizer = class extends AbstractTokenizer {
|
|
static {
|
|
__name(this, "BlobTokenizer");
|
|
}
|
|
/**
|
|
* Construct BufferTokenizer
|
|
* @param blob - Uint8Array to tokenize
|
|
* @param options Tokenizer options
|
|
*/
|
|
constructor(blob, options) {
|
|
super(options);
|
|
this.blob = blob;
|
|
this.fileInfo = { ...options?.fileInfo ?? {}, ...{ size: blob.size, mimeType: blob.type } };
|
|
}
|
|
/**
|
|
* Read buffer from tokenizer
|
|
* @param uint8Array - Uint8Array to tokenize
|
|
* @param options - Read behaviour options
|
|
* @returns {Promise<number>}
|
|
*/
|
|
async readBuffer(uint8Array, options) {
|
|
const normOptions = this.normalizeOptions(uint8Array, options);
|
|
const bytesRead = await this.peekBuffer(uint8Array, normOptions);
|
|
this.position = normOptions.position + bytesRead;
|
|
return bytesRead;
|
|
}
|
|
/**
|
|
* Peek (read ahead) buffer from tokenizer
|
|
* @param buffer
|
|
* @param options - Read behaviour options
|
|
* @returns {Promise<number>}
|
|
*/
|
|
async peekBuffer(buffer, options) {
|
|
const normOptions = this.normalizeOptions(buffer, options);
|
|
const bytes2read = Math.max(0, Math.min(this.blob.size - normOptions.position, normOptions.length));
|
|
if (!normOptions.mayBeLess && bytes2read < normOptions.length) {
|
|
throw new EndOfStreamError();
|
|
}
|
|
for (let offset = 0; offset < bytes2read; ) {
|
|
const chunkLength = Math.min(this.maxBufferSize, bytes2read - offset);
|
|
const position = normOptions.position + offset;
|
|
const arrayBuffer = await this.blob.slice(position, position + chunkLength).arrayBuffer();
|
|
buffer.set(new Uint8Array(arrayBuffer), offset);
|
|
offset += chunkLength;
|
|
}
|
|
return bytes2read;
|
|
}
|
|
close() {
|
|
return super.close();
|
|
}
|
|
supportsRandomAccess() {
|
|
return true;
|
|
}
|
|
setPosition(position) {
|
|
this.position = position;
|
|
}
|
|
};
|
|
}
|
|
});
|
|
|
|
// ../../node_modules/.pnpm/strtok3@10.6.2/node_modules/strtok3/lib/BufferTokenizer.js
|
|
var BufferTokenizer;
|
|
var init_BufferTokenizer = __esm({
|
|
"../../node_modules/.pnpm/strtok3@10.6.2/node_modules/strtok3/lib/BufferTokenizer.js"() {
|
|
init_AbstractTokenizer();
|
|
init_stream();
|
|
BufferTokenizer = class extends AbstractTokenizer {
|
|
static {
|
|
__name(this, "BufferTokenizer");
|
|
}
|
|
/**
|
|
* Construct BufferTokenizer
|
|
* @param uint8Array - Uint8Array to tokenize
|
|
* @param options Tokenizer options
|
|
*/
|
|
constructor(uint8Array, options) {
|
|
super(options);
|
|
this.uint8Array = uint8Array;
|
|
this.fileInfo = { ...options?.fileInfo ?? {}, ...{ size: uint8Array.length } };
|
|
}
|
|
/**
|
|
* Read buffer from tokenizer
|
|
* @param uint8Array - Uint8Array to tokenize
|
|
* @param options - Read behaviour options
|
|
* @returns {Promise<number>}
|
|
*/
|
|
async readBuffer(uint8Array, options) {
|
|
const normOptions = this.normalizeOptions(uint8Array, options);
|
|
const bytesRead = await this.peekBuffer(uint8Array, normOptions);
|
|
this.position = normOptions.position + bytesRead;
|
|
return bytesRead;
|
|
}
|
|
/**
|
|
* Peek (read ahead) buffer from tokenizer
|
|
* @param uint8Array
|
|
* @param options - Read behaviour options
|
|
* @returns {Promise<number>}
|
|
*/
|
|
async peekBuffer(uint8Array, options) {
|
|
const normOptions = this.normalizeOptions(uint8Array, options);
|
|
const bytes2read = Math.max(0, Math.min(this.uint8Array.length - normOptions.position, normOptions.length));
|
|
if (!normOptions.mayBeLess && bytes2read < normOptions.length) {
|
|
throw new EndOfStreamError();
|
|
}
|
|
uint8Array.set(this.uint8Array.subarray(normOptions.position, normOptions.position + bytes2read));
|
|
return bytes2read;
|
|
}
|
|
close() {
|
|
return super.close();
|
|
}
|
|
supportsRandomAccess() {
|
|
return true;
|
|
}
|
|
setPosition(position) {
|
|
this.position = position;
|
|
}
|
|
};
|
|
}
|
|
});
|
|
|
|
// ../../node_modules/.pnpm/strtok3@10.6.2/node_modules/strtok3/lib/ReadStreamTokenizer.js
|
|
var ignoreChunkSize, ReadStreamTokenizer;
|
|
var init_ReadStreamTokenizer = __esm({
|
|
"../../node_modules/.pnpm/strtok3@10.6.2/node_modules/strtok3/lib/ReadStreamTokenizer.js"() {
|
|
init_AbstractTokenizer();
|
|
init_stream();
|
|
ignoreChunkSize = 256e3;
|
|
ReadStreamTokenizer = class extends AbstractTokenizer {
|
|
static {
|
|
__name(this, "ReadStreamTokenizer");
|
|
}
|
|
/**
|
|
* Constructor
|
|
* @param streamReader stream-reader to read from
|
|
* @param options Tokenizer options
|
|
*/
|
|
constructor(streamReader, options) {
|
|
super(options);
|
|
this.streamReader = streamReader;
|
|
this.fileInfo = options?.fileInfo ?? {};
|
|
}
|
|
/**
|
|
* Read buffer from tokenizer
|
|
* @param uint8Array - Target Uint8Array to fill with data read from the tokenizer-stream
|
|
* @param options - Read behaviour options
|
|
* @returns Promise with number of bytes read
|
|
*/
|
|
async readBuffer(uint8Array, options) {
|
|
const normOptions = this.normalizeOptions(uint8Array, options);
|
|
const skipBytes = normOptions.position - this.position;
|
|
if (skipBytes > 0) {
|
|
await this.ignore(skipBytes);
|
|
return this.readBuffer(uint8Array, options);
|
|
}
|
|
if (skipBytes < 0) {
|
|
throw new Error("`options.position` must be equal or greater than `tokenizer.position`");
|
|
}
|
|
if (normOptions.length === 0) {
|
|
return 0;
|
|
}
|
|
let bytesRead = 0;
|
|
while (bytesRead < normOptions.length) {
|
|
const chunkLength = Math.min(this.maxBufferSize, normOptions.length - bytesRead);
|
|
const count = await this.streamReader.read(uint8Array.subarray(bytesRead, bytesRead + chunkLength), true);
|
|
bytesRead += count;
|
|
this.position += count;
|
|
if (count < chunkLength) {
|
|
break;
|
|
}
|
|
}
|
|
if (!normOptions.mayBeLess && bytesRead < normOptions.length) {
|
|
throw new EndOfStreamError();
|
|
}
|
|
return bytesRead;
|
|
}
|
|
/**
|
|
* Peek (read ahead) buffer from tokenizer
|
|
* @param uint8Array - Uint8Array (or Buffer) to write data to
|
|
* @param options - Read behaviour options
|
|
* @returns Promise with number of bytes peeked
|
|
*/
|
|
async peekBuffer(uint8Array, options) {
|
|
const normOptions = this.normalizeOptions(uint8Array, options);
|
|
if (normOptions.length === 0) {
|
|
return 0;
|
|
}
|
|
const lookaheadSize = normOptions.length + normOptions.position - this.position;
|
|
this.validateBufferSize(lookaheadSize);
|
|
let bytesRead = 0;
|
|
if (normOptions.position) {
|
|
const skipBytes = normOptions.position - this.position;
|
|
if (skipBytes > 0) {
|
|
const skipBuffer = new Uint8Array(normOptions.length + skipBytes);
|
|
bytesRead = await this.peekBuffer(skipBuffer, { mayBeLess: normOptions.mayBeLess });
|
|
const bytesPeeked = Math.max(0, bytesRead - skipBytes);
|
|
uint8Array.set(skipBuffer.subarray(skipBytes, skipBytes + bytesPeeked));
|
|
return bytesPeeked;
|
|
}
|
|
if (skipBytes < 0) {
|
|
throw new Error("Cannot peek from a negative offset in a stream");
|
|
}
|
|
}
|
|
if (normOptions.length > 0) {
|
|
try {
|
|
const peekBuffer = new Uint8Array(normOptions.length);
|
|
bytesRead = await this.streamReader.peek(peekBuffer, true);
|
|
uint8Array.set(peekBuffer.subarray(0, bytesRead));
|
|
} catch (err) {
|
|
if (options?.mayBeLess && err instanceof EndOfStreamError) {
|
|
return 0;
|
|
}
|
|
throw err;
|
|
}
|
|
if (!normOptions.mayBeLess && bytesRead < normOptions.length) {
|
|
throw new EndOfStreamError();
|
|
}
|
|
}
|
|
return bytesRead;
|
|
}
|
|
/**
|
|
* @param length Number of bytes to ignore. Must be ≥ 0.
|
|
*/
|
|
async ignore(length) {
|
|
if (length < 0) {
|
|
throw new RangeError("ignore length must be \u2265 0 bytes");
|
|
}
|
|
this.validateLength(length, "ignore length");
|
|
this.validateLength(this.position + length, "end position");
|
|
const bufSize = Math.min(ignoreChunkSize, this.maxBufferSize, length);
|
|
const buf = new Uint8Array(bufSize);
|
|
let totBytesRead = 0;
|
|
while (totBytesRead < length) {
|
|
const remaining = length - totBytesRead;
|
|
const bytesRead = await this.readBuffer(buf, { length: Math.min(bufSize, remaining) });
|
|
if (bytesRead < 0) {
|
|
return bytesRead;
|
|
}
|
|
totBytesRead += bytesRead;
|
|
}
|
|
return totBytesRead;
|
|
}
|
|
abort() {
|
|
this.removeAbortListener();
|
|
return this.streamReader.abort();
|
|
}
|
|
async close() {
|
|
this.removeAbortListener();
|
|
return this.streamReader.close();
|
|
}
|
|
supportsRandomAccess() {
|
|
return false;
|
|
}
|
|
};
|
|
}
|
|
});
|
|
|
|
// ../../node_modules/.pnpm/strtok3@10.6.2/node_modules/strtok3/lib/isRandomAccessTokenizer.js
|
|
var init_isRandomAccessTokenizer = __esm({
|
|
"../../node_modules/.pnpm/strtok3@10.6.2/node_modules/strtok3/lib/isRandomAccessTokenizer.js"() {
|
|
}
|
|
});
|
|
|
|
// ../../node_modules/.pnpm/strtok3@10.6.2/node_modules/strtok3/lib/TokenizerBoundaryError.js
|
|
var init_TokenizerBoundaryError = __esm({
|
|
"../../node_modules/.pnpm/strtok3@10.6.2/node_modules/strtok3/lib/TokenizerBoundaryError.js"() {
|
|
}
|
|
});
|
|
|
|
// ../../node_modules/.pnpm/strtok3@10.6.2/node_modules/strtok3/lib/TokenizerView.js
|
|
var init_TokenizerView = __esm({
|
|
"../../node_modules/.pnpm/strtok3@10.6.2/node_modules/strtok3/lib/TokenizerView.js"() {
|
|
init_isRandomAccessTokenizer();
|
|
init_stream();
|
|
init_TokenizerBoundaryError();
|
|
}
|
|
});
|
|
|
|
// ../../node_modules/.pnpm/strtok3@10.6.2/node_modules/strtok3/lib/core.js
|
|
function fromWebStream(webStream, options) {
|
|
getMaxBufferSize(options);
|
|
throwIfAborted(options?.abortSignal);
|
|
const webStreamReader = makeWebStreamReader(webStream);
|
|
return new ReadStreamTokenizer(webStreamReader, options);
|
|
}
|
|
function fromBuffer(uint8Array, options) {
|
|
return new BufferTokenizer(uint8Array, options);
|
|
}
|
|
function fromBlob(blob, options) {
|
|
return new BlobTokenizer(blob, options);
|
|
}
|
|
var init_core = __esm({
|
|
"../../node_modules/.pnpm/strtok3@10.6.2/node_modules/strtok3/lib/core.js"() {
|
|
init_AbortSignal();
|
|
init_BlobTokenizer();
|
|
init_BufferSizeError();
|
|
init_BufferTokenizer();
|
|
init_ReadStreamTokenizer();
|
|
init_stream();
|
|
init_AbstractTokenizer();
|
|
init_BufferSizeError();
|
|
init_isRandomAccessTokenizer();
|
|
init_stream();
|
|
init_TokenizerBoundaryError();
|
|
init_TokenizerView();
|
|
__name(fromWebStream, "fromWebStream");
|
|
__name(fromBuffer, "fromBuffer");
|
|
__name(fromBlob, "fromBlob");
|
|
}
|
|
});
|
|
|
|
// ../../node_modules/.pnpm/@tokenizer+inflate@0.4.1/node_modules/@tokenizer/inflate/lib/ZipToken.js
|
|
var Signature, DataDescriptor, LocalFileHeaderToken, EndOfCentralDirectoryRecordToken, FileHeader;
|
|
var init_ZipToken = __esm({
|
|
"../../node_modules/.pnpm/@tokenizer+inflate@0.4.1/node_modules/@tokenizer/inflate/lib/ZipToken.js"() {
|
|
init_lib2();
|
|
Signature = {
|
|
LocalFileHeader: 67324752,
|
|
DataDescriptor: 134695760,
|
|
CentralFileHeader: 33639248,
|
|
EndOfCentralDirectory: 101010256
|
|
};
|
|
DataDescriptor = {
|
|
get(array) {
|
|
return {
|
|
signature: UINT32_LE.get(array, 0),
|
|
compressedSize: UINT32_LE.get(array, 8),
|
|
uncompressedSize: UINT32_LE.get(array, 12)
|
|
};
|
|
},
|
|
len: 16
|
|
};
|
|
LocalFileHeaderToken = {
|
|
get(array) {
|
|
const flags = UINT16_LE.get(array, 6);
|
|
return {
|
|
signature: UINT32_LE.get(array, 0),
|
|
minVersion: UINT16_LE.get(array, 4),
|
|
dataDescriptor: !!(flags & 8),
|
|
compressedMethod: UINT16_LE.get(array, 8),
|
|
compressedSize: UINT32_LE.get(array, 18),
|
|
uncompressedSize: UINT32_LE.get(array, 22),
|
|
filenameLength: UINT16_LE.get(array, 26),
|
|
extraFieldLength: UINT16_LE.get(array, 28),
|
|
filename: null
|
|
};
|
|
},
|
|
len: 30
|
|
};
|
|
EndOfCentralDirectoryRecordToken = {
|
|
get(array) {
|
|
return {
|
|
signature: UINT32_LE.get(array, 0),
|
|
nrOfThisDisk: UINT16_LE.get(array, 4),
|
|
nrOfThisDiskWithTheStart: UINT16_LE.get(array, 6),
|
|
nrOfEntriesOnThisDisk: UINT16_LE.get(array, 8),
|
|
nrOfEntriesOfSize: UINT16_LE.get(array, 10),
|
|
sizeOfCd: UINT32_LE.get(array, 12),
|
|
offsetOfStartOfCd: UINT32_LE.get(array, 16),
|
|
zipFileCommentLength: UINT16_LE.get(array, 20)
|
|
};
|
|
},
|
|
len: 22
|
|
};
|
|
FileHeader = {
|
|
get(array) {
|
|
const flags = UINT16_LE.get(array, 8);
|
|
return {
|
|
signature: UINT32_LE.get(array, 0),
|
|
minVersion: UINT16_LE.get(array, 6),
|
|
dataDescriptor: !!(flags & 8),
|
|
compressedMethod: UINT16_LE.get(array, 10),
|
|
compressedSize: UINT32_LE.get(array, 20),
|
|
uncompressedSize: UINT32_LE.get(array, 24),
|
|
filenameLength: UINT16_LE.get(array, 28),
|
|
extraFieldLength: UINT16_LE.get(array, 30),
|
|
fileCommentLength: UINT16_LE.get(array, 32),
|
|
relativeOffsetOfLocalHeader: UINT32_LE.get(array, 42),
|
|
filename: null
|
|
};
|
|
},
|
|
len: 46
|
|
};
|
|
}
|
|
});
|
|
|
|
// ../../node_modules/.pnpm/@tokenizer+inflate@0.4.1/node_modules/@tokenizer/inflate/lib/ZipHandler.js
|
|
function signatureToArray(signature) {
|
|
const signatureBytes = new Uint8Array(UINT32_LE.len);
|
|
UINT32_LE.put(signatureBytes, 0, signature);
|
|
return signatureBytes;
|
|
}
|
|
function indexOf(buffer, portion) {
|
|
const bufferLength = buffer.length;
|
|
const portionLength = portion.length;
|
|
if (portionLength > bufferLength)
|
|
return -1;
|
|
for (let i = 0; i <= bufferLength - portionLength; i++) {
|
|
let found = true;
|
|
for (let j = 0; j < portionLength; j++) {
|
|
if (buffer[i + j] !== portion[j]) {
|
|
found = false;
|
|
break;
|
|
}
|
|
}
|
|
if (found) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
function mergeArrays(chunks) {
|
|
const totalLength = chunks.reduce((acc, curr) => acc + curr.length, 0);
|
|
const mergedArray = new Uint8Array(totalLength);
|
|
let offset = 0;
|
|
for (const chunk of chunks) {
|
|
mergedArray.set(chunk, offset);
|
|
offset += chunk.length;
|
|
}
|
|
return mergedArray;
|
|
}
|
|
var import_debug, debug, syncBufferSize, ddSignatureArray, eocdSignatureBytes, ZipHandler;
|
|
var init_ZipHandler = __esm({
|
|
"../../node_modules/.pnpm/@tokenizer+inflate@0.4.1/node_modules/@tokenizer/inflate/lib/ZipHandler.js"() {
|
|
init_lib2();
|
|
import_debug = __toESM(require_src(), 1);
|
|
init_ZipToken();
|
|
__name(signatureToArray, "signatureToArray");
|
|
debug = (0, import_debug.default)("tokenizer:inflate");
|
|
syncBufferSize = 256 * 1024;
|
|
ddSignatureArray = signatureToArray(Signature.DataDescriptor);
|
|
eocdSignatureBytes = signatureToArray(Signature.EndOfCentralDirectory);
|
|
ZipHandler = class _ZipHandler {
|
|
static {
|
|
__name(this, "ZipHandler");
|
|
}
|
|
constructor(tokenizer) {
|
|
this.tokenizer = tokenizer;
|
|
this.syncBuffer = new Uint8Array(syncBufferSize);
|
|
}
|
|
async isZip() {
|
|
return await this.peekSignature() === Signature.LocalFileHeader;
|
|
}
|
|
peekSignature() {
|
|
return this.tokenizer.peekToken(UINT32_LE);
|
|
}
|
|
async findEndOfCentralDirectoryLocator() {
|
|
const randomReadTokenizer = this.tokenizer;
|
|
const chunkLength = Math.min(16 * 1024, randomReadTokenizer.fileInfo.size);
|
|
const buffer = this.syncBuffer.subarray(0, chunkLength);
|
|
await this.tokenizer.readBuffer(buffer, { position: randomReadTokenizer.fileInfo.size - chunkLength });
|
|
for (let i = buffer.length - 4; i >= 0; i--) {
|
|
if (buffer[i] === eocdSignatureBytes[0] && buffer[i + 1] === eocdSignatureBytes[1] && buffer[i + 2] === eocdSignatureBytes[2] && buffer[i + 3] === eocdSignatureBytes[3]) {
|
|
return randomReadTokenizer.fileInfo.size - chunkLength + i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
async readCentralDirectory() {
|
|
if (!this.tokenizer.supportsRandomAccess()) {
|
|
debug("Cannot reading central-directory without random-read support");
|
|
return;
|
|
}
|
|
debug("Reading central-directory...");
|
|
const pos = this.tokenizer.position;
|
|
const offset = await this.findEndOfCentralDirectoryLocator();
|
|
if (offset > 0) {
|
|
debug("Central-directory 32-bit signature found");
|
|
const eocdHeader = await this.tokenizer.readToken(EndOfCentralDirectoryRecordToken, offset);
|
|
const files = [];
|
|
this.tokenizer.setPosition(eocdHeader.offsetOfStartOfCd);
|
|
for (let n = 0; n < eocdHeader.nrOfEntriesOfSize; ++n) {
|
|
const entry = await this.tokenizer.readToken(FileHeader);
|
|
if (entry.signature !== Signature.CentralFileHeader) {
|
|
throw new Error("Expected Central-File-Header signature");
|
|
}
|
|
entry.filename = await this.tokenizer.readToken(new StringType(entry.filenameLength, "utf-8"));
|
|
await this.tokenizer.ignore(entry.extraFieldLength);
|
|
await this.tokenizer.ignore(entry.fileCommentLength);
|
|
files.push(entry);
|
|
debug(`Add central-directory file-entry: n=${n + 1}/${files.length}: filename=${files[n].filename}`);
|
|
}
|
|
this.tokenizer.setPosition(pos);
|
|
return files;
|
|
}
|
|
this.tokenizer.setPosition(pos);
|
|
}
|
|
async unzip(fileCb) {
|
|
const entries = await this.readCentralDirectory();
|
|
if (entries) {
|
|
return this.iterateOverCentralDirectory(entries, fileCb);
|
|
}
|
|
let stop = false;
|
|
do {
|
|
const zipHeader = await this.readLocalFileHeader();
|
|
if (!zipHeader)
|
|
break;
|
|
const next = fileCb(zipHeader);
|
|
stop = !!next.stop;
|
|
let fileData;
|
|
await this.tokenizer.ignore(zipHeader.extraFieldLength);
|
|
if (zipHeader.dataDescriptor && zipHeader.compressedSize === 0) {
|
|
const chunks = [];
|
|
let len = syncBufferSize;
|
|
debug("Compressed-file-size unknown, scanning for next data-descriptor-signature....");
|
|
let nextHeaderIndex = -1;
|
|
while (nextHeaderIndex < 0 && len === syncBufferSize) {
|
|
len = await this.tokenizer.peekBuffer(this.syncBuffer, { mayBeLess: true });
|
|
nextHeaderIndex = indexOf(this.syncBuffer.subarray(0, len), ddSignatureArray);
|
|
const size = nextHeaderIndex >= 0 ? nextHeaderIndex : len;
|
|
if (next.handler) {
|
|
const data = new Uint8Array(size);
|
|
await this.tokenizer.readBuffer(data);
|
|
chunks.push(data);
|
|
} else {
|
|
await this.tokenizer.ignore(size);
|
|
}
|
|
}
|
|
debug(`Found data-descriptor-signature at pos=${this.tokenizer.position}`);
|
|
if (next.handler) {
|
|
await this.inflate(zipHeader, mergeArrays(chunks), next.handler);
|
|
}
|
|
} else {
|
|
if (next.handler) {
|
|
debug(`Reading compressed-file-data: ${zipHeader.compressedSize} bytes`);
|
|
fileData = new Uint8Array(zipHeader.compressedSize);
|
|
await this.tokenizer.readBuffer(fileData);
|
|
await this.inflate(zipHeader, fileData, next.handler);
|
|
} else {
|
|
debug(`Ignoring compressed-file-data: ${zipHeader.compressedSize} bytes`);
|
|
await this.tokenizer.ignore(zipHeader.compressedSize);
|
|
}
|
|
}
|
|
debug(`Reading data-descriptor at pos=${this.tokenizer.position}`);
|
|
if (zipHeader.dataDescriptor) {
|
|
const dataDescriptor = await this.tokenizer.readToken(DataDescriptor);
|
|
if (dataDescriptor.signature !== 134695760) {
|
|
throw new Error(`Expected data-descriptor-signature at position ${this.tokenizer.position - DataDescriptor.len}`);
|
|
}
|
|
}
|
|
} while (!stop);
|
|
}
|
|
async iterateOverCentralDirectory(entries, fileCb) {
|
|
for (const fileHeader of entries) {
|
|
const next = fileCb(fileHeader);
|
|
if (next.handler) {
|
|
this.tokenizer.setPosition(fileHeader.relativeOffsetOfLocalHeader);
|
|
const zipHeader = await this.readLocalFileHeader();
|
|
if (zipHeader) {
|
|
await this.tokenizer.ignore(zipHeader.extraFieldLength);
|
|
const fileData = new Uint8Array(fileHeader.compressedSize);
|
|
await this.tokenizer.readBuffer(fileData);
|
|
await this.inflate(zipHeader, fileData, next.handler);
|
|
}
|
|
}
|
|
if (next.stop)
|
|
break;
|
|
}
|
|
}
|
|
async inflate(zipHeader, fileData, cb) {
|
|
if (zipHeader.compressedMethod === 0) {
|
|
return cb(fileData);
|
|
}
|
|
if (zipHeader.compressedMethod !== 8) {
|
|
throw new Error(`Unsupported ZIP compression method: ${zipHeader.compressedMethod}`);
|
|
}
|
|
debug(`Decompress filename=${zipHeader.filename}, compressed-size=${fileData.length}`);
|
|
const uncompressedData = await _ZipHandler.decompressDeflateRaw(fileData);
|
|
return cb(uncompressedData);
|
|
}
|
|
static async decompressDeflateRaw(data) {
|
|
const input = new ReadableStream({
|
|
start(controller) {
|
|
controller.enqueue(data);
|
|
controller.close();
|
|
}
|
|
});
|
|
const ds = new DecompressionStream("deflate-raw");
|
|
const output = input.pipeThrough(ds);
|
|
try {
|
|
const response = new Response(output);
|
|
const buffer = await response.arrayBuffer();
|
|
return new Uint8Array(buffer);
|
|
} catch (err) {
|
|
const message = err instanceof Error ? `Failed to deflate ZIP entry: ${err.message}` : "Unknown decompression error in ZIP entry";
|
|
throw new TypeError(message);
|
|
}
|
|
}
|
|
async readLocalFileHeader() {
|
|
const signature = await this.tokenizer.peekToken(UINT32_LE);
|
|
if (signature === Signature.LocalFileHeader) {
|
|
const header = await this.tokenizer.readToken(LocalFileHeaderToken);
|
|
header.filename = await this.tokenizer.readToken(new StringType(header.filenameLength, "utf-8"));
|
|
return header;
|
|
}
|
|
if (signature === Signature.CentralFileHeader) {
|
|
return false;
|
|
}
|
|
if (signature === 3759263696) {
|
|
throw new Error("Encrypted ZIP");
|
|
}
|
|
throw new Error("Unexpected signature");
|
|
}
|
|
};
|
|
__name(indexOf, "indexOf");
|
|
__name(mergeArrays, "mergeArrays");
|
|
}
|
|
});
|
|
|
|
// ../../node_modules/.pnpm/@tokenizer+inflate@0.4.1/node_modules/@tokenizer/inflate/lib/GzipHandler.js
|
|
var GzipHandler;
|
|
var init_GzipHandler = __esm({
|
|
"../../node_modules/.pnpm/@tokenizer+inflate@0.4.1/node_modules/@tokenizer/inflate/lib/GzipHandler.js"() {
|
|
GzipHandler = class {
|
|
static {
|
|
__name(this, "GzipHandler");
|
|
}
|
|
constructor(tokenizer) {
|
|
this.tokenizer = tokenizer;
|
|
}
|
|
inflate() {
|
|
const tokenizer = this.tokenizer;
|
|
return new ReadableStream({
|
|
async pull(controller) {
|
|
const buffer = new Uint8Array(1024);
|
|
const size = await tokenizer.readBuffer(buffer, { mayBeLess: true });
|
|
if (size === 0) {
|
|
controller.close();
|
|
return;
|
|
}
|
|
controller.enqueue(buffer.subarray(0, size));
|
|
}
|
|
}).pipeThrough(new DecompressionStream("gzip"));
|
|
}
|
|
};
|
|
}
|
|
});
|
|
|
|
// ../../node_modules/.pnpm/@tokenizer+inflate@0.4.1/node_modules/@tokenizer/inflate/lib/index.js
|
|
var init_lib3 = __esm({
|
|
"../../node_modules/.pnpm/@tokenizer+inflate@0.4.1/node_modules/@tokenizer/inflate/lib/index.js"() {
|
|
init_ZipHandler();
|
|
init_GzipHandler();
|
|
}
|
|
});
|
|
|
|
// ../../node_modules/.pnpm/uint8array-extras@1.6.0/node_modules/uint8array-extras/index.js
|
|
function isType(value, typeConstructor, typeStringified) {
|
|
if (!value) {
|
|
return false;
|
|
}
|
|
if (value.constructor === typeConstructor) {
|
|
return true;
|
|
}
|
|
return objectToString.call(value) === typeStringified;
|
|
}
|
|
function isUint8Array(value) {
|
|
return isType(value, Uint8Array, uint8ArrayStringified);
|
|
}
|
|
function isArrayBuffer(value) {
|
|
return isType(value, ArrayBuffer, arrayBufferStringified);
|
|
}
|
|
function isUint8ArrayOrArrayBuffer(value) {
|
|
return isUint8Array(value) || isArrayBuffer(value);
|
|
}
|
|
function toUint8ArrayIfArrayBuffer(value) {
|
|
return isArrayBuffer(value) ? new Uint8Array(value) : value;
|
|
}
|
|
function assertUint8ArrayOrArrayBuffer(value) {
|
|
if (!isUint8ArrayOrArrayBuffer(value)) {
|
|
throw new TypeError(`Expected \`Uint8Array\` or \`ArrayBuffer\`, got \`${typeof value}\``);
|
|
}
|
|
}
|
|
function concatUint8Arrays(arrays, totalLength) {
|
|
if (arrays.length === 0) {
|
|
return new Uint8Array(0);
|
|
}
|
|
totalLength ??= arrays.reduce((accumulator, currentValue) => accumulator + currentValue.byteLength, 0);
|
|
const returnValue = new Uint8Array(totalLength);
|
|
let offset = 0;
|
|
for (let array of arrays) {
|
|
assertUint8ArrayOrArrayBuffer(array);
|
|
array = toUint8ArrayIfArrayBuffer(array);
|
|
returnValue.set(array, offset);
|
|
offset += array.length;
|
|
}
|
|
return returnValue;
|
|
}
|
|
function getUintBE(view) {
|
|
const { byteLength } = view;
|
|
if (byteLength === 6) {
|
|
return view.getUint16(0) * 2 ** 32 + view.getUint32(2);
|
|
}
|
|
if (byteLength === 5) {
|
|
return view.getUint8(0) * 2 ** 32 + view.getUint32(1);
|
|
}
|
|
if (byteLength === 4) {
|
|
return view.getUint32(0);
|
|
}
|
|
if (byteLength === 3) {
|
|
return view.getUint8(0) * 2 ** 16 + view.getUint16(1);
|
|
}
|
|
if (byteLength === 2) {
|
|
return view.getUint16(0);
|
|
}
|
|
if (byteLength === 1) {
|
|
return view.getUint8(0);
|
|
}
|
|
}
|
|
var objectToString, uint8ArrayStringified, arrayBufferStringified, cachedDecoders, cachedEncoder, byteToHexLookupTable;
|
|
var init_uint8array_extras = __esm({
|
|
"../../node_modules/.pnpm/uint8array-extras@1.6.0/node_modules/uint8array-extras/index.js"() {
|
|
objectToString = Object.prototype.toString;
|
|
uint8ArrayStringified = "[object Uint8Array]";
|
|
arrayBufferStringified = "[object ArrayBuffer]";
|
|
__name(isType, "isType");
|
|
__name(isUint8Array, "isUint8Array");
|
|
__name(isArrayBuffer, "isArrayBuffer");
|
|
__name(isUint8ArrayOrArrayBuffer, "isUint8ArrayOrArrayBuffer");
|
|
__name(toUint8ArrayIfArrayBuffer, "toUint8ArrayIfArrayBuffer");
|
|
__name(assertUint8ArrayOrArrayBuffer, "assertUint8ArrayOrArrayBuffer");
|
|
__name(concatUint8Arrays, "concatUint8Arrays");
|
|
cachedDecoders = {
|
|
utf8: new globalThis.TextDecoder("utf8")
|
|
};
|
|
cachedEncoder = new globalThis.TextEncoder();
|
|
byteToHexLookupTable = Array.from({ length: 256 }, (_, index) => index.toString(16).padStart(2, "0"));
|
|
__name(getUintBE, "getUintBE");
|
|
}
|
|
});
|
|
|
|
// ../../node_modules/.pnpm/file-type@22.1.1/node_modules/file-type/source/tokens.js
|
|
function stringToBytes(string, encoding) {
|
|
if (encoding === "utf-16le") {
|
|
const bytes = [];
|
|
for (let index = 0; index < string.length; index++) {
|
|
const code = string.charCodeAt(index);
|
|
bytes.push(code & 255, code >> 8 & 255);
|
|
}
|
|
return bytes;
|
|
}
|
|
if (encoding === "utf-16be") {
|
|
const bytes = [];
|
|
for (let index = 0; index < string.length; index++) {
|
|
const code = string.charCodeAt(index);
|
|
bytes.push(code >> 8 & 255, code & 255);
|
|
}
|
|
return bytes;
|
|
}
|
|
return [...string].map((character) => character.charCodeAt(0));
|
|
}
|
|
function tarHeaderChecksumMatches(arrayBuffer, offset = 0) {
|
|
const readSum = Number.parseInt(new StringType(6).get(arrayBuffer, 148).replace(new RegExp("\\0.*$", "v"), "").trim(), 8);
|
|
if (Number.isNaN(readSum)) {
|
|
return false;
|
|
}
|
|
let sum = 8 * 32;
|
|
for (let index = offset; index < offset + 148; index++) {
|
|
sum += arrayBuffer[index];
|
|
}
|
|
for (let index = offset + 156; index < offset + 512; index++) {
|
|
sum += arrayBuffer[index];
|
|
}
|
|
return readSum === sum;
|
|
}
|
|
var uint32SyncSafeToken;
|
|
var init_tokens = __esm({
|
|
"../../node_modules/.pnpm/file-type@22.1.1/node_modules/file-type/source/tokens.js"() {
|
|
init_lib2();
|
|
__name(stringToBytes, "stringToBytes");
|
|
__name(tarHeaderChecksumMatches, "tarHeaderChecksumMatches");
|
|
uint32SyncSafeToken = {
|
|
get: /* @__PURE__ */ __name((buffer, offset) => buffer[offset + 3] & 127 | (buffer[offset + 2] & 127) << 7 | (buffer[offset + 1] & 127) << 14 | (buffer[offset] & 127) << 21, "get"),
|
|
len: 4
|
|
};
|
|
}
|
|
});
|
|
|
|
// ../../node_modules/.pnpm/file-type@22.1.1/node_modules/file-type/source/supported.js
|
|
var extensions, mimeTypes;
|
|
var init_supported = __esm({
|
|
"../../node_modules/.pnpm/file-type@22.1.1/node_modules/file-type/source/supported.js"() {
|
|
extensions = [
|
|
"jpg",
|
|
"png",
|
|
"apng",
|
|
"gif",
|
|
"webp",
|
|
"flif",
|
|
"xcf",
|
|
"cr2",
|
|
"cr3",
|
|
"orf",
|
|
"arw",
|
|
"dng",
|
|
"nef",
|
|
"rw2",
|
|
"raf",
|
|
"tif",
|
|
"bmp",
|
|
"icns",
|
|
"jxr",
|
|
"psd",
|
|
"indd",
|
|
"zip",
|
|
"tar",
|
|
"rar",
|
|
"gz",
|
|
"bz2",
|
|
"7z",
|
|
"dmg",
|
|
"mp4",
|
|
"mid",
|
|
"mkv",
|
|
"webm",
|
|
"mov",
|
|
"avi",
|
|
"mpg",
|
|
"mp2",
|
|
"mp3",
|
|
"m4a",
|
|
"oga",
|
|
"ogg",
|
|
"ogv",
|
|
"opus",
|
|
"flac",
|
|
"wav",
|
|
"spx",
|
|
"amr",
|
|
"pdf",
|
|
"epub",
|
|
"elf",
|
|
"macho",
|
|
"exe",
|
|
"swf",
|
|
"rtf",
|
|
"wasm",
|
|
"woff",
|
|
"woff2",
|
|
"eot",
|
|
"ttf",
|
|
"otf",
|
|
"ttc",
|
|
"ico",
|
|
"flv",
|
|
"ps",
|
|
"xz",
|
|
"sqlite",
|
|
"nes",
|
|
"crx",
|
|
"xpi",
|
|
"cab",
|
|
"deb",
|
|
"ar",
|
|
"rpm",
|
|
"Z",
|
|
"lz",
|
|
"cfb",
|
|
"mxf",
|
|
"mts",
|
|
"blend",
|
|
"bpg",
|
|
"docx",
|
|
"pptx",
|
|
"xlsx",
|
|
"3gp",
|
|
"3g2",
|
|
"j2c",
|
|
"jp2",
|
|
"jpm",
|
|
"jpx",
|
|
"mj2",
|
|
"aif",
|
|
"qcp",
|
|
"odt",
|
|
"ods",
|
|
"odp",
|
|
"xml",
|
|
"mobi",
|
|
"heic",
|
|
"cur",
|
|
"ktx",
|
|
"ape",
|
|
"wv",
|
|
"dcm",
|
|
"ics",
|
|
"glb",
|
|
"pcap",
|
|
"dsf",
|
|
"lnk",
|
|
"alias",
|
|
"voc",
|
|
"ac3",
|
|
"m4v",
|
|
"m4p",
|
|
"m4b",
|
|
"f4v",
|
|
"f4p",
|
|
"f4b",
|
|
"f4a",
|
|
"mie",
|
|
"asf",
|
|
"ogm",
|
|
"ogx",
|
|
"mpc",
|
|
"arrow",
|
|
"shp",
|
|
"aac",
|
|
"mp1",
|
|
"it",
|
|
"s3m",
|
|
"xm",
|
|
"skp",
|
|
"avif",
|
|
"eps",
|
|
"lzh",
|
|
"pgp",
|
|
"asar",
|
|
"stl",
|
|
"chm",
|
|
"3mf",
|
|
"zst",
|
|
"jxl",
|
|
"vcf",
|
|
"jls",
|
|
"pst",
|
|
"dwg",
|
|
"parquet",
|
|
"class",
|
|
"arj",
|
|
"cpio",
|
|
"ace",
|
|
"avro",
|
|
"icc",
|
|
"fbx",
|
|
"vsdx",
|
|
"vtt",
|
|
"apk",
|
|
"drc",
|
|
"lz4",
|
|
"potx",
|
|
"xltx",
|
|
"dotx",
|
|
"xltm",
|
|
"ott",
|
|
"ots",
|
|
"otp",
|
|
"odg",
|
|
"otg",
|
|
"xlsm",
|
|
"docm",
|
|
"dotm",
|
|
"potm",
|
|
"pptm",
|
|
"jar",
|
|
"jmp",
|
|
"rm",
|
|
"sav",
|
|
"ppsm",
|
|
"ppsx",
|
|
"tar.gz",
|
|
"reg",
|
|
"dat",
|
|
"key",
|
|
"numbers",
|
|
"pages",
|
|
"iso"
|
|
];
|
|
mimeTypes = [
|
|
"image/jpeg",
|
|
"image/png",
|
|
"image/gif",
|
|
"image/webp",
|
|
"image/flif",
|
|
"image/x-xcf",
|
|
"image/x-canon-cr2",
|
|
"image/x-canon-cr3",
|
|
"image/tiff",
|
|
"image/bmp",
|
|
"image/vnd.ms-photo",
|
|
"image/vnd.adobe.photoshop",
|
|
"application/x-indesign",
|
|
"application/epub+zip",
|
|
"application/x-xpinstall",
|
|
"application/vnd.ms-powerpoint.slideshow.macroenabled.12",
|
|
"application/vnd.oasis.opendocument.text",
|
|
"application/vnd.oasis.opendocument.spreadsheet",
|
|
"application/vnd.oasis.opendocument.presentation",
|
|
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
"application/vnd.openxmlformats-officedocument.presentationml.slideshow",
|
|
"application/zip",
|
|
"application/x-tar",
|
|
"application/x-rar-compressed",
|
|
"application/gzip",
|
|
"application/x-bzip2",
|
|
"application/x-7z-compressed",
|
|
"application/x-apple-diskimage",
|
|
"application/vnd.apache.arrow.file",
|
|
"video/mp4",
|
|
"audio/midi",
|
|
"video/matroska",
|
|
"video/webm",
|
|
"video/quicktime",
|
|
"video/vnd.avi",
|
|
"audio/wav",
|
|
"audio/qcelp",
|
|
"audio/x-ms-asf",
|
|
"video/x-ms-asf",
|
|
"application/vnd.ms-asf",
|
|
"video/mpeg",
|
|
"video/3gpp",
|
|
"audio/mpeg",
|
|
"audio/mp4",
|
|
// RFC 4337
|
|
"video/ogg",
|
|
"audio/ogg",
|
|
"audio/ogg; codecs=opus",
|
|
"application/ogg",
|
|
"audio/flac",
|
|
"audio/ape",
|
|
"audio/wavpack",
|
|
"audio/amr",
|
|
"application/pdf",
|
|
"application/x-elf",
|
|
"application/x-mach-binary",
|
|
"application/x-msdownload",
|
|
"application/x-shockwave-flash",
|
|
"application/rtf",
|
|
"application/wasm",
|
|
"font/woff",
|
|
"font/woff2",
|
|
"application/vnd.ms-fontobject",
|
|
"font/ttf",
|
|
"font/otf",
|
|
"font/collection",
|
|
"image/x-icon",
|
|
"video/x-flv",
|
|
"application/postscript",
|
|
"application/eps",
|
|
"application/x-xz",
|
|
"application/x-sqlite3",
|
|
"application/x-nintendo-nes-rom",
|
|
"application/x-google-chrome-extension",
|
|
"application/vnd.ms-cab-compressed",
|
|
"application/x-deb",
|
|
"application/x-unix-archive",
|
|
"application/x-rpm",
|
|
"application/x-compress",
|
|
"application/lzip",
|
|
"application/x-cfb",
|
|
"application/x-mie",
|
|
"application/mxf",
|
|
"video/mp2t",
|
|
"application/x-blender",
|
|
"image/bpg",
|
|
"image/j2c",
|
|
"image/jp2",
|
|
"image/jpx",
|
|
"image/jpm",
|
|
"image/mj2",
|
|
"audio/aiff",
|
|
"application/xml",
|
|
"application/x-mobipocket-ebook",
|
|
"image/heif",
|
|
"image/heif-sequence",
|
|
"image/heic",
|
|
"image/heic-sequence",
|
|
"image/icns",
|
|
"image/ktx",
|
|
"application/dicom",
|
|
"audio/x-musepack",
|
|
"text/calendar",
|
|
"text/vcard",
|
|
"text/vtt",
|
|
"model/gltf-binary",
|
|
"application/vnd.tcpdump.pcap",
|
|
"audio/x-dsf",
|
|
// Non-standard
|
|
"application/x-ms-shortcut",
|
|
// Informal, used by freedesktop.org shared-mime-info
|
|
"application/x-ft-apple.alias",
|
|
"audio/x-voc",
|
|
"audio/vnd.dolby.dd-raw",
|
|
"audio/x-m4a",
|
|
"image/apng",
|
|
"image/x-olympus-orf",
|
|
"image/x-sony-arw",
|
|
"image/x-adobe-dng",
|
|
"image/x-nikon-nef",
|
|
"image/x-panasonic-rw2",
|
|
"image/x-fujifilm-raf",
|
|
"video/x-m4v",
|
|
"video/3gpp2",
|
|
"application/x-esri-shape",
|
|
"audio/aac",
|
|
"audio/x-it",
|
|
"audio/x-s3m",
|
|
"audio/x-xm",
|
|
"video/MP1S",
|
|
"video/MP2P",
|
|
"application/vnd.sketchup.skp",
|
|
"image/avif",
|
|
"application/x-lzh-compressed",
|
|
"application/pgp-encrypted",
|
|
"application/x-asar",
|
|
"model/stl",
|
|
"application/vnd.ms-htmlhelp",
|
|
"model/3mf",
|
|
"image/jxl",
|
|
"application/zstd",
|
|
"image/jls",
|
|
"application/vnd.ms-outlook",
|
|
"image/vnd.dwg",
|
|
"application/vnd.apache.parquet",
|
|
"application/java-vm",
|
|
"application/x-arj",
|
|
"application/x-cpio",
|
|
"application/x-ace-compressed",
|
|
"application/avro",
|
|
"application/vnd.iccprofile",
|
|
"application/x-ft-fbx",
|
|
"application/vnd.visio",
|
|
"application/vnd.android.package-archive",
|
|
"application/x-ft-draco",
|
|
"application/x-lz4",
|
|
// Informal, used by freedesktop.org shared-mime-info
|
|
"application/vnd.openxmlformats-officedocument.presentationml.template",
|
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.template",
|
|
"application/vnd.openxmlformats-officedocument.wordprocessingml.template",
|
|
"application/vnd.ms-excel.template.macroenabled.12",
|
|
"application/vnd.oasis.opendocument.text-template",
|
|
"application/vnd.oasis.opendocument.spreadsheet-template",
|
|
"application/vnd.oasis.opendocument.presentation-template",
|
|
"application/vnd.oasis.opendocument.graphics",
|
|
"application/vnd.oasis.opendocument.graphics-template",
|
|
"application/vnd.ms-excel.sheet.macroenabled.12",
|
|
"application/vnd.ms-word.document.macroenabled.12",
|
|
"application/vnd.ms-word.template.macroenabled.12",
|
|
"application/vnd.ms-powerpoint.template.macroenabled.12",
|
|
"application/vnd.ms-powerpoint.presentation.macroenabled.12",
|
|
"application/java-archive",
|
|
"application/vnd.rn-realmedia",
|
|
"application/x-spss-sav",
|
|
"application/x-ms-regedit",
|
|
"application/x-ft-windows-registry-hive",
|
|
"application/x-jmp-data",
|
|
"application/vnd.apple.keynote",
|
|
"application/vnd.apple.numbers",
|
|
"application/vnd.apple.pages",
|
|
"application/x-iso9660-image"
|
|
];
|
|
}
|
|
});
|
|
|
|
// ../../node_modules/.pnpm/file-type@22.1.1/node_modules/file-type/source/parser.js
|
|
function getSafeBound(value, maximum, reason) {
|
|
if (!Number.isFinite(value) || value < 0 || value > maximum) {
|
|
throw new ParserHardLimitError(`${reason} has invalid size ${value} (maximum ${maximum} bytes)`);
|
|
}
|
|
return value;
|
|
}
|
|
async function safeIgnore(tokenizer, length, { maximumLength = maximumUntrustedSkipSizeInBytes, reason = "skip" } = {}) {
|
|
const safeLength = getSafeBound(length, maximumLength, reason);
|
|
await tokenizer.ignore(safeLength);
|
|
}
|
|
async function safeReadBuffer(tokenizer, buffer, options, { maximumLength = buffer.length, reason = "read" } = {}) {
|
|
const length = options?.length ?? buffer.length;
|
|
const safeLength = getSafeBound(length, maximumLength, reason);
|
|
return tokenizer.readBuffer(buffer, {
|
|
...options,
|
|
length: safeLength
|
|
});
|
|
}
|
|
function checkBytes(buffer, headers, options) {
|
|
options = {
|
|
offset: 0,
|
|
...options
|
|
};
|
|
for (const [index, header] of headers.entries()) {
|
|
if (options.mask) {
|
|
if (header !== (options.mask[index] & buffer[index + options.offset])) {
|
|
return false;
|
|
}
|
|
} else if (header !== buffer[index + options.offset]) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
function hasUnknownFileSize(tokenizer) {
|
|
const fileSize = tokenizer.fileInfo.size;
|
|
return !Number.isFinite(fileSize) || fileSize === Number.MAX_SAFE_INTEGER;
|
|
}
|
|
function hasExceededUnknownSizeScanBudget(tokenizer, startOffset, maximumBytes) {
|
|
return hasUnknownFileSize(tokenizer) && tokenizer.position - startOffset > maximumBytes;
|
|
}
|
|
var maximumUntrustedSkipSizeInBytes, ParserHardLimitError;
|
|
var init_parser = __esm({
|
|
"../../node_modules/.pnpm/file-type@22.1.1/node_modules/file-type/source/parser.js"() {
|
|
maximumUntrustedSkipSizeInBytes = 16 * 1024 * 1024;
|
|
ParserHardLimitError = class extends Error {
|
|
static {
|
|
__name(this, "ParserHardLimitError");
|
|
}
|
|
};
|
|
__name(getSafeBound, "getSafeBound");
|
|
__name(safeIgnore, "safeIgnore");
|
|
__name(safeReadBuffer, "safeReadBuffer");
|
|
__name(checkBytes, "checkBytes");
|
|
__name(hasUnknownFileSize, "hasUnknownFileSize");
|
|
__name(hasExceededUnknownSizeScanBudget, "hasExceededUnknownSizeScanBudget");
|
|
}
|
|
});
|
|
|
|
// ../../node_modules/.pnpm/file-type@22.1.1/node_modules/file-type/source/detectors/zip.js
|
|
async function decompressDeflateRawWithLimit(data, { maximumLength = maximumZipEntrySizeInBytes } = {}) {
|
|
const input = new ReadableStream({
|
|
start(controller) {
|
|
controller.enqueue(data);
|
|
controller.close();
|
|
}
|
|
});
|
|
const output = input.pipeThrough(new DecompressionStream("deflate-raw"));
|
|
const reader = output.getReader();
|
|
const chunks = [];
|
|
let totalLength = 0;
|
|
try {
|
|
for (; ; ) {
|
|
const { done, value } = await reader.read();
|
|
if (done) {
|
|
break;
|
|
}
|
|
totalLength += value.length;
|
|
if (totalLength > maximumLength) {
|
|
await reader.cancel().catch(() => {
|
|
});
|
|
throw new Error(`ZIP entry decompressed data exceeds ${maximumLength} bytes`);
|
|
}
|
|
chunks.push(value);
|
|
}
|
|
} catch (error) {
|
|
if (error.code !== "ERR_TRAILING_JUNK_AFTER_STREAM_END") {
|
|
throw error;
|
|
}
|
|
} finally {
|
|
reader.releaseLock();
|
|
}
|
|
const uncompressedData = new Uint8Array(totalLength);
|
|
let offset = 0;
|
|
for (const chunk of chunks) {
|
|
uncompressedData.set(chunk, offset);
|
|
offset += chunk.length;
|
|
}
|
|
return uncompressedData;
|
|
}
|
|
function mergeByteChunks(chunks, totalLength) {
|
|
const merged = new Uint8Array(totalLength);
|
|
let offset = 0;
|
|
for (const chunk of chunks) {
|
|
merged.set(chunk, offset);
|
|
offset += chunk.length;
|
|
}
|
|
return merged;
|
|
}
|
|
function getMaximumZipBufferedReadLength(tokenizer) {
|
|
const fileSize = tokenizer.fileInfo.size;
|
|
const remainingBytes = Number.isFinite(fileSize) ? Math.max(0, fileSize - tokenizer.position) : Number.MAX_SAFE_INTEGER;
|
|
return Math.min(remainingBytes, maximumZipBufferedReadSizeInBytes);
|
|
}
|
|
function isRecoverableZipError(error) {
|
|
if (error instanceof EndOfStreamError) {
|
|
return true;
|
|
}
|
|
if (error instanceof ParserHardLimitError) {
|
|
return true;
|
|
}
|
|
if (!(error instanceof Error)) {
|
|
return false;
|
|
}
|
|
if (recoverableZipErrorMessages.has(error.message)) {
|
|
return true;
|
|
}
|
|
if (recoverableZipErrorCodes.has(error.code)) {
|
|
return true;
|
|
}
|
|
for (const prefix of recoverableZipErrorMessagePrefixes) {
|
|
if (error.message.startsWith(prefix)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
function canReadZipEntryForDetection(zipHeader, maximumSize = maximumZipEntrySizeInBytes) {
|
|
const sizes = [zipHeader.compressedSize, zipHeader.uncompressedSize];
|
|
for (const size of sizes) {
|
|
if (!Number.isFinite(size) || size < 0 || size > maximumSize) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
function createIWorkZipDetectionState() {
|
|
return {
|
|
hasDocumentEntry: false,
|
|
hasMasterSlideEntry: false,
|
|
hasTablesEntry: false,
|
|
hasCalculationEngineEntry: false
|
|
};
|
|
}
|
|
function updateIWorkZipDetectionStateFromFilename(iWorkState, filename) {
|
|
if (filename === "Index/Document.iwa") {
|
|
iWorkState.hasDocumentEntry = true;
|
|
}
|
|
if (filename.startsWith("Index/MasterSlide")) {
|
|
iWorkState.hasMasterSlideEntry = true;
|
|
}
|
|
if (filename.startsWith("Index/Tables/")) {
|
|
iWorkState.hasTablesEntry = true;
|
|
}
|
|
if (filename === "Index/CalculationEngine.iwa") {
|
|
iWorkState.hasCalculationEngineEntry = true;
|
|
}
|
|
}
|
|
function getIWorkFileTypeFromZipEntries(iWorkState) {
|
|
if (!iWorkState.hasDocumentEntry) {
|
|
return;
|
|
}
|
|
if (iWorkState.hasMasterSlideEntry) {
|
|
return { ext: "key", mime: "application/vnd.apple.keynote" };
|
|
}
|
|
if (iWorkState.hasTablesEntry) {
|
|
return { ext: "numbers", mime: "application/vnd.apple.numbers" };
|
|
}
|
|
return { ext: "pages", mime: "application/vnd.apple.pages" };
|
|
}
|
|
function getFileTypeFromMimeType(mimeType) {
|
|
mimeType = mimeType.toLowerCase();
|
|
switch (mimeType) {
|
|
case "application/epub+zip":
|
|
return { ext: "epub", mime: mimeType };
|
|
case "application/vnd.oasis.opendocument.text":
|
|
return { ext: "odt", mime: mimeType };
|
|
case "application/vnd.oasis.opendocument.text-template":
|
|
return { ext: "ott", mime: mimeType };
|
|
case "application/vnd.oasis.opendocument.spreadsheet":
|
|
return { ext: "ods", mime: mimeType };
|
|
case "application/vnd.oasis.opendocument.spreadsheet-template":
|
|
return { ext: "ots", mime: mimeType };
|
|
case "application/vnd.oasis.opendocument.presentation":
|
|
return { ext: "odp", mime: mimeType };
|
|
case "application/vnd.oasis.opendocument.presentation-template":
|
|
return { ext: "otp", mime: mimeType };
|
|
case "application/vnd.oasis.opendocument.graphics":
|
|
return { ext: "odg", mime: mimeType };
|
|
case "application/vnd.oasis.opendocument.graphics-template":
|
|
return { ext: "otg", mime: mimeType };
|
|
case "application/vnd.openxmlformats-officedocument.presentationml.slideshow":
|
|
return { ext: "ppsx", mime: mimeType };
|
|
case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":
|
|
return { ext: "xlsx", mime: mimeType };
|
|
case "application/vnd.ms-excel.sheet.macroenabled":
|
|
return { ext: "xlsm", mime: "application/vnd.ms-excel.sheet.macroenabled.12" };
|
|
case "application/vnd.openxmlformats-officedocument.spreadsheetml.template":
|
|
return { ext: "xltx", mime: mimeType };
|
|
case "application/vnd.ms-excel.template.macroenabled":
|
|
return { ext: "xltm", mime: "application/vnd.ms-excel.template.macroenabled.12" };
|
|
case "application/vnd.ms-powerpoint.slideshow.macroenabled":
|
|
return { ext: "ppsm", mime: "application/vnd.ms-powerpoint.slideshow.macroenabled.12" };
|
|
case "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
|
|
return { ext: "docx", mime: mimeType };
|
|
case "application/vnd.ms-word.document.macroenabled":
|
|
return { ext: "docm", mime: "application/vnd.ms-word.document.macroenabled.12" };
|
|
case "application/vnd.openxmlformats-officedocument.wordprocessingml.template":
|
|
return { ext: "dotx", mime: mimeType };
|
|
case "application/vnd.ms-word.template.macroenabledtemplate":
|
|
return { ext: "dotm", mime: "application/vnd.ms-word.template.macroenabled.12" };
|
|
case "application/vnd.openxmlformats-officedocument.presentationml.template":
|
|
return { ext: "potx", mime: mimeType };
|
|
case "application/vnd.ms-powerpoint.template.macroenabled":
|
|
return { ext: "potm", mime: "application/vnd.ms-powerpoint.template.macroenabled.12" };
|
|
case "application/vnd.openxmlformats-officedocument.presentationml.presentation":
|
|
return { ext: "pptx", mime: mimeType };
|
|
case "application/vnd.ms-powerpoint.presentation.macroenabled":
|
|
return { ext: "pptm", mime: "application/vnd.ms-powerpoint.presentation.macroenabled.12" };
|
|
case "application/vnd.ms-visio.drawing":
|
|
return { ext: "vsdx", mime: "application/vnd.visio" };
|
|
case "application/vnd.ms-package.3dmanufacturing-3dmodel+xml":
|
|
return { ext: "3mf", mime: "model/3mf" };
|
|
default:
|
|
}
|
|
}
|
|
function createOpenXmlZipDetectionState() {
|
|
return {
|
|
hasContentTypesEntry: false,
|
|
hasParsedContentTypesEntry: false,
|
|
isParsingContentTypes: false,
|
|
hasUnparseableContentTypes: false,
|
|
hasWordDirectory: false,
|
|
hasPresentationDirectory: false,
|
|
hasSpreadsheetDirectory: false,
|
|
hasThreeDimensionalModelEntry: false
|
|
};
|
|
}
|
|
function updateOpenXmlZipDetectionStateFromFilename(openXmlState, filename) {
|
|
if (filename.startsWith("word/")) {
|
|
openXmlState.hasWordDirectory = true;
|
|
}
|
|
if (filename.startsWith("ppt/")) {
|
|
openXmlState.hasPresentationDirectory = true;
|
|
}
|
|
if (filename.startsWith("xl/")) {
|
|
openXmlState.hasSpreadsheetDirectory = true;
|
|
}
|
|
if (filename.startsWith("3D/") && filename.endsWith(".model")) {
|
|
openXmlState.hasThreeDimensionalModelEntry = true;
|
|
}
|
|
}
|
|
function getOpenXmlFileTypeFromDirectoryNames(openXmlState) {
|
|
if (openXmlState.hasWordDirectory) {
|
|
return {
|
|
ext: "docx",
|
|
mime: "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
|
|
};
|
|
}
|
|
if (openXmlState.hasPresentationDirectory) {
|
|
return {
|
|
ext: "pptx",
|
|
mime: "application/vnd.openxmlformats-officedocument.presentationml.presentation"
|
|
};
|
|
}
|
|
if (openXmlState.hasSpreadsheetDirectory) {
|
|
return {
|
|
ext: "xlsx",
|
|
mime: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
};
|
|
}
|
|
if (openXmlState.hasThreeDimensionalModelEntry) {
|
|
return {
|
|
ext: "3mf",
|
|
mime: "model/3mf"
|
|
};
|
|
}
|
|
}
|
|
function getOpenXmlFileTypeFromZipEntries(openXmlState) {
|
|
if (!openXmlState.hasContentTypesEntry || openXmlState.hasUnparseableContentTypes || openXmlState.isParsingContentTypes || openXmlState.hasParsedContentTypesEntry) {
|
|
return;
|
|
}
|
|
return getOpenXmlFileTypeFromDirectoryNames(openXmlState);
|
|
}
|
|
function getOpenXmlMimeTypeFromContentTypesXml(xmlContent) {
|
|
const endPosition = xmlContent.indexOf('.main+xml"');
|
|
if (endPosition === -1) {
|
|
const mimeType = "application/vnd.ms-package.3dmanufacturing-3dmodel+xml";
|
|
if (xmlContent.includes(`ContentType="${mimeType}"`)) {
|
|
return mimeType;
|
|
}
|
|
return;
|
|
}
|
|
const truncatedContent = xmlContent.slice(0, endPosition);
|
|
const firstQuotePosition = truncatedContent.lastIndexOf('"');
|
|
return truncatedContent.slice(firstQuotePosition + 1);
|
|
}
|
|
function findZipDataDescriptorOffset(buffer, bytesConsumed) {
|
|
if (buffer.length < zipDataDescriptorLengthInBytes) {
|
|
return -1;
|
|
}
|
|
const lastPossibleDescriptorOffset = buffer.length - zipDataDescriptorLengthInBytes;
|
|
for (let index = 0; index <= lastPossibleDescriptorOffset; index++) {
|
|
if (UINT32_LE.get(buffer, index) === zipDataDescriptorSignature && UINT32_LE.get(buffer, index + 8) === bytesConsumed + index) {
|
|
return index;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
async function readZipDataDescriptorEntryWithLimit(zipHandler, { shouldBuffer, maximumLength = maximumZipEntrySizeInBytes } = {}) {
|
|
const { syncBuffer } = zipHandler;
|
|
const { length: syncBufferLength } = syncBuffer;
|
|
const chunks = [];
|
|
let bytesConsumed = 0;
|
|
for (; ; ) {
|
|
const length = await zipHandler.tokenizer.peekBuffer(syncBuffer, { mayBeLess: true });
|
|
const dataDescriptorOffset = findZipDataDescriptorOffset(syncBuffer.subarray(0, length), bytesConsumed);
|
|
const retainedLength = dataDescriptorOffset >= 0 ? 0 : length === syncBufferLength ? Math.min(zipDataDescriptorOverlapLengthInBytes, length - 1) : 0;
|
|
const chunkLength = dataDescriptorOffset >= 0 ? dataDescriptorOffset : length - retainedLength;
|
|
if (chunkLength === 0) {
|
|
break;
|
|
}
|
|
bytesConsumed += chunkLength;
|
|
if (bytesConsumed > maximumLength) {
|
|
throw new ParserHardLimitError(`ZIP entry data descriptor not found within ${maximumLength} bytes`);
|
|
}
|
|
if (shouldBuffer) {
|
|
const data = new Uint8Array(chunkLength);
|
|
await zipHandler.tokenizer.readBuffer(data);
|
|
chunks.push(data);
|
|
} else {
|
|
await zipHandler.tokenizer.ignore(chunkLength);
|
|
}
|
|
if (dataDescriptorOffset >= 0) {
|
|
break;
|
|
}
|
|
}
|
|
if (!hasUnknownFileSize(zipHandler.tokenizer)) {
|
|
zipHandler.knownSizeDescriptorScannedBytes += bytesConsumed;
|
|
}
|
|
if (!shouldBuffer) {
|
|
return;
|
|
}
|
|
return mergeByteChunks(chunks, bytesConsumed);
|
|
}
|
|
function getRemainingZipScanBudget(zipHandler, startOffset) {
|
|
if (hasUnknownFileSize(zipHandler.tokenizer)) {
|
|
return Math.max(0, maximumUntrustedSkipSizeInBytes - (zipHandler.tokenizer.position - startOffset));
|
|
}
|
|
return Math.max(0, maximumZipEntrySizeInBytes - zipHandler.knownSizeDescriptorScannedBytes);
|
|
}
|
|
async function readZipEntryData(zipHandler, zipHeader, { shouldBuffer, maximumDescriptorLength = maximumZipEntrySizeInBytes } = {}) {
|
|
if (zipHeader.dataDescriptor && zipHeader.compressedSize === 0) {
|
|
return readZipDataDescriptorEntryWithLimit(zipHandler, {
|
|
shouldBuffer,
|
|
maximumLength: maximumDescriptorLength
|
|
});
|
|
}
|
|
if (!shouldBuffer) {
|
|
await safeIgnore(zipHandler.tokenizer, zipHeader.compressedSize, {
|
|
maximumLength: hasUnknownFileSize(zipHandler.tokenizer) ? maximumZipEntrySizeInBytes : zipHandler.tokenizer.fileInfo.size,
|
|
reason: "ZIP entry compressed data"
|
|
});
|
|
return;
|
|
}
|
|
const maximumLength = getMaximumZipBufferedReadLength(zipHandler.tokenizer);
|
|
if (!Number.isFinite(zipHeader.compressedSize) || zipHeader.compressedSize < 0 || zipHeader.compressedSize > maximumLength) {
|
|
throw new Error(`ZIP entry compressed data exceeds ${maximumLength} bytes`);
|
|
}
|
|
const fileData = new Uint8Array(zipHeader.compressedSize);
|
|
await zipHandler.tokenizer.readBuffer(fileData);
|
|
return fileData;
|
|
}
|
|
async function detectZip(tokenizer) {
|
|
let fileType;
|
|
const openXmlState = createOpenXmlZipDetectionState();
|
|
const iWorkState = createIWorkZipDetectionState();
|
|
try {
|
|
await new ZipHandler(tokenizer).unzip((zipHeader) => {
|
|
updateOpenXmlZipDetectionStateFromFilename(openXmlState, zipHeader.filename);
|
|
updateIWorkZipDetectionStateFromFilename(iWorkState, zipHeader.filename);
|
|
if (iWorkState.hasDocumentEntry && (iWorkState.hasMasterSlideEntry || iWorkState.hasTablesEntry)) {
|
|
fileType = getIWorkFileTypeFromZipEntries(iWorkState);
|
|
return { stop: true };
|
|
}
|
|
const isOpenXmlContentTypesEntry = zipHeader.filename === "[Content_Types].xml";
|
|
const openXmlFileTypeFromEntries = getOpenXmlFileTypeFromZipEntries(openXmlState);
|
|
if (!isOpenXmlContentTypesEntry && openXmlFileTypeFromEntries) {
|
|
fileType = openXmlFileTypeFromEntries;
|
|
return {
|
|
stop: true
|
|
};
|
|
}
|
|
switch (zipHeader.filename) {
|
|
case "META-INF/mozilla.rsa":
|
|
fileType = {
|
|
ext: "xpi",
|
|
mime: "application/x-xpinstall"
|
|
};
|
|
return {
|
|
stop: true
|
|
};
|
|
case "META-INF/MANIFEST.MF":
|
|
fileType = {
|
|
ext: "jar",
|
|
mime: "application/java-archive"
|
|
};
|
|
return {
|
|
stop: true
|
|
};
|
|
case "mimetype":
|
|
if (!canReadZipEntryForDetection(zipHeader, maximumZipTextEntrySizeInBytes)) {
|
|
return {};
|
|
}
|
|
return {
|
|
async handler(fileData) {
|
|
const mimeType = new TextDecoder("utf-8").decode(fileData).trim();
|
|
fileType = getFileTypeFromMimeType(mimeType);
|
|
},
|
|
stop: true
|
|
};
|
|
case "[Content_Types].xml": {
|
|
openXmlState.hasContentTypesEntry = true;
|
|
if (!canReadZipEntryForDetection(zipHeader, maximumZipTextEntrySizeInBytes)) {
|
|
openXmlState.hasUnparseableContentTypes = true;
|
|
return {};
|
|
}
|
|
openXmlState.isParsingContentTypes = true;
|
|
return {
|
|
async handler(fileData) {
|
|
const xmlContent = new TextDecoder("utf-8").decode(fileData);
|
|
const mimeType = getOpenXmlMimeTypeFromContentTypesXml(xmlContent);
|
|
if (mimeType) {
|
|
fileType = getFileTypeFromMimeType(mimeType);
|
|
}
|
|
openXmlState.hasParsedContentTypesEntry = true;
|
|
openXmlState.isParsingContentTypes = false;
|
|
},
|
|
stop: true
|
|
};
|
|
}
|
|
default:
|
|
if (new RegExp("classes\\d*\\.dex", "v").test(zipHeader.filename)) {
|
|
fileType = {
|
|
ext: "apk",
|
|
mime: "application/vnd.android.package-archive"
|
|
};
|
|
return { stop: true };
|
|
}
|
|
return {};
|
|
}
|
|
});
|
|
} catch (error) {
|
|
if (!isRecoverableZipError(error)) {
|
|
throw error;
|
|
}
|
|
if (openXmlState.isParsingContentTypes) {
|
|
openXmlState.isParsingContentTypes = false;
|
|
openXmlState.hasUnparseableContentTypes = true;
|
|
}
|
|
if (!fileType && (error instanceof EndOfStreamError || error instanceof ParserHardLimitError) && !openXmlState.hasContentTypesEntry) {
|
|
fileType = getOpenXmlFileTypeFromDirectoryNames(openXmlState);
|
|
}
|
|
}
|
|
const iWorkFileType = hasUnknownFileSize(tokenizer) && iWorkState.hasDocumentEntry && !iWorkState.hasMasterSlideEntry && !iWorkState.hasTablesEntry && !iWorkState.hasCalculationEngineEntry ? void 0 : getIWorkFileTypeFromZipEntries(iWorkState);
|
|
return fileType ?? getOpenXmlFileTypeFromZipEntries(openXmlState) ?? iWorkFileType ?? {
|
|
ext: "zip",
|
|
mime: "application/zip"
|
|
};
|
|
}
|
|
var maximumZipEntrySizeInBytes, maximumZipEntryCount, maximumZipBufferedReadSizeInBytes, maximumZipTextEntrySizeInBytes, recoverableZipErrorMessages, recoverableZipErrorMessagePrefixes, recoverableZipErrorCodes, zipDataDescriptorSignature, zipDataDescriptorLengthInBytes, zipDataDescriptorOverlapLengthInBytes;
|
|
var init_zip = __esm({
|
|
"../../node_modules/.pnpm/file-type@22.1.1/node_modules/file-type/source/detectors/zip.js"() {
|
|
init_lib2();
|
|
init_core();
|
|
init_lib3();
|
|
init_parser();
|
|
maximumZipEntrySizeInBytes = 1024 * 1024;
|
|
maximumZipEntryCount = 1024;
|
|
maximumZipBufferedReadSizeInBytes = 2 ** 31 - 1;
|
|
maximumZipTextEntrySizeInBytes = maximumZipEntrySizeInBytes;
|
|
recoverableZipErrorMessages = /* @__PURE__ */ new Set([
|
|
"Unexpected signature",
|
|
"Encrypted ZIP",
|
|
"Expected Central-File-Header signature"
|
|
]);
|
|
recoverableZipErrorMessagePrefixes = [
|
|
"ZIP entry count exceeds ",
|
|
"Unsupported ZIP compression method:",
|
|
"ZIP entry compressed data exceeds ",
|
|
"ZIP entry decompressed data exceeds ",
|
|
"Expected data-descriptor-signature at position "
|
|
];
|
|
recoverableZipErrorCodes = /* @__PURE__ */ new Set([
|
|
"Z_BUF_ERROR",
|
|
"Z_DATA_ERROR",
|
|
"ERR_INVALID_STATE"
|
|
]);
|
|
__name(decompressDeflateRawWithLimit, "decompressDeflateRawWithLimit");
|
|
__name(mergeByteChunks, "mergeByteChunks");
|
|
__name(getMaximumZipBufferedReadLength, "getMaximumZipBufferedReadLength");
|
|
__name(isRecoverableZipError, "isRecoverableZipError");
|
|
__name(canReadZipEntryForDetection, "canReadZipEntryForDetection");
|
|
__name(createIWorkZipDetectionState, "createIWorkZipDetectionState");
|
|
__name(updateIWorkZipDetectionStateFromFilename, "updateIWorkZipDetectionStateFromFilename");
|
|
__name(getIWorkFileTypeFromZipEntries, "getIWorkFileTypeFromZipEntries");
|
|
__name(getFileTypeFromMimeType, "getFileTypeFromMimeType");
|
|
__name(createOpenXmlZipDetectionState, "createOpenXmlZipDetectionState");
|
|
__name(updateOpenXmlZipDetectionStateFromFilename, "updateOpenXmlZipDetectionStateFromFilename");
|
|
__name(getOpenXmlFileTypeFromDirectoryNames, "getOpenXmlFileTypeFromDirectoryNames");
|
|
__name(getOpenXmlFileTypeFromZipEntries, "getOpenXmlFileTypeFromZipEntries");
|
|
__name(getOpenXmlMimeTypeFromContentTypesXml, "getOpenXmlMimeTypeFromContentTypesXml");
|
|
zipDataDescriptorSignature = 134695760;
|
|
zipDataDescriptorLengthInBytes = 16;
|
|
zipDataDescriptorOverlapLengthInBytes = zipDataDescriptorLengthInBytes - 1;
|
|
__name(findZipDataDescriptorOffset, "findZipDataDescriptorOffset");
|
|
__name(readZipDataDescriptorEntryWithLimit, "readZipDataDescriptorEntryWithLimit");
|
|
__name(getRemainingZipScanBudget, "getRemainingZipScanBudget");
|
|
__name(readZipEntryData, "readZipEntryData");
|
|
ZipHandler.prototype.inflate = async function(zipHeader, fileData, callback) {
|
|
if (zipHeader.compressedMethod === 0) {
|
|
return callback(fileData);
|
|
}
|
|
if (zipHeader.compressedMethod !== 8) {
|
|
throw new Error(`Unsupported ZIP compression method: ${zipHeader.compressedMethod}`);
|
|
}
|
|
const uncompressedData = await decompressDeflateRawWithLimit(fileData, { maximumLength: maximumZipEntrySizeInBytes });
|
|
return callback(uncompressedData);
|
|
};
|
|
ZipHandler.prototype.unzip = async function(fileCallback) {
|
|
let stop = false;
|
|
let zipEntryCount = 0;
|
|
const zipScanStart = this.tokenizer.position;
|
|
this.knownSizeDescriptorScannedBytes = 0;
|
|
do {
|
|
if (hasExceededUnknownSizeScanBudget(this.tokenizer, zipScanStart, maximumUntrustedSkipSizeInBytes)) {
|
|
throw new ParserHardLimitError(`ZIP stream probing exceeds ${maximumUntrustedSkipSizeInBytes} bytes`);
|
|
}
|
|
const zipHeader = await this.readLocalFileHeader();
|
|
if (!zipHeader) {
|
|
break;
|
|
}
|
|
zipEntryCount++;
|
|
if (zipEntryCount > maximumZipEntryCount) {
|
|
throw new Error(`ZIP entry count exceeds ${maximumZipEntryCount}`);
|
|
}
|
|
const next = fileCallback(zipHeader);
|
|
stop = Boolean(next.stop);
|
|
await this.tokenizer.ignore(zipHeader.extraFieldLength);
|
|
const fileData = await readZipEntryData(this, zipHeader, {
|
|
shouldBuffer: Boolean(next.handler),
|
|
maximumDescriptorLength: Math.min(maximumZipEntrySizeInBytes, getRemainingZipScanBudget(this, zipScanStart))
|
|
});
|
|
if (next.handler) {
|
|
await this.inflate(zipHeader, fileData, next.handler);
|
|
}
|
|
if (zipHeader.dataDescriptor) {
|
|
const dataDescriptor = new Uint8Array(zipDataDescriptorLengthInBytes);
|
|
await this.tokenizer.readBuffer(dataDescriptor);
|
|
if (UINT32_LE.get(dataDescriptor, 0) !== zipDataDescriptorSignature) {
|
|
throw new Error(`Expected data-descriptor-signature at position ${this.tokenizer.position - dataDescriptor.length}`);
|
|
}
|
|
}
|
|
if (hasExceededUnknownSizeScanBudget(this.tokenizer, zipScanStart, maximumUntrustedSkipSizeInBytes)) {
|
|
throw new ParserHardLimitError(`ZIP stream probing exceeds ${maximumUntrustedSkipSizeInBytes} bytes`);
|
|
}
|
|
} while (!stop);
|
|
};
|
|
__name(detectZip, "detectZip");
|
|
}
|
|
});
|
|
|
|
// ../../node_modules/.pnpm/file-type@22.1.1/node_modules/file-type/source/detectors/ebml.js
|
|
async function detectEbml(tokenizer) {
|
|
async function readField() {
|
|
const msb = await tokenizer.peekNumber(UINT8);
|
|
let mask = 128;
|
|
let ic = 0;
|
|
while ((msb & mask) === 0 && mask !== 0) {
|
|
++ic;
|
|
mask >>= 1;
|
|
}
|
|
const id = new Uint8Array(ic + 1);
|
|
await safeReadBuffer(tokenizer, id, void 0, {
|
|
maximumLength: id.length,
|
|
reason: "EBML field"
|
|
});
|
|
return id;
|
|
}
|
|
__name(readField, "readField");
|
|
async function readElement() {
|
|
const idField = await readField();
|
|
const lengthField = await readField();
|
|
lengthField[0] ^= 128 >> lengthField.length - 1;
|
|
const nrLength = Math.min(6, lengthField.length);
|
|
const idView = new DataView(idField.buffer);
|
|
const lengthView = new DataView(lengthField.buffer, lengthField.length - nrLength, nrLength);
|
|
return {
|
|
id: getUintBE(idView),
|
|
len: getUintBE(lengthView)
|
|
};
|
|
}
|
|
__name(readElement, "readElement");
|
|
async function readChildren(children) {
|
|
let ebmlElementCount = 0;
|
|
while (children > 0) {
|
|
ebmlElementCount++;
|
|
if (ebmlElementCount > maximumEbmlElementCount) {
|
|
return;
|
|
}
|
|
if (hasExceededUnknownSizeScanBudget(tokenizer, ebmlScanStart, maximumUntrustedSkipSizeInBytes)) {
|
|
return;
|
|
}
|
|
const previousPosition = tokenizer.position;
|
|
const element = await readElement();
|
|
if (element.id === 17026) {
|
|
if (element.len > maximumEbmlDocumentTypeSizeInBytes) {
|
|
return;
|
|
}
|
|
const documentTypeLength = getSafeBound(element.len, maximumEbmlDocumentTypeSizeInBytes, "EBML DocType");
|
|
const rawValue = await tokenizer.readToken(new StringType(documentTypeLength));
|
|
return rawValue.replaceAll(new RegExp("\\0.*$", "gv"), "");
|
|
}
|
|
if (hasUnknownFileSize(tokenizer) && (!Number.isFinite(element.len) || element.len < 0 || element.len > maximumEbmlElementPayloadSizeInBytes)) {
|
|
return;
|
|
}
|
|
await safeIgnore(tokenizer, element.len, {
|
|
maximumLength: hasUnknownFileSize(tokenizer) ? maximumEbmlElementPayloadSizeInBytes : tokenizer.fileInfo.size,
|
|
reason: "EBML payload"
|
|
});
|
|
--children;
|
|
if (tokenizer.position <= previousPosition) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
__name(readChildren, "readChildren");
|
|
const rootElement = await readElement();
|
|
const ebmlScanStart = tokenizer.position;
|
|
const documentType = await readChildren(rootElement.len);
|
|
switch (documentType) {
|
|
case "webm":
|
|
return {
|
|
ext: "webm",
|
|
mime: "video/webm"
|
|
};
|
|
case "matroska":
|
|
return {
|
|
ext: "mkv",
|
|
mime: "video/matroska"
|
|
};
|
|
default:
|
|
}
|
|
}
|
|
var maximumEbmlDocumentTypeSizeInBytes, maximumEbmlElementPayloadSizeInBytes, maximumEbmlElementCount;
|
|
var init_ebml = __esm({
|
|
"../../node_modules/.pnpm/file-type@22.1.1/node_modules/file-type/source/detectors/ebml.js"() {
|
|
init_lib2();
|
|
init_uint8array_extras();
|
|
init_parser();
|
|
maximumEbmlDocumentTypeSizeInBytes = 64;
|
|
maximumEbmlElementPayloadSizeInBytes = 1024 * 1024;
|
|
maximumEbmlElementCount = 256;
|
|
__name(detectEbml, "detectEbml");
|
|
}
|
|
});
|
|
|
|
// ../../node_modules/.pnpm/file-type@22.1.1/node_modules/file-type/source/detectors/png.js
|
|
function isPngAncillaryChunk(type) {
|
|
return (type.codePointAt(0) & 32) !== 0;
|
|
}
|
|
async function detectPng(tokenizer) {
|
|
const pngFileType = {
|
|
ext: "png",
|
|
mime: "image/png"
|
|
};
|
|
const apngFileType = {
|
|
ext: "apng",
|
|
mime: "image/apng"
|
|
};
|
|
await tokenizer.ignore(8);
|
|
async function readChunkHeader() {
|
|
return {
|
|
length: await tokenizer.readToken(INT32_BE),
|
|
type: await tokenizer.readToken(new StringType(4, "latin1"))
|
|
};
|
|
}
|
|
__name(readChunkHeader, "readChunkHeader");
|
|
const isUnknownPngStream = hasUnknownFileSize(tokenizer);
|
|
const pngScanStart = tokenizer.position;
|
|
let pngChunkCount = 0;
|
|
let hasSeenImageHeader = false;
|
|
do {
|
|
pngChunkCount++;
|
|
if (pngChunkCount > maximumPngChunkCount) {
|
|
break;
|
|
}
|
|
if (hasExceededUnknownSizeScanBudget(tokenizer, pngScanStart, maximumPngStreamScanBudgetInBytes)) {
|
|
break;
|
|
}
|
|
const previousPosition = tokenizer.position;
|
|
const chunk = await readChunkHeader();
|
|
if (chunk.length < 0) {
|
|
return;
|
|
}
|
|
if (chunk.type === "IHDR") {
|
|
if (chunk.length !== 13) {
|
|
return;
|
|
}
|
|
hasSeenImageHeader = true;
|
|
}
|
|
switch (chunk.type) {
|
|
case "IDAT":
|
|
return pngFileType;
|
|
case "acTL":
|
|
return apngFileType;
|
|
default:
|
|
if (!hasSeenImageHeader && chunk.type !== "CgBI") {
|
|
return;
|
|
}
|
|
if (isUnknownPngStream && chunk.length > maximumPngChunkSizeInBytes) {
|
|
return hasSeenImageHeader && isPngAncillaryChunk(chunk.type) ? pngFileType : void 0;
|
|
}
|
|
try {
|
|
await safeIgnore(tokenizer, chunk.length + 4, {
|
|
maximumLength: isUnknownPngStream ? maximumPngChunkSizeInBytes + 4 : tokenizer.fileInfo.size,
|
|
reason: "PNG chunk payload"
|
|
});
|
|
} catch (error) {
|
|
if (!isUnknownPngStream && (error instanceof ParserHardLimitError || error instanceof EndOfStreamError)) {
|
|
return pngFileType;
|
|
}
|
|
throw error;
|
|
}
|
|
}
|
|
if (tokenizer.position <= previousPosition) {
|
|
break;
|
|
}
|
|
} while (tokenizer.position + 8 < tokenizer.fileInfo.size);
|
|
return pngFileType;
|
|
}
|
|
var maximumPngChunkCount, maximumPngStreamScanBudgetInBytes, maximumPngChunkSizeInBytes;
|
|
var init_png = __esm({
|
|
"../../node_modules/.pnpm/file-type@22.1.1/node_modules/file-type/source/detectors/png.js"() {
|
|
init_lib2();
|
|
init_core();
|
|
init_parser();
|
|
maximumPngChunkCount = 512;
|
|
maximumPngStreamScanBudgetInBytes = 16 * 1024 * 1024;
|
|
maximumPngChunkSizeInBytes = 1024 * 1024;
|
|
__name(isPngAncillaryChunk, "isPngAncillaryChunk");
|
|
__name(detectPng, "detectPng");
|
|
}
|
|
});
|
|
|
|
// ../../node_modules/.pnpm/file-type@22.1.1/node_modules/file-type/source/detectors/asf.js
|
|
async function detectAsf(tokenizer) {
|
|
let isMalformedAsf = false;
|
|
try {
|
|
async function readHeader() {
|
|
const guid = new Uint8Array(16);
|
|
await safeReadBuffer(tokenizer, guid, void 0, {
|
|
maximumLength: guid.length,
|
|
reason: "ASF header GUID"
|
|
});
|
|
return {
|
|
id: guid,
|
|
size: Number(await tokenizer.readToken(UINT64_LE))
|
|
};
|
|
}
|
|
__name(readHeader, "readHeader");
|
|
await safeIgnore(tokenizer, 30, {
|
|
maximumLength: 30,
|
|
reason: "ASF header prelude"
|
|
});
|
|
const isUnknownFileSize = hasUnknownFileSize(tokenizer);
|
|
const asfHeaderScanStart = tokenizer.position;
|
|
let asfHeaderObjectCount = 0;
|
|
while (tokenizer.position + 24 < tokenizer.fileInfo.size) {
|
|
asfHeaderObjectCount++;
|
|
if (asfHeaderObjectCount > maximumAsfHeaderObjectCount) {
|
|
break;
|
|
}
|
|
if (hasExceededUnknownSizeScanBudget(tokenizer, asfHeaderScanStart, maximumUntrustedSkipSizeInBytes)) {
|
|
break;
|
|
}
|
|
const previousPosition = tokenizer.position;
|
|
const header = await readHeader();
|
|
let payload = header.size - 24;
|
|
if (!Number.isFinite(payload) || payload < 0) {
|
|
isMalformedAsf = true;
|
|
break;
|
|
}
|
|
if (checkBytes(header.id, [145, 7, 220, 183, 183, 169, 207, 17, 142, 230, 0, 192, 12, 32, 83, 101])) {
|
|
const typeId = new Uint8Array(16);
|
|
payload -= await safeReadBuffer(tokenizer, typeId, void 0, {
|
|
maximumLength: typeId.length,
|
|
reason: "ASF stream type GUID"
|
|
});
|
|
if (checkBytes(typeId, [64, 158, 105, 248, 77, 91, 207, 17, 168, 253, 0, 128, 95, 92, 68, 43])) {
|
|
return {
|
|
ext: "asf",
|
|
mime: "audio/x-ms-asf"
|
|
};
|
|
}
|
|
if (checkBytes(typeId, [192, 239, 25, 188, 77, 91, 207, 17, 168, 253, 0, 128, 95, 92, 68, 43])) {
|
|
return {
|
|
ext: "asf",
|
|
mime: "video/x-ms-asf"
|
|
};
|
|
}
|
|
break;
|
|
}
|
|
if (isUnknownFileSize && payload > maximumAsfHeaderPayloadSizeInBytes) {
|
|
isMalformedAsf = true;
|
|
break;
|
|
}
|
|
await safeIgnore(tokenizer, payload, {
|
|
maximumLength: isUnknownFileSize ? maximumAsfHeaderPayloadSizeInBytes : tokenizer.fileInfo.size,
|
|
reason: "ASF header payload"
|
|
});
|
|
if (tokenizer.position <= previousPosition) {
|
|
isMalformedAsf = true;
|
|
break;
|
|
}
|
|
}
|
|
} catch (error) {
|
|
if (error instanceof EndOfStreamError || error instanceof ParserHardLimitError) {
|
|
if (hasUnknownFileSize(tokenizer)) {
|
|
isMalformedAsf = true;
|
|
}
|
|
} else {
|
|
throw error;
|
|
}
|
|
}
|
|
if (isMalformedAsf) {
|
|
return;
|
|
}
|
|
return {
|
|
ext: "asf",
|
|
mime: "application/vnd.ms-asf"
|
|
};
|
|
}
|
|
var maximumAsfHeaderObjectCount, maximumAsfHeaderPayloadSizeInBytes;
|
|
var init_asf = __esm({
|
|
"../../node_modules/.pnpm/file-type@22.1.1/node_modules/file-type/source/detectors/asf.js"() {
|
|
init_lib2();
|
|
init_core();
|
|
init_parser();
|
|
maximumAsfHeaderObjectCount = 512;
|
|
maximumAsfHeaderPayloadSizeInBytes = 1024 * 1024;
|
|
__name(detectAsf, "detectAsf");
|
|
}
|
|
});
|
|
|
|
// ../../node_modules/.pnpm/file-type@22.1.1/node_modules/file-type/source/index.js
|
|
function normalizeSampleSize(sampleSize) {
|
|
if (!Number.isFinite(sampleSize)) {
|
|
return reasonableDetectionSizeInBytes;
|
|
}
|
|
return Math.max(1, Math.trunc(sampleSize));
|
|
}
|
|
function normalizeMpegOffsetTolerance(mpegOffsetTolerance) {
|
|
if (!Number.isFinite(mpegOffsetTolerance)) {
|
|
return 0;
|
|
}
|
|
return Math.max(0, Math.min(maximumMpegOffsetTolerance, Math.trunc(mpegOffsetTolerance)));
|
|
}
|
|
function getKnownFileSizeOrMaximum(fileSize) {
|
|
if (!Number.isFinite(fileSize)) {
|
|
return Number.MAX_SAFE_INTEGER;
|
|
}
|
|
return Math.max(0, fileSize);
|
|
}
|
|
function importAtRuntime(specifier) {
|
|
return import(
|
|
/* @vite-ignore */
|
|
/* webpackIgnore: true */
|
|
specifier
|
|
);
|
|
}
|
|
function toDefaultStream(stream) {
|
|
return stream.pipeThrough(new TransformStream());
|
|
}
|
|
function readWithSignal(reader, signal) {
|
|
if (signal === void 0) {
|
|
return reader.read();
|
|
}
|
|
signal.throwIfAborted();
|
|
return Promise.race([
|
|
reader.read(),
|
|
new Promise((_resolve, reject) => {
|
|
signal.addEventListener("abort", () => {
|
|
reject(signal.reason);
|
|
reader.cancel(signal.reason).catch(() => {
|
|
});
|
|
}, { once: true });
|
|
})
|
|
]);
|
|
}
|
|
function createByteLimitedReadableStream(stream, maximumBytes) {
|
|
const reader = stream.getReader();
|
|
let emittedBytes = 0;
|
|
let sourceDone = false;
|
|
let sourceCanceled = false;
|
|
const cancelSource = /* @__PURE__ */ __name(async (reason) => {
|
|
if (sourceDone || sourceCanceled) {
|
|
return;
|
|
}
|
|
sourceCanceled = true;
|
|
await reader.cancel(reason);
|
|
}, "cancelSource");
|
|
return new ReadableStream({
|
|
async pull(controller) {
|
|
if (emittedBytes >= maximumBytes) {
|
|
controller.close();
|
|
await cancelSource();
|
|
return;
|
|
}
|
|
const { done, value } = await reader.read();
|
|
if (done || !value) {
|
|
sourceDone = true;
|
|
controller.close();
|
|
return;
|
|
}
|
|
const remainingBytes = maximumBytes - emittedBytes;
|
|
if (value.length > remainingBytes) {
|
|
controller.enqueue(value.subarray(0, remainingBytes));
|
|
emittedBytes += remainingBytes;
|
|
controller.close();
|
|
await cancelSource();
|
|
return;
|
|
}
|
|
controller.enqueue(value);
|
|
emittedBytes += value.length;
|
|
},
|
|
async cancel(reason) {
|
|
await cancelSource(reason);
|
|
}
|
|
});
|
|
}
|
|
async function fileTypeFromStream(stream, options) {
|
|
return new FileTypeParser(options).fromStream(stream);
|
|
}
|
|
async function fileTypeFromBuffer(input, options) {
|
|
return new FileTypeParser(options).fromBuffer(input);
|
|
}
|
|
async function fileTypeFromBlob(blob, options) {
|
|
return new FileTypeParser(options).fromBlob(blob);
|
|
}
|
|
async function fileTypeFromTokenizer(tokenizer, options) {
|
|
return new FileTypeParser(options).fromTokenizer(tokenizer);
|
|
}
|
|
async function fileTypeStream(webStream, options) {
|
|
return new FileTypeParser(options).toDetectionStream(webStream, options);
|
|
}
|
|
async function fileTypeFromFile(path, options) {
|
|
return new FileTypeParser(options).fromFile(path);
|
|
}
|
|
var reasonableDetectionSizeInBytes, maximumMpegOffsetTolerance, maximumNestedGzipDetectionSizeInBytes, maximumNestedGzipProbeDepth, unknownSizeGzipProbeTimeoutInMilliseconds, maximumId3HeaderSizeInBytes, maximumTiffTagCount, maximumDetectionReentryCount, maximumTiffStreamIfdOffsetInBytes, maximumTiffIfdOffsetInBytes, FileTypeParser, supportedExtensions, supportedMimeTypes;
|
|
var init_source = __esm({
|
|
"../../node_modules/.pnpm/file-type@22.1.1/node_modules/file-type/source/index.js"() {
|
|
init_lib2();
|
|
init_core();
|
|
init_lib3();
|
|
init_uint8array_extras();
|
|
init_tokens();
|
|
init_supported();
|
|
init_parser();
|
|
init_zip();
|
|
init_ebml();
|
|
init_png();
|
|
init_asf();
|
|
reasonableDetectionSizeInBytes = 4100;
|
|
maximumMpegOffsetTolerance = reasonableDetectionSizeInBytes - 4;
|
|
maximumNestedGzipDetectionSizeInBytes = maximumUntrustedSkipSizeInBytes;
|
|
maximumNestedGzipProbeDepth = 1;
|
|
unknownSizeGzipProbeTimeoutInMilliseconds = 100;
|
|
maximumId3HeaderSizeInBytes = maximumUntrustedSkipSizeInBytes;
|
|
maximumTiffTagCount = 512;
|
|
maximumDetectionReentryCount = 256;
|
|
maximumTiffStreamIfdOffsetInBytes = 1024 * 1024;
|
|
maximumTiffIfdOffsetInBytes = maximumUntrustedSkipSizeInBytes;
|
|
__name(normalizeSampleSize, "normalizeSampleSize");
|
|
__name(normalizeMpegOffsetTolerance, "normalizeMpegOffsetTolerance");
|
|
__name(getKnownFileSizeOrMaximum, "getKnownFileSizeOrMaximum");
|
|
__name(importAtRuntime, "importAtRuntime");
|
|
__name(toDefaultStream, "toDefaultStream");
|
|
__name(readWithSignal, "readWithSignal");
|
|
__name(createByteLimitedReadableStream, "createByteLimitedReadableStream");
|
|
__name(fileTypeFromStream, "fileTypeFromStream");
|
|
__name(fileTypeFromBuffer, "fileTypeFromBuffer");
|
|
__name(fileTypeFromBlob, "fileTypeFromBlob");
|
|
__name(fileTypeFromTokenizer, "fileTypeFromTokenizer");
|
|
__name(fileTypeStream, "fileTypeStream");
|
|
FileTypeParser = class _FileTypeParser {
|
|
static {
|
|
__name(this, "FileTypeParser");
|
|
}
|
|
constructor(options) {
|
|
const normalizedMpegOffsetTolerance = normalizeMpegOffsetTolerance(options?.mpegOffsetTolerance);
|
|
this.options = {
|
|
...options,
|
|
mpegOffsetTolerance: normalizedMpegOffsetTolerance
|
|
};
|
|
this.detectors = [
|
|
...this.options.customDetectors ?? [],
|
|
{ id: "core", detect: this.detectConfident },
|
|
{ id: "core.imprecise", detect: this.detectImprecise }
|
|
];
|
|
this.tokenizerOptions = {
|
|
abortSignal: this.options.signal
|
|
};
|
|
this.gzipProbeDepth = 0;
|
|
}
|
|
getTokenizerOptions() {
|
|
return {
|
|
...this.tokenizerOptions
|
|
};
|
|
}
|
|
createTokenizerFromWebStream(stream) {
|
|
return fromWebStream(toDefaultStream(stream), this.getTokenizerOptions());
|
|
}
|
|
async parseTokenizer(tokenizer, detectionReentryCount = 0) {
|
|
this.detectionReentryCount = detectionReentryCount;
|
|
const initialPosition = tokenizer.position;
|
|
for (const detector of this.detectors) {
|
|
let fileType;
|
|
try {
|
|
fileType = await detector.detect(tokenizer);
|
|
} catch (error) {
|
|
if (error instanceof EndOfStreamError) {
|
|
return;
|
|
}
|
|
if (error instanceof ParserHardLimitError) {
|
|
return;
|
|
}
|
|
throw error;
|
|
}
|
|
if (fileType) {
|
|
return fileType;
|
|
}
|
|
if (initialPosition !== tokenizer.position) {
|
|
return void 0;
|
|
}
|
|
}
|
|
}
|
|
async fromTokenizer(tokenizer) {
|
|
try {
|
|
return await this.parseTokenizer(tokenizer);
|
|
} finally {
|
|
await tokenizer.close();
|
|
}
|
|
}
|
|
async fromBuffer(input) {
|
|
if (!(input instanceof Uint8Array || input instanceof ArrayBuffer)) {
|
|
throw new TypeError(`Expected the \`input\` argument to be of type \`Uint8Array\` or \`ArrayBuffer\`, got \`${typeof input}\``);
|
|
}
|
|
const buffer = input instanceof Uint8Array ? input : new Uint8Array(input);
|
|
if (!(buffer?.length > 1)) {
|
|
return;
|
|
}
|
|
return this.fromTokenizer(fromBuffer(buffer, this.getTokenizerOptions()));
|
|
}
|
|
async fromBlob(blob) {
|
|
this.options.signal?.throwIfAborted();
|
|
const tokenizer = fromBlob(blob, this.getTokenizerOptions());
|
|
return this.fromTokenizer(tokenizer);
|
|
}
|
|
async fromStream(stream) {
|
|
this.options.signal?.throwIfAborted();
|
|
const tokenizer = this.createTokenizerFromWebStream(stream);
|
|
return this.fromTokenizer(tokenizer);
|
|
}
|
|
async fromFile(path) {
|
|
this.options.signal?.throwIfAborted();
|
|
const [{ default: fsPromises }, { FileTokenizer }] = await Promise.all([
|
|
importAtRuntime("node:fs/promises"),
|
|
importAtRuntime("strtok3")
|
|
]);
|
|
const fileHandle = await fsPromises.open(path, fsPromises.constants.O_RDONLY | fsPromises.constants.O_NONBLOCK);
|
|
const fileStat = await fileHandle.stat();
|
|
if (!fileStat.isFile()) {
|
|
await fileHandle.close();
|
|
return;
|
|
}
|
|
const tokenizer = new FileTokenizer(fileHandle, {
|
|
...this.getTokenizerOptions(),
|
|
fileInfo: { path, size: fileStat.size }
|
|
});
|
|
return this.fromTokenizer(tokenizer);
|
|
}
|
|
async toDetectionStream(stream, options) {
|
|
this.options.signal?.throwIfAborted();
|
|
const sampleSize = normalizeSampleSize(options?.sampleSize ?? reasonableDetectionSizeInBytes);
|
|
let detectedFileType;
|
|
let streamEnded = false;
|
|
const reader = stream.getReader();
|
|
const chunks = [];
|
|
let totalSize = 0;
|
|
try {
|
|
while (totalSize < sampleSize) {
|
|
const { value, done } = await readWithSignal(reader, this.options.signal);
|
|
if (done || !value) {
|
|
streamEnded = true;
|
|
break;
|
|
}
|
|
chunks.push(value);
|
|
totalSize += value.length;
|
|
}
|
|
if (!streamEnded && totalSize === sampleSize) {
|
|
const { value, done } = await readWithSignal(reader, this.options.signal);
|
|
if (done || !value) {
|
|
streamEnded = true;
|
|
} else {
|
|
chunks.push(value);
|
|
totalSize += value.length;
|
|
}
|
|
}
|
|
} finally {
|
|
reader.releaseLock();
|
|
}
|
|
if (totalSize > 0) {
|
|
const sample = chunks.length === 1 ? chunks[0] : concatUint8Arrays(chunks);
|
|
try {
|
|
detectedFileType = await this.fromBuffer(sample.subarray(0, sampleSize));
|
|
} catch (error) {
|
|
if (!(error instanceof EndOfStreamError)) {
|
|
throw error;
|
|
}
|
|
detectedFileType = void 0;
|
|
}
|
|
if (!streamEnded && detectedFileType?.ext === "pages") {
|
|
detectedFileType = {
|
|
ext: "zip",
|
|
mime: "application/zip"
|
|
};
|
|
}
|
|
}
|
|
const transformStream = new TransformStream({
|
|
start(controller) {
|
|
for (const chunk of chunks) {
|
|
controller.enqueue(chunk);
|
|
}
|
|
},
|
|
transform(chunk, controller) {
|
|
controller.enqueue(chunk);
|
|
}
|
|
});
|
|
const newStream = stream.pipeThrough(transformStream);
|
|
newStream.fileType = detectedFileType;
|
|
return newStream;
|
|
}
|
|
async detectGzip(tokenizer) {
|
|
if (this.gzipProbeDepth >= maximumNestedGzipProbeDepth) {
|
|
return {
|
|
ext: "gz",
|
|
mime: "application/gzip"
|
|
};
|
|
}
|
|
const gzipHandler = new GzipHandler(tokenizer);
|
|
const limitedInflatedStream = createByteLimitedReadableStream(gzipHandler.inflate(), maximumNestedGzipDetectionSizeInBytes);
|
|
const hasUnknownSize = hasUnknownFileSize(tokenizer);
|
|
let timeout;
|
|
let probeSignal;
|
|
let probeParser;
|
|
let compressedFileType;
|
|
if (hasUnknownSize) {
|
|
const timeoutController = new AbortController();
|
|
timeout = setTimeout(() => {
|
|
timeoutController.abort(new DOMException(`Operation timed out after ${unknownSizeGzipProbeTimeoutInMilliseconds} ms`, "TimeoutError"));
|
|
}, unknownSizeGzipProbeTimeoutInMilliseconds);
|
|
probeSignal = this.options.signal === void 0 ? timeoutController.signal : AbortSignal.any([this.options.signal, timeoutController.signal]);
|
|
probeParser = new _FileTypeParser({
|
|
...this.options,
|
|
signal: probeSignal
|
|
});
|
|
probeParser.gzipProbeDepth = this.gzipProbeDepth + 1;
|
|
} else {
|
|
this.gzipProbeDepth++;
|
|
}
|
|
try {
|
|
compressedFileType = await (probeParser ?? this).fromStream(limitedInflatedStream);
|
|
} catch (error) {
|
|
if (error?.name === "AbortError" && probeSignal?.reason?.name !== "TimeoutError") {
|
|
throw error;
|
|
}
|
|
} finally {
|
|
clearTimeout(timeout);
|
|
if (!hasUnknownSize) {
|
|
this.gzipProbeDepth--;
|
|
}
|
|
}
|
|
if (compressedFileType?.ext === "tar") {
|
|
return {
|
|
ext: "tar.gz",
|
|
mime: "application/gzip"
|
|
};
|
|
}
|
|
return {
|
|
ext: "gz",
|
|
mime: "application/gzip"
|
|
};
|
|
}
|
|
check(header, options) {
|
|
return checkBytes(this.buffer, header, options);
|
|
}
|
|
checkString(header, options) {
|
|
return this.check(stringToBytes(header, options?.encoding), options);
|
|
}
|
|
// Detections with a high degree of certainty in identifying the correct file type
|
|
detectConfident = /* @__PURE__ */ __name(async (tokenizer) => {
|
|
this.buffer = new Uint8Array(reasonableDetectionSizeInBytes);
|
|
if (tokenizer.fileInfo.size === void 0) {
|
|
tokenizer.fileInfo.size = Number.MAX_SAFE_INTEGER;
|
|
}
|
|
this.tokenizer = tokenizer;
|
|
if (hasUnknownFileSize(tokenizer)) {
|
|
await tokenizer.peekBuffer(this.buffer, { length: 3, mayBeLess: true });
|
|
if (this.check([31, 139, 8])) {
|
|
return this.detectGzip(tokenizer);
|
|
}
|
|
}
|
|
await tokenizer.peekBuffer(this.buffer, { length: 32, mayBeLess: true });
|
|
if (this.check([66, 77])) {
|
|
return {
|
|
ext: "bmp",
|
|
mime: "image/bmp"
|
|
};
|
|
}
|
|
if (this.check([11, 119])) {
|
|
return {
|
|
ext: "ac3",
|
|
mime: "audio/vnd.dolby.dd-raw"
|
|
};
|
|
}
|
|
if (this.check([120, 1])) {
|
|
return {
|
|
ext: "dmg",
|
|
mime: "application/x-apple-diskimage"
|
|
};
|
|
}
|
|
if (this.check([77, 90])) {
|
|
return {
|
|
ext: "exe",
|
|
mime: "application/x-msdownload"
|
|
};
|
|
}
|
|
if (this.check([37, 33])) {
|
|
await tokenizer.peekBuffer(this.buffer, { length: 24, mayBeLess: true });
|
|
if (this.checkString("PS-Adobe-", { offset: 2 }) && this.checkString(" EPSF-", { offset: 14 })) {
|
|
return {
|
|
ext: "eps",
|
|
mime: "application/eps"
|
|
};
|
|
}
|
|
return {
|
|
ext: "ps",
|
|
mime: "application/postscript"
|
|
};
|
|
}
|
|
if (this.check([31, 160]) || this.check([31, 157])) {
|
|
return {
|
|
ext: "Z",
|
|
mime: "application/x-compress"
|
|
};
|
|
}
|
|
if (this.check([199, 113])) {
|
|
return {
|
|
ext: "cpio",
|
|
mime: "application/x-cpio"
|
|
};
|
|
}
|
|
if (this.check([96, 234])) {
|
|
return {
|
|
ext: "arj",
|
|
mime: "application/x-arj"
|
|
};
|
|
}
|
|
if (this.check([239, 187, 191])) {
|
|
if (this.detectionReentryCount >= maximumDetectionReentryCount) {
|
|
return;
|
|
}
|
|
this.detectionReentryCount++;
|
|
await this.tokenizer.ignore(3);
|
|
return this.detectConfident(tokenizer);
|
|
}
|
|
if (this.check([71, 73, 70])) {
|
|
return {
|
|
ext: "gif",
|
|
mime: "image/gif"
|
|
};
|
|
}
|
|
if (this.check([73, 73, 188])) {
|
|
return {
|
|
ext: "jxr",
|
|
mime: "image/vnd.ms-photo"
|
|
};
|
|
}
|
|
if (this.check([31, 139, 8])) {
|
|
return this.detectGzip(tokenizer);
|
|
}
|
|
if (this.check([66, 90, 104])) {
|
|
return {
|
|
ext: "bz2",
|
|
mime: "application/x-bzip2"
|
|
};
|
|
}
|
|
if (this.checkString("ID3")) {
|
|
await safeIgnore(tokenizer, 6, {
|
|
maximumLength: 6,
|
|
reason: "ID3 header prefix"
|
|
});
|
|
const id3HeaderLength = await tokenizer.readToken(uint32SyncSafeToken);
|
|
const isUnknownFileSize = hasUnknownFileSize(tokenizer);
|
|
if (!Number.isFinite(id3HeaderLength) || id3HeaderLength < 0 || isUnknownFileSize && (id3HeaderLength > maximumId3HeaderSizeInBytes || tokenizer.position + id3HeaderLength > maximumId3HeaderSizeInBytes)) {
|
|
return;
|
|
}
|
|
if (tokenizer.position + id3HeaderLength > tokenizer.fileInfo.size) {
|
|
if (isUnknownFileSize) {
|
|
return;
|
|
}
|
|
return {
|
|
ext: "mp3",
|
|
mime: "audio/mpeg"
|
|
};
|
|
}
|
|
try {
|
|
await safeIgnore(tokenizer, id3HeaderLength, {
|
|
maximumLength: isUnknownFileSize ? maximumId3HeaderSizeInBytes : tokenizer.fileInfo.size,
|
|
reason: "ID3 payload"
|
|
});
|
|
} catch (error) {
|
|
if (error instanceof EndOfStreamError) {
|
|
return;
|
|
}
|
|
throw error;
|
|
}
|
|
if (this.detectionReentryCount >= maximumDetectionReentryCount) {
|
|
return;
|
|
}
|
|
this.detectionReentryCount++;
|
|
return this.parseTokenizer(tokenizer, this.detectionReentryCount);
|
|
}
|
|
if (this.checkString("MP+")) {
|
|
return {
|
|
ext: "mpc",
|
|
mime: "audio/x-musepack"
|
|
};
|
|
}
|
|
if ((this.buffer[0] === 67 || this.buffer[0] === 70) && this.check([87, 83], { offset: 1 })) {
|
|
return {
|
|
ext: "swf",
|
|
mime: "application/x-shockwave-flash"
|
|
};
|
|
}
|
|
if (this.check([255, 216, 255])) {
|
|
if (this.check([247], { offset: 3 })) {
|
|
return {
|
|
ext: "jls",
|
|
mime: "image/jls"
|
|
};
|
|
}
|
|
return {
|
|
ext: "jpg",
|
|
mime: "image/jpeg"
|
|
};
|
|
}
|
|
if (this.check([79, 98, 106, 1])) {
|
|
return {
|
|
ext: "avro",
|
|
mime: "application/avro"
|
|
};
|
|
}
|
|
if (this.checkString("FLIF")) {
|
|
return {
|
|
ext: "flif",
|
|
mime: "image/flif"
|
|
};
|
|
}
|
|
if (this.checkString("8BPS")) {
|
|
return {
|
|
ext: "psd",
|
|
mime: "image/vnd.adobe.photoshop"
|
|
};
|
|
}
|
|
if (this.checkString("MPCK")) {
|
|
return {
|
|
ext: "mpc",
|
|
mime: "audio/x-musepack"
|
|
};
|
|
}
|
|
if (this.checkString("FORM")) {
|
|
return {
|
|
ext: "aif",
|
|
mime: "audio/aiff"
|
|
};
|
|
}
|
|
if (this.checkString("icns", { offset: 0 })) {
|
|
return {
|
|
ext: "icns",
|
|
mime: "image/icns"
|
|
};
|
|
}
|
|
if (this.check([80, 75, 3, 4])) {
|
|
return detectZip(tokenizer);
|
|
}
|
|
if (this.checkString("OggS")) {
|
|
await tokenizer.ignore(28);
|
|
const type = new Uint8Array(8);
|
|
await tokenizer.readBuffer(type);
|
|
if (checkBytes(type, [79, 112, 117, 115, 72, 101, 97, 100])) {
|
|
return {
|
|
ext: "opus",
|
|
mime: "audio/ogg; codecs=opus"
|
|
};
|
|
}
|
|
if (checkBytes(type, [128, 116, 104, 101, 111, 114, 97])) {
|
|
return {
|
|
ext: "ogv",
|
|
mime: "video/ogg"
|
|
};
|
|
}
|
|
if (checkBytes(type, [1, 118, 105, 100, 101, 111, 0])) {
|
|
return {
|
|
ext: "ogm",
|
|
mime: "video/ogg"
|
|
};
|
|
}
|
|
if (checkBytes(type, [127, 70, 76, 65, 67])) {
|
|
return {
|
|
ext: "oga",
|
|
mime: "audio/ogg"
|
|
};
|
|
}
|
|
if (checkBytes(type, [83, 112, 101, 101, 120, 32, 32])) {
|
|
return {
|
|
ext: "spx",
|
|
mime: "audio/ogg"
|
|
};
|
|
}
|
|
if (checkBytes(type, [1, 118, 111, 114, 98, 105, 115])) {
|
|
return {
|
|
ext: "ogg",
|
|
mime: "audio/ogg"
|
|
};
|
|
}
|
|
return {
|
|
ext: "ogx",
|
|
mime: "application/ogg"
|
|
};
|
|
}
|
|
if (this.check([80, 75]) && (this.buffer[2] === 3 || this.buffer[2] === 5 || this.buffer[2] === 7) && (this.buffer[3] === 4 || this.buffer[3] === 6 || this.buffer[3] === 8)) {
|
|
return {
|
|
ext: "zip",
|
|
mime: "application/zip"
|
|
};
|
|
}
|
|
if (this.checkString("MThd")) {
|
|
return {
|
|
ext: "mid",
|
|
mime: "audio/midi"
|
|
};
|
|
}
|
|
if (this.checkString("wOFF") && (this.check([0, 1, 0, 0], { offset: 4 }) || this.checkString("OTTO", { offset: 4 }))) {
|
|
return {
|
|
ext: "woff",
|
|
mime: "font/woff"
|
|
};
|
|
}
|
|
if (this.checkString("wOF2") && (this.check([0, 1, 0, 0], { offset: 4 }) || this.checkString("OTTO", { offset: 4 }))) {
|
|
return {
|
|
ext: "woff2",
|
|
mime: "font/woff2"
|
|
};
|
|
}
|
|
if (this.check([212, 195, 178, 161]) || this.check([161, 178, 195, 212])) {
|
|
return {
|
|
ext: "pcap",
|
|
mime: "application/vnd.tcpdump.pcap"
|
|
};
|
|
}
|
|
if (this.checkString("DSD ")) {
|
|
return {
|
|
ext: "dsf",
|
|
mime: "audio/x-dsf"
|
|
// Non-standard
|
|
};
|
|
}
|
|
if (this.checkString("LZIP")) {
|
|
return {
|
|
ext: "lz",
|
|
mime: "application/lzip"
|
|
};
|
|
}
|
|
if (this.checkString("fLaC")) {
|
|
return {
|
|
ext: "flac",
|
|
mime: "audio/flac"
|
|
};
|
|
}
|
|
if (this.check([66, 80, 71, 251])) {
|
|
return {
|
|
ext: "bpg",
|
|
mime: "image/bpg"
|
|
};
|
|
}
|
|
if (this.checkString("wvpk")) {
|
|
return {
|
|
ext: "wv",
|
|
mime: "audio/wavpack"
|
|
};
|
|
}
|
|
if (this.checkString("%PDF")) {
|
|
return {
|
|
ext: "pdf",
|
|
mime: "application/pdf"
|
|
};
|
|
}
|
|
if (this.check([0, 97, 115, 109])) {
|
|
return {
|
|
ext: "wasm",
|
|
mime: "application/wasm"
|
|
};
|
|
}
|
|
if (this.check([73, 73])) {
|
|
const fileType = await this.readTiffHeader(false);
|
|
if (fileType) {
|
|
return fileType;
|
|
}
|
|
}
|
|
if (this.check([77, 77])) {
|
|
const fileType = await this.readTiffHeader(true);
|
|
if (fileType) {
|
|
return fileType;
|
|
}
|
|
}
|
|
if (this.checkString("MAC ")) {
|
|
return {
|
|
ext: "ape",
|
|
mime: "audio/ape"
|
|
};
|
|
}
|
|
if (this.check([26, 69, 223, 163])) {
|
|
return detectEbml(tokenizer);
|
|
}
|
|
if (this.checkString("SQLi")) {
|
|
return {
|
|
ext: "sqlite",
|
|
mime: "application/x-sqlite3"
|
|
};
|
|
}
|
|
if (this.check([78, 69, 83, 26])) {
|
|
return {
|
|
ext: "nes",
|
|
mime: "application/x-nintendo-nes-rom"
|
|
};
|
|
}
|
|
if (this.checkString("Cr24")) {
|
|
return {
|
|
ext: "crx",
|
|
mime: "application/x-google-chrome-extension"
|
|
};
|
|
}
|
|
if (this.checkString("MSCF") || this.checkString("ISc(")) {
|
|
return {
|
|
ext: "cab",
|
|
mime: "application/vnd.ms-cab-compressed"
|
|
};
|
|
}
|
|
if (this.check([237, 171, 238, 219])) {
|
|
return {
|
|
ext: "rpm",
|
|
mime: "application/x-rpm"
|
|
};
|
|
}
|
|
if (this.check([197, 208, 211, 198])) {
|
|
return {
|
|
ext: "eps",
|
|
mime: "application/eps"
|
|
};
|
|
}
|
|
if (this.check([40, 181, 47, 253])) {
|
|
return {
|
|
ext: "zst",
|
|
mime: "application/zstd"
|
|
};
|
|
}
|
|
if (this.check([127, 69, 76, 70])) {
|
|
return {
|
|
ext: "elf",
|
|
mime: "application/x-elf"
|
|
};
|
|
}
|
|
if (this.check([33, 66, 68, 78])) {
|
|
return {
|
|
ext: "pst",
|
|
mime: "application/vnd.ms-outlook"
|
|
};
|
|
}
|
|
if (this.checkString("PAR1") || this.checkString("PARE")) {
|
|
return {
|
|
ext: "parquet",
|
|
mime: "application/vnd.apache.parquet"
|
|
};
|
|
}
|
|
if (this.checkString("ttcf")) {
|
|
return {
|
|
ext: "ttc",
|
|
mime: "font/collection"
|
|
};
|
|
}
|
|
if (this.check([254, 237, 250, 206]) || this.check([254, 237, 250, 207]) || this.check([206, 250, 237, 254]) || this.check([207, 250, 237, 254])) {
|
|
return {
|
|
ext: "macho",
|
|
mime: "application/x-mach-binary"
|
|
};
|
|
}
|
|
if (this.check([4, 34, 77, 24])) {
|
|
return {
|
|
ext: "lz4",
|
|
mime: "application/x-lz4"
|
|
// Informal, used by freedesktop.org shared-mime-info
|
|
};
|
|
}
|
|
if (this.checkString("regf")) {
|
|
return {
|
|
ext: "dat",
|
|
mime: "application/x-ft-windows-registry-hive"
|
|
};
|
|
}
|
|
if (this.checkString("$FL2") || this.checkString("$FL3")) {
|
|
return {
|
|
ext: "sav",
|
|
mime: "application/x-spss-sav"
|
|
};
|
|
}
|
|
if (this.check([79, 84, 84, 79, 0])) {
|
|
return {
|
|
ext: "otf",
|
|
mime: "font/otf"
|
|
};
|
|
}
|
|
if (this.checkString("#!AMR")) {
|
|
return {
|
|
ext: "amr",
|
|
mime: "audio/amr"
|
|
};
|
|
}
|
|
if (this.checkString(String.raw`{\rtf`)) {
|
|
return {
|
|
ext: "rtf",
|
|
mime: "application/rtf"
|
|
};
|
|
}
|
|
if (this.check([70, 76, 86, 1])) {
|
|
return {
|
|
ext: "flv",
|
|
mime: "video/x-flv"
|
|
};
|
|
}
|
|
if (this.checkString("IMPM")) {
|
|
return {
|
|
ext: "it",
|
|
mime: "audio/x-it"
|
|
};
|
|
}
|
|
if (this.checkString("-lh0-", { offset: 2 }) || this.checkString("-lh1-", { offset: 2 }) || this.checkString("-lh2-", { offset: 2 }) || this.checkString("-lh3-", { offset: 2 }) || this.checkString("-lh4-", { offset: 2 }) || this.checkString("-lh5-", { offset: 2 }) || this.checkString("-lh6-", { offset: 2 }) || this.checkString("-lh7-", { offset: 2 }) || this.checkString("-lzs-", { offset: 2 }) || this.checkString("-lz4-", { offset: 2 }) || this.checkString("-lz5-", { offset: 2 }) || this.checkString("-lhd-", { offset: 2 })) {
|
|
return {
|
|
ext: "lzh",
|
|
mime: "application/x-lzh-compressed"
|
|
};
|
|
}
|
|
if (this.check([0, 0, 1, 186])) {
|
|
if (this.check([33], { offset: 4, mask: [241] })) {
|
|
return {
|
|
ext: "mpg",
|
|
// May also be .ps, .mpeg
|
|
mime: "video/MP1S"
|
|
};
|
|
}
|
|
if (this.check([68], { offset: 4, mask: [196] })) {
|
|
return {
|
|
ext: "mpg",
|
|
// May also be .mpg, .m2p, .vob or .sub
|
|
mime: "video/MP2P"
|
|
};
|
|
}
|
|
}
|
|
if (this.checkString("ITSF")) {
|
|
return {
|
|
ext: "chm",
|
|
mime: "application/vnd.ms-htmlhelp"
|
|
};
|
|
}
|
|
if (this.check([202, 254, 186, 190])) {
|
|
const machOArchitectureCount = UINT32_BE.get(this.buffer, 4);
|
|
const javaClassFileMajorVersion = UINT16_BE.get(this.buffer, 6);
|
|
if (machOArchitectureCount > 0 && machOArchitectureCount <= 30) {
|
|
return {
|
|
ext: "macho",
|
|
mime: "application/x-mach-binary"
|
|
};
|
|
}
|
|
if (javaClassFileMajorVersion > 30) {
|
|
return {
|
|
ext: "class",
|
|
mime: "application/java-vm"
|
|
};
|
|
}
|
|
}
|
|
if (this.checkString(".RMF")) {
|
|
return {
|
|
ext: "rm",
|
|
mime: "application/vnd.rn-realmedia"
|
|
};
|
|
}
|
|
if (this.checkString("DRACO")) {
|
|
return {
|
|
ext: "drc",
|
|
mime: "application/x-ft-draco"
|
|
};
|
|
}
|
|
if (this.check([253, 55, 122, 88, 90, 0])) {
|
|
return {
|
|
ext: "xz",
|
|
mime: "application/x-xz"
|
|
};
|
|
}
|
|
if (this.checkString("<?xml ")) {
|
|
return {
|
|
ext: "xml",
|
|
mime: "application/xml"
|
|
};
|
|
}
|
|
if (this.check([55, 122, 188, 175, 39, 28])) {
|
|
return {
|
|
ext: "7z",
|
|
mime: "application/x-7z-compressed"
|
|
};
|
|
}
|
|
if (this.check([82, 97, 114, 33, 26, 7]) && (this.buffer[6] === 0 || this.buffer[6] === 1)) {
|
|
return {
|
|
ext: "rar",
|
|
mime: "application/x-rar-compressed"
|
|
};
|
|
}
|
|
if (this.checkString("solid ")) {
|
|
return {
|
|
ext: "stl",
|
|
mime: "model/stl"
|
|
};
|
|
}
|
|
if (this.checkString("AC")) {
|
|
const version = new StringType(4, "latin1").get(this.buffer, 2);
|
|
if (new RegExp("^\\d+$", "v").test(version) && version >= 1e3 && version <= 1050) {
|
|
return {
|
|
ext: "dwg",
|
|
mime: "image/vnd.dwg"
|
|
};
|
|
}
|
|
}
|
|
if (this.checkString("070707")) {
|
|
return {
|
|
ext: "cpio",
|
|
mime: "application/x-cpio"
|
|
};
|
|
}
|
|
if (this.checkString("BLENDER")) {
|
|
return {
|
|
ext: "blend",
|
|
mime: "application/x-blender"
|
|
};
|
|
}
|
|
if (this.checkString("!<arch>")) {
|
|
await tokenizer.ignore(8);
|
|
const string = await tokenizer.readToken(new StringType(13, "ascii"));
|
|
if (string === "debian-binary") {
|
|
return {
|
|
ext: "deb",
|
|
mime: "application/x-deb"
|
|
};
|
|
}
|
|
return {
|
|
ext: "ar",
|
|
mime: "application/x-unix-archive"
|
|
};
|
|
}
|
|
if (this.checkString("WEBVTT") && // One of LF, CR, tab, space, or end of file must follow "WEBVTT" per the spec (see `fixture/fixture-vtt-*.vtt` for examples). Note that `\0` is technically the null character (there is no such thing as an EOF character). However, checking for `\0` gives us the same result as checking for the end of the stream.
|
|
["\n", "\r", " ", " ", "\0"].some((char7) => this.checkString(char7, { offset: 6 }))) {
|
|
return {
|
|
ext: "vtt",
|
|
mime: "text/vtt"
|
|
};
|
|
}
|
|
if (this.check([137, 80, 78, 71, 13, 10, 26, 10])) {
|
|
return detectPng(tokenizer);
|
|
}
|
|
if (this.check([65, 82, 82, 79, 87, 49, 0, 0])) {
|
|
return {
|
|
ext: "arrow",
|
|
mime: "application/vnd.apache.arrow.file"
|
|
};
|
|
}
|
|
if (this.check([103, 108, 84, 70, 2, 0, 0, 0])) {
|
|
return {
|
|
ext: "glb",
|
|
mime: "model/gltf-binary"
|
|
};
|
|
}
|
|
if (this.check([102, 114, 101, 101], { offset: 4 }) || this.check([109, 100, 97, 116], { offset: 4 }) || this.check([109, 111, 111, 118], { offset: 4 }) || this.check([119, 105, 100, 101], { offset: 4 })) {
|
|
return {
|
|
ext: "mov",
|
|
mime: "video/quicktime"
|
|
};
|
|
}
|
|
if (this.check([73, 73, 82, 79, 8, 0, 0, 0, 24])) {
|
|
return {
|
|
ext: "orf",
|
|
mime: "image/x-olympus-orf"
|
|
};
|
|
}
|
|
if (this.checkString("gimp xcf ")) {
|
|
return {
|
|
ext: "xcf",
|
|
mime: "image/x-xcf"
|
|
};
|
|
}
|
|
if (this.checkString("ftyp", { offset: 4 }) && (this.buffer[8] & 96) !== 0) {
|
|
const brandMajor = new StringType(4, "latin1").get(this.buffer, 8).replace("\0", " ").trim();
|
|
switch (brandMajor) {
|
|
case "avif":
|
|
case "avis":
|
|
return { ext: "avif", mime: "image/avif" };
|
|
case "mif1":
|
|
return { ext: "heic", mime: "image/heif" };
|
|
case "msf1":
|
|
return { ext: "heic", mime: "image/heif-sequence" };
|
|
case "heic":
|
|
case "heix":
|
|
return { ext: "heic", mime: "image/heic" };
|
|
case "hevc":
|
|
case "hevx":
|
|
return { ext: "heic", mime: "image/heic-sequence" };
|
|
case "qt":
|
|
return { ext: "mov", mime: "video/quicktime" };
|
|
case "M4V":
|
|
case "M4VH":
|
|
case "M4VP":
|
|
return { ext: "m4v", mime: "video/x-m4v" };
|
|
case "M4P":
|
|
return { ext: "m4p", mime: "video/mp4" };
|
|
case "M4B":
|
|
return { ext: "m4b", mime: "audio/mp4" };
|
|
case "M4A":
|
|
return { ext: "m4a", mime: "audio/x-m4a" };
|
|
case "F4V":
|
|
return { ext: "f4v", mime: "video/mp4" };
|
|
case "F4P":
|
|
return { ext: "f4p", mime: "video/mp4" };
|
|
case "F4A":
|
|
return { ext: "f4a", mime: "audio/mp4" };
|
|
case "F4B":
|
|
return { ext: "f4b", mime: "audio/mp4" };
|
|
case "crx":
|
|
return { ext: "cr3", mime: "image/x-canon-cr3" };
|
|
default:
|
|
if (brandMajor.startsWith("3g")) {
|
|
if (brandMajor.startsWith("3g2")) {
|
|
return { ext: "3g2", mime: "video/3gpp2" };
|
|
}
|
|
return { ext: "3gp", mime: "video/3gpp" };
|
|
}
|
|
return { ext: "mp4", mime: "video/mp4" };
|
|
}
|
|
}
|
|
if (this.checkString("REGEDIT4\r\n")) {
|
|
return {
|
|
ext: "reg",
|
|
mime: "application/x-ms-regedit"
|
|
};
|
|
}
|
|
if (this.check([82, 73, 70, 70])) {
|
|
if (this.checkString("WEBP", { offset: 8 })) {
|
|
return {
|
|
ext: "webp",
|
|
mime: "image/webp"
|
|
};
|
|
}
|
|
if (this.check([65, 86, 73], { offset: 8 })) {
|
|
return {
|
|
ext: "avi",
|
|
mime: "video/vnd.avi"
|
|
};
|
|
}
|
|
if (this.check([87, 65, 86, 69], { offset: 8 })) {
|
|
return {
|
|
ext: "wav",
|
|
mime: "audio/wav"
|
|
};
|
|
}
|
|
if (this.check([81, 76, 67, 77], { offset: 8 })) {
|
|
return {
|
|
ext: "qcp",
|
|
mime: "audio/qcelp"
|
|
};
|
|
}
|
|
}
|
|
if (this.check([73, 73, 85, 0, 24, 0, 0, 0, 136, 231, 116, 216])) {
|
|
return {
|
|
ext: "rw2",
|
|
mime: "image/x-panasonic-rw2"
|
|
};
|
|
}
|
|
if (this.check([48, 38, 178, 117, 142, 102, 207, 17, 166, 217])) {
|
|
return detectAsf(tokenizer);
|
|
}
|
|
if (this.check([171, 75, 84, 88, 32, 49, 49, 187, 13, 10, 26, 10])) {
|
|
return {
|
|
ext: "ktx",
|
|
mime: "image/ktx"
|
|
};
|
|
}
|
|
if ((this.check([126, 16, 4]) || this.check([126, 24, 4])) && this.check([48, 77, 73, 69], { offset: 4 })) {
|
|
return {
|
|
ext: "mie",
|
|
mime: "application/x-mie"
|
|
};
|
|
}
|
|
if (this.check([39, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], { offset: 2 })) {
|
|
return {
|
|
ext: "shp",
|
|
mime: "application/x-esri-shape"
|
|
};
|
|
}
|
|
if (this.check([255, 79, 255, 81])) {
|
|
return {
|
|
ext: "j2c",
|
|
mime: "image/j2c"
|
|
};
|
|
}
|
|
if (this.check([0, 0, 0, 12, 106, 80, 32, 32, 13, 10, 135, 10])) {
|
|
await tokenizer.ignore(20);
|
|
const type = await tokenizer.readToken(new StringType(4, "ascii"));
|
|
switch (type) {
|
|
case "jp2 ":
|
|
return {
|
|
ext: "jp2",
|
|
mime: "image/jp2"
|
|
};
|
|
case "jpx ":
|
|
return {
|
|
ext: "jpx",
|
|
mime: "image/jpx"
|
|
};
|
|
case "jpm ":
|
|
return {
|
|
ext: "jpm",
|
|
mime: "image/jpm"
|
|
};
|
|
case "mjp2":
|
|
return {
|
|
ext: "mj2",
|
|
mime: "image/mj2"
|
|
};
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
if (this.check([255, 10]) || this.check([0, 0, 0, 12, 74, 88, 76, 32, 13, 10, 135, 10])) {
|
|
return {
|
|
ext: "jxl",
|
|
mime: "image/jxl"
|
|
};
|
|
}
|
|
if (this.check([254, 255])) {
|
|
if (this.checkString("<?xml ", { offset: 2, encoding: "utf-16be" })) {
|
|
return {
|
|
ext: "xml",
|
|
mime: "application/xml"
|
|
};
|
|
}
|
|
return void 0;
|
|
}
|
|
if (this.check([208, 207, 17, 224, 161, 177, 26, 225])) {
|
|
return {
|
|
ext: "cfb",
|
|
mime: "application/x-cfb"
|
|
};
|
|
}
|
|
await tokenizer.peekBuffer(this.buffer, { length: Math.min(256, tokenizer.fileInfo.size), mayBeLess: true });
|
|
if (this.check([97, 99, 115, 112], { offset: 36 })) {
|
|
return {
|
|
ext: "icc",
|
|
mime: "application/vnd.iccprofile"
|
|
};
|
|
}
|
|
if (this.checkString("**ACE", { offset: 7 }) && this.checkString("**", { offset: 12 })) {
|
|
return {
|
|
ext: "ace",
|
|
mime: "application/x-ace-compressed"
|
|
};
|
|
}
|
|
if (this.checkString("BEGIN:")) {
|
|
if (this.checkString("VCARD", { offset: 6 })) {
|
|
return {
|
|
ext: "vcf",
|
|
mime: "text/vcard"
|
|
};
|
|
}
|
|
if (this.checkString("VCALENDAR", { offset: 6 })) {
|
|
return {
|
|
ext: "ics",
|
|
mime: "text/calendar"
|
|
};
|
|
}
|
|
}
|
|
if (this.checkString("FUJIFILMCCD-RAW")) {
|
|
return {
|
|
ext: "raf",
|
|
mime: "image/x-fujifilm-raf"
|
|
};
|
|
}
|
|
if (this.checkString("Extended Module:")) {
|
|
return {
|
|
ext: "xm",
|
|
mime: "audio/x-xm"
|
|
};
|
|
}
|
|
if (this.checkString("Creative Voice File")) {
|
|
return {
|
|
ext: "voc",
|
|
mime: "audio/x-voc"
|
|
};
|
|
}
|
|
if (this.check([4, 0, 0, 0]) && this.buffer.length >= 16) {
|
|
const jsonSize = new DataView(this.buffer.buffer).getUint32(12, true);
|
|
if (jsonSize > 12 && this.buffer.length >= jsonSize + 16) {
|
|
try {
|
|
const header = new TextDecoder().decode(this.buffer.subarray(16, jsonSize + 16));
|
|
const json = JSON.parse(header);
|
|
if (json.files) {
|
|
return {
|
|
ext: "asar",
|
|
mime: "application/x-asar"
|
|
};
|
|
}
|
|
} catch {
|
|
}
|
|
}
|
|
}
|
|
if (this.check([6, 14, 43, 52, 2, 5, 1, 1, 13, 1, 2, 1, 1, 2])) {
|
|
return {
|
|
ext: "mxf",
|
|
mime: "application/mxf"
|
|
};
|
|
}
|
|
if (this.checkString("SCRM", { offset: 44 })) {
|
|
return {
|
|
ext: "s3m",
|
|
mime: "audio/x-s3m"
|
|
};
|
|
}
|
|
if (this.check([71]) && this.check([71], { offset: 188 })) {
|
|
return {
|
|
ext: "mts",
|
|
mime: "video/mp2t"
|
|
};
|
|
}
|
|
if (this.check([71], { offset: 4 }) && this.check([71], { offset: 196 })) {
|
|
return {
|
|
ext: "mts",
|
|
mime: "video/mp2t"
|
|
};
|
|
}
|
|
if (this.check([66, 79, 79, 75, 77, 79, 66, 73], { offset: 60 })) {
|
|
return {
|
|
ext: "mobi",
|
|
mime: "application/x-mobipocket-ebook"
|
|
};
|
|
}
|
|
if (this.check([68, 73, 67, 77], { offset: 128 })) {
|
|
return {
|
|
ext: "dcm",
|
|
mime: "application/dicom"
|
|
};
|
|
}
|
|
if (this.check([76, 0, 0, 0, 1, 20, 2, 0, 0, 0, 0, 0, 192, 0, 0, 0, 0, 0, 0, 70])) {
|
|
return {
|
|
ext: "lnk",
|
|
mime: "application/x-ms-shortcut"
|
|
// Informal, used by freedesktop.org shared-mime-info
|
|
};
|
|
}
|
|
if (this.check([98, 111, 111, 107, 0, 0, 0, 0, 109, 97, 114, 107, 0, 0, 0, 0])) {
|
|
return {
|
|
ext: "alias",
|
|
mime: "application/x-ft-apple.alias"
|
|
};
|
|
}
|
|
if (this.checkString("Kaydara FBX Binary \0")) {
|
|
return {
|
|
ext: "fbx",
|
|
mime: "application/x-ft-fbx"
|
|
};
|
|
}
|
|
if (this.check([76, 80], { offset: 34 }) && (this.check([0, 0, 1], { offset: 8 }) || this.check([1, 0, 2], { offset: 8 }) || this.check([2, 0, 2], { offset: 8 }))) {
|
|
return {
|
|
ext: "eot",
|
|
mime: "application/vnd.ms-fontobject"
|
|
};
|
|
}
|
|
if (this.check([6, 6, 237, 245, 216, 29, 70, 229, 189, 49, 239, 231, 254, 116, 183, 29])) {
|
|
return {
|
|
ext: "indd",
|
|
mime: "application/x-indesign"
|
|
};
|
|
}
|
|
if (this.check([255, 255, 0, 0, 7, 0, 0, 0, 4, 0, 0, 0, 1, 0, 1, 0]) || this.check([0, 0, 255, 255, 0, 0, 0, 7, 0, 0, 0, 4, 0, 1, 0, 1])) {
|
|
return {
|
|
ext: "jmp",
|
|
mime: "application/x-jmp-data"
|
|
};
|
|
}
|
|
await tokenizer.peekBuffer(this.buffer, { length: Math.min(512, tokenizer.fileInfo.size), mayBeLess: true });
|
|
if (this.checkString("ustar", { offset: 257 }) && (this.checkString("\0", { offset: 262 }) || this.checkString(" ", { offset: 262 })) || this.check([0, 0, 0, 0, 0, 0], { offset: 257 }) && tarHeaderChecksumMatches(this.buffer)) {
|
|
return {
|
|
ext: "tar",
|
|
mime: "application/x-tar"
|
|
};
|
|
}
|
|
if (this.check([255, 254])) {
|
|
const encoding = "utf-16le";
|
|
if (this.checkString("<?xml ", { offset: 2, encoding })) {
|
|
return {
|
|
ext: "xml",
|
|
mime: "application/xml"
|
|
};
|
|
}
|
|
if (this.check([255, 14], { offset: 2 }) && this.checkString("SketchUp Model", { offset: 4, encoding })) {
|
|
return {
|
|
ext: "skp",
|
|
mime: "application/vnd.sketchup.skp"
|
|
};
|
|
}
|
|
if (this.checkString("Windows Registry Editor Version 5.00\r\n", { offset: 2, encoding })) {
|
|
return {
|
|
ext: "reg",
|
|
mime: "application/x-ms-regedit"
|
|
};
|
|
}
|
|
return void 0;
|
|
}
|
|
if (this.checkString("-----BEGIN PGP MESSAGE-----")) {
|
|
return {
|
|
ext: "pgp",
|
|
mime: "application/pgp-encrypted"
|
|
};
|
|
}
|
|
const isoStandardIdentifierOffset = 32769;
|
|
const isoStandardIdentifierLength = 5;
|
|
if (tokenizer.supportsRandomAccess() && tokenizer.fileInfo.size >= isoStandardIdentifierOffset + isoStandardIdentifierLength) {
|
|
const isoStandardIdentifier = new Uint8Array(isoStandardIdentifierLength);
|
|
await tokenizer.peekBuffer(isoStandardIdentifier, {
|
|
position: isoStandardIdentifierOffset,
|
|
length: isoStandardIdentifierLength,
|
|
mayBeLess: true
|
|
});
|
|
if (checkBytes(isoStandardIdentifier, stringToBytes("CD001"))) {
|
|
return {
|
|
ext: "iso",
|
|
mime: "application/x-iso9660-image"
|
|
};
|
|
}
|
|
}
|
|
}, "detectConfident");
|
|
// Detections with limited supporting data, resulting in a higher likelihood of false positives
|
|
detectImprecise = /* @__PURE__ */ __name(async (tokenizer) => {
|
|
this.buffer = new Uint8Array(reasonableDetectionSizeInBytes);
|
|
const fileSize = getKnownFileSizeOrMaximum(tokenizer.fileInfo.size);
|
|
await tokenizer.peekBuffer(this.buffer, { length: Math.min(8, fileSize), mayBeLess: true });
|
|
if (this.check([0, 0, 1, 186]) || this.check([0, 0, 1, 179])) {
|
|
return {
|
|
ext: "mpg",
|
|
mime: "video/mpeg"
|
|
};
|
|
}
|
|
if (this.check([0, 1, 0, 0, 0])) {
|
|
return {
|
|
ext: "ttf",
|
|
mime: "font/ttf"
|
|
};
|
|
}
|
|
if (this.check([0, 0, 1, 0])) {
|
|
return {
|
|
ext: "ico",
|
|
mime: "image/x-icon"
|
|
};
|
|
}
|
|
if (this.check([0, 0, 2, 0])) {
|
|
return {
|
|
ext: "cur",
|
|
mime: "image/x-icon"
|
|
};
|
|
}
|
|
await tokenizer.peekBuffer(this.buffer, { length: Math.min(4 + this.options.mpegOffsetTolerance, fileSize), mayBeLess: true });
|
|
if (this.buffer.length >= 4 + this.options.mpegOffsetTolerance) {
|
|
for (let depth = 0; depth <= this.options.mpegOffsetTolerance; ++depth) {
|
|
const type = this.scanMpeg(depth);
|
|
if (type) {
|
|
return type;
|
|
}
|
|
}
|
|
}
|
|
}, "detectImprecise");
|
|
async readTiffTag(bigEndian) {
|
|
const tagId = await this.tokenizer.readToken(bigEndian ? UINT16_BE : UINT16_LE);
|
|
await this.tokenizer.ignore(10);
|
|
switch (tagId) {
|
|
case 50341:
|
|
return {
|
|
ext: "arw",
|
|
mime: "image/x-sony-arw"
|
|
};
|
|
case 50706:
|
|
return {
|
|
ext: "dng",
|
|
mime: "image/x-adobe-dng"
|
|
};
|
|
default:
|
|
}
|
|
}
|
|
async readTiffIFD(bigEndian) {
|
|
const numberOfTags = await this.tokenizer.readToken(bigEndian ? UINT16_BE : UINT16_LE);
|
|
if (numberOfTags > maximumTiffTagCount) {
|
|
return;
|
|
}
|
|
if (hasUnknownFileSize(this.tokenizer) && 2 + numberOfTags * 12 > maximumTiffIfdOffsetInBytes) {
|
|
return;
|
|
}
|
|
for (let n = 0; n < numberOfTags; ++n) {
|
|
const fileType = await this.readTiffTag(bigEndian);
|
|
if (fileType) {
|
|
return fileType;
|
|
}
|
|
}
|
|
}
|
|
async readTiffHeader(bigEndian) {
|
|
const tiffFileType = {
|
|
ext: "tif",
|
|
mime: "image/tiff"
|
|
};
|
|
const version = (bigEndian ? UINT16_BE : UINT16_LE).get(this.buffer, 2);
|
|
const ifdOffset = (bigEndian ? UINT32_BE : UINT32_LE).get(this.buffer, 4);
|
|
if (version === 42) {
|
|
if (ifdOffset >= 6) {
|
|
if (this.checkString("CR", { offset: 8 })) {
|
|
return {
|
|
ext: "cr2",
|
|
mime: "image/x-canon-cr2"
|
|
};
|
|
}
|
|
if (ifdOffset >= 8) {
|
|
const someId1 = (bigEndian ? UINT16_BE : UINT16_LE).get(this.buffer, 8);
|
|
const someId2 = (bigEndian ? UINT16_BE : UINT16_LE).get(this.buffer, 10);
|
|
if (someId1 === 28 && someId2 === 254 || someId1 === 31 && someId2 === 11) {
|
|
return {
|
|
ext: "nef",
|
|
mime: "image/x-nikon-nef"
|
|
};
|
|
}
|
|
}
|
|
}
|
|
if (hasUnknownFileSize(this.tokenizer) && ifdOffset > maximumTiffStreamIfdOffsetInBytes) {
|
|
return tiffFileType;
|
|
}
|
|
const maximumTiffOffset = hasUnknownFileSize(this.tokenizer) ? maximumTiffIfdOffsetInBytes : this.tokenizer.fileInfo.size;
|
|
try {
|
|
await safeIgnore(this.tokenizer, ifdOffset, {
|
|
maximumLength: maximumTiffOffset,
|
|
reason: "TIFF IFD offset"
|
|
});
|
|
} catch (error) {
|
|
if (error instanceof EndOfStreamError) {
|
|
return;
|
|
}
|
|
throw error;
|
|
}
|
|
let fileType;
|
|
try {
|
|
fileType = await this.readTiffIFD(bigEndian);
|
|
} catch (error) {
|
|
if (error instanceof EndOfStreamError) {
|
|
return;
|
|
}
|
|
throw error;
|
|
}
|
|
return fileType ?? tiffFileType;
|
|
}
|
|
if (version === 43) {
|
|
return tiffFileType;
|
|
}
|
|
}
|
|
/**
|
|
Scan check MPEG 1 or 2 Layer 3 header, or 'layer 0' for ADTS (MPEG sync-word 0xFFE).
|
|
|
|
@param offset - Offset to scan for sync-preamble.
|
|
@returns {{ext: string, mime: string}}
|
|
*/
|
|
scanMpeg(offset) {
|
|
if (this.check([255, 224], { offset, mask: [255, 224] })) {
|
|
if (this.check([16], { offset: offset + 1, mask: [22] })) {
|
|
return {
|
|
ext: "aac",
|
|
mime: "audio/aac"
|
|
};
|
|
}
|
|
if (this.check([255, 254], { offset })) {
|
|
return;
|
|
}
|
|
if (this.check([8], { offset: offset + 1, mask: [24] })) {
|
|
return;
|
|
}
|
|
if (this.check([240], { offset: offset + 2, mask: [240] })) {
|
|
return;
|
|
}
|
|
if (this.check([12], { offset: offset + 2, mask: [12] })) {
|
|
return;
|
|
}
|
|
if (this.check([2], { offset: offset + 1, mask: [6] })) {
|
|
return {
|
|
ext: "mp3",
|
|
mime: "audio/mpeg"
|
|
};
|
|
}
|
|
if (this.check([4], { offset: offset + 1, mask: [6] })) {
|
|
return {
|
|
ext: "mp2",
|
|
mime: "audio/mpeg"
|
|
};
|
|
}
|
|
if (this.check([6], { offset: offset + 1, mask: [6] })) {
|
|
return {
|
|
ext: "mp1",
|
|
mime: "audio/mpeg"
|
|
};
|
|
}
|
|
}
|
|
}
|
|
};
|
|
supportedExtensions = new Set(extensions);
|
|
supportedMimeTypes = new Set(mimeTypes);
|
|
__name(fileTypeFromFile, "fileTypeFromFile");
|
|
}
|
|
});
|
|
init_source();
|
|
export {
|
|
FileTypeParser,
|
|
fileTypeFromBlob,
|
|
fileTypeFromBuffer,
|
|
fileTypeFromFile,
|
|
fileTypeFromStream,
|
|
fileTypeFromTokenizer,
|
|
fileTypeStream,
|
|
normalizeSampleSize,
|
|
reasonableDetectionSizeInBytes,
|
|
supportedExtensions,
|
|
supportedMimeTypes
|
|
};
|