app-builder-lib 26.13.1 → 26.15.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 (102) hide show
  1. package/helpers/dynamic-import.js +24 -7
  2. package/out/asar/asarFileChecker.js.map +1 -1
  3. package/out/configuration.d.ts +11 -0
  4. package/out/configuration.js.map +1 -1
  5. package/out/electron/ElectronFramework.js +1 -5
  6. package/out/electron/ElectronFramework.js.map +1 -1
  7. package/out/frameworks/LibUiFramework.d.ts +25 -0
  8. package/out/frameworks/LibUiFramework.js +107 -19
  9. package/out/frameworks/LibUiFramework.js.map +1 -1
  10. package/out/mac/MacTargetHelper.d.ts +7 -2
  11. package/out/mac/MacTargetHelper.js +13 -10
  12. package/out/mac/MacTargetHelper.js.map +1 -1
  13. package/out/macPackager.js +2 -3
  14. package/out/macPackager.js.map +1 -1
  15. package/out/node-module-collector/moduleManager.d.ts +6 -0
  16. package/out/node-module-collector/moduleManager.js +65 -55
  17. package/out/node-module-collector/moduleManager.js.map +1 -1
  18. package/out/node-module-collector/nodeModulesCollector.d.ts +17 -8
  19. package/out/node-module-collector/nodeModulesCollector.js +87 -61
  20. package/out/node-module-collector/nodeModulesCollector.js.map +1 -1
  21. package/out/node-module-collector/pnpmNodeModulesCollector.js +7 -5
  22. package/out/node-module-collector/pnpmNodeModulesCollector.js.map +1 -1
  23. package/out/options/linuxOptions.d.ts +10 -0
  24. package/out/options/linuxOptions.js.map +1 -1
  25. package/out/options/macOptions.d.ts +41 -2
  26. package/out/options/macOptions.js.map +1 -1
  27. package/out/packager.d.ts +0 -4
  28. package/out/packager.js +0 -19
  29. package/out/packager.js.map +1 -1
  30. package/out/platformPackager.d.ts +1 -5
  31. package/out/platformPackager.js +9 -31
  32. package/out/platformPackager.js.map +1 -1
  33. package/out/targets/FpmTarget.js +6 -5
  34. package/out/targets/FpmTarget.js.map +1 -1
  35. package/out/targets/LinuxTargetHelper.d.ts +2 -1
  36. package/out/targets/LinuxTargetHelper.js +23 -0
  37. package/out/targets/LinuxTargetHelper.js.map +1 -1
  38. package/out/targets/MsiTarget.js +2 -1
  39. package/out/targets/MsiTarget.js.map +1 -1
  40. package/out/targets/appimage/AppImageTarget.js +6 -1
  41. package/out/targets/appimage/AppImageTarget.js.map +1 -1
  42. package/out/targets/appimage/appImageUtil.d.ts +4 -2
  43. package/out/targets/appimage/appImageUtil.js +2 -2
  44. package/out/targets/appimage/appImageUtil.js.map +1 -1
  45. package/out/targets/archive.d.ts +0 -1
  46. package/out/targets/archive.js +60 -88
  47. package/out/targets/archive.js.map +1 -1
  48. package/out/targets/blockmap/blockmap.d.ts +16 -0
  49. package/out/targets/blockmap/blockmap.js +153 -0
  50. package/out/targets/blockmap/blockmap.js.map +1 -0
  51. package/out/targets/differentialUpdateInfoBuilder.js +3 -3
  52. package/out/targets/differentialUpdateInfoBuilder.js.map +1 -1
  53. package/out/targets/nsis/NsisTarget.js +6 -12
  54. package/out/targets/nsis/NsisTarget.js.map +1 -1
  55. package/out/targets/nsis/nsisValidation.js +5 -4
  56. package/out/targets/nsis/nsisValidation.js.map +1 -1
  57. package/out/targets/pkg.d.ts +13 -0
  58. package/out/targets/pkg.js +34 -9
  59. package/out/targets/pkg.js.map +1 -1
  60. package/out/targets/snap/core24.js +4 -3
  61. package/out/targets/snap/core24.js.map +1 -1
  62. package/out/targets/snap/coreLegacy.d.ts +23 -0
  63. package/out/targets/snap/coreLegacy.js +161 -23
  64. package/out/targets/snap/coreLegacy.js.map +1 -1
  65. package/out/toolsets/7zip.d.ts +2 -0
  66. package/out/toolsets/7zip.js +72 -0
  67. package/out/toolsets/7zip.js.map +1 -0
  68. package/out/toolsets/icons.d.ts +8 -0
  69. package/out/toolsets/icons.js +37 -0
  70. package/out/toolsets/icons.js.map +1 -0
  71. package/out/toolsets/wine.d.ts +5 -0
  72. package/out/toolsets/wine.js +100 -0
  73. package/out/toolsets/wine.js.map +1 -0
  74. package/out/util/electronGet.js +36 -5
  75. package/out/util/electronGet.js.map +1 -1
  76. package/out/util/iconConverter.d.ts +25 -0
  77. package/out/util/iconConverter.js +260 -0
  78. package/out/util/iconConverter.js.map +1 -0
  79. package/out/util/packageDependencies.d.ts +0 -6
  80. package/out/util/packageDependencies.js +0 -17
  81. package/out/util/packageDependencies.js.map +1 -1
  82. package/out/util/yarn.d.ts +0 -3
  83. package/out/util/yarn.js +3 -15
  84. package/out/util/yarn.js.map +1 -1
  85. package/out/version.d.ts +1 -1
  86. package/out/version.js +1 -1
  87. package/out/version.js.map +1 -1
  88. package/out/vm/WineVm.d.ts +5 -2
  89. package/out/vm/WineVm.js +19 -5
  90. package/out/vm/WineVm.js.map +1 -1
  91. package/out/vm/vm.js.map +1 -1
  92. package/package.json +10 -9
  93. package/scheme.json +39 -4
  94. package/templates/snap/desktop-common.sh +444 -0
  95. package/templates/snap/desktop-gnome-specific.sh +31 -0
  96. package/templates/snap/desktop-init.sh +52 -0
  97. package/out/util/appBuilder.d.ts +0 -4
  98. package/out/util/appBuilder.js +0 -36
  99. package/out/util/appBuilder.js.map +0 -1
  100. package/out/wine.d.ts +0 -5
  101. package/out/wine.js +0 -31
  102. package/out/wine.js.map +0 -1
