app-builder-lib 27.0.0-alpha.3 → 27.0.0-alpha.4

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 (116) hide show
  1. package/dist/codeSign/win/signtoolBaseSignManager.d.ts.map +1 -1
  2. package/dist/codeSign/win/signtoolBaseSignManager.js +9 -2
  3. package/dist/codeSign/win/signtoolBaseSignManager.js.map +1 -1
  4. package/dist/configuration.d.ts +3 -3
  5. package/dist/configuration.js.map +1 -1
  6. package/dist/indexInternal.d.ts +1 -1
  7. package/dist/indexInternal.d.ts.map +1 -1
  8. package/dist/indexInternal.js +1 -1
  9. package/dist/indexInternal.js.map +1 -1
  10. package/dist/macPackager.d.ts +5 -0
  11. package/dist/macPackager.d.ts.map +1 -1
  12. package/dist/macPackager.js +35 -0
  13. package/dist/macPackager.js.map +1 -1
  14. package/dist/node-module-collector/moduleManager.d.ts +2 -1
  15. package/dist/node-module-collector/moduleManager.d.ts.map +1 -1
  16. package/dist/node-module-collector/moduleManager.js +2 -0
  17. package/dist/node-module-collector/moduleManager.js.map +1 -1
  18. package/dist/node-module-collector/nodeModulesCollector.d.ts +13 -23
  19. package/dist/node-module-collector/nodeModulesCollector.d.ts.map +1 -1
  20. package/dist/node-module-collector/nodeModulesCollector.js +52 -122
  21. package/dist/node-module-collector/nodeModulesCollector.js.map +1 -1
  22. package/dist/node-module-collector/types.d.ts +2 -0
  23. package/dist/node-module-collector/types.d.ts.map +1 -1
  24. package/dist/node-module-collector/types.js.map +1 -1
  25. package/dist/options/linuxOptions.d.ts +0 -10
  26. package/dist/options/linuxOptions.d.ts.map +1 -1
  27. package/dist/options/linuxOptions.js.map +1 -1
  28. package/dist/packager.js +1 -1
  29. package/dist/packager.js.map +1 -1
  30. package/dist/platformPackager.d.ts +1 -0
  31. package/dist/platformPackager.d.ts.map +1 -1
  32. package/dist/platformPackager.js +5 -6
  33. package/dist/platformPackager.js.map +1 -1
  34. package/dist/targets/linux/FlatpakTarget.d.ts.map +1 -1
  35. package/dist/targets/linux/FlatpakTarget.js +4 -1
  36. package/dist/targets/linux/FlatpakTarget.js.map +1 -1
  37. package/dist/targets/linux/FpmTarget.d.ts +6 -0
  38. package/dist/targets/linux/FpmTarget.d.ts.map +1 -1
  39. package/dist/targets/linux/FpmTarget.js +25 -3
  40. package/dist/targets/linux/FpmTarget.js.map +1 -1
  41. package/dist/targets/linux/LinuxTargetHelper.d.ts +14 -0
  42. package/dist/targets/linux/LinuxTargetHelper.d.ts.map +1 -1
  43. package/dist/targets/linux/LinuxTargetHelper.js +38 -59
  44. package/dist/targets/linux/LinuxTargetHelper.js.map +1 -1
  45. package/dist/targets/linux/appimage/AppImageTarget.d.ts +1 -0
  46. package/dist/targets/linux/appimage/AppImageTarget.d.ts.map +1 -1
  47. package/dist/targets/linux/appimage/AppImageTarget.js +8 -9
  48. package/dist/targets/linux/appimage/AppImageTarget.js.map +1 -1
  49. package/dist/targets/linux/appimage/appImageUtil.d.ts +4 -0
  50. package/dist/targets/linux/appimage/appImageUtil.d.ts.map +1 -1
  51. package/dist/targets/linux/appimage/appImageUtil.js +11 -4
  52. package/dist/targets/linux/appimage/appImageUtil.js.map +1 -1
  53. package/dist/targets/linux/appimage/appLauncher.d.ts.map +1 -1
  54. package/dist/targets/linux/appimage/appLauncher.js +5 -11
  55. package/dist/targets/linux/appimage/appLauncher.js.map +1 -1
  56. package/dist/targets/linux/launcherScript.d.ts +32 -0
  57. package/dist/targets/linux/launcherScript.d.ts.map +1 -0
  58. package/dist/targets/linux/launcherScript.js +24 -0
  59. package/dist/targets/linux/launcherScript.js.map +1 -0
  60. package/dist/targets/linux/snap/coreLegacy.d.ts.map +1 -1
  61. package/dist/targets/linux/snap/coreLegacy.js +6 -6
  62. package/dist/targets/linux/snap/coreLegacy.js.map +1 -1
  63. package/dist/targets/linux/snap/snapCommand.d.ts +2 -2
  64. package/dist/targets/linux/snap/snapCommand.d.ts.map +1 -1
  65. package/dist/targets/linux/snap/snapCommand.js +4 -10
  66. package/dist/targets/linux/snap/snapCommand.js.map +1 -1
  67. package/dist/targets/win/AppxTarget.d.ts.map +1 -1
  68. package/dist/targets/win/AppxTarget.js +6 -6
  69. package/dist/targets/win/AppxTarget.js.map +1 -1
  70. package/dist/targets/win/MsiTarget.d.ts.map +1 -1
  71. package/dist/targets/win/MsiTarget.js +8 -11
  72. package/dist/targets/win/MsiTarget.js.map +1 -1
  73. package/dist/targets/win/nsis/NsisTarget.js +3 -3
  74. package/dist/targets/win/nsis/NsisTarget.js.map +1 -1
  75. package/dist/targets/win/nsis/nsisScriptGenerator.js +1 -1
  76. package/dist/targets/win/nsis/nsisScriptGenerator.js.map +1 -1
  77. package/dist/toolsets/icons.d.ts.map +1 -1
  78. package/dist/toolsets/icons.js +10 -2
  79. package/dist/toolsets/icons.js.map +1 -1
  80. package/dist/util/appFileCopier.d.ts.map +1 -1
  81. package/dist/util/appFileCopier.js +9 -4
  82. package/dist/util/appFileCopier.js.map +1 -1
  83. package/dist/util/archCompatibility.d.ts +42 -0
  84. package/dist/util/archCompatibility.d.ts.map +1 -0
  85. package/dist/util/archCompatibility.js +202 -0
  86. package/dist/util/archCompatibility.js.map +1 -0
  87. package/dist/util/installOrRebuild.d.ts +38 -0
  88. package/dist/util/installOrRebuild.d.ts.map +1 -0
  89. package/dist/util/{yarn.js → installOrRebuild.js} +65 -14
  90. package/dist/util/installOrRebuild.js.map +1 -0
  91. package/dist/util/langs.d.ts.map +1 -1
  92. package/dist/util/langs.js +1 -0
  93. package/dist/util/langs.js.map +1 -1
  94. package/dist/util/mac/macosIconComposer.d.ts +2 -1
  95. package/dist/util/mac/macosIconComposer.d.ts.map +1 -1
  96. package/dist/util/mac/macosIconComposer.js +40 -58
  97. package/dist/util/mac/macosIconComposer.js.map +1 -1
  98. package/dist/util/streamSpawnToFile.d.ts +47 -0
  99. package/dist/util/streamSpawnToFile.d.ts.map +1 -0
  100. package/dist/util/streamSpawnToFile.js +110 -0
  101. package/dist/util/streamSpawnToFile.js.map +1 -0
  102. package/dist/util/toolsetLock.d.ts +2 -0
  103. package/dist/util/toolsetLock.d.ts.map +1 -1
  104. package/dist/util/toolsetLock.js +31 -5
  105. package/dist/util/toolsetLock.js.map +1 -1
  106. package/dist/version.d.ts +1 -1
  107. package/dist/version.js +1 -1
  108. package/dist/version.js.map +1 -1
  109. package/package.json +8 -8
  110. package/scheme.json +3 -8
  111. package/templates/appx/appxmanifest.xml +1 -2
  112. package/templates/nsis/assistedMessages.yml +17 -0
  113. package/templates/nsis/messages.yml +5 -0
  114. package/dist/util/yarn.d.ts +0 -23
  115. package/dist/util/yarn.d.ts.map +0 -1
  116. package/dist/util/yarn.js.map +0 -1
