{"version":3,"sources":["../../src/browser/detectBrowser.ts","../../src/constants/browserPaths.ts","../../src/types/types.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\n\nimport {\n  getBundledChromiumCandidates,\n  getWindowsBrowserCandidates,\n  type BrowserPathCandidate\n} from \"../constants/browserPaths\";\nimport { PdfEngineError, type DetectedBrowser } from \"../types/types\";\n\nexport type BrowserDetectionOptions = {\n  executablePath?: string;\n  cwd?: string;\n  env?: NodeJS.ProcessEnv;\n  platform?: NodeJS.Platform;\n  processExecPath?: string;\n  fileExists?: (filePath: string) => boolean;\n};\n\nfunction defaultFileExists(filePath: string): boolean {\n  try {\n    return fs.statSync(filePath).isFile();\n  } catch {\n    return false;\n  }\n}\n\nfunction assertSafeExecutablePath(executablePath: string, source: string): void {\n  if (executablePath.includes(\"\\0\")) {\n    throw new PdfEngineError(\n      \"VALIDATION_ERROR\",\n      `${source} browser executable path contains an invalid null byte.`\n    );\n  }\n}\n\nfunction toDetectedBrowser(candidate: BrowserPathCandidate): DetectedBrowser {\n  return {\n    name: candidate.name,\n    source: candidate.source,\n    executablePath: path.resolve(candidate.executablePath)\n  };\n}\n\nexport function detectBrowser(options: BrowserDetectionOptions = {}): DetectedBrowser {\n  const env = options.env ?? process.env;\n  const cwd = options.cwd ?? process.cwd();\n  const platform = options.platform ?? process.platform;\n  const processExecPath = options.processExecPath ?? process.execPath;\n  const fileExists = options.fileExists ?? defaultFileExists;\n  const triedPaths: string[] = [];\n\n  if (options.executablePath) {\n    assertSafeExecutablePath(options.executablePath, \"Configured\");\n\n    if (!fileExists(options.executablePath)) {\n      throw new PdfEngineError(\n        \"VALIDATION_ERROR\",\n        \"Configured browser executablePath does not exist or is not a file.\",\n        {\n          details: {\n            executablePath: options.executablePath\n          }\n        }\n      );\n    }\n\n    return {\n      name: \"Configured Chromium\",\n      source: \"override\",\n      executablePath: path.resolve(options.executablePath)\n    };\n  }\n\n  const installedCandidates =\n    platform === \"win32\" ? getWindowsBrowserCandidates(env) : [];\n  const bundledCandidates = getBundledChromiumCandidates(env, cwd, processExecPath);\n  const candidates = [...installedCandidates, ...bundledCandidates];\n\n  for (const candidate of candidates) {\n    assertSafeExecutablePath(candidate.executablePath, candidate.name);\n    triedPaths.push(candidate.executablePath);\n\n    if (fileExists(candidate.executablePath)) {\n      return toDetectedBrowser(candidate);\n    }\n  }\n\n  throw new PdfEngineError(\n    \"BROWSER_NOT_FOUND\",\n    \"No local Chrome, Edge, or bundled Chromium executable was found.\",\n    {\n      details: {\n        triedPaths\n      }\n    }\n  );\n}\n","import path from \"node:path\";\n\nimport type { BrowserSource } from \"../types/types\";\n\nexport const CHROMIUM_PATH_ENV = \"REACT_PDF_ENGINE_CHROMIUM_PATH\";\n\nexport type BrowserPathCandidate = {\n  name: string;\n  source: BrowserSource;\n  executablePath: string;\n};\n\nconst windowsPath = path.win32;\n\nfunction compact(values: Array<string | undefined>): string[] {\n  return values.filter((value): value is string => Boolean(value));\n}\n\nfunction uniqueCandidates(candidates: BrowserPathCandidate[]): BrowserPathCandidate[] {\n  const seen = new Set<string>();\n  const unique: BrowserPathCandidate[] = [];\n\n  for (const candidate of candidates) {\n    const key = windowsPath.normalize(candidate.executablePath).toLowerCase();\n    if (seen.has(key)) {\n      continue;\n    }\n\n    seen.add(key);\n    unique.push(candidate);\n  }\n\n  return unique;\n}\n\nexport function getWindowsBrowserCandidates(\n  env: NodeJS.ProcessEnv = process.env\n): BrowserPathCandidate[] {\n  const programFiles = compact([env.ProgramFiles, env[\"ProgramFiles(x86)\"]]);\n  const localAppData = env.LOCALAPPDATA;\n\n  const chromePaths = [\n    ...programFiles.map((root) =>\n      windowsPath.join(root, \"Google\", \"Chrome\", \"Application\", \"chrome.exe\")\n    ),\n    localAppData\n      ? windowsPath.join(localAppData, \"Google\", \"Chrome\", \"Application\", \"chrome.exe\")\n      : undefined\n  ];\n\n  const edgePaths = [\n    ...programFiles.map((root) =>\n      windowsPath.join(root, \"Microsoft\", \"Edge\", \"Application\", \"msedge.exe\")\n    ),\n    localAppData\n      ? windowsPath.join(localAppData, \"Microsoft\", \"Edge\", \"Application\", \"msedge.exe\")\n      : undefined\n  ];\n\n  return uniqueCandidates([\n    ...compact(chromePaths).map((executablePath) => ({\n      name: \"Google Chrome\",\n      source: \"chrome\" as const,\n      executablePath\n    })),\n    ...compact(edgePaths).map((executablePath) => ({\n      name: \"Microsoft Edge\",\n      source: \"edge\" as const,\n      executablePath\n    }))\n  ]);\n}\n\nexport function getBundledChromiumCandidates(\n  env: NodeJS.ProcessEnv = process.env,\n  cwd = process.cwd(),\n  processExecPath = process.execPath\n): BrowserPathCandidate[] {\n  const executableName = process.platform === \"win32\" ? \"chrome.exe\" : \"chrome\";\n  const roots = compact([\n    cwd,\n    path.dirname(processExecPath),\n    process.env.APPDIR,\n    process.env.PORTABLE_EXECUTABLE_DIR\n  ]);\n\n  const relativePaths = [\n    [\"chromium\", executableName],\n    [\"chromium\", \"chrome-win\", executableName],\n    [\"chrome-win\", executableName],\n    [\"bin\", \"chromium\", executableName],\n    [\"resources\", \"chromium\", executableName],\n    [\"resources\", \"chrome-win\", executableName]\n  ];\n\n  const envCandidate = env[CHROMIUM_PATH_ENV]\n    ? [\n        {\n          name: \"Bundled Chromium\",\n          source: \"bundled\" as const,\n          executablePath: env[CHROMIUM_PATH_ENV]\n        }\n      ]\n    : [];\n\n  const conventionCandidates = roots.flatMap((root) =>\n    relativePaths.map((segments) => ({\n      name: \"Bundled Chromium\",\n      source: \"bundled\" as const,\n      executablePath: path.join(root, ...segments)\n    }))\n  );\n\n  return uniqueCandidates([...envCandidate, ...conventionCandidates]);\n}\n","export type PdfOutputMode = \"buffer\" | \"file\";\n\nexport type PdfEngineErrorCode =\n  | \"VALIDATION_ERROR\"\n  | \"BROWSER_NOT_FOUND\"\n  | \"BROWSER_LAUNCH_FAILED\"\n  | \"ASSET_LOAD_FAILED\"\n  | \"RENDER_FAILED\"\n  | \"TIMEOUT\"\n  | \"FILE_OUTPUT_FAILED\";\n\nexport type BrowserSource = \"override\" | \"chrome\" | \"edge\" | \"bundled\";\n\nexport type CssLength = string;\n\nexport type PdfPageSize = {\n  width: CssLength;\n  height: CssLength;\n};\n\nexport type PdfMargins = {\n  top?: CssLength;\n  right?: CssLength;\n  bottom?: CssLength;\n  left?: CssLength;\n};\n\nexport type RenderPdfOptions = {\n  html: string;\n  size: PdfPageSize;\n  margins?: PdfMargins;\n  landscape?: boolean;\n  output?: PdfOutputMode;\n  outputPath?: string;\n  scale?: number;\n  timeout?: number;\n  executablePath?: string;\n};\n\nexport type NormalizedRenderPdfOptions = {\n  html: string;\n  size: PdfPageSize;\n  margins?: Required<PdfMargins>;\n  landscape?: boolean;\n  output: PdfOutputMode;\n  outputPath?: string;\n  scale: number;\n  timeout: number;\n  executablePath?: string;\n};\n\nexport type RenderPdfFileResult = {\n  path: string;\n};\n\nexport type RenderPdfResult = Buffer | RenderPdfFileResult;\n\nexport type DetectedBrowser = {\n  name: string;\n  source: BrowserSource;\n  executablePath: string;\n};\n\nexport type AssetLoadFailure = {\n  url: string;\n  errorText: string;\n};\n\nexport type PdfEngineErrorOptions = {\n  cause?: unknown;\n  details?: unknown;\n};\n\nexport class PdfEngineError extends Error {\n  readonly code: PdfEngineErrorCode;\n  readonly details?: unknown;\n\n  constructor(\n    code: PdfEngineErrorCode,\n    message: string,\n    options: PdfEngineErrorOptions = {}\n  ) {\n    super(message);\n    this.name = \"PdfEngineError\";\n    this.code = code;\n\n    if (\"cause\" in options) {\n      this.cause = options.cause;\n    }\n\n    if (\"details\" in options) {\n      this.details = options.details;\n    }\n  }\n}\n"],"mappings":"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","names":["path","path"]}