{"version":3,"file":"tauri.cjs","sources":["../src/vfs/taurifs.ts"],"sourcesContent":["/**\n * TauriFS — reads TL packages directly from the Tauri app's filesystem.\n *\n * For the Tauri target, the consumer ships the full TL TDS as app resources\n * (or copies it to AppData on first run). This backend lets the engine read\n * those files via @tauri-apps/plugin-fs — no OPFS, no per-file fetches, no\n * download flow.\n *\n * Usage:\n *\n *   import { createEngine } from '@typeward/texlive-wasm';\n *   import { withTauriFs } from '@typeward/texlive-wasm/tauri';\n *   import { BaseDirectory } from '@tauri-apps/plugin-fs';\n *\n *   const engine = await withTauriFs(\n *     (vfs) => createEngine('xelatex', { vfs }),\n *     { texmfRoot: 'texmf', baseDir: BaseDirectory.AppData },\n *   );\n */\n\nimport type { EngineHandle, VfsBackend } from '../core/types';\nimport { safeRelativePath } from '../core/paths';\n\nexport interface TauriFsOptions {\n  /** Subdirectory under the chosen base dir where the TDS lives. e.g. \"texmf\". */\n  texmfRoot: string;\n  /**\n   * Tauri BaseDirectory enum value. We accept it as a number to avoid a\n   * hard dependency on @tauri-apps/api types here. Prefer importing\n   * `BaseDirectory` from @tauri-apps/plugin-fs; for reference, Tauri 2\n   * values are: Resource = 11, AppConfig = 13, AppData = 14,\n   * AppLocalData = 15.\n   */\n  baseDir: number;\n}\n\n/**\n * Create a TauriFS backend. Imports @tauri-apps/plugin-fs dynamically so this\n * module doesn't pull it in for non-Tauri consumers.\n */\nexport async function createTauriFs(opts: TauriFsOptions): Promise<VfsBackend> {\n  // Dynamic import — the plugin is a peerDependency.\n  const fs = await import('@tauri-apps/plugin-fs').catch(() => null);\n  if (!fs) {\n    throw new Error(\n      'texlive-wasm/tauri: @tauri-apps/plugin-fs is not installed. ' +\n        'Add it as a dependency in your Tauri app.',\n    );\n  }\n\n  // Unlike the other backends, a path that escapes here escapes into the\n  // user's real filesystem: plugin-fs resolves it against a base dir with the\n  // app's own permissions. Every TDS path arriving from an engine log goes\n  // through the same funnel as everywhere else.\n  const resolve = (tdsPath: string): string | null => {\n    const rel = safeRelativePath(tdsPath);\n    if (!rel) return null;\n    const root = opts.texmfRoot.replace(/\\/+$/, '');\n    return root ? `${root}/${rel}` : rel;\n  };\n\n  return {\n    id: 'taurifs',\n    async read(tdsPath: string): Promise<Uint8Array | null> {\n      const full = resolve(tdsPath);\n      if (!full) return null;\n      try {\n        return await (fs as typeof import('@tauri-apps/plugin-fs')).readFile(full, {\n          baseDir: opts.baseDir,\n        });\n      } catch {\n        return null;\n      }\n    },\n    async exists(tdsPath: string): Promise<boolean> {\n      const full = resolve(tdsPath);\n      if (!full) return false;\n      try {\n        return await (fs as typeof import('@tauri-apps/plugin-fs')).exists(full, {\n          baseDir: opts.baseDir,\n        });\n      } catch {\n        return false;\n      }\n    },\n  };\n}\n\n/**\n * Detect whether the current runtime is a Tauri app. Cheap and safe to\n * call from anywhere (returns false in Node, browsers, web workers).\n */\nexport function isTauri(): boolean {\n  const g = globalThis as { __TAURI_INTERNALS__?: unknown; __TAURI__?: unknown };\n  return Boolean(g.__TAURI_INTERNALS__ || g.__TAURI__);\n}\n\n/**\n * Convenience: create an engine with TauriFS prepended to its backend list.\n *\n * Use this when the consumer wants the engine to read TDS files straight\n * from the bundled Tauri resources. The TauriFs backend is consulted first\n * (highest priority), so any file present locally wins over CDN fallback.\n *\n * The actual engine is constructed by the caller-supplied factory, which\n * receives the prepared backend chain. In practice the factory is just\n * `createEngine` from this package.\n */\nexport async function withTauriFs(\n  factory: (vfs: VfsBackend[]) => Promise<EngineHandle>,\n  opts: TauriFsOptions & { extraBackends?: VfsBackend[] },\n): Promise<EngineHandle> {\n  if (!isTauri()) {\n    throw new Error('withTauriFs: not running in a Tauri app (window.__TAURI__ missing)');\n  }\n  const tauriFs = await createTauriFs(opts);\n  return factory([tauriFs, ...(opts.extraBackends ?? [])]);\n}\n"],"names":["safeRelativePath"],"mappings":";;;;;;AAwCA,eAAsB,cAAc,IAAA,EAA2C;AAE7E,EAAA,MAAM,KAAK,MAAM,OAAO,uBAAuB,CAAA,CAAE,KAAA,CAAM,MAAM,IAAI,CAAA;AACjE,EAAA,IAAI,CAAC,EAAA,EAAI;AACP,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KAEF;AAAA,EACF;AAMA,EAAA,MAAM,OAAA,GAAU,CAAC,OAAA,KAAmC;AAClD,IAAA,MAAM,GAAA,GAAMA,uBAAiB,OAAO,CAAA;AACpC,IAAA,IAAI,CAAC,KAAK,OAAO,IAAA;AACjB,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,SAAA,CAAU,OAAA,CAAQ,QAAQ,EAAE,CAAA;AAC9C,IAAA,OAAO,IAAA,GAAO,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,GAAG,CAAA,CAAA,GAAK,GAAA;AAAA,EACnC,CAAA;AAEA,EAAA,OAAO;AAAA,IACL,EAAA,EAAI,SAAA;AAAA,IACJ,MAAM,KAAK,OAAA,EAA6C;AACtD,MAAA,MAAM,IAAA,GAAO,QAAQ,OAAO,CAAA;AAC5B,MAAA,IAAI,CAAC,MAAM,OAAO,IAAA;AAClB,MAAA,IAAI;AACF,QAAA,OAAO,MAAO,EAAA,CAA8C,QAAA,CAAS,IAAA,EAAM;AAAA,UACzE,SAAS,IAAA,CAAK;AAAA,SACf,CAAA;AAAA,MACH,CAAA,CAAA,MAAQ;AACN,QAAA,OAAO,IAAA;AAAA,MACT;AAAA,IACF,CAAA;AAAA,IACA,MAAM,OAAO,OAAA,EAAmC;AAC9C,MAAA,MAAM,IAAA,GAAO,QAAQ,OAAO,CAAA;AAC5B,MAAA,IAAI,CAAC,MAAM,OAAO,KAAA;AAClB,MAAA,IAAI;AACF,QAAA,OAAO,MAAO,EAAA,CAA8C,MAAA,CAAO,IAAA,EAAM;AAAA,UACvE,SAAS,IAAA,CAAK;AAAA,SACf,CAAA;AAAA,MACH,CAAA,CAAA,MAAQ;AACN,QAAA,OAAO,KAAA;AAAA,MACT;AAAA,IACF;AAAA,GACF;AACF;AAMO,SAAS,OAAA,GAAmB;AACjC,EAAA,MAAM,CAAA,GAAI,UAAA;AACV,EAAA,OAAO,OAAA,CAAQ,CAAA,CAAE,mBAAA,IAAuB,CAAA,CAAE,SAAS,CAAA;AACrD;AAaA,eAAsB,WAAA,CACpB,SACA,IAAA,EACuB;AACvB,EAAA,IAAI,CAAC,SAAQ,EAAG;AACd,IAAA,MAAM,IAAI,MAAM,oEAAoE,CAAA;AAAA,EACtF;AACA,EAAA,MAAM,OAAA,GAAU,MAAM,aAAA,CAAc,IAAI,CAAA;AACxC,EAAA,OAAO,OAAA,CAAQ,CAAC,OAAA,EAAS,GAAI,KAAK,aAAA,IAAiB,EAAG,CAAC,CAAA;AACzD;;;;;;"}