@@ -1,7 +1,6 @@
1
1
  // Adapted from https://github.com/electron/packager/pull/1806
2
2
  import { spawn } from "builder-util";
3
3
  import * as fs from "fs/promises";
4
- import * as os from "node:os";
5
4
  import * as path from "node:path";
6
5
  import plist from "plist";
7
6
  import * as semver from "semver";
@@ -38,62 +37,45 @@ async function checkActoolVersion(tmpDir) {
38
37
  * @param inputPath The path to the `.icon` file
39
38
  * @returns The asset catalog and extra assets
40
39
  */
41
- export async function generateAssetCatalogForIcon(inputPath) {
42
- const tmpDir = await fs.mkdtemp(path.resolve(os.tmpdir(), "icon-compile-"));
43
- const cleanup = async () => {
44
- await fs.rm(tmpDir, {
45
- recursive: true,
46
- force: true,
47
- });
48
- };
49
- try {
50
- await checkActoolVersion(tmpDir);
51
- }
52
- catch (error) {
53
- await cleanup();
54
- throw error;
55
- }
56
- const iconPath = path.resolve(tmpDir, "Icon.icon");
57
- const outputPath = path.resolve(tmpDir, "out");
58
- try {
59
- await fs.cp(inputPath, iconPath, {
60
- recursive: true,
61
- });
62
- await fs.mkdir(outputPath, {
63
- recursive: true,
64
- });
65
- await spawn("actool", [
66
- iconPath,
67
- "--compile",
68
- outputPath,
69
- "--output-format",
70
- "human-readable-text",
71
- "--notices",
72
- "--warnings",
73
- "--output-partial-info-plist",
74
- path.resolve(outputPath, "assetcatalog_generated_info.plist"),
75
- "--app-icon",
76
- "Icon",
77
- "--include-all-app-icons",
78
- "--accent-color",
79
- "AccentColor",
80
- "--enable-on-demand-resources",
81
- "NO",
82
- "--development-region",
83
- "en",
84
- "--target-device",
85
- "mac",
86
- "--minimum-deployment-target",
87
- "26.0",
88
- "--platform",
89
- "macosx",
90
- ]);
91
- const assetCatalog = await fs.readFile(path.resolve(outputPath, "Assets.car"));
92
- const icnsFile = await fs.readFile(path.resolve(outputPath, "Icon.icns"));
93
- return { assetCatalog, icnsFile };
94
- }
95
- finally {
96
- await cleanup();
97
- }
40
+ export async function generateAssetCatalogForIcon(tmpDir, inputPath) {
41
+ const tmpDirPath = await tmpDir.createTempDir({ prefix: "macos-icon-composer" });
42
+ await checkActoolVersion(tmpDirPath);
43
+ const iconPath = path.resolve(tmpDirPath, "Icon.icon");
44
+ const outputPath = path.resolve(tmpDirPath, "out");
45
+ await fs.cp(inputPath, iconPath, {
46
+ recursive: true,
47
+ });
48
+ await fs.mkdir(outputPath, {
49
+ recursive: true,
50
+ });
51
+ await spawn("actool", [
52
+ iconPath,
53
+ "--compile",
54
+ outputPath,
55
+ "--output-format",
56
+ "human-readable-text",
57
+ "--notices",
58
+ "--warnings",
59
+ "--output-partial-info-plist",
60
+ path.resolve(outputPath, "assetcatalog_generated_info.plist"),
61
+ "--app-icon",
62
+ "Icon",
63
+ "--include-all-app-icons",
64
+ "--accent-color",
65
+ "AccentColor",
66
+ "--enable-on-demand-resources",
67
+ "NO",
68
+ "--development-region",
69
+ "en",
70
+ "--target-device",
71
+ "mac",
72
+ "--minimum-deployment-target",
73
+ "26.0",
74
+ "--platform",
75
+ "macosx",
76
+ ]);
77
+ const assetCatalog = await fs.readFile(path.resolve(outputPath, "Assets.car"));
78
+ const icnsFile = await fs.readFile(path.resolve(outputPath, "Icon.icns"));
79
+ return { assetCatalog, icnsFile };
98
80
  }
99
81
  //# sourceMappingURL=macosIconComposer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"macosIconComposer.js","sourceRoot":"","sources":["../../../src/util/mac/macosIconComposer.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAE9D,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAA;AACpC,OAAO,KAAK,EAAE,MAAM,aAAa,CAAA;AACjC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAA;AAC7B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAA;AACjC,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAA;AAOhC,MAAM,4BAA4B,GAAG,IAAI,KAAK,CAC5C,qIAAqI,CACtI,CAAA;AAED,KAAK,UAAU,kBAAkB,CAAC,MAAc;IAC9C,MAAM,oBAAoB,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,YAAY,CAAC,CAAA;IAE/D,IAAI,WAAW,GAAuD,SAAS,CAAA;IAE/E,IAAI,gBAAgB,GAAyB,IAAI,CAAA;IACjD,IAAI,WAAW,GAAiB,IAAI,CAAA;IACpC,IAAI,CAAC;QACH,gBAAgB,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,oBAAoB,EAAE,GAAG,CAAC,CAAA;QAC3D,MAAM,KAAK,CAAC,QAAQ,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,gBAAgB,CAAC,EAAE,EAAE,gBAAgB,CAAC,EAAE,CAAC,EAAE,CAAC,CAAA;QACrG,MAAM,mBAAmB,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC,CAAA;QAC3E,WAAW,GAAG,KAAK,CAAC,KAAK,CAAC,mBAAmB,CAA2C,CAAA;IAC1F,CAAC;IAAC,OAAO,CAAM,EAAE,CAAC;QAChB,WAAW,GAAG,CAAC,CAAA;IACjB,CAAC;YAAS,CAAC;QACT,IAAI,gBAAgB,EAAE,CAAC;YACrB,MAAM,gBAAgB,CAAC,KAAK,EAAE,CAAA;QAChC,CAAC;IACH,CAAC;IAED,IAAI,WAAW,IAAI,CAAC,WAAW,IAAI,CAAC,WAAW,CAAC,0BAA0B,CAAC,IAAI,CAAC,WAAW,CAAC,0BAA0B,CAAC,CAAC,sBAAsB,CAAC,EAAE,CAAC;QAChJ,MAAM,4BAA4B,CAAA;IACpC,CAAC;IAED,MAAM,aAAa,GAAG,WAAW,CAAC,0BAA0B,CAAC,CAAC,sBAAsB,CAAC,CAAA;IACrF,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,aAAa,CAAE,EAAE,QAAQ,CAAC,EAAE,CAAC;QACzD,MAAM,IAAI,KAAK,CAAC,4EAA4E,aAAa,oEAAoE,CAAC,CAAA;IAChL,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAAC,SAAiB;IACjE,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,eAAe,CAAC,CAAC,CAAA;IAC3E,MAAM,OAAO,GAAG,KAAK,IAAI,EAAE;QACzB,MAAM,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE;YAClB,SAAS,EAAE,IAAI;YACf,KAAK,EAAE,IAAI;SACZ,CAAC,CAAA;IACJ,CAAC,CAAA;IAED,IAAI,CAAC;QACH,MAAM,kBAAkB,CAAC,MAAM,CAAC,CAAA;IAClC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,EAAE,CAAA;QACf,MAAM,KAAK,CAAA;IACb,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;IAClD,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;IAE9C,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,EAAE;YAC/B,SAAS,EAAE,IAAI;SAChB,CAAC,CAAA;QAEF,MAAM,EAAE,CAAC,KAAK,CAAC,UAAU,EAAE;YACzB,SAAS,EAAE,IAAI;SAChB,CAAC,CAAA;QAEF,MAAM,KAAK,CAAC,QAAQ,EAAE;YACpB,QAAQ;YACR,WAAW;YACX,UAAU;YACV,iBAAiB;YACjB,qBAAqB;YACrB,WAAW;YACX,YAAY;YACZ,6BAA6B;YAC7B,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,mCAAmC,CAAC;YAC7D,YAAY;YACZ,MAAM;YACN,yBAAyB;YACzB,gBAAgB;YAChB,aAAa;YACb,8BAA8B;YAC9B,IAAI;YACJ,sBAAsB;YACtB,IAAI;YACJ,iBAAiB;YACjB,KAAK;YACL,6BAA6B;YAC7B,MAAM;YACN,YAAY;YACZ,QAAQ;SACT,CAAC,CAAA;QAEF,MAAM,YAAY,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC,CAAA;QAC9E,MAAM,QAAQ,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC,CAAA;QAEzE,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAA;IACnC,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,EAAE,CAAA;IACjB,CAAC;AACH,CAAC","sourcesContent":["// Adapted from https://github.com/electron/packager/pull/1806\n\nimport { spawn } from \"builder-util\"\nimport * as fs from \"fs/promises\"\nimport * as os from \"node:os\"\nimport * as path from \"node:path\"\nimport plist from \"plist\"\nimport * as semver from \"semver\"\n\nexport interface AssetCatalogResult {\n assetCatalog: Buffer\n icnsFile: Buffer\n}\n\nconst INVALID_ACTOOL_VERSION_ERROR = new Error(\n \"Failed to check actool version. Is Xcode 26 or higher installed? See output of the `actool --version` CLI command for more details.\"\n)\n\nasync function checkActoolVersion(tmpDir: string) {\n const acToolOutputFileName = path.resolve(tmpDir, \"actool.log\")\n\n let versionInfo: Record<string, Record<string, string>> | undefined = undefined\n\n let acToolOutputFile: fs.FileHandle | null = null\n let errorQueued: Error | null = null\n try {\n acToolOutputFile = await fs.open(acToolOutputFileName, \"w\")\n await spawn(\"actool\", [\"--version\"], { stdio: [\"ignore\", acToolOutputFile.fd, acToolOutputFile.fd] })\n const acToolVersionOutput = await fs.readFile(acToolOutputFileName, \"utf8\")\n versionInfo = plist.parse(acToolVersionOutput) as Record<string, Record<string, string>>\n } catch (e: any) {\n errorQueued = e\n } finally {\n if (acToolOutputFile) {\n await acToolOutputFile.close()\n }\n }\n\n if (errorQueued || !versionInfo || !versionInfo[\"com.apple.actool.version\"] || !versionInfo[\"com.apple.actool.version\"][\"short-bundle-version\"]) {\n throw INVALID_ACTOOL_VERSION_ERROR\n }\n\n const acToolVersion = versionInfo[\"com.apple.actool.version\"][\"short-bundle-version\"]\n if (!semver.gte(semver.coerce(acToolVersion)!, \"26.0.0\")) {\n throw new Error(`Unsupported actool version. Must be on actool 26.0.0 or higher but found ${acToolVersion}. Install Xcode 26 or higher to get a supported version of actool.`)\n }\n}\n\n/**\n * Generates an asset catalog and extra assets that are useful for packaging the app.\n * @param inputPath The path to the `.icon` file\n * @returns The asset catalog and extra assets\n */\nexport async function generateAssetCatalogForIcon(inputPath: string): Promise<AssetCatalogResult> {\n const tmpDir = await fs.mkdtemp(path.resolve(os.tmpdir(), \"icon-compile-\"))\n const cleanup = async () => {\n await fs.rm(tmpDir, {\n recursive: true,\n force: true,\n })\n }\n\n try {\n await checkActoolVersion(tmpDir)\n } catch (error) {\n await cleanup()\n throw error\n }\n\n const iconPath = path.resolve(tmpDir, \"Icon.icon\")\n const outputPath = path.resolve(tmpDir, \"out\")\n\n try {\n await fs.cp(inputPath, iconPath, {\n recursive: true,\n })\n\n await fs.mkdir(outputPath, {\n recursive: true,\n })\n\n await spawn(\"actool\", [\n iconPath,\n \"--compile\",\n outputPath,\n \"--output-format\",\n \"human-readable-text\",\n \"--notices\",\n \"--warnings\",\n \"--output-partial-info-plist\",\n path.resolve(outputPath, \"assetcatalog_generated_info.plist\"),\n \"--app-icon\",\n \"Icon\",\n \"--include-all-app-icons\",\n \"--accent-color\",\n \"AccentColor\",\n \"--enable-on-demand-resources\",\n \"NO\",\n \"--development-region\",\n \"en\",\n \"--target-device\",\n \"mac\",\n \"--minimum-deployment-target\",\n \"26.0\",\n \"--platform\",\n \"macosx\",\n ])\n\n const assetCatalog = await fs.readFile(path.resolve(outputPath, \"Assets.car\"))\n const icnsFile = await fs.readFile(path.resolve(outputPath, \"Icon.icns\"))\n\n return { assetCatalog, icnsFile }\n } finally {\n await cleanup()\n }\n}\n"]}
1
+ {"version":3,"file":"macosIconComposer.js","sourceRoot":"","sources":["../../../src/util/mac/macosIconComposer.ts"],"names":[],"mappings":"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","sourcesContent":["// Adapted from https://github.com/electron/packager/pull/1806\n\nimport { spawn, TmpDir } from \"builder-util\"\nimport * as fs from \"fs/promises\"\nimport * as path from \"node:path\"\nimport plist from \"plist\"\nimport * as semver from \"semver\"\n\nexport interface AssetCatalogResult {\n assetCatalog: Buffer\n icnsFile: Buffer\n}\n\nconst INVALID_ACTOOL_VERSION_ERROR = new Error(\n \"Failed to check actool version. Is Xcode 26 or higher installed? See output of the `actool --version` CLI command for more details.\"\n)\n\nasync function checkActoolVersion(tmpDir: string) {\n const acToolOutputFileName = path.resolve(tmpDir, \"actool.log\")\n\n let versionInfo: Record<string, Record<string, string>> | undefined = undefined\n\n let acToolOutputFile: fs.FileHandle | null = null\n let errorQueued: Error | null = null\n try {\n acToolOutputFile = await fs.open(acToolOutputFileName, \"w\")\n await spawn(\"actool\", [\"--version\"], { stdio: [\"ignore\", acToolOutputFile.fd, acToolOutputFile.fd] })\n const acToolVersionOutput = await fs.readFile(acToolOutputFileName, \"utf8\")\n versionInfo = plist.parse(acToolVersionOutput) as Record<string, Record<string, string>>\n } catch (e: any) {\n errorQueued = e\n } finally {\n if (acToolOutputFile) {\n await acToolOutputFile.close()\n }\n }\n\n if (errorQueued || !versionInfo || !versionInfo[\"com.apple.actool.version\"] || !versionInfo[\"com.apple.actool.version\"][\"short-bundle-version\"]) {\n throw INVALID_ACTOOL_VERSION_ERROR\n }\n\n const acToolVersion = versionInfo[\"com.apple.actool.version\"][\"short-bundle-version\"]\n if (!semver.gte(semver.coerce(acToolVersion)!, \"26.0.0\")) {\n throw new Error(`Unsupported actool version. Must be on actool 26.0.0 or higher but found ${acToolVersion}. Install Xcode 26 or higher to get a supported version of actool.`)\n }\n}\n\n/**\n * Generates an asset catalog and extra assets that are useful for packaging the app.\n * @param inputPath The path to the `.icon` file\n * @returns The asset catalog and extra assets\n */\nexport async function generateAssetCatalogForIcon(tmpDir: TmpDir, inputPath: string): Promise<AssetCatalogResult> {\n const tmpDirPath = await tmpDir.createTempDir({ prefix: \"macos-icon-composer\" })\n\n await checkActoolVersion(tmpDirPath)\n\n const iconPath = path.resolve(tmpDirPath, \"Icon.icon\")\n const outputPath = path.resolve(tmpDirPath, \"out\")\n\n await fs.cp(inputPath, iconPath, {\n recursive: true,\n })\n\n await fs.mkdir(outputPath, {\n recursive: true,\n })\n\n await spawn(\"actool\", [\n iconPath,\n \"--compile\",\n outputPath,\n \"--output-format\",\n \"human-readable-text\",\n \"--notices\",\n \"--warnings\",\n \"--output-partial-info-plist\",\n path.resolve(outputPath, \"assetcatalog_generated_info.plist\"),\n \"--app-icon\",\n \"Icon\",\n \"--include-all-app-icons\",\n \"--accent-color\",\n \"AccentColor\",\n \"--enable-on-demand-resources\",\n \"NO\",\n \"--development-region\",\n \"en\",\n \"--target-device\",\n \"mac\",\n \"--minimum-deployment-target\",\n \"26.0\",\n \"--platform\",\n \"macosx\",\n ])\n\n const assetCatalog = await fs.readFile(path.resolve(outputPath, \"Assets.car\"))\n const icnsFile = await fs.readFile(path.resolve(outputPath, \"Icon.icns\"))\n\n return { assetCatalog, icnsFile }\n}\n"]}
@@ -0,0 +1,47 @@
1
+ export interface StreamSpawnResult {
2
+ /** The child's exit code (null if it was killed by a signal). */
3
+ code: number | null;
4
+ /** Everything the child wrote to stderr, accumulated. */
5
+ stderr: string;
6
+ }
7
+ /**
8
+ * Spawns a command and streams its stdout to a file, returning the exit code and captured stderr.
9
+ *
10
+ * stdout is piped straight to `outputFile` (never buffered in memory), so arbitrarily large output —
11
+ * a full dependency tree, a verbose `install` log — costs no heap. stderr is small by comparison and
12
+ * is accumulated so the caller can surface it on failure.
13
+ *
14
+ * On Windows the package-manager command is typically a `.cmd` shim (npm.cmd/pnpm.cmd/yarn.cmd),
15
+ * which Node can no longer spawn directly (CVE-2024-27980). Rather than spawn with `shell: true` —
16
+ * which emits the DEP0190 "args with shell" deprecation warning and forces manual metacharacter
17
+ * escaping — wrap the invocation in a single PowerShell `-EncodedCommand`. The base64 (UTF-16LE)
18
+ * payload sidesteps every shell-quoting layer, and `powershell.exe` is a real executable we spawn
19
+ * directly with no shell. See buildPowerShellEncodedArgs for the UTF-8 / exit-code handling. This
20
+ * also avoids the cmd.exe "The batch file cannot be found." re-open race that plagues `.cmd` shims.
21
+ *
22
+ * Resolves with `{ code, stderr }` for ANY exit code — interpreting a non-zero code is the caller's
23
+ * job (e.g. `npm list` returns 1 in expected scenarios). Only genuine infrastructure failures —
24
+ * spawn errors and write-stream errors — reject.
25
+ *
26
+ * @param command - The command to execute
27
+ * @param args - Array of command-line arguments
28
+ * @param cwd - The working directory to execute the command in
29
+ * @param outputFile - The path to the file where stdout will be streamed
30
+ * @param env - The environment for the child process (callers are responsible for stripping secrets)
31
+ */
32
+ export declare function streamSpawnToFile(command: string, args: string[], cwd: string, outputFile: string, env: NodeJS.ProcessEnv): Promise<StreamSpawnResult>;
33
+ /**
34
+ * Build the argv for invoking a Windows command through `powershell.exe -EncodedCommand`.
35
+ *
36
+ * Each token is wrapped in a PowerShell single-quoted string (with embedded single quotes doubled),
37
+ * so no character is interpreted by a shell. The script:
38
+ * - pins `[Console]::OutputEncoding` to UTF-8 *without* a BOM so the JSON dependency tree is not
39
+ * corrupted by the console's OEM code page (and no BOM is prepended to break `JSON.parse`),
40
+ * - invokes the command via the call operator `&`,
41
+ * - re-emits the command's own exit code via `exit $LASTEXITCODE` (e.g. `npm list` returns 1 in
42
+ * expected scenarios, which the caller's shouldIgnore logic relies on).
43
+ *
44
+ * The whole script is base64-encoded as UTF-16LE per PowerShell's `-EncodedCommand` contract.
45
+ */
46
+ export declare function buildPowerShellEncodedArgs(command: string, args: string[]): string[];
47
+ //# sourceMappingURL=streamSpawnToFile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streamSpawnToFile.d.ts","sourceRoot":"","sources":["../../src/util/streamSpawnToFile.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,iBAAiB;IAChC,iEAAiE;IACjE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,yDAAyD;IACzD,MAAM,EAAE,MAAM,CAAA;CACf;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAkEtJ;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAMpF"}
@@ -0,0 +1,110 @@
1
+ import * as childProcess from "child_process";
2
+ import { createWriteStream } from "node:fs";
3
+ /**
4
+ * Spawns a command and streams its stdout to a file, returning the exit code and captured stderr.
5
+ *
6
+ * stdout is piped straight to `outputFile` (never buffered in memory), so arbitrarily large output —
7
+ * a full dependency tree, a verbose `install` log — costs no heap. stderr is small by comparison and
8
+ * is accumulated so the caller can surface it on failure.
9
+ *
10
+ * On Windows the package-manager command is typically a `.cmd` shim (npm.cmd/pnpm.cmd/yarn.cmd),
11
+ * which Node can no longer spawn directly (CVE-2024-27980). Rather than spawn with `shell: true` —
12
+ * which emits the DEP0190 "args with shell" deprecation warning and forces manual metacharacter
13
+ * escaping — wrap the invocation in a single PowerShell `-EncodedCommand`. The base64 (UTF-16LE)
14
+ * payload sidesteps every shell-quoting layer, and `powershell.exe` is a real executable we spawn
15
+ * directly with no shell. See buildPowerShellEncodedArgs for the UTF-8 / exit-code handling. This
16
+ * also avoids the cmd.exe "The batch file cannot be found." re-open race that plagues `.cmd` shims.
17
+ *
18
+ * Resolves with `{ code, stderr }` for ANY exit code — interpreting a non-zero code is the caller's
19
+ * job (e.g. `npm list` returns 1 in expected scenarios). Only genuine infrastructure failures —
20
+ * spawn errors and write-stream errors — reject.
21
+ *
22
+ * @param command - The command to execute
23
+ * @param args - Array of command-line arguments
24
+ * @param cwd - The working directory to execute the command in
25
+ * @param outputFile - The path to the file where stdout will be streamed
26
+ * @param env - The environment for the child process (callers are responsible for stripping secrets)
27
+ */
28
+ export function streamSpawnToFile(command, args, cwd, outputFile, env) {
29
+ const [spawnCommand, spawnArgs] = process.platform === "win32" ? ["powershell.exe", buildPowerShellEncodedArgs(command, args)] : [command, args];
30
+ return new Promise((resolve, reject) => {
31
+ const outStream = createWriteStream(outputFile);
32
+ const child = childProcess.spawn(spawnCommand, spawnArgs, { cwd, env });
33
+ let stderr = "";
34
+ // The process can close before all piped stdout has been flushed to disk. Resolving on the
35
+ // child's "close" alone races the write stream and lets the caller read a TRUNCATED file
36
+ // (manifesting as "No JSON content found in output"). Gate the settle on BOTH the child exit
37
+ // (for the code/stderr) and the write stream's "finish" (all bytes flushed).
38
+ let exitCode = null;
39
+ let childClosed = false;
40
+ let streamFinished = false;
41
+ let settled = false;
42
+ // `pipe` ends `outStream` when stdout EOFs, which triggers its "finish" once flushed.
43
+ child.stdout.pipe(outStream);
44
+ child.stderr.on("data", chunk => {
45
+ stderr += chunk.toString();
46
+ });
47
+ const fail = (err) => {
48
+ if (settled) {
49
+ return;
50
+ }
51
+ settled = true;
52
+ // Best-effort cleanup: stop the child and close the stream so we don't
53
+ // waste CPU writing to a broken fd after rejection.
54
+ try {
55
+ child.kill();
56
+ }
57
+ catch {
58
+ // ignore
59
+ }
60
+ try {
61
+ outStream.destroy();
62
+ }
63
+ catch {
64
+ // ignore
65
+ }
66
+ reject(err);
67
+ };
68
+ const settle = () => {
69
+ if (settled || !childClosed || !streamFinished) {
70
+ return;
71
+ }
72
+ settled = true;
73
+ resolve({ code: exitCode, stderr });
74
+ };
75
+ outStream.on("error", err => fail(new Error(`Failed writing process output (${command}): ${err.message}`)));
76
+ outStream.on("finish", () => {
77
+ streamFinished = true;
78
+ settle();
79
+ });
80
+ child.on("error", err => {
81
+ fail(new Error(`Process spawn (${command} ${JSON.stringify(args)}) failed: ${err.message}`));
82
+ });
83
+ child.on("close", code => {
84
+ exitCode = code;
85
+ childClosed = true;
86
+ settle();
87
+ });
88
+ });
89
+ }
90
+ /**
91
+ * Build the argv for invoking a Windows command through `powershell.exe -EncodedCommand`.
92
+ *
93
+ * Each token is wrapped in a PowerShell single-quoted string (with embedded single quotes doubled),
94
+ * so no character is interpreted by a shell. The script:
95
+ * - pins `[Console]::OutputEncoding` to UTF-8 *without* a BOM so the JSON dependency tree is not
96
+ * corrupted by the console's OEM code page (and no BOM is prepended to break `JSON.parse`),
97
+ * - invokes the command via the call operator `&`,
98
+ * - re-emits the command's own exit code via `exit $LASTEXITCODE` (e.g. `npm list` returns 1 in
99
+ * expected scenarios, which the caller's shouldIgnore logic relies on).
100
+ *
101
+ * The whole script is base64-encoded as UTF-16LE per PowerShell's `-EncodedCommand` contract.
102
+ */
103
+ export function buildPowerShellEncodedArgs(command, args) {
104
+ const psQuote = (value) => `'${value.replace(/'/g, "''")}'`;
105
+ const invocation = ["&", psQuote(command), ...args.map(psQuote)].join(" ");
106
+ const script = `[Console]::OutputEncoding=[System.Text.UTF8Encoding]::new($false); ${invocation}; exit $LASTEXITCODE`;
107
+ const encoded = Buffer.from(script, "utf16le").toString("base64");
108
+ return ["-NoProfile", "-NonInteractive", "-EncodedCommand", encoded];
109
+ }
110
+ //# sourceMappingURL=streamSpawnToFile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streamSpawnToFile.js","sourceRoot":"","sources":["../../src/util/streamSpawnToFile.ts"],"names":[],"mappings":"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","sourcesContent":["import * as childProcess from \"child_process\"\nimport { createWriteStream } from \"node:fs\"\n\nexport interface StreamSpawnResult {\n /** The child's exit code (null if it was killed by a signal). */\n code: number | null\n /** Everything the child wrote to stderr, accumulated. */\n stderr: string\n}\n\n/**\n * Spawns a command and streams its stdout to a file, returning the exit code and captured stderr.\n *\n * stdout is piped straight to `outputFile` (never buffered in memory), so arbitrarily large output —\n * a full dependency tree, a verbose `install` log — costs no heap. stderr is small by comparison and\n * is accumulated so the caller can surface it on failure.\n *\n * On Windows the package-manager command is typically a `.cmd` shim (npm.cmd/pnpm.cmd/yarn.cmd),\n * which Node can no longer spawn directly (CVE-2024-27980). Rather than spawn with `shell: true` —\n * which emits the DEP0190 \"args with shell\" deprecation warning and forces manual metacharacter\n * escaping — wrap the invocation in a single PowerShell `-EncodedCommand`. The base64 (UTF-16LE)\n * payload sidesteps every shell-quoting layer, and `powershell.exe` is a real executable we spawn\n * directly with no shell. See buildPowerShellEncodedArgs for the UTF-8 / exit-code handling. This\n * also avoids the cmd.exe \"The batch file cannot be found.\" re-open race that plagues `.cmd` shims.\n *\n * Resolves with `{ code, stderr }` for ANY exit code — interpreting a non-zero code is the caller's\n * job (e.g. `npm list` returns 1 in expected scenarios). Only genuine infrastructure failures —\n * spawn errors and write-stream errors — reject.\n *\n * @param command - The command to execute\n * @param args - Array of command-line arguments\n * @param cwd - The working directory to execute the command in\n * @param outputFile - The path to the file where stdout will be streamed\n * @param env - The environment for the child process (callers are responsible for stripping secrets)\n */\nexport function streamSpawnToFile(command: string, args: string[], cwd: string, outputFile: string, env: NodeJS.ProcessEnv): Promise<StreamSpawnResult> {\n const [spawnCommand, spawnArgs] = process.platform === \"win32\" ? ([\"powershell.exe\", buildPowerShellEncodedArgs(command, args)] as const) : ([command, args] as const)\n\n return new Promise<StreamSpawnResult>((resolve, reject) => {\n const outStream = createWriteStream(outputFile)\n\n const child = childProcess.spawn(spawnCommand, spawnArgs, { cwd, env })\n\n let stderr = \"\"\n // The process can close before all piped stdout has been flushed to disk. Resolving on the\n // child's \"close\" alone races the write stream and lets the caller read a TRUNCATED file\n // (manifesting as \"No JSON content found in output\"). Gate the settle on BOTH the child exit\n // (for the code/stderr) and the write stream's \"finish\" (all bytes flushed).\n let exitCode: number | null = null\n let childClosed = false\n let streamFinished = false\n let settled = false\n\n // `pipe` ends `outStream` when stdout EOFs, which triggers its \"finish\" once flushed.\n child.stdout.pipe(outStream)\n child.stderr.on(\"data\", chunk => {\n stderr += chunk.toString()\n })\n\n const fail = (err: Error) => {\n if (settled) {\n return\n }\n settled = true\n // Best-effort cleanup: stop the child and close the stream so we don't\n // waste CPU writing to a broken fd after rejection.\n try {\n child.kill()\n } catch {\n // ignore\n }\n try {\n outStream.destroy()\n } catch {\n // ignore\n }\n reject(err)\n }\n\n const settle = () => {\n if (settled || !childClosed || !streamFinished) {\n return\n }\n settled = true\n resolve({ code: exitCode, stderr })\n }\n\n outStream.on(\"error\", err => fail(new Error(`Failed writing process output (${command}): ${err.message}`)))\n outStream.on(\"finish\", () => {\n streamFinished = true\n settle()\n })\n child.on(\"error\", err => {\n fail(new Error(`Process spawn (${command} ${JSON.stringify(args)}) failed: ${err.message}`))\n })\n child.on(\"close\", code => {\n exitCode = code\n childClosed = true\n settle()\n })\n })\n}\n\n/**\n * Build the argv for invoking a Windows command through `powershell.exe -EncodedCommand`.\n *\n * Each token is wrapped in a PowerShell single-quoted string (with embedded single quotes doubled),\n * so no character is interpreted by a shell. The script:\n * - pins `[Console]::OutputEncoding` to UTF-8 *without* a BOM so the JSON dependency tree is not\n * corrupted by the console's OEM code page (and no BOM is prepended to break `JSON.parse`),\n * - invokes the command via the call operator `&`,\n * - re-emits the command's own exit code via `exit $LASTEXITCODE` (e.g. `npm list` returns 1 in\n * expected scenarios, which the caller's shouldIgnore logic relies on).\n *\n * The whole script is base64-encoded as UTF-16LE per PowerShell's `-EncodedCommand` contract.\n */\nexport function buildPowerShellEncodedArgs(command: string, args: string[]): string[] {\n const psQuote = (value: string) => `'${value.replace(/'/g, \"''\")}'`\n const invocation = [\"&\", psQuote(command), ...args.map(psQuote)].join(\" \")\n const script = `[Console]::OutputEncoding=[System.Text.UTF8Encoding]::new($false); ${invocation}; exit $LASTEXITCODE`\n const encoded = Buffer.from(script, \"utf16le\").toString(\"base64\")\n return [\"-NoProfile\", \"-NonInteractive\", \"-EncodedCommand\", encoded]\n}\n"]}
@@ -1,2 +1,4 @@
1
1
  export declare function withToolsetLock<T>(task: () => Promise<T>): Promise<T>;
2
+ export declare function withSigntoolLock<T>(task: () => Promise<T>): Promise<T>;
3
+ export declare function withIconsLock<T>(task: () => Promise<T>): Promise<T>;
2
4
  //# sourceMappingURL=toolsetLock.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"toolsetLock.d.ts","sourceRoot":"","sources":["../../src/util/toolsetLock.ts"],"names":[],"mappings":"AAQA,wBAAsB,eAAe,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAW3E"}
1
+ {"version":3,"file":"toolsetLock.d.ts","sourceRoot":"","sources":["../../src/util/toolsetLock.ts"],"names":[],"mappings":"AAuBA,wBAAgB,eAAe,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAErE;AAUD,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAEtE;AASD,wBAAgB,aAAa,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAEnE"}
@@ -3,10 +3,12 @@ import { writeFile } from "fs/promises";
3
3
  import * as lockfile from "proper-lockfile";
4
4
  import * as os from "os";
5
5
  import * as path from "path";
6
- const LOCK_FILE = path.join(os.tmpdir(), ".electron-builder-toolset.lock");
7
- export async function withToolsetLock(task) {
8
- await writeFile(LOCK_FILE, "", { flag: "a" });
9
- const release = await lockfile.lock(LOCK_FILE, {
6
+ const TOOLSET_LOCK_FILE = path.join(os.tmpdir(), ".electron-builder-toolset.lock");
7
+ const SIGNTOOL_LOCK_FILE = path.join(os.tmpdir(), ".electron-builder-signtool.lock");
8
+ const ICONS_LOCK_FILE = path.join(os.tmpdir(), ".electron-builder-icons.lock");
9
+ async function withLock(lockFile, task) {
10
+ await writeFile(lockFile, "", { flag: "a" });
11
+ const release = await lockfile.lock(lockFile, {
10
12
  retries: { retries: 100, minTimeout: 1000, maxTimeout: 5000 },
11
13
  stale: 120_000,
12
14
  });
@@ -14,7 +16,31 @@ export async function withToolsetLock(task) {
14
16
  return await task();
15
17
  }
16
18
  finally {
17
- await release().catch((err) => log.warn({ err }, "failed to release toolset lock"));
19
+ await release().catch((err) => log.warn({ err }, "failed to release lock"));
18
20
  }
19
21
  }
22
+ export function withToolsetLock(task) {
23
+ return withLock(TOOLSET_LOCK_FILE, task);
24
+ }
25
+ // `signtool sign /f <pfx>` imports the PFX via PFXImportCertStore, which mutates the per-user
26
+ // CryptoAPI/CNG key+cert storage — a process-global resource that is not safe for concurrent access.
27
+ // winPackager already serializes signing within a single packager (signingQueue), but parallel builds
28
+ // (e.g. the test harness running multiple packagers across vitest workers that share one Windows user
29
+ // profile) race on that shared store and intermittently fail, after cert selection, with
30
+ // "SignTool Error: An error occurred while attempting to load the signing certificate". A dedicated
31
+ // cross-process lock (separate from the toolset lock so it does not block MSI/Squirrel builds)
32
+ // serializes signtool invocations. No-op overhead for real single builds, which are already serial.
33
+ export function withSigntoolLock(task) {
34
+ return withLock(SIGNTOOL_LOCK_FILE, task);
35
+ }
36
+ // The icons toolset CLI (icon-tool.js) converts via a WebAssembly-backed image pipeline, and each
37
+ // invocation reserves a large `WebAssembly.Memory`. A single build converting one icon is fine, but
38
+ // parallel builds — most acutely the test harness running many packagers across forked vitest workers
39
+ // on one machine — spawn enough concurrent icon-tool processes to exhaust memory, failing with
40
+ // "WebAssembly.Memory(): could not allocate memory". A cross-process lock (separate from the toolset
41
+ // lock so it does not serialize against MSI/Squirrel/DMG builds) caps icon conversion at one at a
42
+ // time. No-op overhead for real single builds, which are already serial.
43
+ export function withIconsLock(task) {
44
+ return withLock(ICONS_LOCK_FILE, task);
45
+ }
20
46
  //# sourceMappingURL=toolsetLock.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"toolsetLock.js","sourceRoot":"","sources":["../../src/util/toolsetLock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAA;AAClC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAA;AAC3C,OAAO,KAAK,EAAE,MAAM,IAAI,CAAA;AACxB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAA;AAE5B,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,gCAAgC,CAAC,CAAA;AAE1E,MAAM,CAAC,KAAK,UAAU,eAAe,CAAI,IAAsB;IAC7D,MAAM,SAAS,CAAC,SAAS,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAA;IAC7C,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE;QAC7C,OAAO,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE;QAC7D,KAAK,EAAE,OAAO;KACf,CAAC,CAAA;IACF,IAAI,CAAC;QACH,OAAO,MAAM,IAAI,EAAE,CAAA;IACrB,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC,GAAU,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,EAAE,gCAAgC,CAAC,CAAC,CAAA;IAC5F,CAAC;AACH,CAAC","sourcesContent":["import { log } from \"builder-util\"\nimport { writeFile } from \"fs/promises\"\nimport * as lockfile from \"proper-lockfile\"\nimport * as os from \"os\"\nimport * as path from \"path\"\n\nconst LOCK_FILE = path.join(os.tmpdir(), \".electron-builder-toolset.lock\")\n\nexport async function withToolsetLock<T>(task: () => Promise<T>): Promise<T> {\n await writeFile(LOCK_FILE, \"\", { flag: \"a\" })\n const release = await lockfile.lock(LOCK_FILE, {\n retries: { retries: 100, minTimeout: 1000, maxTimeout: 5000 },\n stale: 120_000,\n })\n try {\n return await task()\n } finally {\n await release().catch((err: Error) => log.warn({ err }, \"failed to release toolset lock\"))\n }\n}\n"]}
1
+ {"version":3,"file":"toolsetLock.js","sourceRoot":"","sources":["../../src/util/toolsetLock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAA;AAClC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAA;AAC3C,OAAO,KAAK,EAAE,MAAM,IAAI,CAAA;AACxB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAA;AAE5B,MAAM,iBAAiB,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,gCAAgC,CAAC,CAAA;AAClF,MAAM,kBAAkB,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,iCAAiC,CAAC,CAAA;AACpF,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,8BAA8B,CAAC,CAAA;AAE9E,KAAK,UAAU,QAAQ,CAAI,QAAgB,EAAE,IAAsB;IACjE,MAAM,SAAS,CAAC,QAAQ,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAA;IAC5C,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE;QAC5C,OAAO,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE;QAC7D,KAAK,EAAE,OAAO;KACf,CAAC,CAAA;IACF,IAAI,CAAC;QACH,OAAO,MAAM,IAAI,EAAE,CAAA;IACrB,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC,GAAU,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,EAAE,wBAAwB,CAAC,CAAC,CAAA;IACpF,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe,CAAI,IAAsB;IACvD,OAAO,QAAQ,CAAC,iBAAiB,EAAE,IAAI,CAAC,CAAA;AAC1C,CAAC;AAED,8FAA8F;AAC9F,qGAAqG;AACrG,sGAAsG;AACtG,sGAAsG;AACtG,yFAAyF;AACzF,oGAAoG;AACpG,+FAA+F;AAC/F,oGAAoG;AACpG,MAAM,UAAU,gBAAgB,CAAI,IAAsB;IACxD,OAAO,QAAQ,CAAC,kBAAkB,EAAE,IAAI,CAAC,CAAA;AAC3C,CAAC;AAED,kGAAkG;AAClG,oGAAoG;AACpG,sGAAsG;AACtG,+FAA+F;AAC/F,qGAAqG;AACrG,kGAAkG;AAClG,yEAAyE;AACzE,MAAM,UAAU,aAAa,CAAI,IAAsB;IACrD,OAAO,QAAQ,CAAC,eAAe,EAAE,IAAI,CAAC,CAAA;AACxC,CAAC","sourcesContent":["import { log } from \"builder-util\"\nimport { writeFile } from \"fs/promises\"\nimport * as lockfile from \"proper-lockfile\"\nimport * as os from \"os\"\nimport * as path from \"path\"\n\nconst TOOLSET_LOCK_FILE = path.join(os.tmpdir(), \".electron-builder-toolset.lock\")\nconst SIGNTOOL_LOCK_FILE = path.join(os.tmpdir(), \".electron-builder-signtool.lock\")\nconst ICONS_LOCK_FILE = path.join(os.tmpdir(), \".electron-builder-icons.lock\")\n\nasync function withLock<T>(lockFile: string, task: () => Promise<T>): Promise<T> {\n await writeFile(lockFile, \"\", { flag: \"a\" })\n const release = await lockfile.lock(lockFile, {\n retries: { retries: 100, minTimeout: 1000, maxTimeout: 5000 },\n stale: 120_000,\n })\n try {\n return await task()\n } finally {\n await release().catch((err: Error) => log.warn({ err }, \"failed to release lock\"))\n }\n}\n\nexport function withToolsetLock<T>(task: () => Promise<T>): Promise<T> {\n return withLock(TOOLSET_LOCK_FILE, task)\n}\n\n// `signtool sign /f <pfx>` imports the PFX via PFXImportCertStore, which mutates the per-user\n// CryptoAPI/CNG key+cert storage — a process-global resource that is not safe for concurrent access.\n// winPackager already serializes signing within a single packager (signingQueue), but parallel builds\n// (e.g. the test harness running multiple packagers across vitest workers that share one Windows user\n// profile) race on that shared store and intermittently fail, after cert selection, with\n// \"SignTool Error: An error occurred while attempting to load the signing certificate\". A dedicated\n// cross-process lock (separate from the toolset lock so it does not block MSI/Squirrel builds)\n// serializes signtool invocations. No-op overhead for real single builds, which are already serial.\nexport function withSigntoolLock<T>(task: () => Promise<T>): Promise<T> {\n return withLock(SIGNTOOL_LOCK_FILE, task)\n}\n\n// The icons toolset CLI (icon-tool.js) converts via a WebAssembly-backed image pipeline, and each\n// invocation reserves a large `WebAssembly.Memory`. A single build converting one icon is fine, but\n// parallel builds — most acutely the test harness running many packagers across forked vitest workers\n// on one machine — spawn enough concurrent icon-tool processes to exhaust memory, failing with\n// \"WebAssembly.Memory(): could not allocate memory\". A cross-process lock (separate from the toolset\n// lock so it does not serialize against MSI/Squirrel/DMG builds) caps icon conversion at one at a\n// time. No-op overhead for real single builds, which are already serial.\nexport function withIconsLock<T>(task: () => Promise<T>): Promise<T> {\n return withLock(ICONS_LOCK_FILE, task)\n}\n"]}
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const PACKAGE_VERSION = "27.0.0-alpha.3";
1
+ export declare const PACKAGE_VERSION = "27.0.0-alpha.4";
2
2
  //# sourceMappingURL=version.d.ts.map
package/dist/version.js CHANGED
@@ -1,2 +1,2 @@
1
- export const PACKAGE_VERSION = "27.0.0-alpha.3";
1
+ export const PACKAGE_VERSION = "27.0.0-alpha.4";
2
2
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG,gBAAgB,CAAA","sourcesContent":["export const PACKAGE_VERSION = \"27.0.0-alpha.3\"\n"]}
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG,gBAAgB,CAAA","sourcesContent":["export const PACKAGE_VERSION = \"27.0.0-alpha.4\"\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "app-builder-lib",
3
3
  "description": "electron-builder lib",
4
- "version": "27.0.0-alpha.3",
4
+ "version": "27.0.0-alpha.4",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "exports": {
@@ -98,9 +98,9 @@
98
98
  "undici": "^7.27.1",
99
99
  "unzipper": "^0.12.3",
100
100
  "which": "^5.0.0",
101
- "builder-util": "27.0.0-alpha.3",
102
- "electron-publish": "27.0.0-alpha.3",
103
- "builder-util-runtime": "10.0.0-alpha.2"
101
+ "builder-util": "27.0.0-alpha.4",
102
+ "builder-util-runtime": "10.0.0-alpha.3",
103
+ "electron-publish": "27.0.0-alpha.4"
104
104
  },
105
105
  "///": "babel in devDependencies for proton tests",
106
106
  "devDependencies": {
@@ -115,12 +115,12 @@
115
115
  "@types/unzipper": "^0.10.11",
116
116
  "@types/which": "^3.0.4",
117
117
  "toml": "^3.0.0",
118
- "dmg-builder": "27.0.0-alpha.3",
119
- "electron-builder-squirrel-windows": "27.0.0-alpha.3"
118
+ "dmg-builder": "27.0.0-alpha.4",
119
+ "electron-builder-squirrel-windows": "27.0.0-alpha.4"
120
120
  },
121
121
  "peerDependencies": {
122
- "dmg-builder": "27.0.0-alpha.3",
123
- "electron-builder-squirrel-windows": "27.0.0-alpha.3"
122
+ "dmg-builder": "27.0.0-alpha.4",
123
+ "electron-builder-squirrel-windows": "27.0.0-alpha.4"
124
124
  },
125
125
  "//": "electron-builder-squirrel-windows and dmg-builder added as dev dep for tests (as otherwise `require` doesn't work using Yarn 2)",
126
126
  "types": "./dist/index.d.ts",
package/scheme.json CHANGED
@@ -2421,11 +2421,6 @@
2421
2421
  "$ref": "#/definitions/ReleaseInfo",
2422
2422
  "description": "The release info. Intended for command line usage:\n\n```\n-c.releaseInfo.releaseNotes=\"new features\"\n```"
2423
2423
  },
2424
- "syncDesktopName": {
2425
- "default": false,
2426
- "description": "When `true`, the installed `.desktop` filename is derived from `desktopName` in `package.json`\n(minus the `.desktop` suffix) so that it matches `StartupWMClass` and Electron's `app_id`.\nFalls back to `executableName` when `desktopName` is absent.",
2427
- "type": "boolean"
2428
- },
2429
2424
  "synopsis": {
2430
2425
  "description": "The [short description](https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Description).",
2431
2426
  "type": [
@@ -7806,15 +7801,15 @@
7806
7801
  "$ref": "#/definitions/ToolsetCustom"
7807
7802
  },
7808
7803
  {
7809
- "const": "1.1.0",
7804
+ "const": "1.2.1",
7810
7805
  "type": "string"
7811
7806
  },
7812
7807
  {
7813
7808
  "type": "null"
7814
7809
  }
7815
7810
  ],
7816
- "default": "1.1.0",
7817
- "description": "Version of the icons-conversion bundle used to convert source images to `.icns`, `.ico`,\nand PNG icon sets.\n\nSet to a {@link ToolsetCustom} object to supply your own icons bundle directory.\n\nAvailable versions:\n| Version | Notes |\n|---------|-------|\n| `\"1.1.0\"` | Current default |\n\nReleases: https://github.com/electron-userland/electron-builder-binaries/blob/master/packages/icons/CHANGELOG.md"
7811
+ "default": "1.2.1",
7812
+ "description": "Version of the icons-conversion bundle used to convert source images to `.icns`, `.ico`,\nand PNG icon sets.\n\nSet to a {@link ToolsetCustom} object to supply your own icons bundle directory.\n\nAvailable versions:\n| Version | Notes |\n|---------|-------|\n| `\"1.2.1\"` | Current default |\n\nReleases: https://github.com/electron-userland/electron-builder-binaries/blob/master/packages/icons/CHANGELOG.md"
7818
7813
  },
7819
7814
  "linuxToolsMac": {
7820
7815
  "anyOf": [
@@ -5,10 +5,9 @@
5
5
  xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
6
6
  xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
7
7
  xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities">
8
- <!-- use single quotes to avoid double quotes escaping in the publisher value -->
9
8
  <Identity Name="${identityName}"
10
9
  ProcessorArchitecture="${arch}"
11
- Publisher='${publisher}'
10
+ Publisher="${publisher}"
12
11
  Version="${version}" />
13
12
  <Properties>
14
13
  <DisplayName>${displayName}</DisplayName>