{"version":3,"file":"bundlefs-Ccuh3yOg.cjs","sources":["../src/vfs/tar.ts","../src/vfs/bundlefs.ts"],"sourcesContent":["/**\n * Tiny streaming tar parser (POSIX ustar format).\n *\n * Used by BundleFS to extract a `.tar` (or brotli/gzip-wrapped tar) into a\n * Map<path, Uint8Array> for MEMFS upload.\n *\n * Why hand-rolled: tar is dead simple (512-byte fixed headers) and bringing\n * in fflate/tarjs/etc. would add a dep just for this single use case.\n */\n\nexport interface TarEntry {\n  path: string;\n  content: Uint8Array;\n  type: 'file' | 'dir' | 'other';\n}\n\nexport interface UntarOptions {\n  /**\n   * Ceiling on the number of entries. The full TeX tree is ~180k files, so\n   * anything past this is not a TDS — it is an archive built to make us\n   * allocate. Default: MAX_TAR_ENTRIES.\n   */\n  maxEntries?: number;\n}\n\n/**\n * Ceiling on the entry count of a single archive. The full TL 2026 tree is\n * roughly 180k files; the bundles we publish are far smaller.\n */\nexport const MAX_TAR_ENTRIES = 250_000;\n\n/**\n * Parse a tar archive into a list of entries.\n *\n * A malformed or hostile archive is an error, not a shorter list: a header\n * whose declared size runs past the end of the buffer, or an entry count no\n * TDS could have, means the bytes are not the archive we asked for. Entry\n * NAMES are not judged here — the caller owns the root they unpack into and\n * confines them with safeRelativePath (see vfs/bundlefs.ts).\n */\nexport function untar(bytes: Uint8Array, options: UntarOptions = {}): TarEntry[] {\n  const maxEntries = options.maxEntries ?? MAX_TAR_ENTRIES;\n  const out: TarEntry[] = [];\n  const decoder = new TextDecoder();\n  let offset = 0;\n  // POSIX ustar prefix support (long pathnames).\n  let pendingLongName: string | null = null;\n\n  while (offset + 512 <= bytes.length) {\n    const block = bytes.subarray(offset, offset + 512);\n    if (isAllZero(block)) {\n      // Trailing zero block(s) signal end of archive.\n      break;\n    }\n\n    const name = readCString(block, 0, 100);\n    const size = parseOctal(block, 124, 12);\n    const typeflag = String.fromCharCode(block[156] ?? 0);\n    const prefix = readCString(block, 345, 155);\n    const fullPath = pendingLongName ?? (prefix ? prefix + '/' + name : name);\n    pendingLongName = null;\n\n    offset += 512;\n    // A size that overruns the buffer means the header is lying (or the\n    // download was truncated); subarray() would silently hand back a short\n    // read, and the engine would compile with half a file.\n    if (size < 0 || !Number.isSafeInteger(size) || offset + size > bytes.length) {\n      throw new Error(\n        `texlive-wasm: tar entry \"${fullPath}\" declares ${size} bytes, past the end of the archive`,\n      );\n    }\n    const contentBlocks = Math.ceil(size / 512);\n    const content = bytes.subarray(offset, offset + size);\n    offset += contentBlocks * 512;\n\n    if (out.length >= maxEntries) {\n      throw new Error(\n        `texlive-wasm: tar archive has more than ${maxEntries} entries; refusing to continue`,\n      );\n    }\n\n    if (typeflag === 'L') {\n      // GNU long-name extension: next entry's name is this content (NUL-terminated).\n      pendingLongName = decoder.decode(content).replace(/\\0+$/, '');\n      continue;\n    }\n    if (typeflag === 'x') {\n      // PAX extended header: may carry a `path` record that overrides the\n      // (possibly truncated) ustar name of the NEXT entry.\n      const paxPath = parsePaxPath(decoder.decode(content));\n      if (paxPath) pendingLongName = paxPath;\n      continue;\n    }\n    if (typeflag === 'g') {\n      // PAX global header — no per-entry data we care about.\n      continue;\n    }\n\n    const type: TarEntry['type'] =\n      typeflag === '5' ? 'dir' : typeflag === '0' || typeflag === '\\0' ? 'file' : 'other';\n    out.push({ path: fullPath, content: type === 'file' ? content : new Uint8Array(), type });\n  }\n  return out;\n}\n\n/**\n * PAX extended-header body is a sequence of \"<len> <key>=<value>\\n\" records\n * where <len> counts the whole record in bytes. Returns the `path` value.\n */\nfunction parsePaxPath(body: string): string | null {\n  let i = 0;\n  while (i < body.length) {\n    const space = body.indexOf(' ', i);\n    if (space < 0) break;\n    const len = Number(body.slice(i, space));\n    if (!Number.isFinite(len) || len <= 0) break;\n    const record = body.slice(space + 1, i + len);\n    const eq = record.indexOf('=');\n    if (eq > 0 && record.slice(0, eq) === 'path') {\n      return record.slice(eq + 1).replace(/\\n$/, '');\n    }\n    i += len;\n  }\n  return null;\n}\n\nfunction readCString(block: Uint8Array, start: number, len: number): string {\n  let end = start;\n  while (end < start + len && block[end] !== 0) end++;\n  return new TextDecoder().decode(block.subarray(start, end));\n}\n\nfunction parseOctal(block: Uint8Array, start: number, len: number): number {\n  let n = 0;\n  for (let i = start; i < start + len; i++) {\n    const c = block[i];\n    if (c === undefined || c === 0 || c === 0x20) continue;\n    if (c < 0x30 || c > 0x37) break;\n    n = n * 8 + (c - 0x30);\n  }\n  return n;\n}\n\nfunction isAllZero(block: Uint8Array): boolean {\n  for (let i = 0; i < block.length; i++) if (block[i] !== 0) return false;\n  return true;\n}\n\n/**\n * Ceiling on what a single archive may expand to. The full TeX tree is the\n * largest thing we legitimately unpack (~275 MB), so anything past this is a\n * compression bomb or a wrong URL — and on a mobile WebView, unpacking it\n * would take the app down before any JS error surfaced.\n */\nexport const MAX_DECOMPRESSED_BYTES = 512 * 1024 * 1024;\n\n/**\n * Decompress a gzip- or brotli-wrapped buffer using native DecompressionStream.\n *\n * `format` may be 'gzip' or 'deflate-raw' or 'br'. Brotli support varies by\n * runtime (Chrome 121+, Firefox 127+, Node 22+); gzip works everywhere since\n * 2023. Caller picks based on what their target supports.\n *\n * The output is bounded as it streams — checking the size after the fact\n * would mean the bomb has already been allocated.\n */\nexport async function decompress(\n  bytes: Uint8Array,\n  format: 'gzip' | 'deflate-raw' | 'br',\n  maxBytes: number = MAX_DECOMPRESSED_BYTES,\n): Promise<Uint8Array> {\n  const Ctor = (globalThis as { DecompressionStream?: typeof DecompressionStream })\n    .DecompressionStream;\n  if (!Ctor) {\n    throw new Error(`DecompressionStream not available; can't decompress ${format}`);\n  }\n  // Copy to ArrayBuffer-backed view (Blob doesn't accept SharedArrayBuffer views).\n  const ab = new ArrayBuffer(bytes.byteLength);\n  new Uint8Array(ab).set(bytes);\n  // `br` is a valid CompressionFormat at runtime in Chrome 121+/FF 127+/Node 22+\n  // but TS's lib.dom.d.ts only declares 'gzip' | 'deflate' | 'deflate-raw'.\n  // We cast — at runtime DecompressionStream throws TypeError if unsupported.\n  const stream = new Blob([ab])\n    .stream()\n    .pipeThrough(new Ctor(format as CompressionFormat))\n    .pipeThrough(limitBytes(maxBytes, format));\n  const buf = await new Response(stream).arrayBuffer();\n  return new Uint8Array(buf);\n}\n\n/** Errors the stream as soon as it has produced more than `maxBytes`. */\nfunction limitBytes(maxBytes: number, format: string): TransformStream<Uint8Array, Uint8Array> {\n  let seen = 0;\n  return new TransformStream<Uint8Array, Uint8Array>({\n    transform(chunk, controller) {\n      seen += chunk.byteLength;\n      if (seen > maxBytes) {\n        controller.error(\n          new Error(\n            `texlive-wasm: ${format} stream expands past the ${maxBytes}-byte limit; refusing to continue`,\n          ),\n        );\n        return;\n      }\n      controller.enqueue(chunk);\n    },\n  });\n}\n","/**\n * BundleFS — serves a TL TDS subset that was preloaded into memory.\n *\n * The bundle is a gzip- or brotli-wrapped tar of `texmf-dist/*` paths. On\n * engine init we fetch it once, decompress via native DecompressionStream,\n * untar into a Map, and serve reads from RAM.\n *\n * - `bundleUrl` is fetched as bytes; the format ('gzip'/'br') is auto-detected\n *   from the URL extension or magic bytes.\n * - `manifestUrl` alone also works: the manifest's `coreBundleUrl` (resolved\n *   relative to the manifest) names the bundle to fetch.\n * - For Node/Tauri tests, callers can pass `bundleBytes` directly.\n */\n\nimport type { VfsBackend } from '../core/types';\nimport { assertSha256, loadManifest } from '../core/manifest';\nimport { safeRelativePath } from '../core/paths';\nimport { decompress, untar } from './tar';\n\nexport interface BundleFsOptions {\n  /** Manifest URL; its `coreBundleUrl` locates the bundle when `bundleUrl` is not given. */\n  manifestUrl?: string;\n  /** Explicit bundle URL override. */\n  bundleUrl?: string;\n  /** Pre-loaded bundle bytes (skip fetch). Useful for tests + Tauri resources. */\n  bundleBytes?: Uint8Array;\n  /**\n   * SHA-256 (hex) the fetched bundle must hash to. When the bundle comes from\n   * a manifest, its `coreBundleSha256` is used automatically.\n   */\n  sha256?: string;\n  /**\n   * Fetch a bundle for which no SHA-256 is known. Off by default: a bundle is\n   * the whole TeX tree the engine will execute, and a cross-origin one that\n   * nothing pins is a supply-chain hole. Same-origin bundles (the app serving\n   * its own assets) are exempt — they carry the same trust as the code doing\n   * the fetching. Turn this on only in development.\n   */\n  allowUnverified?: boolean;\n  /**\n   * Compression format. Default: auto-detect from bundleUrl suffix (`.gz`\n   * / `.br`) or via magic-byte sniff on the bytes.\n   */\n  format?: 'gzip' | 'br';\n  /**\n   * Strip a leading path prefix from every entry. Default: `'texmf/'` (the\n   * bundle produced by `scripts/pack-tds.mjs` nests everything under that).\n   */\n  stripPrefix?: string;\n  /** Ceiling on the decompressed archive. Default: tar.ts's MAX_DECOMPRESSED_BYTES. */\n  maxBytes?: number;\n  /** Ceiling on the compressed download. Default: MAX_COMPRESSED_BYTES. */\n  maxCompressedBytes?: number;\n}\n\n/**\n * Ceiling on the bundle we are willing to download. The full TDS bundle is\n * ~120 MB compressed; twice that is already not a bundle we published.\n */\nexport const MAX_COMPRESSED_BYTES = 256 * 1024 * 1024;\n\nexport async function createBundleFs(opts: BundleFsOptions): Promise<VfsBackend> {\n  const files = new Map<string, Uint8Array>();\n  const stripPrefix = opts.stripPrefix ?? 'texmf/';\n\n  async function load(): Promise<void> {\n    let bytes = opts.bundleBytes;\n    let bundleUrl = opts.bundleUrl;\n    let expectedSha = opts.sha256;\n    if (!bytes && !bundleUrl && opts.manifestUrl) {\n      const manifest = await loadManifest(opts.manifestUrl);\n      if (manifest.coreBundleUrl) {\n        bundleUrl = new URL(manifest.coreBundleUrl, absolutize(opts.manifestUrl)).toString();\n        expectedSha ??= manifest.coreBundleSha256 ?? undefined;\n      }\n    }\n    if (!bytes && bundleUrl) {\n      requireIntegrity(bundleUrl, expectedSha, opts.allowUnverified === true);\n      const r = await fetch(bundleUrl);\n      if (!r.ok) throw new Error(`BundleFs: HTTP ${r.status} for ${bundleUrl}`);\n      bytes = new Uint8Array(await r.arrayBuffer());\n      const maxCompressed = opts.maxCompressedBytes ?? MAX_COMPRESSED_BYTES;\n      if (bytes.byteLength > maxCompressed) {\n        throw new Error(\n          `BundleFs: ${bundleUrl} is ${bytes.byteLength} bytes, past the ${maxCompressed}-byte ` +\n            `download limit; refusing to unpack it`,\n        );\n      }\n    }\n    if (!bytes) return;\n    // Verify the compressed blob before unpacking it: everything in here —\n    // packages, formats, ls-R — is fed straight to the engine, so a poisoned\n    // bundle is arbitrary TeX. Verifying once beats hashing 17k files.\n    if (expectedSha) {\n      await assertSha256(bytes, expectedSha, bundleUrl ?? 'bundle');\n    }\n    const format = opts.format ?? detectFormat(bundleUrl, bytes);\n    if (!format) {\n      throw new Error(\n        `BundleFs: cannot tell what ${bundleUrl ?? 'the supplied bundle'} is compressed with — ` +\n          `it is neither gzip nor a plain tar. Brotli has no magic bytes, so name the file ` +\n          `.tar.br or pass format: 'br' explicitly.`,\n      );\n    }\n    const tar = format === 'raw' ? bytes : await decompress(bytes, format, opts.maxBytes);\n    let rejected = 0;\n    let firstRejected = '';\n    let duplicates = 0;\n    for (const entry of untar(tar)) {\n      if (entry.type !== 'file') continue;\n      let path = entry.path;\n      if (path.startsWith(stripPrefix)) path = path.slice(stripPrefix.length);\n      // Tar entry names are attacker-controlled if the bundle is. A `..`\n      // segment climbs out of the tree; an absolute name is not something tar\n      // produces (it strips the leading slash on create), so treat it as the\n      // red flag it is rather than quietly reinterpreting it as relative.\n      const safe = path.startsWith('/') ? null : safeRelativePath(path);\n      if (!safe) {\n        rejected++;\n        firstRejected ||= entry.path;\n        continue;\n      }\n      // A second entry for the same name is how an archive says one thing to\n      // whatever inspected it and another to whoever unpacks it last. First\n      // one wins; the shadowing copy is dropped.\n      if (files.has(safe)) {\n        duplicates++;\n        continue;\n      }\n      files.set(safe, entry.content);\n    }\n    if (rejected > 0) {\n      console.warn(\n        `texlive-wasm: BundleFs dropped ${rejected} archive entr${rejected === 1 ? 'y' : 'ies'} ` +\n          `with an escaping path (first: ${firstRejected}) from ${bundleUrl ?? 'the supplied bundle'}`,\n      );\n    }\n    if (duplicates > 0) {\n      console.warn(\n        `texlive-wasm: BundleFs dropped ${duplicates} duplicate archive entr` +\n          `${duplicates === 1 ? 'y' : 'ies'} from ${bundleUrl ?? 'the supplied bundle'}; ` +\n          `the first copy of each name is the one served`,\n      );\n    }\n  }\n\n  return {\n    id: 'bundlefs',\n    read(tdsPath: string): Uint8Array | null {\n      return files.get(stripLeading(tdsPath)) ?? null;\n    },\n    exists(tdsPath: string): boolean {\n      return files.has(stripLeading(tdsPath));\n    },\n    list(prefix: string): string[] {\n      const p = stripLeading(prefix);\n      const out: string[] = [];\n      for (const path of files.keys()) {\n        if (path.startsWith(p)) out.push(path);\n      }\n      return out;\n    },\n    async init() {\n      await load();\n    },\n  };\n}\n\nfunction stripLeading(p: string): string {\n  return p.replace(/^\\/+/, '');\n}\n\n/**\n * A bundle we fetch is the entire TeX tree the engine executes — its formats,\n * its config, every package a document can \\input. Bytes for it must be\n * pinned by a digest unless they come from our own origin, where tampering\n * with them already means tampering with the app.\n */\nfunction requireIntegrity(bundleUrl: string, sha256: string | undefined, allow: boolean): void {\n  if (sha256 || allow || isSameOrigin(bundleUrl)) return;\n  throw new Error(\n    `BundleFs: refusing to load ${bundleUrl} — no SHA-256 for it. Publish the digest in the ` +\n      `manifest (coreBundleSha256), pass it as \\`sha256\\`, or serve the bundle from the app's ` +\n      `own origin. For development only, set allowUnverified/allowUnverifiedAssets.`,\n  );\n}\n\n/**\n * Same origin as the code doing the fetching — i.e. the worker's own origin.\n *\n * Tauri's asset protocol is NOT exempt: `convertFileSrc()` hands back an\n * `asset://localhost` / `http://asset.localhost` URL, whose origin is not the\n * page's, so a bundle addressed that way must still be pinned with `sha256`\n * (or read off disk and passed as `bundleBytes`, which skips fetching).\n */\nfunction isSameOrigin(url: string): boolean {\n  if (typeof location === 'undefined') return false;\n  try {\n    return new URL(url, location.href).origin === location.origin;\n  } catch {\n    return false;\n  }\n}\n\n/** Make a possibly-relative manifest URL absolute so it can be a URL base. */\nfunction absolutize(url: string): string {\n  if (/^[a-z][a-z0-9+.-]*:/i.test(url)) return url;\n  const origin = typeof location !== 'undefined' ? location.href : 'file:///';\n  return new URL(url, origin).toString();\n}\n\n/**\n * Identify the bundle's compression, or null when nothing identifies it.\n *\n * Brotli has no magic bytes, so it can only be asserted (by the `.tar.br`\n * suffix or an explicit `format`) — never inferred. Guessing 'br' for\n * \"anything else\" fed every unrecognized byte stream, including an HTML error\n * page a proxy substituted for the bundle, into DecompressionStream('br').\n */\nexport function detectFormat(\n  url: string | undefined,\n  bytes: Uint8Array,\n): 'gzip' | 'br' | 'raw' | null {\n  if (url) {\n    // Query strings and fragments are legal on an asset URL.\n    const path = url.split(/[?#]/)[0] ?? url;\n    if (path.endsWith('.tar.gz') || path.endsWith('.tgz')) return 'gzip';\n    if (path.endsWith('.tar.br')) return 'br';\n    if (path.endsWith('.tar')) return 'raw';\n  }\n  // gzip has magic bytes 1F 8B.\n  if (bytes.length >= 2 && bytes[0] === 0x1f && bytes[1] === 0x8b) return 'gzip';\n  // A plain tar has \"ustar\" at offset 257 of the first header block.\n  if (\n    bytes.length >= 262 &&\n    bytes[257] === 0x75 && // u\n    bytes[258] === 0x73 && // s\n    bytes[259] === 0x74 && // t\n    bytes[260] === 0x61 && // a\n    bytes[261] === 0x72 // r\n  ) {\n    return 'raw';\n  }\n  return null;\n}\n"],"names":["manifest","loadManifest","assertSha256","safeRelativePath"],"mappings":"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"}