app-builder-lib 26.15.6 → 26.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/out/configuration.d.ts +32 -0
  2. package/out/configuration.js.map +1 -1
  3. package/out/electron/ElectronFramework.d.ts +2 -1
  4. package/out/electron/ElectronFramework.js +30 -25
  5. package/out/electron/ElectronFramework.js.map +1 -1
  6. package/out/macPackager.d.ts +7 -2
  7. package/out/macPackager.js +40 -11
  8. package/out/macPackager.js.map +1 -1
  9. package/out/node-module-collector/nodeModulesCollector.d.ts +11 -1
  10. package/out/node-module-collector/nodeModulesCollector.js +16 -2
  11. package/out/node-module-collector/nodeModulesCollector.js.map +1 -1
  12. package/out/node-module-collector/pnpmNodeModulesCollector.js +3 -1
  13. package/out/node-module-collector/pnpmNodeModulesCollector.js.map +1 -1
  14. package/out/targets/AppxTarget.js +5 -5
  15. package/out/targets/AppxTarget.js.map +1 -1
  16. package/out/targets/MsiTarget.js +8 -11
  17. package/out/targets/MsiTarget.js.map +1 -1
  18. package/out/targets/appimage/appImageUtil.d.ts +1 -1
  19. package/out/targets/appimage/appImageUtil.js +3 -3
  20. package/out/targets/appimage/appImageUtil.js.map +1 -1
  21. package/out/targets/appimage/appLauncher.js +3 -9
  22. package/out/targets/appimage/appLauncher.js.map +1 -1
  23. package/out/targets/blockmap/blockmap.js +2 -2
  24. package/out/targets/blockmap/blockmap.js.map +1 -1
  25. package/out/targets/nsis/nsisOptions.d.ts +2 -0
  26. package/out/targets/nsis/nsisOptions.js.map +1 -1
  27. package/out/toolsets/icons.js +2 -2
  28. package/out/toolsets/icons.js.map +1 -1
  29. package/out/toolsets/linux.js +3 -3
  30. package/out/toolsets/linux.js.map +1 -1
  31. package/out/util/appFileCopier.d.ts +21 -0
  32. package/out/util/appFileCopier.js +58 -0
  33. package/out/util/appFileCopier.js.map +1 -1
  34. package/out/util/electronGet.d.ts +46 -0
  35. package/out/util/electronGet.js +191 -35
  36. package/out/util/electronGet.js.map +1 -1
  37. package/out/version.d.ts +1 -1
  38. package/out/version.js +1 -1
  39. package/out/version.js.map +1 -1
  40. package/package.json +8 -8
  41. package/scheme.json +20 -1
  42. package/templates/appx/appxmanifest.xml +1 -2
  43. package/templates/nsis/include/allowOnlyOneInstallerInstance.nsh +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"appFileCopier.js","sourceRoot":"","sources":["../../src/util/appFileCopier.ts"],"names":[],"mappings":"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","sourcesContent":["import { AsyncTaskManager, FileCopier, FileTransformer, isEmptyOrSpaces, Link, log, MAX_FILE_REQUESTS, statOrNull, walk } from \"builder-util\"\nimport { Stats } from \"fs\"\nimport { ensureSymlink } from \"fs-extra\"\nimport { mkdir, readlink } from \"fs/promises\"\nimport * as path from \"path\"\nimport asyncPool from \"tiny-async-pool\"\nimport { isLibOrExe } from \"../asar/unpackDetector\"\nimport { Platform } from \"../core\"\nimport { excludedExts, FileMatcher } from \"../fileMatcher\"\nimport { createElectronCompilerHost, NODE_MODULES_PATTERN } from \"../fileTransformer\"\nimport { getCollectorByPackageManager, PM } from \"../node-module-collector\"\nimport { LogMessageByKey, logMessageLevelByKey, ModuleManager } from \"../node-module-collector/moduleManager\"\nimport { Packager } from \"../packager\"\nimport { PlatformPackager } from \"../platformPackager\"\nimport { AppFileWalker } from \"./AppFileWalker\"\nimport { NodeModuleCopyHelper } from \"./NodeModuleCopyHelper\"\nimport { NodeModuleInfo } from \"./packageDependencies\"\n\nconst BOWER_COMPONENTS_PATTERN = `${path.sep}bower_components${path.sep}`\n/** @internal */\nexport const ELECTRON_COMPILE_SHIM_FILENAME = \"__shim.js\"\n\nexport function getDestinationPath(file: string, fileSet: ResolvedFileSet) {\n if (file === fileSet.src) {\n return fileSet.destination\n }\n\n const src = fileSet.src\n const dest = fileSet.destination\n // get node_modules path relative to src and then append to dest\n if (file.startsWith(src)) {\n return path.join(dest, path.relative(src, file))\n }\n return dest\n}\n\nexport async function copyAppFiles(fileSet: ResolvedFileSet, packager: Packager, transformer: FileTransformer) {\n const metadata = fileSet.metadata\n // search auto unpacked dir\n const taskManager = new AsyncTaskManager(packager.cancellationToken)\n const createdParentDirs = new Set<string>()\n\n const fileCopier = new FileCopier(file => {\n return !isLibOrExe(file)\n }, transformer)\n const links: Array<Link> = []\n for (let i = 0, n = fileSet.files.length; i < n; i++) {\n const sourceFile = fileSet.files[i]\n const stat = metadata.get(sourceFile)\n if (stat == null) {\n // dir\n continue\n }\n\n const destinationFile = getDestinationPath(sourceFile, fileSet)\n if (stat.isSymbolicLink()) {\n links.push({ file: destinationFile, link: await readlink(sourceFile) })\n continue\n }\n\n const fileParent = path.dirname(destinationFile)\n if (!createdParentDirs.has(fileParent)) {\n createdParentDirs.add(fileParent)\n await mkdir(fileParent, { recursive: true })\n }\n\n taskManager.addTask(fileCopier.copy(sourceFile, destinationFile, stat))\n if (taskManager.tasks.length > MAX_FILE_REQUESTS) {\n await taskManager.awaitTasks()\n }\n }\n\n if (taskManager.tasks.length > 0) {\n await taskManager.awaitTasks()\n }\n\n await asyncPool(MAX_FILE_REQUESTS, links, it => ensureSymlink(it.link, it.file))\n}\n\n// os path separator is used\nexport interface ResolvedFileSet {\n src: string\n destination: string\n\n files: Array<string>\n metadata: Map<string, Stats>\n transformedFiles?: Map<number, string | Buffer> | null\n}\n\n// used only for ASAR, if no asar, file transformed on the fly\nexport async function transformFiles(transformer: FileTransformer, fileSet: ResolvedFileSet): Promise<void> {\n if (transformer == null) {\n return\n }\n\n let transformedFiles = fileSet.transformedFiles\n if (fileSet.transformedFiles == null) {\n transformedFiles = new Map()\n fileSet.transformedFiles = transformedFiles\n }\n\n const metadata = fileSet.metadata\n const filesPromise = fileSet.files.map(async (it, index) => {\n const fileStat = metadata.get(it)\n if (fileStat == null || !fileStat.isFile()) {\n return\n }\n\n const transformedValue = transformer(it)\n if (transformedValue == null) {\n return\n }\n\n if (typeof transformedValue === \"object\" && \"then\" in transformedValue) {\n return (transformedValue as Promise<any>).then(it => {\n if (it != null) {\n transformedFiles!.set(index, it)\n }\n return\n })\n }\n transformedFiles!.set(index, transformedValue as string | Buffer)\n return\n })\n // `asyncPool` doesn't provide `index` in it's handler, so we `map` first before using it\n await asyncPool(MAX_FILE_REQUESTS, filesPromise, promise => promise)\n}\n\nexport async function computeFileSets(\n matchers: Array<FileMatcher>,\n transformer: FileTransformer | null,\n platformPackager: PlatformPackager<any>,\n isElectronCompile: boolean\n): Promise<Array<ResolvedFileSet>> {\n const fileSets: Array<ResolvedFileSet> = []\n const packager = platformPackager.info\n\n for (const matcher of matchers) {\n const fileWalker = new AppFileWalker(matcher, packager)\n\n const fromStat = await statOrNull(matcher.from)\n if (fromStat == null) {\n log.debug({ directory: matcher.from, reason: \"doesn't exist\" }, `skipped copying`)\n continue\n }\n\n const files = await walk(matcher.from, fileWalker.filter, fileWalker)\n const metadata = fileWalker.metadata\n fileSets.push(validateFileSet({ src: matcher.from, files, metadata, destination: matcher.to }))\n }\n\n if (isElectronCompile) {\n // cache files should be first (better IO)\n fileSets.unshift(await compileUsingElectronCompile(fileSets[0], packager))\n }\n return fileSets\n}\n\nfunction getNodeModuleExcludedExts(platformPackager: PlatformPackager<any>) {\n // do not exclude *.h files (https://github.com/electron-userland/electron-builder/issues/2852)\n const result = [\".o\", \".obj\"].concat(excludedExts.split(\",\").map(it => `.${it}`))\n if (platformPackager.config.includePdb !== true) {\n result.push(\".pdb\")\n }\n if (platformPackager.platform !== Platform.WINDOWS) {\n // https://github.com/electron-userland/electron-builder/issues/1738\n result.push(\".dll\")\n result.push(\".exe\")\n }\n return result\n}\n\nfunction validateFileSet(fileSet: ResolvedFileSet): ResolvedFileSet {\n if (fileSet.src == null || fileSet.src.length === 0) {\n throw new Error(\"fileset src is empty\")\n }\n return fileSet\n}\n\n/** @internal */\nexport async function computeNodeModuleFileSets(platformPackager: PlatformPackager<any>, mainMatcher: FileMatcher): Promise<Array<ResolvedFileSet>> {\n const deps = await collectNodeModulesWithLogging(platformPackager)\n\n const nodeModuleExcludedExts = getNodeModuleExcludedExts(platformPackager)\n // serial execution because copyNodeModules is concurrent and so, no need to increase queue/pressure\n const result = new Array<ResolvedFileSet>()\n let index = 0\n const NODE_MODULES = \"node_modules\"\n\n const collectNodeModules = async (dep: NodeModuleInfo, destination: string) => {\n const source = dep.dir\n const matcher = new FileMatcher(source, destination, mainMatcher.macroExpander, mainMatcher.patterns)\n const copier = new NodeModuleCopyHelper(matcher, platformPackager.info)\n const files = await copier.collectNodeModules(dep, nodeModuleExcludedExts, path.relative(mainMatcher.to, destination))\n result[index++] = validateFileSet({ src: source, destination, files, metadata: copier.metadata })\n\n log.debug({ dep: dep.name, from: log.filePath(source), to: log.filePath(destination), filesCount: files.length }, \"identified module\")\n\n if (dep.dependencies) {\n for (const c of dep.dependencies) {\n await collectNodeModules(c, path.join(destination, NODE_MODULES, c.name))\n }\n }\n }\n\n for (const dep of deps) {\n const destination = path.join(mainMatcher.to, NODE_MODULES, dep.name)\n await collectNodeModules(dep, destination)\n }\n return result\n}\n\ntype CollectedNodeModules = { nodeModules: NodeModuleInfo[]; logSummary: ModuleManager[\"logSummary\"] }\n\n/** Runs a single package-manager collector against a single directory. */\ntype CollectorRunner = (pm: PM, dir: string) => Promise<CollectedNodeModules>\n\n// `workspace:`/`file:`/`link:`/`portal:` dependencies are symlinked into place rather than\n// installed as standalone, hoistable packages, so they may legitimately be absent from a\n// collected tree and cannot be used to validate it.\nconst LOCAL_DEPENDENCY_SPEC = /^(?:workspace|file|link|portal):/\n\n/**\n * Determines whether a collected module tree actually describes the package being built.\n *\n * A package-manager `list` invocation can resolve to the wrong project root — most notably when\n * electron-builder is run from a workspace sub-package whose dependencies are hoisted to the\n * workspace root. In that case the collector returns a non-empty but unrelated tree. Accepting it\n * would suppress the manual-traversal fallback that resolves the correct modules, so we need to\n * tell a matching collection from a mismatched one.\n *\n * A collection matches when at least one of the package's declared external (registry-installed,\n * non-`workspace:`/`file:`/`link:`/`portal:`) production dependencies is present at the top level —\n * those direct dependencies are always hoisted to the top level of a correct collection. When the\n * package declares no external production dependencies there is nothing to validate against, so any\n * non-empty collection is accepted.\n */\nexport function collectionMatchesAppDependencies(nodeModules: NodeModuleInfo[], dependencies: Record<string, string> | undefined): boolean {\n const requiredExternalDeps = Object.entries(dependencies ?? {})\n .filter(([, spec]) => !LOCAL_DEPENDENCY_SPEC.test(spec))\n .map(([name]) => name)\n if (requiredExternalDeps.length === 0) {\n return true\n }\n const collected = new Set(nodeModules.map(it => it.name))\n return requiredExternalDeps.some(name => collected.has(name))\n}\n\n/**\n * Walks the candidate (package-manager, directory) combinations and returns the first collection\n * that both contains modules and matches the package being built (see\n * {@link collectionMatchesAppDependencies}). A non-empty collection that does NOT match — e.g. a\n * workspace-root tree returned for a sub-package — is retained only as a last-resort fallback so a\n * later approach (notably {@link PM.TRAVERSAL}) can supply the correct modules.\n */\nexport async function resolveFirstMatchingCollection(options: {\n pmApproaches: PM[]\n searchDirectories: string[]\n dependencies: Record<string, string> | undefined\n run: CollectorRunner\n}): Promise<CollectedNodeModules | undefined> {\n const { pmApproaches, searchDirectories, dependencies, run } = options\n let fallback: CollectedNodeModules | undefined\n\n for (const pm of pmApproaches) {\n for (const dir of searchDirectories) {\n log.info({ pm, searchDir: dir }, \"searching for node modules\")\n const deps = await run(pm, dir)\n if (deps.nodeModules.length === 0) {\n log.info({ pm, searchDir: dir }, \"no node modules found in collection, trying next search directory\")\n continue\n }\n if (collectionMatchesAppDependencies(deps.nodeModules, dependencies)) {\n log.debug({ pm, searchDir: dir, depCount: deps.nodeModules.length }, \"collected node modules\")\n return deps\n }\n log.info({ pm, searchDir: dir }, \"collected node modules do not match the target package, trying next search directory/approach\")\n fallback ??= deps\n }\n }\n return fallback\n}\n\nasync function collectNodeModulesWithLogging(platformPackager: PlatformPackager<any>) {\n const packager = platformPackager.info\n const { tempDirManager, appDir, projectDir } = packager\n\n const searchDirectories = Array.from(new Set([appDir, projectDir, await packager.getWorkspaceRoot()])).filter((it): it is string => isEmptyOrSpaces(it) === false)\n const pmApproaches = [await packager.getPackageManager(), PM.TRAVERSAL]\n\n // Validate against the as-declared (pre-extraMetadata) production dependencies so a configured\n // `extraMetadata.dependencies` entry that isn't installed cannot reject a correct collection.\n const deps = await resolveFirstMatchingCollection({\n pmApproaches,\n searchDirectories,\n dependencies: packager.originalMetadata.dependencies,\n run: (pm, dir) => getCollectorByPackageManager(pm, dir, tempDirManager).getNodeModules({ packageName: packager.nodePackageName }),\n })\n\n if (!deps?.nodeModules?.length) {\n log.warn({ searchDirectories: searchDirectories.map(it => log.filePath(it)) }, \"no node modules returned while searching directories\")\n return []\n }\n\n const summary = Object.entries(deps.logSummary ?? {}).filter(([, dependencies]) => Array.isArray(dependencies) && dependencies.length > 0)\n for (const [errorMessage, dependencies] of summary) {\n const logLevel = logMessageLevelByKey[errorMessage as LogMessageByKey] || \"debug\"\n log[logLevel]({ dependencies }, errorMessage)\n }\n\n return deps.nodeModules\n}\n\nasync function compileUsingElectronCompile(mainFileSet: ResolvedFileSet, packager: Packager): Promise<ResolvedFileSet> {\n log.info(\"compiling using electron-compile\")\n\n const electronCompileCache = await packager.tempDirManager.getTempDir({ prefix: \"electron-compile-cache\" })\n const cacheDir = path.join(electronCompileCache, \".cache\")\n // clear and create cache dir\n await mkdir(cacheDir, { recursive: true })\n const compilerHost = await createElectronCompilerHost(mainFileSet.src, cacheDir)\n const nextSlashIndex = mainFileSet.src.length + 1\n // pre-compute electron-compile to cache dir - we need to process only subdirectories, not direct files of app dir\n const filesPromise: Promise<any>[] = mainFileSet.files.map(file => {\n if (\n file.includes(NODE_MODULES_PATTERN) ||\n file.includes(BOWER_COMPONENTS_PATTERN) ||\n !file.includes(path.sep, nextSlashIndex) || // ignore not root files\n !mainFileSet.metadata.get(file)!.isFile()\n ) {\n return\n }\n return compilerHost.compile(file)\n })\n await asyncPool(MAX_FILE_REQUESTS, filesPromise, promise => promise)\n await compilerHost.saveConfiguration()\n\n const metadata = new Map<string, Stats>()\n const cacheFiles = await walk(cacheDir, file => !file.startsWith(\".\"), {\n consume: (file, fileStat) => {\n if (fileStat.isFile()) {\n metadata.set(file, fileStat)\n }\n return null\n },\n })\n\n // add shim\n const shimPath = `${mainFileSet.src}${path.sep}${ELECTRON_COMPILE_SHIM_FILENAME}`\n mainFileSet.files.push(shimPath)\n mainFileSet.metadata.set(shimPath, { isFile: () => true, isDirectory: () => false, isSymbolicLink: () => false } as any)\n if (mainFileSet.transformedFiles == null) {\n mainFileSet.transformedFiles = new Map()\n }\n mainFileSet.transformedFiles.set(\n mainFileSet.files.length - 1,\n `\n'use strict';\nrequire('electron-compile').init(__dirname, require('path').resolve(__dirname, '${packager.metadata.main || \"index\"}'), true);\n`\n )\n return { src: electronCompileCache, files: cacheFiles, metadata, destination: mainFileSet.destination }\n}\n"]}