@@ -214,7 +214,7 @@ class ModuleManager {
214
214
  * Looks for node_modules/\*\/node_modules/pkgName (and deeper)
215
215
  */
216
216
  async downwardSearch(parentDir, pkgName, requiredRange, maxExplored = 2000, maxDepth = 6) {
217
- var _a, _b, _c, _d;
217
+ var _a;
218
218
  const start = path.join(path.resolve(parentDir), "node_modules");
219
219
  if (!(await this.exists[start]) || !((_a = (await this.lstat[start])) === null || _a === void 0 ? void 0 : _a.isDirectory())) {
220
220
  return null;
@@ -242,70 +242,80 @@ class ModuleManager {
242
242
  continue;
243
243
  }
244
244
  const entryPath = path.join(dir, entry);
245
- // handle scoped packages @scope/name
246
245
  if (entry.startsWith("@")) {
247
- // queue the scope directory itself to explore its children
248
- if ((await this.exists[entryPath]) && ((_b = (await this.lstat[entryPath])) === null || _b === void 0 ? void 0 : _b.isDirectory())) {
249
- const scopeEntries = await fs.readdir(entryPath);
250
- for (const sc of scopeEntries) {
251
- const scPath = path.join(entryPath, sc);
252
- // check scPath/node_modules/pkgName
253
- const candidatePkgJson = path.join(scPath, "node_modules", pkgName, "package.json");
254
- if (await this.exists[candidatePkgJson]) {
255
- const json = await this.json[candidatePkgJson];
256
- if (json && this.semverSatisfies(json.version, requiredRange)) {
257
- return { packageDir: path.dirname(candidatePkgJson), packageJson: json };
258
- }
259
- }
260
- // enqueue scPath/node_modules to explore further
261
- const scNodeModules = path.join(scPath, "node_modules");
262
- if ((await this.exists[scNodeModules]) && ((_c = (await this.lstat[scNodeModules])) === null || _c === void 0 ? void 0 : _c.isDirectory())) {
263
- if (!visited.has(scNodeModules)) {
264
- visited.add(scNodeModules);
265
- queue.push({ dir: scNodeModules, depth: depth + 1 });
266
- }
267
- }
268
- }
246
+ const found = await this.processScope(entryPath, pkgName, requiredRange, depth, visited, queue);
247
+ if (found) {
248
+ return found;
269
249
  }
270
250
  continue;
271
251
  }
272
- // check for direct candidate: entry/node_modules/pkgName
273
- try {
274
- const stat = await this.lstat[entryPath];
275
- if (!(stat === null || stat === void 0 ? void 0 : stat.isDirectory())) {
276
- continue;
277
- }
278
- }
279
- catch {
280
- continue;
281
- }
282
- const candidatePkgJson = path.join(entryPath, "node_modules", pkgName, "package.json");
283
- if (await this.exists[candidatePkgJson]) {
284
- const json = await this.json[candidatePkgJson];
285
- if (json && this.semverSatisfies(json.version, requiredRange)) {
286
- return { packageDir: path.dirname(candidatePkgJson), packageJson: json };
287
- }
252
+ const found = await this.processEntry(entryPath, pkgName, requiredRange, depth, visited, queue);
253
+ if (found) {
254
+ return found;
288
255
  }
289
- // also check entry/node_modules directly for pkgName (some layouts)
290
- const candidateDirect = path.join(entryPath, pkgName, "package.json");
291
- if (await this.exists[candidateDirect]) {
292
- const json = await this.json[candidateDirect];
293
- if (json && this.semverSatisfies(json.version, requiredRange)) {
294
- return { packageDir: path.dirname(candidateDirect), packageJson: json };
295
- }
296
- }
297
- // enqueue entry/node_modules for deeper traversal
298
- const nextNodeModules = path.join(entryPath, "node_modules");
299
- if ((await this.exists[nextNodeModules]) && ((_d = (await this.lstat[nextNodeModules])) === null || _d === void 0 ? void 0 : _d.isDirectory())) {
300
- if (!visited.has(nextNodeModules)) {
301
- visited.add(nextNodeModules);
302
- queue.push({ dir: nextNodeModules, depth: depth + 1 });
303
- }
256
+ }
257
+ }
258
+ return null;
259
+ }
260
+ /** Handle a non-scoped entry directory inside a node_modules folder. */
261
+ async processEntry(entryPath, pkgName, requiredRange, depth, visited, queue) {
262
+ const stat = await this.lstat[entryPath];
263
+ if (!(stat === null || stat === void 0 ? void 0 : stat.isDirectory())) {
264
+ return null;
265
+ }
266
+ // Check entry/node_modules/pkgName (nested dep under a package)
267
+ const nested = path.join(entryPath, "node_modules", pkgName, "package.json");
268
+ if (await this.exists[nested]) {
269
+ const json = await this.json[nested];
270
+ if (json && this.semverSatisfies(json.version, requiredRange)) {
271
+ return { packageDir: path.dirname(nested), packageJson: json };
272
+ }
273
+ }
274
+ // Check entry/pkgName directly (some flat layouts place pkgName as a sibling)
275
+ const direct = path.join(entryPath, pkgName, "package.json");
276
+ if (await this.exists[direct]) {
277
+ const json = await this.json[direct];
278
+ if (json && this.semverSatisfies(json.version, requiredRange)) {
279
+ return { packageDir: path.dirname(direct), packageJson: json };
280
+ }
281
+ }
282
+ await this.enqueueIfExists(path.join(entryPath, "node_modules"), depth, visited, queue);
283
+ return null;
284
+ }
285
+ /** Handle a scoped-package directory (@scope) inside a node_modules folder. */
286
+ async processScope(scopePath, pkgName, requiredRange, depth, visited, queue) {
287
+ var _a;
288
+ if (!(await this.exists[scopePath]) || !((_a = (await this.lstat[scopePath])) === null || _a === void 0 ? void 0 : _a.isDirectory())) {
289
+ return null;
290
+ }
291
+ let scopeEntries;
292
+ try {
293
+ scopeEntries = await fs.readdir(scopePath);
294
+ }
295
+ catch {
296
+ return null;
297
+ }
298
+ for (const sc of scopeEntries) {
299
+ const scPath = path.join(scopePath, sc);
300
+ const candidatePkgJson = path.join(scPath, "node_modules", pkgName, "package.json");
301
+ if (await this.exists[candidatePkgJson]) {
302
+ const json = await this.json[candidatePkgJson];
303
+ if (json && this.semverSatisfies(json.version, requiredRange)) {
304
+ return { packageDir: path.dirname(candidatePkgJson), packageJson: json };
304
305
  }
305
306
  }
307
+ await this.enqueueIfExists(path.join(scPath, "node_modules"), depth, visited, queue);
306
308
  }
307
309
  return null;
308
310
  }
311
+ /** Enqueue a node_modules directory for BFS only if it exists on disk and hasn't been visited. */
312
+ async enqueueIfExists(nmPath, depth, visited, queue) {
313
+ var _a;
314
+ if (!visited.has(nmPath) && (await this.exists[nmPath]) && ((_a = (await this.lstat[nmPath])) === null || _a === void 0 ? void 0 : _a.isDirectory())) {
315
+ visited.add(nmPath);
316
+ queue.push({ dir: nmPath, depth: depth + 1 });
317
+ }
318
+ }
309
319
  }
310
320
  exports.ModuleManager = ModuleManager;
311
321
  //# sourceMappingURL=moduleManager.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"moduleManager.js","sourceRoot":"","sources":["../../src/node-module-collector/moduleManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { exists, isEmptyOrSpaces, log, LogLevel } from \"builder-util\"\nimport { PackageJson } from \"./types\"\nimport * as fs from \"fs-extra\"\nimport * as path from \"path\"\nimport * as semver from \"semver\"\n\nexport enum LogMessageByKey {\n PKG_DUPLICATE_REF = \"duplicate dependency references\",\n PKG_DUPLICATE_REF_UNRESOLVED = \"unresolved duplicate dependency references\",\n PKG_NOT_FOUND = \"cannot find path for dependency\",\n PKG_NOT_ON_DISK = \"dependency not found on disk\",\n PKG_SELF_REF = \"self-referential dependencies\",\n PKG_OPTIONAL_NOT_INSTALLED = \"missing optional dependencies\",\n PKG_OPTIONAL_PLATFORM_NOT_INSTALLED = \"platform-specific optional dependencies not bundled — add them to your project's optionalDependencies if your app requires them (pnpm 10+ does not auto-install transitive platform binaries)\",\n PKG_COLLECTOR_OUTPUT = \"collector stderr output\",\n PKG_VERSION_OVERRIDDEN = \"dependencies resolved to a version outside the declared range (installed version accepted — likely resolved via package manager overrides)\",\n}\nexport const logMessageLevelByKey: Record<LogMessageByKey, LogLevel> = {\n [LogMessageByKey.PKG_DUPLICATE_REF]: \"info\",\n [LogMessageByKey.PKG_DUPLICATE_REF_UNRESOLVED]: \"warn\",\n [LogMessageByKey.PKG_NOT_FOUND]: \"warn\",\n [LogMessageByKey.PKG_NOT_ON_DISK]: \"warn\",\n [LogMessageByKey.PKG_SELF_REF]: \"debug\",\n [LogMessageByKey.PKG_OPTIONAL_NOT_INSTALLED]: \"info\",\n [LogMessageByKey.PKG_OPTIONAL_PLATFORM_NOT_INSTALLED]: \"warn\",\n [LogMessageByKey.PKG_COLLECTOR_OUTPUT]: \"warn\",\n [LogMessageByKey.PKG_VERSION_OVERRIDDEN]: \"debug\",\n}\n\nexport type Package = { packageDir: string; packageJson: PackageJson }\n\n// Type aliases for clarity\ntype JsonCache = Record<string, Promise<PackageJson | null>>\ntype RealPathCache = Record<string, Promise<string>>\ntype ExistsCache = Record<string, Promise<boolean>>\ntype LstatCache = Record<string, Promise<fs.Stats | null>>\ntype PackageCache = Record<string, Promise<Package | null>>\ntype LogSummaryCache = Record<LogMessageByKey, string[]>\n\nexport class ModuleManager {\n /** Cache for package.json contents (readJson) */\n readonly json: JsonCache\n /** Cache for resolved real paths (if symlink, realpath; otherwise resolve) */\n readonly realPath: RealPathCache\n /** Cache for file/directory existence checks */\n readonly exists: ExistsCache\n /** Cache for lstat results */\n readonly lstat: LstatCache\n /** Cache for package lookups (key: \"packageName||fromDir||semverRange\"). Use helper function `versionedCacheKey` */\n readonly packageData: PackageCache\n /** For logging purposes, just track all dependencies for each key */\n readonly logSummary: LogSummaryCache\n\n private readonly jsonMap: Map<string, PackageJson | null> = new Map()\n private readonly realPathMap: Map<string, string> = new Map()\n private readonly existsMap: Map<string, boolean> = new Map()\n private readonly lstatMap: Map<string, fs.Stats | null> = new Map()\n private readonly packageDataMap: Map<string, Package | null> = new Map()\n private readonly logSummaryMap: Map<LogMessageByKey, string[]> = new Map()\n\n constructor() {\n this.logSummary = this.createLogSummarySyncProxy()\n\n this.exists = this.createAsyncProxy(this.existsMap, (p: string) => exists(p))\n this.json = this.createAsyncProxy(this.jsonMap, (p: string) => fs.readJson(p).catch(() => null))\n this.lstat = this.createAsyncProxy(this.lstatMap, (p: string) => fs.lstat(p).catch(() => null))\n this.packageData = this.createAsyncProxy(this.packageDataMap, (p: string) => this.locatePackageVersionFromCacheKey(p).catch(() => null))\n this.realPath = this.createAsyncProxy(this.realPathMap, async (p: string) => {\n const filePath = path.resolve(p)\n const stat = await this.lstat[filePath]\n return stat?.isSymbolicLink() ? fs.realpath(filePath) : filePath\n })\n }\n\n private createLogSummarySyncProxy(): LogSummaryCache {\n return new Proxy({} as LogSummaryCache, {\n get: (_, key: LogMessageByKey) => {\n if (!this.logSummaryMap.has(key)) {\n this.logSummaryMap.set(key, [])\n }\n return this.logSummaryMap.get(key)!\n },\n set: (_, key: LogMessageByKey, value: string[]) => {\n this.logSummaryMap.set(key, value)\n return true\n },\n has: (_, key: LogMessageByKey) => {\n return this.logSummaryMap.has(key)\n },\n // Add these to make Object.entries() work\n ownKeys: _ => {\n return Array.from(this.logSummaryMap.keys())\n },\n getOwnPropertyDescriptor: (_, key) => {\n if (this.logSummaryMap.has(key as LogMessageByKey)) {\n return {\n enumerable: true,\n configurable: true,\n }\n }\n return undefined\n },\n })\n }\n\n // this allows dot-notation access while still supporting async retrieval\n // e.g., cache.packageJson[somePath] returns Promise<PackageJson>\n private createAsyncProxy<T>(map: Map<string, T>, compute: (key: string) => T | Promise<T>): Record<string, Promise<T>> {\n return new Proxy({} as Record<string, Promise<T>>, {\n async get(_, key: string) {\n if (map.has(key)) {\n return Promise.resolve(map.get(key)!)\n }\n return await Promise.resolve(compute(key)).then(value => {\n map.set(key, value)\n return value\n })\n },\n set(_, key: string, value: T) {\n map.set(key, value)\n return true\n },\n has(_, key: string) {\n return map.has(key)\n },\n })\n }\n\n versionedCacheKey(pkg: { name: string; path: string; semver?: string }): string {\n return [pkg.name, pkg.path, pkg.semver || \"\"].join(\"||\")\n }\n\n protected async locatePackageVersionFromCacheKey(key: string): Promise<Package | null> {\n const [name, fromDir, semverRange] = key.split(\"||\")\n const result = await this.locatePackageVersion({ parentDir: fromDir, pkgName: name, requiredRange: semverRange })\n if (result == null) {\n return null\n }\n return { ...result, packageDir: await this.realPath[result.packageDir] }\n }\n\n public async locatePackageVersion({\n parentDir,\n pkgName,\n requiredRange,\n skipDownwardSearch = false,\n }: {\n /**\n * The directory to start searching from. Typed optional because pnpm JSON output can omit\n * the `path` field at runtime even when the TypeScript type says `string`. An undefined\n * parentDir is treated as \"package not found\" rather than a crash.\n */\n parentDir?: string\n /**\n * The package name to locate. Typed optional for the same reason as parentDir: the pnpm\n * list JSON can omit `name`/`from` fields (e.g. when the root package.json has no name),\n * producing an undefined pkgName at runtime despite the TypeScript type.\n */\n pkgName?: string\n requiredRange?: string\n /**\n * When true, skip the BFS-based `downwardSearch`. Use for layouts that are guaranteed flat\n * (e.g. pnpm's `.pnpm` virtual store), where the downward walk burns thousands of `readdir`\n * / `lstat` calls and finds nothing.\n */\n skipDownwardSearch?: boolean\n }): Promise<Package | null> {\n if (!parentDir || !pkgName) {\n return null\n }\n\n const found = await this.searchForPackage(parentDir, pkgName, requiredRange, skipDownwardSearch)\n if (found) {\n return found\n }\n\n // Second pass: find any installed version of the package when the declared-range search\n // returns nothing. This handles package manager `overrides` (Bun, npm, pnpm, Yarn) that\n // resolve a transitive dependency to a version intentionally outside its declared range.\n // File-system results are already cached, so this pass costs only JS overhead.\n if (requiredRange) {\n const overrideResult = await this.searchForPackage(parentDir, pkgName, undefined, skipDownwardSearch)\n if (overrideResult) {\n log.debug(\n { pkg: pkgName, declared: requiredRange, installed: overrideResult.packageJson.version },\n \"accepting installed package version that doesn't satisfy the declared range\"\n )\n this.logSummary[LogMessageByKey.PKG_VERSION_OVERRIDDEN].push(`${pkgName}@${overrideResult.packageJson.version} (declared ${requiredRange})`)\n return overrideResult\n }\n }\n\n return null\n }\n\n private async searchForPackage(parentDir: string, pkgName: string, requiredRange: string | undefined, skipDownwardSearch: boolean): Promise<Package | null> {\n // 1) check direct parent node_modules/pkgName first\n const direct = path.join(path.resolve(parentDir), \"node_modules\", pkgName, \"package.json\")\n if (await this.exists[direct]) {\n const json = await this.json[direct]\n if (json && this.semverSatisfies(json.version, requiredRange)) {\n return { packageDir: path.dirname(direct), packageJson: json }\n }\n }\n\n // 2) upward hoisted search, then 3) downward non-hoisted search\n const upward = await this.upwardSearch(parentDir, pkgName, requiredRange)\n if (upward) {\n return upward\n }\n if (skipDownwardSearch) {\n return null\n }\n return (await this.downwardSearch(parentDir, pkgName, requiredRange)) || null\n }\n\n private semverSatisfies(found: string, range?: string): boolean {\n if (isEmptyOrSpaces(range) || range === \"*\") {\n return true\n }\n\n if (range === found) {\n return true\n }\n\n if (semver.validRange(range) == null) {\n // ignore, we can't verify non-semver ranges\n // e.g. git urls, file:, patch:, etc. Example:\n // \"@ai-sdk/google\": \"patch:@ai-sdk/google@npm%3A2.0.43#~/.yarn/patches/@ai-sdk-google-npm-2.0.43-689ed559b3.patch\"\n log.debug({ found, range }, \"unable to validate semver version range, assuming match\")\n return true\n }\n\n try {\n return semver.satisfies(found, range)\n } catch {\n // fallback: simple equality or basic prefix handling (^, ~)\n if (range.startsWith(\"^\") || range.startsWith(\"~\")) {\n const r = range.slice(1)\n return r === found\n }\n // if range is like \"8.x\" or \"8.*\" match major\n const m = range.match(/^(\\d+)[.(*|x)]*/)\n const fm = found.match(/^(\\d+)\\./)\n if (m && fm) {\n return m[1] === fm[1]\n }\n return false\n }\n }\n\n /**\n * Upward search (hoisted)\n */\n private async upwardSearch(parentDir: string, pkgName: string, requiredRange?: string): Promise<Package | null> {\n let current = path.resolve(parentDir)\n const root = path.parse(current).root\n while (true) {\n const candidate = path.join(current, \"node_modules\", pkgName, \"package.json\")\n if (await this.exists[candidate]) {\n const json = await this.json[candidate]\n if (json && this.semverSatisfies(json.version, requiredRange)) {\n return { packageDir: path.dirname(candidate), packageJson: json }\n }\n // otherwise keep searching upward (we may find a different hoisted version)\n }\n if (current === root) {\n break\n }\n const parent = path.dirname(current)\n if (parent === current) {\n break\n }\n current = parent\n }\n return null\n }\n\n /**\n * Breadth-first downward search from parentDir/node_modules\n * Looks for node_modules/\\*\\/node_modules/pkgName (and deeper)\n */\n private async downwardSearch(parentDir: string, pkgName: string, requiredRange?: string, maxExplored = 2000, maxDepth = 6): Promise<Package | null> {\n const start = path.join(path.resolve(parentDir), \"node_modules\")\n if (!(await this.exists[start]) || !(await this.lstat[start])?.isDirectory()) {\n return null\n }\n\n const visited = new Set<string>()\n const queue: Array<{ dir: string; depth: number }> = [{ dir: start, depth: 0 }]\n let explored = 0\n\n while (queue.length > 0) {\n const { dir, depth } = queue.shift()!\n if (explored++ > maxExplored) {\n break\n }\n if (depth > maxDepth) {\n continue\n }\n let entries: string[]\n try {\n entries = await fs.readdir(dir)\n } catch {\n continue\n }\n for (const entry of entries) {\n if (entry.startsWith(\".\")) {\n continue\n }\n const entryPath = path.join(dir, entry)\n // handle scoped packages @scope/name\n if (entry.startsWith(\"@\")) {\n // queue the scope directory itself to explore its children\n if ((await this.exists[entryPath]) && (await this.lstat[entryPath])?.isDirectory()) {\n const scopeEntries = await fs.readdir(entryPath)\n for (const sc of scopeEntries) {\n const scPath = path.join(entryPath, sc)\n // check scPath/node_modules/pkgName\n const candidatePkgJson = path.join(scPath, \"node_modules\", pkgName, \"package.json\")\n if (await this.exists[candidatePkgJson]) {\n const json = await this.json[candidatePkgJson]\n if (json && this.semverSatisfies(json.version, requiredRange)) {\n return { packageDir: path.dirname(candidatePkgJson), packageJson: json }\n }\n }\n // enqueue scPath/node_modules to explore further\n const scNodeModules = path.join(scPath, \"node_modules\")\n if ((await this.exists[scNodeModules]) && (await this.lstat[scNodeModules])?.isDirectory()) {\n if (!visited.has(scNodeModules)) {\n visited.add(scNodeModules)\n queue.push({ dir: scNodeModules, depth: depth + 1 })\n }\n }\n }\n }\n continue\n }\n\n // check for direct candidate: entry/node_modules/pkgName\n try {\n const stat = await this.lstat[entryPath]\n if (!stat?.isDirectory()) {\n continue\n }\n } catch {\n continue\n }\n\n const candidatePkgJson = path.join(entryPath, \"node_modules\", pkgName, \"package.json\")\n if (await this.exists[candidatePkgJson]) {\n const json = await this.json[candidatePkgJson]\n if (json && this.semverSatisfies(json.version, requiredRange)) {\n return { packageDir: path.dirname(candidatePkgJson), packageJson: json }\n }\n }\n\n // also check entry/node_modules directly for pkgName (some layouts)\n const candidateDirect = path.join(entryPath, pkgName, \"package.json\")\n if (await this.exists[candidateDirect]) {\n const json = await this.json[candidateDirect]\n if (json && this.semverSatisfies(json.version, requiredRange)) {\n return { packageDir: path.dirname(candidateDirect), packageJson: json }\n }\n }\n\n // enqueue entry/node_modules for deeper traversal\n const nextNodeModules = path.join(entryPath, \"node_modules\")\n if ((await this.exists[nextNodeModules]) && (await this.lstat[nextNodeModules])?.isDirectory()) {\n if (!visited.has(nextNodeModules)) {\n visited.add(nextNodeModules)\n queue.push({ dir: nextNodeModules, depth: depth + 1 })\n }\n }\n }\n }\n\n return null\n }\n}\n"]}
1
+ {"version":3,"file":"moduleManager.js","sourceRoot":"","sources":["../../src/node-module-collector/moduleManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { exists, isEmptyOrSpaces, log, LogLevel } from \"builder-util\"\nimport { PackageJson } from \"./types\"\nimport * as fs from \"fs-extra\"\nimport * as path from \"path\"\nimport * as semver from \"semver\"\n\nexport enum LogMessageByKey {\n PKG_DUPLICATE_REF = \"duplicate dependency references\",\n PKG_DUPLICATE_REF_UNRESOLVED = \"unresolved duplicate dependency references\",\n PKG_NOT_FOUND = \"cannot find path for dependency\",\n PKG_NOT_ON_DISK = \"dependency not found on disk\",\n PKG_SELF_REF = \"self-referential dependencies\",\n PKG_OPTIONAL_NOT_INSTALLED = \"missing optional dependencies\",\n PKG_OPTIONAL_PLATFORM_NOT_INSTALLED = \"platform-specific optional dependencies not bundled — add them to your project's optionalDependencies if your app requires them (pnpm 10+ does not auto-install transitive platform binaries)\",\n PKG_COLLECTOR_OUTPUT = \"collector stderr output\",\n PKG_VERSION_OVERRIDDEN = \"dependencies resolved to a version outside the declared range (installed version accepted — likely resolved via package manager overrides)\",\n}\nexport const logMessageLevelByKey: Record<LogMessageByKey, LogLevel> = {\n [LogMessageByKey.PKG_DUPLICATE_REF]: \"info\",\n [LogMessageByKey.PKG_DUPLICATE_REF_UNRESOLVED]: \"warn\",\n [LogMessageByKey.PKG_NOT_FOUND]: \"warn\",\n [LogMessageByKey.PKG_NOT_ON_DISK]: \"warn\",\n [LogMessageByKey.PKG_SELF_REF]: \"debug\",\n [LogMessageByKey.PKG_OPTIONAL_NOT_INSTALLED]: \"info\",\n [LogMessageByKey.PKG_OPTIONAL_PLATFORM_NOT_INSTALLED]: \"warn\",\n [LogMessageByKey.PKG_COLLECTOR_OUTPUT]: \"warn\",\n [LogMessageByKey.PKG_VERSION_OVERRIDDEN]: \"debug\",\n}\n\nexport type Package = { packageDir: string; packageJson: PackageJson }\n\n// Type aliases for clarity\ntype JsonCache = Record<string, Promise<PackageJson | null>>\ntype RealPathCache = Record<string, Promise<string>>\ntype ExistsCache = Record<string, Promise<boolean>>\ntype LstatCache = Record<string, Promise<fs.Stats | null>>\ntype PackageCache = Record<string, Promise<Package | null>>\ntype LogSummaryCache = Record<LogMessageByKey, string[]>\n\nexport class ModuleManager {\n /** Cache for package.json contents (readJson) */\n readonly json: JsonCache\n /** Cache for resolved real paths (if symlink, realpath; otherwise resolve) */\n readonly realPath: RealPathCache\n /** Cache for file/directory existence checks */\n readonly exists: ExistsCache\n /** Cache for lstat results */\n readonly lstat: LstatCache\n /** Cache for package lookups (key: \"packageName||fromDir||semverRange\"). Use helper function `versionedCacheKey` */\n readonly packageData: PackageCache\n /** For logging purposes, just track all dependencies for each key */\n readonly logSummary: LogSummaryCache\n\n private readonly jsonMap: Map<string, PackageJson | null> = new Map()\n private readonly realPathMap: Map<string, string> = new Map()\n private readonly existsMap: Map<string, boolean> = new Map()\n private readonly lstatMap: Map<string, fs.Stats | null> = new Map()\n private readonly packageDataMap: Map<string, Package | null> = new Map()\n private readonly logSummaryMap: Map<LogMessageByKey, string[]> = new Map()\n\n constructor() {\n this.logSummary = this.createLogSummarySyncProxy()\n\n this.exists = this.createAsyncProxy(this.existsMap, (p: string) => exists(p))\n this.json = this.createAsyncProxy(this.jsonMap, (p: string) => fs.readJson(p).catch(() => null))\n this.lstat = this.createAsyncProxy(this.lstatMap, (p: string) => fs.lstat(p).catch(() => null))\n this.packageData = this.createAsyncProxy(this.packageDataMap, (p: string) => this.locatePackageVersionFromCacheKey(p).catch(() => null))\n this.realPath = this.createAsyncProxy(this.realPathMap, async (p: string) => {\n const filePath = path.resolve(p)\n const stat = await this.lstat[filePath]\n return stat?.isSymbolicLink() ? fs.realpath(filePath) : filePath\n })\n }\n\n private createLogSummarySyncProxy(): LogSummaryCache {\n return new Proxy({} as LogSummaryCache, {\n get: (_, key: LogMessageByKey) => {\n if (!this.logSummaryMap.has(key)) {\n this.logSummaryMap.set(key, [])\n }\n return this.logSummaryMap.get(key)!\n },\n set: (_, key: LogMessageByKey, value: string[]) => {\n this.logSummaryMap.set(key, value)\n return true\n },\n has: (_, key: LogMessageByKey) => {\n return this.logSummaryMap.has(key)\n },\n // Add these to make Object.entries() work\n ownKeys: _ => {\n return Array.from(this.logSummaryMap.keys())\n },\n getOwnPropertyDescriptor: (_, key) => {\n if (this.logSummaryMap.has(key as LogMessageByKey)) {\n return {\n enumerable: true,\n configurable: true,\n }\n }\n return undefined\n },\n })\n }\n\n // this allows dot-notation access while still supporting async retrieval\n // e.g., cache.packageJson[somePath] returns Promise<PackageJson>\n private createAsyncProxy<T>(map: Map<string, T>, compute: (key: string) => T | Promise<T>): Record<string, Promise<T>> {\n return new Proxy({} as Record<string, Promise<T>>, {\n async get(_, key: string) {\n if (map.has(key)) {\n return Promise.resolve(map.get(key)!)\n }\n return await Promise.resolve(compute(key)).then(value => {\n map.set(key, value)\n return value\n })\n },\n set(_, key: string, value: T) {\n map.set(key, value)\n return true\n },\n has(_, key: string) {\n return map.has(key)\n },\n })\n }\n\n versionedCacheKey(pkg: { name: string; path: string; semver?: string }): string {\n return [pkg.name, pkg.path, pkg.semver || \"\"].join(\"||\")\n }\n\n protected async locatePackageVersionFromCacheKey(key: string): Promise<Package | null> {\n const [name, fromDir, semverRange] = key.split(\"||\")\n const result = await this.locatePackageVersion({ parentDir: fromDir, pkgName: name, requiredRange: semverRange })\n if (result == null) {\n return null\n }\n return { ...result, packageDir: await this.realPath[result.packageDir] }\n }\n\n public async locatePackageVersion({\n parentDir,\n pkgName,\n requiredRange,\n skipDownwardSearch = false,\n }: {\n /**\n * The directory to start searching from. Typed optional because pnpm JSON output can omit\n * the `path` field at runtime even when the TypeScript type says `string`. An undefined\n * parentDir is treated as \"package not found\" rather than a crash.\n */\n parentDir?: string\n /**\n * The package name to locate. Typed optional for the same reason as parentDir: the pnpm\n * list JSON can omit `name`/`from` fields (e.g. when the root package.json has no name),\n * producing an undefined pkgName at runtime despite the TypeScript type.\n */\n pkgName?: string\n requiredRange?: string\n /**\n * When true, skip the BFS-based `downwardSearch`. Use for layouts that are guaranteed flat\n * (e.g. pnpm's `.pnpm` virtual store), where the downward walk burns thousands of `readdir`\n * / `lstat` calls and finds nothing.\n */\n skipDownwardSearch?: boolean\n }): Promise<Package | null> {\n if (!parentDir || !pkgName) {\n return null\n }\n\n const found = await this.searchForPackage(parentDir, pkgName, requiredRange, skipDownwardSearch)\n if (found) {\n return found\n }\n\n // Second pass: find any installed version of the package when the declared-range search\n // returns nothing. This handles package manager `overrides` (Bun, npm, pnpm, Yarn) that\n // resolve a transitive dependency to a version intentionally outside its declared range.\n // File-system results are already cached, so this pass costs only JS overhead.\n if (requiredRange) {\n const overrideResult = await this.searchForPackage(parentDir, pkgName, undefined, skipDownwardSearch)\n if (overrideResult) {\n log.debug(\n { pkg: pkgName, declared: requiredRange, installed: overrideResult.packageJson.version },\n \"accepting installed package version that doesn't satisfy the declared range\"\n )\n this.logSummary[LogMessageByKey.PKG_VERSION_OVERRIDDEN].push(`${pkgName}@${overrideResult.packageJson.version} (declared ${requiredRange})`)\n return overrideResult\n }\n }\n\n return null\n }\n\n private async searchForPackage(parentDir: string, pkgName: string, requiredRange: string | undefined, skipDownwardSearch: boolean): Promise<Package | null> {\n // 1) check direct parent node_modules/pkgName first\n const direct = path.join(path.resolve(parentDir), \"node_modules\", pkgName, \"package.json\")\n if (await this.exists[direct]) {\n const json = await this.json[direct]\n if (json && this.semverSatisfies(json.version, requiredRange)) {\n return { packageDir: path.dirname(direct), packageJson: json }\n }\n }\n\n // 2) upward hoisted search, then 3) downward non-hoisted search\n const upward = await this.upwardSearch(parentDir, pkgName, requiredRange)\n if (upward) {\n return upward\n }\n if (skipDownwardSearch) {\n return null\n }\n return (await this.downwardSearch(parentDir, pkgName, requiredRange)) || null\n }\n\n private semverSatisfies(found: string, range?: string): boolean {\n if (isEmptyOrSpaces(range) || range === \"*\") {\n return true\n }\n\n if (range === found) {\n return true\n }\n\n if (semver.validRange(range) == null) {\n // ignore, we can't verify non-semver ranges\n // e.g. git urls, file:, patch:, etc. Example:\n // \"@ai-sdk/google\": \"patch:@ai-sdk/google@npm%3A2.0.43#~/.yarn/patches/@ai-sdk-google-npm-2.0.43-689ed559b3.patch\"\n log.debug({ found, range }, \"unable to validate semver version range, assuming match\")\n return true\n }\n\n try {\n return semver.satisfies(found, range)\n } catch {\n // fallback: simple equality or basic prefix handling (^, ~)\n if (range.startsWith(\"^\") || range.startsWith(\"~\")) {\n const r = range.slice(1)\n return r === found\n }\n // if range is like \"8.x\" or \"8.*\" match major\n const m = range.match(/^(\\d+)[.(*|x)]*/)\n const fm = found.match(/^(\\d+)\\./)\n if (m && fm) {\n return m[1] === fm[1]\n }\n return false\n }\n }\n\n /**\n * Upward search (hoisted)\n */\n private async upwardSearch(parentDir: string, pkgName: string, requiredRange?: string): Promise<Package | null> {\n let current = path.resolve(parentDir)\n const root = path.parse(current).root\n while (true) {\n const candidate = path.join(current, \"node_modules\", pkgName, \"package.json\")\n if (await this.exists[candidate]) {\n const json = await this.json[candidate]\n if (json && this.semverSatisfies(json.version, requiredRange)) {\n return { packageDir: path.dirname(candidate), packageJson: json }\n }\n // otherwise keep searching upward (we may find a different hoisted version)\n }\n if (current === root) {\n break\n }\n const parent = path.dirname(current)\n if (parent === current) {\n break\n }\n current = parent\n }\n return null\n }\n\n /**\n * Breadth-first downward search from parentDir/node_modules\n * Looks for node_modules/\\*\\/node_modules/pkgName (and deeper)\n */\n private async downwardSearch(parentDir: string, pkgName: string, requiredRange?: string, maxExplored = 2000, maxDepth = 6): Promise<Package | null> {\n const start = path.join(path.resolve(parentDir), \"node_modules\")\n if (!(await this.exists[start]) || !(await this.lstat[start])?.isDirectory()) {\n return null\n }\n\n const visited = new Set<string>()\n const queue: Array<{ dir: string; depth: number }> = [{ dir: start, depth: 0 }]\n let explored = 0\n\n while (queue.length > 0) {\n const { dir, depth } = queue.shift()!\n if (explored++ > maxExplored) {\n break\n }\n if (depth > maxDepth) {\n continue\n }\n let entries: string[]\n try {\n entries = await fs.readdir(dir)\n } catch {\n continue\n }\n for (const entry of entries) {\n if (entry.startsWith(\".\")) {\n continue\n }\n const entryPath = path.join(dir, entry)\n if (entry.startsWith(\"@\")) {\n const found = await this.processScope(entryPath, pkgName, requiredRange, depth, visited, queue)\n if (found) {\n return found\n }\n continue\n }\n const found = await this.processEntry(entryPath, pkgName, requiredRange, depth, visited, queue)\n if (found) {\n return found\n }\n }\n }\n\n return null\n }\n\n /** Handle a non-scoped entry directory inside a node_modules folder. */\n private async processEntry(\n entryPath: string,\n pkgName: string,\n requiredRange: string | undefined,\n depth: number,\n visited: Set<string>,\n queue: Array<{ dir: string; depth: number }>\n ): Promise<Package | null> {\n const stat = await this.lstat[entryPath]\n if (!stat?.isDirectory()) {\n return null\n }\n\n // Check entry/node_modules/pkgName (nested dep under a package)\n const nested = path.join(entryPath, \"node_modules\", pkgName, \"package.json\")\n if (await this.exists[nested]) {\n const json = await this.json[nested]\n if (json && this.semverSatisfies(json.version, requiredRange)) {\n return { packageDir: path.dirname(nested), packageJson: json }\n }\n }\n\n // Check entry/pkgName directly (some flat layouts place pkgName as a sibling)\n const direct = path.join(entryPath, pkgName, \"package.json\")\n if (await this.exists[direct]) {\n const json = await this.json[direct]\n if (json && this.semverSatisfies(json.version, requiredRange)) {\n return { packageDir: path.dirname(direct), packageJson: json }\n }\n }\n\n await this.enqueueIfExists(path.join(entryPath, \"node_modules\"), depth, visited, queue)\n return null\n }\n\n /** Handle a scoped-package directory (@scope) inside a node_modules folder. */\n private async processScope(\n scopePath: string,\n pkgName: string,\n requiredRange: string | undefined,\n depth: number,\n visited: Set<string>,\n queue: Array<{ dir: string; depth: number }>\n ): Promise<Package | null> {\n if (!(await this.exists[scopePath]) || !(await this.lstat[scopePath])?.isDirectory()) {\n return null\n }\n let scopeEntries: string[]\n try {\n scopeEntries = await fs.readdir(scopePath)\n } catch {\n return null\n }\n for (const sc of scopeEntries) {\n const scPath = path.join(scopePath, sc)\n const candidatePkgJson = path.join(scPath, \"node_modules\", pkgName, \"package.json\")\n if (await this.exists[candidatePkgJson]) {\n const json = await this.json[candidatePkgJson]\n if (json && this.semverSatisfies(json.version, requiredRange)) {\n return { packageDir: path.dirname(candidatePkgJson), packageJson: json }\n }\n }\n await this.enqueueIfExists(path.join(scPath, \"node_modules\"), depth, visited, queue)\n }\n return null\n }\n\n /** Enqueue a node_modules directory for BFS only if it exists on disk and hasn't been visited. */\n private async enqueueIfExists(nmPath: string, depth: number, visited: Set<string>, queue: Array<{ dir: string; depth: number }>): Promise<void> {\n if (!visited.has(nmPath) && (await this.exists[nmPath]) && (await this.lstat[nmPath])?.isDirectory()) {\n visited.add(nmPath)\n queue.push({ dir: nmPath, depth: depth + 1 })\n }\n }\n}\n"]}
@@ -106,8 +106,9 @@ export declare abstract class NodeModulesCollector<ProdDepType extends Dependenc
106
106
  * Executes a command and streams its output to a file.
107
107
  *
108
108
  * Spawns a child process to execute the specified command with arguments, capturing stdout
109
- * to a file. Handles Windows-specific quirks by wrapping .cmd files in a temporary .bat file
110
- * when necessary. Enables corepack strict mode by default but allows process.env overrides.
109
+ * to a file. On Windows, wraps the invocation in `powershell.exe -EncodedCommand` (UTF-16LE
110
+ * base64) to avoid spawning `.cmd` shims directly and to eliminate shell-injection surface area.
111
+ * Enables corepack strict mode by default but allows process.env overrides.
111
112
  *
112
113
  * Special handling for `npm list` exit code 1, which is expected in certain scenarios.
113
114
  *
@@ -119,10 +120,18 @@ export declare abstract class NodeModulesCollector<ProdDepType extends Dependenc
119
120
  * @throws {Error} If the child process spawn fails or exits with a non-zero code
120
121
  */
121
122
  protected streamCollectorCommandToFile(command: string, args: string[], cwd: string, tempOutputFile: string): Promise<void>;
122
- /**
123
- * Windows-only. Wraps .cmd files and executables at paths containing spaces in a temporary .bat
124
- * file so that cmd.exe spawns them correctly. Returns the original command/args unchanged when
125
- * no wrapping is required. Must only be called on win32.
126
- */
127
- private resolveWindowsCommand;
128
123
  }
124
+ /**
125
+ * Build the argv for invoking a Windows command through `powershell.exe -EncodedCommand`.
126
+ *
127
+ * Each token is wrapped in a PowerShell single-quoted string (with embedded single quotes doubled),
128
+ * so no character is interpreted by a shell. The script:
129
+ * - pins `[Console]::OutputEncoding` to UTF-8 *without* a BOM so the JSON dependency tree is not
130
+ * corrupted by the console's OEM code page (and no BOM is prepended to break `JSON.parse`),
131
+ * - invokes the command via the call operator `&`,
132
+ * - re-emits the command's own exit code via `exit $LASTEXITCODE` (e.g. `npm list` returns 1 in
133
+ * expected scenarios, which the caller's shouldIgnore logic relies on).
134
+ *
135
+ * The whole script is base64-encoded as UTF-16LE per PowerShell's `-EncodedCommand` contract.
136
+ */
137
+ export declare function buildPowerShellEncodedArgs(command: string, args: string[]): string[];
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.NodeModulesCollector = void 0;
4
+ exports.buildPowerShellEncodedArgs = buildPowerShellEncodedArgs;
4
5
  const builder_util_1 = require("builder-util");
5
6
  const childProcess = require("child_process");
6
- const crypto_1 = require("crypto");
7
7
  const fs = require("fs-extra");
8
8
  const fs_extra_1 = require("fs-extra");
9
9
  const lazy_val_1 = require("lazy-val");
@@ -24,7 +24,7 @@ class NodeModulesCollector {
24
24
  const command = (0, packageManager_1.getPackageManagerCommand)(manager);
25
25
  const config = (await this.asyncExec(command, ["config", "list"])).stdout;
26
26
  if (config == null) {
27
- builder_util_1.log.debug({ manager }, "unable to determine if node_modules are hoisted: no config output. falling back to hoisted mode");
27
+ builder_util_1.log.debug({ manager }, "unable to determine node-linker setting; assuming non-hoisted (virtual store) layout");
28
28
  return false;
29
29
  }
30
30
  const lines = Object.fromEntries(config.split("\n").map(line => line.split("=").map(s => s.trim())));
@@ -82,7 +82,7 @@ class NodeModulesCollector {
82
82
  interval: 2000,
83
83
  backoff: 2000,
84
84
  shouldRetry: async (error) => {
85
- var _a;
85
+ var _a, _b;
86
86
  const fields = { error: error.message, tempOutputFile, cwd: this.rootDir, packageManager: pm };
87
87
  if (!(await (0, builder_util_1.exists)(tempOutputFile))) {
88
88
  builder_util_1.log.debug(fields, "dependency tree output file missing, retrying");
@@ -104,7 +104,8 @@ class NodeModulesCollector {
104
104
  else {
105
105
  fields.content = fileContent;
106
106
  }
107
- if ((_a = error.message) === null || _a === void 0 ? void 0 : _a.includes("Unexpected end of JSON input")) {
107
+ // Both indicate truncated/polluted PM output (a transient that re-running the command clears).
108
+ if (((_a = error.message) === null || _a === void 0 ? void 0 : _a.includes("Unexpected end of JSON input")) || ((_b = error.message) === null || _b === void 0 ? void 0 : _b.includes("No JSON content found in output"))) {
108
109
  builder_util_1.log.debug(fields, "JSON parse error in dependency tree, retrying");
109
110
  return true;
110
111
  }
@@ -297,8 +298,9 @@ class NodeModulesCollector {
297
298
  * Executes a command and streams its output to a file.
298
299
  *
299
300
  * Spawns a child process to execute the specified command with arguments, capturing stdout
300
- * to a file. Handles Windows-specific quirks by wrapping .cmd files in a temporary .bat file
301
- * when necessary. Enables corepack strict mode by default but allows process.env overrides.
301
+ * to a file. On Windows, wraps the invocation in `powershell.exe -EncodedCommand` (UTF-16LE
302
+ * base64) to avoid spawning `.cmd` shims directly and to eliminate shell-injection surface area.
303
+ * Enables corepack strict mode by default but allows process.env overrides.
302
304
  *
303
305
  * Special handling for `npm list` exit code 1, which is expected in certain scenarios.
304
306
  *
@@ -310,46 +312,63 @@ class NodeModulesCollector {
310
312
  * @throws {Error} If the child process spawn fails or exits with a non-zero code
311
313
  */
312
314
  async streamCollectorCommandToFile(command, args, cwd, tempOutputFile) {
313
- // Capture execName from the original command before resolveWindowsCommand may rewrite it to
314
- // cmd.exe — shouldIgnore must key off the original invocation (e.g. "npm", not "cmd").
315
+ // Derive execName from the original command so the npm-list shouldIgnore check below keys off the
316
+ // real invocation (e.g. "npm"), not the "powershell" wrapper we spawn on Windows.
315
317
  const execName = path.basename(command, path.extname(command));
316
- if (process.platform === "win32") {
317
- const resolved = await this.resolveWindowsCommand(command, args);
318
- command = resolved.command;
319
- args = resolved.args;
320
- }
321
- const isWindows = process.platform === "win32";
322
- // shell: true is required on Windows — see https://github.com/electron-userland/electron-builder/issues/9488
323
- // On non-Windows, shell:false means args are passed directly to the process with no shell
324
- // interpretation, so the metacharacter guard is only necessary on Windows.
325
- if (isWindows) {
326
- // Guard against cmd.exe metacharacters. Parentheses are intentionally excluded because they
327
- // appear in legitimate Windows paths (e.g. "C:\Program Files (x86)").
328
- const SHELL_INJECTION_RE = /[;&|`${}[\]<>!%^]/;
329
- for (const arg of args) {
330
- if (SHELL_INJECTION_RE.test(arg)) {
331
- throw new Error(`Refusing to spawn "${command}": argument "${arg}" contains shell metacharacters. Possible injection attempt.`);
332
- }
333
- }
334
- }
318
+ // On Windows the package-manager command is typically a `.cmd` shim (npm.cmd/pnpm.cmd/yarn.cmd),
319
+ // which Node can no longer spawn directly (CVE-2024-27980). Rather than spawn with `shell: true` —
320
+ // which emits the DEP0190 "args with shell" deprecation warning and forces manual metacharacter
321
+ // escaping — wrap the invocation in a single PowerShell `-EncodedCommand`. The base64 (UTF-16LE)
322
+ // payload sidesteps every shell-quoting layer, and `powershell.exe` is a real executable we spawn
323
+ // directly with no shell. See buildPowerShellEncodedArgs for the UTF-8 / exit-code handling.
324
+ const [spawnCommand, spawnArgs] = process.platform === "win32" ? ["powershell.exe", buildPowerShellEncodedArgs(command, args)] : [command, args];
335
325
  await new Promise((resolve, reject) => {
336
326
  const outStream = (0, fs_extra_1.createWriteStream)(tempOutputFile);
337
- const child = childProcess.spawn(command, args, {
327
+ const child = childProcess.spawn(spawnCommand, spawnArgs, {
338
328
  cwd,
339
329
  // Package manager invocations do not need signing/publishing credentials.
340
330
  env: { COREPACK_ENABLE_STRICT: "0", ...(0, builder_util_1.stripSensitiveEnvVars)(process.env) },
341
- shell: isWindows, // shell: true is required on Windows — see https://github.com/electron-userland/electron-builder/issues/9488
342
331
  });
343
332
  let stderr = "";
333
+ // The process can close before all piped stdout has been flushed to disk. Resolving on the
334
+ // child's "close" alone races the write stream and lets the caller read a TRUNCATED file
335
+ // (manifesting as "No JSON content found in output"). Gate the settle on BOTH the child exit
336
+ // (for the code/stderr) and the write stream's "finish" (all bytes flushed).
337
+ let exitCode = null;
338
+ let childClosed = false;
339
+ let streamFinished = false;
340
+ let settled = false;
341
+ // `pipe` ends `outStream` when stdout EOFs, which triggers its "finish" once flushed.
344
342
  child.stdout.pipe(outStream);
345
343
  child.stderr.on("data", chunk => {
346
344
  stderr += chunk.toString();
347
345
  });
348
- child.on("error", err => {
349
- reject(new Error(`Node module collector spawn (${command} ${JSON.stringify(args)}) failed: ${err.message}`));
350
- });
351
- child.on("close", code => {
352
- outStream.close();
346
+ const fail = (err) => {
347
+ if (settled) {
348
+ return;
349
+ }
350
+ settled = true;
351
+ // Best-effort cleanup: stop the child and close the stream so we don't
352
+ // waste CPU writing to a broken fd after rejection.
353
+ try {
354
+ child.kill();
355
+ }
356
+ catch {
357
+ // ignore
358
+ }
359
+ try {
360
+ outStream.destroy();
361
+ }
362
+ catch {
363
+ // ignore
364
+ }
365
+ reject(err);
366
+ };
367
+ const settle = () => {
368
+ if (settled || !childClosed || !streamFinished) {
369
+ return;
370
+ }
371
+ const code = exitCode;
353
372
  // https://github.com/npm/npm/issues/17624
354
373
  const shouldIgnore = code === 1 && "npm" === execName.toLowerCase() && args.includes("list");
355
374
  if (shouldIgnore) {
@@ -365,38 +384,45 @@ class NodeModulesCollector {
365
384
  this.cache.logSummary[moduleManager_1.LogMessageByKey.PKG_COLLECTOR_OUTPUT].push(stderr);
366
385
  }
367
386
  }
387
+ settled = true;
368
388
  const shouldResolve = code === 0 || shouldIgnore;
369
389
  return shouldResolve ? resolve() : reject(new Error(`Node module collector process exited with code ${code}:\n${stderr}`));
390
+ };
391
+ outStream.on("error", err => fail(new Error(`Node module collector failed writing output (${command}): ${err.message}`)));
392
+ outStream.on("finish", () => {
393
+ streamFinished = true;
394
+ settle();
395
+ });
396
+ child.on("error", err => {
397
+ fail(new Error(`Node module collector spawn (${command} ${JSON.stringify(args)}) failed: ${err.message}`));
398
+ });
399
+ child.on("close", code => {
400
+ exitCode = code;
401
+ childClosed = true;
402
+ settle();
370
403
  });
371
404
  });
372
405
  }
373
- /**
374
- * Windows-only. Wraps .cmd files and executables at paths containing spaces in a temporary .bat
375
- * file so that cmd.exe spawns them correctly. Returns the original command/args unchanged when
376
- * no wrapping is required. Must only be called on win32.
377
- */
378
- async resolveWindowsCommand(command, args) {
379
- if (process.platform !== "win32") {
380
- throw new Error("resolveWindowsCommand should only be called on Windows platforms");
381
- }
382
- const ext = path.extname(command).toLowerCase();
383
- // Wrap .cmd files and any Windows executable path that contains spaces (e.g. extensionless
384
- // shims from tools like Volta installed at "C:\Program Files\Volta\") to ensure the path is
385
- // quoted correctly when passed to `spawn(..., { shell: true })`.
386
- const needsWrap = ext === ".cmd" || command.includes(" ");
387
- if (!needsWrap) {
388
- return { command, args };
389
- }
390
- const execName = path.basename(command, ext);
391
- const tempBatFile = await this.tempDirManager.getTempFile({
392
- prefix: execName + "-" + (0, crypto_1.randomBytes)(8).toString("hex"),
393
- suffix: ".bat",
394
- });
395
- const escapedCommand = command.replace(/"/g, `""`);
396
- const batScript = `@echo off\r\n"${escapedCommand}" %*\r\n`; // <-- CRLF required for .bat
397
- await fs.writeFile(tempBatFile, batScript, { encoding: "utf8", mode: 0o600 });
398
- return { command: "cmd.exe", args: ["/c", `"${tempBatFile}"`, ...args] };
399
- }
400
406
  }
401
407
  exports.NodeModulesCollector = NodeModulesCollector;
408
+ /**
409
+ * Build the argv for invoking a Windows command through `powershell.exe -EncodedCommand`.
410
+ *
411
+ * Each token is wrapped in a PowerShell single-quoted string (with embedded single quotes doubled),
412
+ * so no character is interpreted by a shell. The script:
413
+ * - pins `[Console]::OutputEncoding` to UTF-8 *without* a BOM so the JSON dependency tree is not
414
+ * corrupted by the console's OEM code page (and no BOM is prepended to break `JSON.parse`),
415
+ * - invokes the command via the call operator `&`,
416
+ * - re-emits the command's own exit code via `exit $LASTEXITCODE` (e.g. `npm list` returns 1 in
417
+ * expected scenarios, which the caller's shouldIgnore logic relies on).
418
+ *
419
+ * The whole script is base64-encoded as UTF-16LE per PowerShell's `-EncodedCommand` contract.
420
+ */
421
+ function buildPowerShellEncodedArgs(command, args) {
422
+ const psQuote = (value) => `'${value.replace(/'/g, "''")}'`;
423
+ const invocation = ["&", psQuote(command), ...args.map(psQuote)].join(" ");
424
+ const script = `[Console]::OutputEncoding=[System.Text.UTF8Encoding]::new($false); ${invocation}; exit $LASTEXITCODE`;
425
+ const encoded = Buffer.from(script, "utf16le").toString("base64");
426
+ return ["-NoProfile", "-NonInteractive", "-EncodedCommand", encoded];
427
+ }
402
428
  //# sourceMappingURL=nodeModulesCollector.js.map