1
+ {"version":3,"file":"appFileCopier.js","sourceRoot":"","sources":["../../src/util/appFileCopier.ts"],"names":[],"mappings":"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","sourcesContent":["import { AsyncTaskManager, FileCopier, FileTransformer, InvalidConfigurationError, isEmptyOrSpaces, Link, log, MAX_FILE_REQUESTS, statOrNull, walk } from \"builder-util\"\nimport { Stats } from \"fs\"\nimport { ensureSymlink } from \"fs-extra\"\nimport { mkdir, readlink } from \"fs/promises\"\nimport * as path from \"path\"\nimport asyncPool from \"tiny-async-pool\"\nimport { isLibOrExe } from \"../asar/unpackDetector\"\nimport { Platform } from \"../core\"\nimport { excludedExts, FileMatcher } from \"../fileMatcher\"\nimport { createElectronCompilerHost, NODE_MODULES_PATTERN } from \"../fileTransformer\"\nimport { getCollectorByPackageManager, PM } from \"../node-module-collector\"\nimport { LogMessageByKey, logMessageLevelByKey, ModuleManager } from \"../node-module-collector/moduleManager\"\nimport { Packager } from \"../packager\"\nimport { PlatformPackager } from \"../platformPackager\"\nimport { AppFileWalker } from \"./AppFileWalker\"\nimport { NodeModuleCopyHelper } from \"./NodeModuleCopyHelper\"\nimport { NodeModuleInfo } from \"./packageDependencies\"\n\nconst BOWER_COMPONENTS_PATTERN = `${path.sep}bower_components${path.sep}`\n/** @internal */\nexport const ELECTRON_COMPILE_SHIM_FILENAME = \"__shim.js\"\n\nexport function getDestinationPath(file: string, fileSet: ResolvedFileSet) {\n if (file === fileSet.src) {\n return fileSet.destination\n }\n\n const src = fileSet.src\n const dest = fileSet.destination\n // get node_modules path relative to src and then append to dest\n if (file.startsWith(src)) {\n return path.join(dest, path.relative(src, file))\n }\n return dest\n}\n\nexport async function copyAppFiles(fileSet: ResolvedFileSet, packager: Packager, transformer: FileTransformer) {\n const metadata = fileSet.metadata\n // search auto unpacked dir\n const taskManager = new AsyncTaskManager(packager.cancellationToken)\n const createdParentDirs = new Set<string>()\n\n const fileCopier = new FileCopier(file => {\n return !isLibOrExe(file)\n }, transformer)\n const links: Array<Link> = []\n for (let i = 0, n = fileSet.files.length; i < n; i++) {\n const sourceFile = fileSet.files[i]\n const stat = metadata.get(sourceFile)\n if (stat == null) {\n // dir\n continue\n }\n\n const destinationFile = getDestinationPath(sourceFile, fileSet)\n if (stat.isSymbolicLink()) {\n links.push({ file: destinationFile, link: await readlink(sourceFile) })\n continue\n }\n\n const fileParent = path.dirname(destinationFile)\n if (!createdParentDirs.has(fileParent)) {\n createdParentDirs.add(fileParent)\n await mkdir(fileParent, { recursive: true })\n }\n\n taskManager.addTask(fileCopier.copy(sourceFile, destinationFile, stat))\n if (taskManager.tasks.length > MAX_FILE_REQUESTS) {\n await taskManager.awaitTasks()\n }\n }\n\n if (taskManager.tasks.length > 0) {\n await taskManager.awaitTasks()\n }\n\n await asyncPool(MAX_FILE_REQUESTS, links, it => ensureSymlink(it.link, it.file))\n}\n\n// os path separator is used\nexport interface ResolvedFileSet {\n src: string\n destination: string\n\n files: Array<string>\n metadata: Map<string, Stats>\n transformedFiles?: Map<number, string | Buffer> | null\n}\n\n// used only for ASAR, if no asar, file transformed on the fly\nexport async function transformFiles(transformer: FileTransformer, fileSet: ResolvedFileSet): Promise<void> {\n if (transformer == null) {\n return\n }\n\n let transformedFiles = fileSet.transformedFiles\n if (fileSet.transformedFiles == null) {\n transformedFiles = new Map()\n fileSet.transformedFiles = transformedFiles\n }\n\n const metadata = fileSet.metadata\n const filesPromise = fileSet.files.map(async (it, index) => {\n const fileStat = metadata.get(it)\n if (fileStat == null || !fileStat.isFile()) {\n return\n }\n\n const transformedValue = transformer(it)\n if (transformedValue == null) {\n return\n }\n\n if (typeof transformedValue === \"object\" && \"then\" in transformedValue) {\n return (transformedValue as Promise<any>).then(it => {\n if (it != null) {\n transformedFiles!.set(index, it)\n }\n return\n })\n }\n transformedFiles!.set(index, transformedValue as string | Buffer)\n return\n })\n // `asyncPool` doesn't provide `index` in it's handler, so we `map` first before using it\n await asyncPool(MAX_FILE_REQUESTS, filesPromise, promise => promise)\n}\n\nexport async function computeFileSets(\n matchers: Array<FileMatcher>,\n transformer: FileTransformer | null,\n platformPackager: PlatformPackager<any>,\n isElectronCompile: boolean\n): Promise<Array<ResolvedFileSet>> {\n const fileSets: Array<ResolvedFileSet> = []\n const packager = platformPackager.info\n\n for (const matcher of matchers) {\n const fileWalker = new AppFileWalker(matcher, packager)\n\n const fromStat = await statOrNull(matcher.from)\n if (fromStat == null) {\n log.debug({ directory: matcher.from, reason: \"doesn't exist\" }, `skipped copying`)\n continue\n }\n\n const files = await walk(matcher.from, fileWalker.filter, fileWalker)\n const metadata = fileWalker.metadata\n fileSets.push(validateFileSet({ src: matcher.from, files, metadata, destination: matcher.to }))\n }\n\n if (isElectronCompile) {\n // cache files should be first (better IO)\n fileSets.unshift(await compileUsingElectronCompile(fileSets[0], packager))\n }\n return fileSets\n}\n\nfunction getNodeModuleExcludedExts(platformPackager: PlatformPackager<any>) {\n // do not exclude *.h files (https://github.com/electron-userland/electron-builder/issues/2852)\n const result = [\".o\", \".obj\"].concat(excludedExts.split(\",\").map(it => `.${it}`))\n if (platformPackager.config.includePdb !== true) {\n result.push(\".pdb\")\n }\n if (platformPackager.platform !== Platform.WINDOWS) {\n // https://github.com/electron-userland/electron-builder/issues/1738\n result.push(\".dll\")\n result.push(\".exe\")\n }\n return result\n}\n\nfunction validateFileSet(fileSet: ResolvedFileSet): ResolvedFileSet {\n if (fileSet.src == null || fileSet.src.length === 0) {\n throw new Error(\"fileset src is empty\")\n }\n return fileSet\n}\n\n/** @internal */\nexport async function computeNodeModuleFileSets(platformPackager: PlatformPackager<any>, mainMatcher: FileMatcher): Promise<Array<ResolvedFileSet>> {\n const deps = await collectNodeModulesWithLogging(platformPackager)\n\n const nodeModuleExcludedExts = getNodeModuleExcludedExts(platformPackager)\n // serial execution because copyNodeModules is concurrent and so, no need to increase queue/pressure\n const result = new Array<ResolvedFileSet>()\n let index = 0\n const NODE_MODULES = \"node_modules\"\n\n const collectNodeModules = async (dep: NodeModuleInfo, destination: string) => {\n const source = dep.dir\n const matcher = new FileMatcher(source, destination, mainMatcher.macroExpander, mainMatcher.patterns)\n const copier = new NodeModuleCopyHelper(matcher, platformPackager.info)\n const files = await copier.collectNodeModules(dep, nodeModuleExcludedExts, path.relative(mainMatcher.to, destination))\n result[index++] = validateFileSet({ src: source, destination, files, metadata: copier.metadata })\n\n log.debug({ dep: dep.name, from: log.filePath(source), to: log.filePath(destination), filesCount: files.length }, \"identified module\")\n\n if (dep.dependencies) {\n for (const c of dep.dependencies) {\n await collectNodeModules(c, path.join(destination, NODE_MODULES, c.name))\n }\n }\n }\n\n for (const dep of deps) {\n const destination = path.join(mainMatcher.to, NODE_MODULES, dep.name)\n await collectNodeModules(dep, destination)\n }\n return result\n}\n\ntype CollectedNodeModules = { nodeModules: NodeModuleInfo[]; logSummary: ModuleManager[\"logSummary\"] }\n\n/** Runs a single package-manager collector against a single directory. */\ntype CollectorRunner = (pm: PM, dir: string) => Promise<CollectedNodeModules>\n\n// `workspace:`/`file:`/`link:`/`portal:` dependencies are symlinked into place rather than\n// installed as standalone, hoistable packages, so they may legitimately be absent from a\n// collected tree and cannot be used to validate it.\nconst LOCAL_DEPENDENCY_SPEC = /^(?:workspace|file|link|portal):/\n\n/**\n * Determines whether a collected module tree actually describes the package being built.\n *\n * A package-manager `list` invocation can resolve to the wrong project root — most notably when\n * electron-builder is run from a workspace sub-package whose dependencies are hoisted to the\n * workspace root. In that case the collector returns a non-empty but unrelated tree. Accepting it\n * would suppress the manual-traversal fallback that resolves the correct modules, so we need to\n * tell a matching collection from a mismatched one.\n *\n * A collection matches when at least one of the package's declared external (registry-installed,\n * non-`workspace:`/`file:`/`link:`/`portal:`) production dependencies is present at the top level —\n * those direct dependencies are always hoisted to the top level of a correct collection. When the\n * package declares no external production dependencies there is nothing to validate against, so any\n * non-empty collection is accepted.\n */\nexport function collectionMatchesAppDependencies(nodeModules: NodeModuleInfo[], dependencies: Record<string, string> | undefined): boolean {\n const requiredExternalDeps = Object.entries(dependencies ?? {})\n .filter(([, spec]) => !LOCAL_DEPENDENCY_SPEC.test(spec))\n .map(([name]) => name)\n if (requiredExternalDeps.length === 0) {\n return true\n }\n const collected = new Set(nodeModules.map(it => it.name))\n return requiredExternalDeps.some(name => collected.has(name))\n}\n\n/**\n * Walks the candidate (package-manager, directory) combinations and returns the first collection\n * that both contains modules and matches the package being built (see\n * {@link collectionMatchesAppDependencies}). A non-empty collection that does NOT match — e.g. a\n * workspace-root tree returned for a sub-package — is retained only as a last-resort fallback so a\n * later approach (notably {@link PM.TRAVERSAL}) can supply the correct modules.\n */\nexport async function resolveFirstMatchingCollection(options: {\n pmApproaches: PM[]\n searchDirectories: string[]\n dependencies: Record<string, string> | undefined\n run: CollectorRunner\n}): Promise<CollectedNodeModules | undefined> {\n const { pmApproaches, searchDirectories, dependencies, run } = options\n let fallback: CollectedNodeModules | undefined\n\n for (const pm of pmApproaches) {\n for (const dir of searchDirectories) {\n log.info({ pm, searchDir: dir }, \"searching for node modules\")\n const deps = await run(pm, dir)\n if (deps.nodeModules.length === 0) {\n log.info({ pm, searchDir: dir }, \"no node modules found in collection, trying next search directory\")\n continue\n }\n if (collectionMatchesAppDependencies(deps.nodeModules, dependencies)) {\n log.debug({ pm, searchDir: dir, depCount: deps.nodeModules.length }, \"collected node modules\")\n return deps\n }\n log.info({ pm, searchDir: dir }, \"collected node modules do not match the target package, trying next search directory/approach\")\n fallback ??= deps\n }\n }\n return fallback\n}\n\n/** Extracts the package name from a `name@version` log-summary entry, handling `@scope/name@version`. */\nfunction dependencyNameFromSummaryId(id: string): string {\n let at: number\n if (id.startsWith(\"@\")) {\n // Scoped package: the version separator is the first `@` after the scope's `/`\n const slashIndex = id.indexOf(\"/\")\n if (slashIndex === -1) {\n return id\n }\n at = id.indexOf(\"@\", slashIndex + 1)\n } else {\n at = id.indexOf(\"@\")\n }\n return at > 0 ? id.slice(0, at) : id\n}\n\n/**\n * Enforces `allowMissingDependencies` against the finished collection summary (issue #10058).\n * Runs only after collection completes, so the error reports the COMPLETE set of missing\n * production dependencies at once instead of failing on the first one.\n *\n * v26 defaults to warn-only: `true` and omitted keep the historical warning behavior of the\n * stable 26.x line, while `false`/`null` fail the build on any missing production dependency\n * (the electron-builder 27+ default). When the option is a `string[]`, only the listed dependency\n * names are allowed to be missing — matched against the package name parsed from the summary's\n * `name@version` entries (scoped names included), with an exact-entry match accepted as well.\n *\n * Only genuinely missing production dependencies (`PKG_NOT_FOUND` / `PKG_NOT_ON_DISK`) are fatal;\n * missing optional dependencies (`PKG_OPTIONAL_NOT_INSTALLED` / `PKG_OPTIONAL_PLATFORM_NOT_INSTALLED`)\n * never fail the build.\n *\n * Exported for tests (an internal-tagged export would be stripped from the declarations the test\n * project consumes).\n */\nexport function enforceAllowMissingDependencies(allowMissingDependencies: boolean | Array<string> | null | undefined, logSummary: ModuleManager[\"logSummary\"] | undefined): void {\n // v26 default: omitted behaves like `true` (warn-only) so existing 26.x builds keep working.\n if (allowMissingDependencies === true || allowMissingDependencies === undefined) {\n return\n }\n const missing = new Set<string>([...(logSummary?.[LogMessageByKey.PKG_NOT_FOUND] ?? []), ...(logSummary?.[LogMessageByKey.PKG_NOT_ON_DISK] ?? [])])\n const allowed = new Set(Array.isArray(allowMissingDependencies) ? allowMissingDependencies : [])\n const fatal = Array.from(missing)\n .filter(id => !allowed.has(dependencyNameFromSummaryId(id)) && !allowed.has(id))\n .sort()\n if (fatal.length === 0) {\n return\n }\n throw new InvalidConfigurationError(\n `The following production dependencies could not be resolved during node-module collection:\\n` +\n fatal.map(id => ` - ${id}`).join(\"\\n\") +\n `\\nInstall the missing dependencies, list names in \\`allowMissingDependencies\\` to allow specific ones to be missing, or set \\`allowMissingDependencies\\` to true to only warn.`\n )\n}\n\n/** Exported for tests (an internal-tagged export would be stripped from the declarations the test project consumes). */\nexport async function collectNodeModulesWithLogging(platformPackager: PlatformPackager<any>) {\n const packager = platformPackager.info\n const { tempDirManager, appDir, projectDir } = packager\n\n const searchDirectories = Array.from(new Set([appDir, projectDir, await packager.getWorkspaceRoot()])).filter((it): it is string => isEmptyOrSpaces(it) === false)\n const pmApproaches = [await packager.getPackageManager(), PM.TRAVERSAL]\n\n // Validate against the as-declared (pre-extraMetadata) production dependencies so a configured\n // `extraMetadata.dependencies` entry that isn't installed cannot reject a correct collection.\n const deps = await resolveFirstMatchingCollection({\n pmApproaches,\n searchDirectories,\n dependencies: packager.originalMetadata.dependencies,\n run: (pm, dir) => getCollectorByPackageManager(pm, dir, tempDirManager).getNodeModules({ packageName: packager.nodePackageName }),\n })\n\n if (!deps?.nodeModules?.length) {\n log.warn({ searchDirectories: searchDirectories.map(it => log.filePath(it)) }, \"no node modules returned while searching directories\")\n return []\n }\n\n const summary = Object.entries(deps.logSummary ?? {}).filter(([, dependencies]) => Array.isArray(dependencies) && dependencies.length > 0)\n for (const [errorMessage, dependencies] of summary) {\n const logLevel = logMessageLevelByKey[errorMessage as LogMessageByKey] || \"debug\"\n log[logLevel]({ dependencies }, errorMessage)\n }\n\n // Enforcement (issue #10058): collection is complete and the summary above has reached the log,\n // so failing here reports every missing production dependency at once.\n enforceAllowMissingDependencies(packager.config.allowMissingDependencies, deps.logSummary)\n\n return deps.nodeModules\n}\n\nasync function compileUsingElectronCompile(mainFileSet: ResolvedFileSet, packager: Packager): Promise<ResolvedFileSet> {\n log.info(\"compiling using electron-compile\")\n\n const electronCompileCache = await packager.tempDirManager.getTempDir({ prefix: \"electron-compile-cache\" })\n const cacheDir = path.join(electronCompileCache, \".cache\")\n // clear and create cache dir\n await mkdir(cacheDir, { recursive: true })\n const compilerHost = await createElectronCompilerHost(mainFileSet.src, cacheDir)\n const nextSlashIndex = mainFileSet.src.length + 1\n // pre-compute electron-compile to cache dir - we need to process only subdirectories, not direct files of app dir\n const filesPromise: Promise<any>[] = mainFileSet.files.map(file => {\n if (\n file.includes(NODE_MODULES_PATTERN) ||\n file.includes(BOWER_COMPONENTS_PATTERN) ||\n !file.includes(path.sep, nextSlashIndex) || // ignore not root files\n !mainFileSet.metadata.get(file)!.isFile()\n ) {\n return\n }\n return compilerHost.compile(file)\n })\n await asyncPool(MAX_FILE_REQUESTS, filesPromise, promise => promise)\n await compilerHost.saveConfiguration()\n\n const metadata = new Map<string, Stats>()\n const cacheFiles = await walk(cacheDir, file => !file.startsWith(\".\"), {\n consume: (file, fileStat) => {\n if (fileStat.isFile()) {\n metadata.set(file, fileStat)\n }\n return null\n },\n })\n\n // add shim\n const shimPath = `${mainFileSet.src}${path.sep}${ELECTRON_COMPILE_SHIM_FILENAME}`\n mainFileSet.files.push(shimPath)\n mainFileSet.metadata.set(shimPath, { isFile: () => true, isDirectory: () => false, isSymbolicLink: () => false } as any)\n if (mainFileSet.transformedFiles == null) {\n mainFileSet.transformedFiles = new Map()\n }\n mainFileSet.transformedFiles.set(\n mainFileSet.files.length - 1,\n `\n'use strict';\nrequire('electron-compile').init(__dirname, require('path').resolve(__dirname, '${packager.metadata.main || \"index\"}'), true);\n`\n )\n return { src: electronCompileCache, files: cacheFiles, metadata, destination: mainFileSet.destination }\n}\n"]}
@@ -1,4 +1,5 @@
1
1
  import { ElectronPlatformArtifactDetails, MirrorOptions } from "@electron/get";
2
+ import * as crypto from "crypto";
2
3
  import { ElectronPlatformName } from "../electron/ElectronFramework";
3
4
  export type ElectronGetOptions = Omit<ElectronPlatformArtifactDetails, "platform" | "arch" | "version" | "artifactName" | "artifactSuffix" | "customFilename" | "tempDirectory" | "downloader" | "cacheMode" | "cacheRoot" | "downloadOptions" | "isGeneric" | "mirrorOptions"> & {
4
5
  mirrorOptions?: Omit<MirrorOptions, "customDir" | "customFilename" | "customVersion">;
@@ -37,6 +38,11 @@ export declare function getCacheDirectory(options: {
37
38
  allowEnvVarOverride: boolean;
38
39
  }): string;
39
40
  export declare function extractArchive(file: string, dir: string): Promise<void>;
41
+ export type ExpectedChecksum = {
42
+ algorithm: "sha256" | "sha512";
43
+ encoding: crypto.BinaryToTextEncoding;
44
+ value: string;
45
+ };
40
46
  /**
41
47
  * Downloads a generic artifact (.tar.gz or .zip) from a GitHub release.
42
48
  * Used for electron-builder-binaries tools (appimage, etc.).
@@ -48,6 +54,46 @@ export declare function downloadBuilderToolset(options: {
48
54
  githubOrgRepo?: string;
49
55
  overrideUrl?: string;
50
56
  }): Promise<string>;
57
+ /**
58
+ * Mirrors @electron/get's default cache root (`env-paths("electron", { suffix: "" }).cache`).
59
+ * @electron/get does not export it, so the (deliberately tiny) platform switch is replicated here.
60
+ * Must stay in sync with the `cacheRoot` default documented in @electron/get's
61
+ * `ElectronDownloadRequestOptions`.
62
+ * Exposed for unit testing; not part of the public API.
63
+ */
64
+ export declare function defaultElectronGetCacheRoot(): string;
65
+ /**
66
+ * Parses the upstream `SHASUMS256.txt` format into the `Record<filename, sha256-hex>` shape that
67
+ * @electron/get accepts as inline `checksums`. Each line is `<sha256-hex> *<filename>` (binary
68
+ * mode) or `<sha256-hex> <filename>` (text mode); malformed lines are ignored.
69
+ * Exposed for unit testing; not part of the public API.
70
+ */
71
+ export declare function parseChecksumFile(content: string): Record<string, string>;
72
+ /**
73
+ * Looks for a locally seeded SHASUMS256 file at the root of the @electron/get cache and returns
74
+ * its contents as inline `checksums`, or null when nothing usable is seeded.
75
+ *
76
+ * Why: without inline `checksums`, @electron/get re-downloads `SHASUMS256.txt` with a hardcoded
77
+ * `cacheMode: Bypass` on EVERY build — even when the artifact itself is a cache hit — so a fully
78
+ * seeded cache still requires network access and air-gapped builds fail (#10039). Cache-seeding
79
+ * tools (e.g. flatpak-node-generator) already place `SHASUMS256.txt-<version>` flat at the cache
80
+ * root; feeding it back as inline `checksums` keeps checksum validation enabled while making it
81
+ * fully offline. A plain `SHASUMS256.txt` at the cache root is accepted as a manual-seeding
82
+ * fallback. A candidate file is only used when it actually contains an entry for the requested
83
+ * artifact, so a stale file for another version can never break an online build.
84
+ * See https://www.electron.build/tutorials/offline-air-gapped-builds for the seeding contract.
85
+ * Exposed for unit testing; not part of the public API.
86
+ */
87
+ export declare function resolveSeededChecksums(cacheRoot: string, version: string, artifactFileName: string): Promise<Record<string, string> | null>;
88
+ /**
89
+ * Assembles the `@electron/get` artifact config from `ArtifactDownloadOptions`, accepting both the
90
+ * legacy `ElectronDownloadOptions` and the modern `ElectronGetOptions` config shapes. When the
91
+ * resolved config has no `checksums` (user-provided `electronDownload.checksums` always wins) and
92
+ * checksum verification is not disabled, a locally seeded `SHASUMS256.txt-<version>` at the cache
93
+ * root is picked up as inline `checksums` so validation works offline (see resolveSeededChecksums).
94
+ * Exposed for unit testing; not part of the public API.
95
+ */
96
+ export declare function buildElectronArtifactConfig(options: ArtifactDownloadOptions): Promise<ElectronPlatformArtifactDetails>;
51
97
  /**
52
98
  * Downloads the electron artifact zip via @electron/get (with caching) and returns the zip file path.
53
99
  * Use when you need to extract the zip yourself (e.g. directly to appOutDir to preserve empty dirs and symlinks).
@@ -4,7 +4,12 @@ exports.getCacheDirectory = getCacheDirectory;
4
4
  exports.isSafeExtractPath = isSafeExtractPath;
5
5
  exports.moveDirAtomic = moveDirAtomic;
6
6
  exports.extractArchive = extractArchive;
7
+ exports.parseExpectedChecksum = parseExpectedChecksum;
7
8
  exports.downloadBuilderToolset = downloadBuilderToolset;
9
+ exports.defaultElectronGetCacheRoot = defaultElectronGetCacheRoot;
10
+ exports.parseChecksumFile = parseChecksumFile;
11
+ exports.resolveSeededChecksums = resolveSeededChecksums;
12
+ exports.buildElectronArtifactConfig = buildElectronArtifactConfig;
8
13
  exports.downloadElectronArtifactZip = downloadElectronArtifactZip;
9
14
  exports.downloadElectronArtifact = downloadElectronArtifact;
10
15
  exports.getBinariesMirrorUrl = getBinariesMirrorUrl;
@@ -211,22 +216,25 @@ async function extractArchive(file, dir) {
211
216
  if (file.endsWith(".tar.gz") || file.endsWith(".tgz")) {
212
217
  await tar.extract({ file, cwd: tmpDir, strip: 1 });
213
218
  }
214
- else if (file.endsWith(".tar.xz") || file.endsWith(".txz")) {
215
- // node-tar cannot decompress xz, so use 7za to turn the .tar.xz into a .tar, then extract that tar.
219
+ else if (file.endsWith(".tar.xz") || file.endsWith(".txz") || file.endsWith(".tar.7z")) {
220
+ // Compressed tarballs node-tar cannot decompress itself (xz, 7z): use 7za to strip the outer
221
+ // compression layer into a .tar, then extract that tar.
222
+ // Note: the .tar.7z check MUST stay ahead of the plain .7z branch below, otherwise only the outer
223
+ // 7z layer is removed and the inner tar is left behind as-is (see https://github.com/electron-userland/electron-builder/issues/10002).
216
224
  const cmd7za = await (0, _7zip_1.getPath7za)();
217
- const xzOutDir = `${tmpDir}.xz`;
218
- await fs.rm(xzOutDir, { recursive: true, force: true });
219
- await fs.mkdir(xzOutDir, { recursive: true });
225
+ const decompressOutDir = `${tmpDir}.decompress`;
226
+ await fs.rm(decompressOutDir, { recursive: true, force: true });
227
+ await fs.mkdir(decompressOutDir, { recursive: true });
220
228
  try {
221
- await (0, builder_util_1.exec)(cmd7za, ["x", "-bd", file, (0, builder_util_1.to7zaOutputSwitch)((0, builder_util_1.sanitizeDirPath)(xzOutDir)), "-y"]);
222
- const innerTar = (await fs.readdir(xzOutDir)).find(f => f.endsWith(".tar"));
229
+ await (0, builder_util_1.exec)(cmd7za, ["x", "-bd", file, (0, builder_util_1.to7zaOutputSwitch)((0, builder_util_1.sanitizeDirPath)(decompressOutDir)), "-y"]);
230
+ const innerTar = (await fs.readdir(decompressOutDir)).find(f => f.endsWith(".tar"));
223
231
  if (innerTar == null) {
224
- throw new Error(`xz decompression of ${path.basename(file)} produced no .tar archive`);
232
+ throw new Error(`decompression of ${path.basename(file)} produced no .tar archive`);
225
233
  }
226
- await tar.extract({ file: path.join(xzOutDir, innerTar), cwd: tmpDir, strip: 1 });
234
+ await tar.extract({ file: path.join(decompressOutDir, innerTar), cwd: tmpDir, strip: 1 });
227
235
  }
228
236
  finally {
229
- await fs.rm(xzOutDir, { recursive: true, force: true });
237
+ await fs.rm(decompressOutDir, { recursive: true, force: true });
230
238
  }
231
239
  }
232
240
  else if (file.endsWith(".zip")) {
@@ -357,24 +365,64 @@ async function downloadArtifactToFile(config, label) {
357
365
  await releaseArtifactLock().catch(err => builder_util_1.log.warn({ err }, "failed to release artifact download lock"));
358
366
  }
359
367
  }
368
+ // @electron/get delegates verification to sumchecker, which only understands SHA-256 hex.
369
+ // The historically documented customNsisBinary/customNsisResources checksums are base64-encoded
370
+ // SHA-512, so those must be verified by electron-builder itself after the download
371
+ // (https://github.com/electron-userland/electron-builder/issues/10040).
372
+ const SHA256_HEX_RE = /^[0-9a-fA-F]{64}$/;
373
+ // 64 raw bytes → 86 significant base64 chars + "==" padding
374
+ const SHA512_BASE64_RE = /^[A-Za-z0-9+/]{86}==$/;
375
+ /** @internal exported for unit testing */
376
+ function parseExpectedChecksum(filename, value) {
377
+ if (SHA256_HEX_RE.test(value)) {
378
+ return { algorithm: "sha256", encoding: "hex", value };
379
+ }
380
+ if (SHA512_BASE64_RE.test(value)) {
381
+ return { algorithm: "sha512", encoding: "base64", value };
382
+ }
383
+ throw new Error(`Unrecognized checksum format for "${filename}": "${value}". ` +
384
+ `Accepted formats: 64-character SHA-256 hex (e.g. "shasum -a 256 <file>") or ` +
385
+ `88-character base64-encoded SHA-512 (e.g. "openssl dgst -sha512 -binary <file> | openssl base64 -A")`);
386
+ }
387
+ function hashFile(file, algorithm, encoding) {
388
+ return new Promise((resolve, reject) => {
389
+ const h = crypto.createHash(algorithm);
390
+ const s = (0, fs_1.createReadStream)(file);
391
+ s.on("error", reject);
392
+ s.on("data", (chunk) => h.update(chunk));
393
+ s.on("end", () => resolve(h.digest(encoding)));
394
+ });
395
+ }
396
+ /**
397
+ * Verifies a downloaded archive against a checksum @electron/get could not validate itself
398
+ * (i.e. base64 SHA-512). Deletes the file and throws on mismatch.
399
+ */
400
+ async function verifyDownloadedArchive(file, label, expected) {
401
+ const actual = await hashFile(file, expected.algorithm, expected.encoding);
402
+ if (actual !== expected.value) {
403
+ await fs.rm(file, { force: true }).catch(() => { });
404
+ throw new Error(`${expected.algorithm} checksum mismatch for ${label}: expected "${expected.value}" but downloaded file is "${actual}". The corrupted download has been removed.`);
405
+ }
406
+ builder_util_1.log.debug({ file: label, algorithm: expected.algorithm }, "checksum verified");
407
+ }
360
408
  /**
361
409
  * Checks electron-builder's own archive cache for a previously downloaded archive.
362
- * Validates the SHA-256 checksum when one is known. Returns the cached path on hit,
363
- * null on miss or checksum mismatch (mismatch also deletes the stale file).
410
+ * Validates the checksum (SHA-256 hex or base64 SHA-512) when one is known. Returns the
411
+ * cached path on hit, null on miss or checksum mismatch (mismatch also deletes the stale file).
412
+ *
413
+ * Air-gapped seeding contract: placing the archive at
414
+ * `<cacheDir>/<releaseName>/<archive>` (e.g. `$ELECTRON_BUILDER_CACHE/appimage@1.0.3/appimage-tools-runtime-20251108.tar.gz`)
415
+ * is sufficient for a fully offline toolset resolution — the checksum here is computed locally
416
+ * against the value hardcoded in the toolset module, and extraction happens locally too. No
417
+ * `.state` file needs to be seeded. See https://www.electron.build/tutorials/offline-air-gapped-builds.
364
418
  */
365
- async function resolveFromArchiveCache(archiveCachePath, label, expectedSha256) {
419
+ async function resolveFromArchiveCache(archiveCachePath, label, expected) {
366
420
  if (!(await (0, builder_util_1.exists)(archiveCachePath))) {
367
421
  return null;
368
422
  }
369
- if (expectedSha256) {
370
- const hash = await new Promise((resolve, reject) => {
371
- const h = crypto.createHash("sha256");
372
- const s = (0, fs_1.createReadStream)(archiveCachePath);
373
- s.on("error", reject);
374
- s.on("data", (chunk) => h.update(chunk));
375
- s.on("end", () => resolve(h.digest("hex")));
376
- });
377
- if (hash !== expectedSha256) {
423
+ if (expected) {
424
+ const hash = await hashFile(archiveCachePath, expected.algorithm, expected.encoding);
425
+ if (hash !== expected.value) {
378
426
  builder_util_1.log.warn({ file: label, archiveCachePath }, "cached archive checksum mismatch — removing and re-downloading");
379
427
  await fs.rm(archiveCachePath).catch(() => { });
380
428
  return null;
@@ -401,8 +449,7 @@ async function persistToArchiveCache(sourcePath, archiveCachePath) {
401
449
  * progress bar, extraction (.zip or .tar.gz), and completion marker.
402
450
  * Both public download functions delegate here after building their respective configs.
403
451
  */
404
- async function downloadAndExtract(config, extractDir, label, archiveCachePath) {
405
- var _a;
452
+ async function downloadAndExtract(config, extractDir, label, archiveCachePath, expectedChecksum) {
406
453
  await fs.mkdir(extractDir, { recursive: true });
407
454
  // Pre-lock fast path: only short-circuit for a definitively complete and valid cache.
408
455
  // Do NOT clean up here — concurrent processes could race to delete under each other.
@@ -446,7 +493,7 @@ async function downloadAndExtract(config, extractDir, label, archiveCachePath) {
446
493
  // This lets repeated builds (or offline environments) skip the download entirely once
447
494
  // the archive has been fetched at least once.
448
495
  if (archiveCachePath) {
449
- downloadedFile = await resolveFromArchiveCache(archiveCachePath, label, (_a = config.checksums) === null || _a === void 0 ? void 0 : _a[label]);
496
+ downloadedFile = await resolveFromArchiveCache(archiveCachePath, label, expectedChecksum);
450
497
  }
451
498
  if (!downloadedFile) {
452
499
  builder_util_1.log.debug({ file: label }, "downloading");
@@ -454,6 +501,12 @@ async function downloadAndExtract(config, extractDir, label, archiveCachePath) {
454
501
  if (!downloadedFile) {
455
502
  throw new Error(`Failed to download artifact: ${label}`);
456
503
  }
504
+ // sha256-hex checksums are verified by @electron/get during the download; any other
505
+ // format was passed with unsafelyDisableChecksums, so verify it here before the
506
+ // archive is cached or extracted.
507
+ if (expectedChecksum != null && expectedChecksum.algorithm !== "sha256") {
508
+ await verifyDownloadedArchive(downloadedFile, label, expectedChecksum);
509
+ }
457
510
  // Persist the downloaded archive so future builds (and offline environments) can
458
511
  // skip the network request entirely.
459
512
  if (archiveCachePath) {
@@ -486,10 +539,23 @@ async function downloadBuilderToolset(options) {
486
539
  if (/[/\\]|\.\./.test(filenameWithExt)) {
487
540
  throw new Error(`downloadBuilderToolset: unsafe filenameWithExt "${filenameWithExt}" — must be a plain filename with no path separators or traversal sequences`);
488
541
  }
542
+ // Classify every provided checksum up front so a malformed value fails fast with a clear
543
+ // config error instead of a sumchecker parse error mid-download (#10040).
544
+ const parsedChecksums = checksums == null ? undefined : new Map(Object.entries(checksums).map(([file, value]) => [file, parseExpectedChecksum(file, value)]));
545
+ if (parsedChecksums != null && new Set(Array.from(parsedChecksums.values(), c => c.algorithm)).size > 1) {
546
+ throw new Error(`checksums for ${releaseName} mix formats — use a single format for all entries: either SHA-256 hex or base64-encoded SHA-512`);
547
+ }
548
+ const expectedChecksum = parsedChecksums === null || parsedChecksums === void 0 ? void 0 : parsedChecksums.get(filenameWithExt);
549
+ // @electron/get can only verify sha256-hex itself; for any other format the download is
550
+ // verified manually in downloadAndExtract, so disable its sumchecker-based validation.
551
+ const electronGetVerifiableChecksums = parsedChecksums != null && Array.from(parsedChecksums.values()).every(c => c.algorithm === "sha256") ? checksums : undefined;
489
552
  const baseUrl = getBinariesMirrorUrl(githubOrgRepo);
490
553
  const fullUrl = overrideUrl ? `${overrideUrl}/${filenameWithExt}` : `${baseUrl}${releaseName}/${filenameWithExt}`;
491
554
  const suffix = hashUrlSafe(fullUrl, 5);
492
- const folderName = `${filenameWithExt.replace(/\.(tar\.gz|tgz|tar\.xz|txz|zip|7z)$/, "")}-${suffix}`;
555
+ // tar.7z is listed before 7z so the full extension is stripped. Deliberate side effect: this changes the
556
+ // extract-dir name for .tar.7z toolsets (e.g. the snap template) from "<name>.tar-<hash>" to "<name>-<hash>",
557
+ // which busts caches poisoned by the broken .tar.7z extraction in 26.15.0-26.15.6 (issue #10002).
558
+ const folderName = `${filenameWithExt.replace(/\.(tar\.gz|tgz|tar\.xz|txz|tar\.7z|zip|7z)$/, "")}-${suffix}`;
493
559
  const extractDir = path.join(getCacheDirectory({ allowEnvVarOverride: true }), releaseName, folderName);
494
560
  // Use resolveAssetURL so @electron/get's ELECTRON_MIRROR env var check cannot override
495
561
  // the builder-binaries URL we've already resolved (see getArtifactRemoteURL in @electron/get).
@@ -505,23 +571,104 @@ async function downloadBuilderToolset(options) {
505
571
  artifactName: filenameWithExt,
506
572
  cacheRoot: path.resolve(getCacheDirectory({ allowEnvVarOverride: true }), "downloads"),
507
573
  cacheMode: resolveCacheMode(),
508
- ...(checksums != null ? { checksums } : { unsafelyDisableChecksums: true }),
574
+ ...(electronGetVerifiableChecksums != null ? { checksums: electronGetVerifiableChecksums } : { unsafelyDisableChecksums: true }),
509
575
  mirrorOptions,
510
576
  isGeneric: true,
511
577
  };
512
- return downloadAndExtract(config, extractDir, filenameWithExt, archiveCachePath);
578
+ return downloadAndExtract(config, extractDir, filenameWithExt, archiveCachePath, expectedChecksum);
513
579
  }
514
580
  // Keys present in ElectronGetOptions but absent from ElectronDownloadOptions.
515
581
  // Used to discriminate between the two config shapes at runtime.
516
- const ELECTRON_GET_EXCLUSIVE_KEYS = ["mirrorOptions", "force", "unsafelyDisableChecksums"];
582
+ // "checksums" is included so that `electronDownload: { checksums: {...} }` alone is routed to the
583
+ // modern branch and actually forwarded to @electron/get instead of being silently dropped.
584
+ const ELECTRON_GET_EXCLUSIVE_KEYS = ["mirrorOptions", "force", "unsafelyDisableChecksums", "checksums"];
517
585
  function isElectronGetOptions(dl) {
518
586
  return ELECTRON_GET_EXCLUSIVE_KEYS.some(k => Object.hasOwnProperty.call(dl, k));
519
587
  }
520
588
  /**
521
- * Downloads and extracts an electron platform artifact (e.g. ffmpeg) using @electron/get.
522
- * Deduplicates concurrent calls for the same artifact within the same process.
589
+ * Mirrors @electron/get's default cache root (`env-paths("electron", { suffix: "" }).cache`).
590
+ * @electron/get does not export it, so the (deliberately tiny) platform switch is replicated here.
591
+ * Must stay in sync with the `cacheRoot` default documented in @electron/get's
592
+ * `ElectronDownloadRequestOptions`.
593
+ * Exposed for unit testing; not part of the public API.
594
+ */
595
+ function defaultElectronGetCacheRoot() {
596
+ const name = "electron";
597
+ const homeDir = os.homedir();
598
+ switch (os.platform()) {
599
+ case "darwin":
600
+ return path.join(homeDir, "Library", "Caches", name);
601
+ case "win32":
602
+ return path.join(process.env.LOCALAPPDATA || path.join(homeDir, "AppData", "Local"), name, "Cache");
603
+ default:
604
+ return path.join(process.env.XDG_CACHE_HOME || path.join(homeDir, ".cache"), name);
605
+ }
606
+ }
607
+ /**
608
+ * Parses the upstream `SHASUMS256.txt` format into the `Record<filename, sha256-hex>` shape that
609
+ * @electron/get accepts as inline `checksums`. Each line is `<sha256-hex> *<filename>` (binary
610
+ * mode) or `<sha256-hex> <filename>` (text mode); malformed lines are ignored.
611
+ * Exposed for unit testing; not part of the public API.
523
612
  */
524
- function buildElectronArtifactConfig(options) {
613
+ function parseChecksumFile(content) {
614
+ const checksums = {};
615
+ for (const rawLine of content.split("\n")) {
616
+ const match = /^([a-fA-F0-9]{64})\s+\*?(.+)$/.exec(rawLine.trim());
617
+ if (match != null) {
618
+ checksums[match[2]] = match[1].toLowerCase();
619
+ }
620
+ }
621
+ return checksums;
622
+ }
623
+ /**
624
+ * Looks for a locally seeded SHASUMS256 file at the root of the @electron/get cache and returns
625
+ * its contents as inline `checksums`, or null when nothing usable is seeded.
626
+ *
627
+ * Why: without inline `checksums`, @electron/get re-downloads `SHASUMS256.txt` with a hardcoded
628
+ * `cacheMode: Bypass` on EVERY build — even when the artifact itself is a cache hit — so a fully
629
+ * seeded cache still requires network access and air-gapped builds fail (#10039). Cache-seeding
630
+ * tools (e.g. flatpak-node-generator) already place `SHASUMS256.txt-<version>` flat at the cache
631
+ * root; feeding it back as inline `checksums` keeps checksum validation enabled while making it
632
+ * fully offline. A plain `SHASUMS256.txt` at the cache root is accepted as a manual-seeding
633
+ * fallback. A candidate file is only used when it actually contains an entry for the requested
634
+ * artifact, so a stale file for another version can never break an online build.
635
+ * See https://www.electron.build/tutorials/offline-air-gapped-builds for the seeding contract.
636
+ * Exposed for unit testing; not part of the public API.
637
+ */
638
+ async function resolveSeededChecksums(cacheRoot, version, artifactFileName) {
639
+ const candidates = [path.join(cacheRoot, `SHASUMS256.txt-${version}`), path.join(cacheRoot, "SHASUMS256.txt")];
640
+ for (const candidate of candidates) {
641
+ if (!(await (0, builder_util_1.exists)(candidate))) {
642
+ continue;
643
+ }
644
+ let content;
645
+ try {
646
+ content = await fs.readFile(candidate, "utf-8");
647
+ }
648
+ catch (err) {
649
+ builder_util_1.log.warn({ file: builder_util_1.log.filePath(candidate), err: err.message }, "failed to read seeded SHASUMS file — ignoring it");
650
+ continue;
651
+ }
652
+ const checksums = parseChecksumFile(content);
653
+ if (checksums[artifactFileName] == null) {
654
+ builder_util_1.log.warn({ file: builder_util_1.log.filePath(candidate), artifactFileName }, "seeded SHASUMS file has no entry for the requested artifact — ignoring it");
655
+ continue;
656
+ }
657
+ builder_util_1.log.debug({ file: builder_util_1.log.filePath(candidate), artifactFileName }, "using locally seeded SHASUMS256 checksums — checksum validation can run offline");
658
+ return checksums;
659
+ }
660
+ return null;
661
+ }
662
+ /**
663
+ * Assembles the `@electron/get` artifact config from `ArtifactDownloadOptions`, accepting both the
664
+ * legacy `ElectronDownloadOptions` and the modern `ElectronGetOptions` config shapes. When the
665
+ * resolved config has no `checksums` (user-provided `electronDownload.checksums` always wins) and
666
+ * checksum verification is not disabled, a locally seeded `SHASUMS256.txt-<version>` at the cache
667
+ * root is picked up as inline `checksums` so validation works offline (see resolveSeededChecksums).
668
+ * Exposed for unit testing; not part of the public API.
669
+ */
670
+ async function buildElectronArtifactConfig(options) {
671
+ var _a;
525
672
  const { electronDownload, arch, version, platformName: platform, artifactName, cacheDir: cacheRoot } = options;
526
673
  let artifactConfig = { cacheRoot, platform, arch, version, artifactName };
527
674
  if (electronDownload != null) {
@@ -557,19 +704,28 @@ function buildElectronArtifactConfig(options) {
557
704
  }
558
705
  }
559
706
  artifactConfig.cacheMode = resolveCacheMode();
707
+ if (artifactConfig.checksums == null && !artifactConfig.unsafelyDisableChecksums) {
708
+ // Matches @electron/get's getArtifactFileName for non-generic artifacts; `artifactSuffix` and
709
+ // `customFilename` cannot diverge here — both are excluded from ElectronGetOptions.
710
+ const artifactFileName = `${artifactConfig.artifactName}-v${artifactConfig.version}-${artifactConfig.platform}-${artifactConfig.arch}.zip`;
711
+ const seededChecksums = await resolveSeededChecksums((_a = artifactConfig.cacheRoot) !== null && _a !== void 0 ? _a : defaultElectronGetCacheRoot(), artifactConfig.version, artifactFileName);
712
+ if (seededChecksums != null) {
713
+ artifactConfig.checksums = seededChecksums;
714
+ }
715
+ }
560
716
  return artifactConfig;
561
717
  }
562
718
  /**
563
719
  * Downloads the electron artifact zip via @electron/get (with caching) and returns the zip file path.
564
720
  * Use when you need to extract the zip yourself (e.g. directly to appOutDir to preserve empty dirs and symlinks).
565
721
  */
566
- function downloadElectronArtifactZip(options) {
567
- const config = buildElectronArtifactConfig(options);
722
+ async function downloadElectronArtifactZip(options) {
723
+ const config = await buildElectronArtifactConfig(options);
568
724
  return downloadArtifactToFile(config, config.artifactName);
569
725
  }
570
726
  async function downloadElectronArtifact(options) {
571
727
  const { arch, version, platformName: platform, artifactName } = options;
572
- const artifactConfig = buildElectronArtifactConfig(options);
728
+ const artifactConfig = await buildElectronArtifactConfig(options);
573
729
  const suffix = hashUrlSafe(JSON.stringify(artifactConfig), 5);
574
730
  const folderName = `${artifactName}-v${version}-${platform}-${arch}-${suffix}`;
575
731
  const extractDir = path.join(getCacheDirectory({ allowEnvVarOverride: true }), `${artifactName}-v${version}`, folderName);