electron-builder-squirrel-windows 27.0.0-alpha.8 → 27.0.0-alpha.9

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.
@@ -1,5 +1,5 @@
1
1
  import { Arch, SquirrelWindowsOptions, Target, WinPackager } from "app-builder-lib";
2
- import { Options as SquirrelOptions } from "electron-winstaller";
2
+ import { InstallerOptions } from "./windowsInstaller.js";
3
3
  export default class SquirrelWindowsTarget extends Target {
4
4
  private readonly packager;
5
5
  readonly outDir: string;
@@ -15,6 +15,6 @@ export default class SquirrelWindowsTarget extends Target {
15
15
  private get exeName();
16
16
  private select7zipArch;
17
17
  private createNuspecTemplateWithProjectUrl;
18
- computeEffectiveDistOptions(appDirectory: string, outputDirectory: string, setupFile: string): Promise<SquirrelOptions>;
18
+ computeEffectiveDistOptions(appDirectory: string, outputDirectory: string, setupFile: string): Promise<InstallerOptions>;
19
19
  }
20
20
  //# sourceMappingURL=SquirrelWindowsTarget.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SquirrelWindowsTarget.d.ts","sourceRoot":"","sources":["../src/SquirrelWindowsTarget.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,IAAI,EAAiB,sBAAsB,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAIlG,OAAO,EAAE,OAAO,IAAI,eAAe,EAA0C,MAAM,qBAAqB,CAAA;AAGxG,MAAM,CAAC,OAAO,OAAO,qBAAsB,SAAQ,MAAM;IAMrD,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM;IANzB,QAAQ,CAAC,OAAO,EAAE,sBAAsB,CAAA;IAExC,gBAAgB,UAAQ;gBAGL,QAAQ,EAAE,WAAW,EAC7B,MAAM,EAAE,MAAM;YAMX,4BAA4B;IAmC1C,OAAO,CAAC,mBAAmB;YAMb,gBAAgB;YA2ChB,yBAAyB;IAwBjC,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI;IAwEzC,OAAO,KAAK,OAAO,GAElB;IAED,OAAO,KAAK,OAAO,GAGlB;IAED,OAAO,CAAC,cAAc;YASR,kCAAkC;IAc1C,2BAA2B,CAAC,YAAY,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;CAuE9H"}
1
+ {"version":3,"file":"SquirrelWindowsTarget.d.ts","sourceRoot":"","sources":["../src/SquirrelWindowsTarget.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAiB,sBAAsB,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAQlG,OAAO,EAAE,gBAAgB,EAA0C,MAAM,uBAAuB,CAAA;AAEhG,MAAM,CAAC,OAAO,OAAO,qBAAsB,SAAQ,MAAM;IAMrD,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM;IANzB,QAAQ,CAAC,OAAO,EAAE,sBAAsB,CAAA;IAExC,gBAAgB,UAAQ;gBAGL,QAAQ,EAAE,WAAW,EAC7B,MAAM,EAAE,MAAM;YAMX,4BAA4B;IAgD1C,OAAO,CAAC,mBAAmB;YAMb,gBAAgB;YAgDhB,yBAAyB;IAwBjC,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI;IAwEzC,OAAO,KAAK,OAAO,GAElB;IAED,OAAO,KAAK,OAAO,GAGlB;IAED,OAAO,CAAC,cAAc;YAiBR,kCAAkC;IAc1C,2BAA2B,CAAC,YAAY,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;CAoE/H"}
@@ -1,14 +1,12 @@
1
- import { createRequire } from "node:module";
2
- import { InvalidConfigurationError, log, isEmptyOrSpaces, exists } from "builder-util";
3
- const _requireResolve = createRequire(import.meta.url).resolve;
4
- import { downloadBuilderToolset, withToolsetLock } from "app-builder-lib/internal";
5
- import { sanitizeFileName } from "builder-util/internal";
6
1
  import { getArchSuffix, Target } from "app-builder-lib";
7
- import * as path from "path";
2
+ import { getRceditBundle, withToolsetLock, WineVmManager } from "app-builder-lib/internal";
3
+ import { InvalidConfigurationError, isEmptyOrSpaces, log } from "builder-util";
4
+ import { sanitizeFileName } from "builder-util/internal";
8
5
  import * as fs from "fs";
9
6
  import * as os from "os";
10
- import { createWindowsInstaller, convertVersion } from "electron-winstaller";
11
- import { WineVmManager } from "app-builder-lib/internal";
7
+ import * as path from "path";
8
+ import { getSquirrelToolsetPath, getWixToolsetPath } from "./toolset.js";
9
+ import { convertVersion, createWindowsInstaller } from "./windowsInstaller.js";
12
10
  export default class SquirrelWindowsTarget extends Target {
13
11
  constructor(packager, outDir) {
14
12
  super("squirrel");
@@ -18,40 +16,50 @@ export default class SquirrelWindowsTarget extends Target {
18
16
  this.options = packager.getOptionsForTarget("squirrelWindows");
19
17
  }
20
18
  async prepareSignedVendorDirectory() {
21
- const customSquirrelVendorDirectory = this.options.customSquirrelVendorDir;
22
19
  const tmpVendorDirectory = await this.packager.tempDirManager.createTempDir({ prefix: "squirrel-windows-vendor" });
23
- if (customSquirrelVendorDirectory && (await exists(customSquirrelVendorDirectory))) {
24
- await fs.promises.cp(customSquirrelVendorDirectory, tmpVendorDirectory, { recursive: true });
25
- }
26
- else {
27
- if (!isEmptyOrSpaces(customSquirrelVendorDirectory)) {
28
- log.warn({ customSquirrelVendorDirectory }, "unable to access custom Squirrel.Windows vendor directory, falling back to default vendor");
29
- }
30
- const windowInstallerPackage = _requireResolve("electron-winstaller/package.json");
31
- const [squirrelBin] = await Promise.all([
32
- downloadBuilderToolset({
33
- releaseName: "squirrel.windows@1.0.0",
34
- filenameWithExt: "squirrel.windows-2.0.1-patched.7z",
35
- checksums: { "squirrel.windows-2.0.1-patched.7z": "76851f0c192eaf9bc6f8f3eecdfe325857ebe70d7833ec62ed846a1acd50c846" },
36
- }),
37
- fs.promises.cp(path.join(path.dirname(windowInstallerPackage), "vendor"), tmpVendorDirectory, { recursive: true }),
38
- ]);
39
- await fs.promises.cp(path.join(squirrelBin, "electron-winstaller", "vendor"), tmpVendorDirectory, { recursive: true });
20
+ // The vendor toolset comes from the maintained squirrel.windows bundle. Pin a version or supply a
21
+ // custom/local bundle (e.g. for air-gapped builds) via `toolsets.squirrel` (a ToolsetCustom object).
22
+ const squirrelToolset = await getSquirrelToolsetPath(this.packager.config.toolsets?.squirrel, this.packager.buildResourcesDir);
23
+ await fs.promises.cp(path.join(squirrelToolset, "electron-winstaller", "vendor"), tmpVendorDirectory, { recursive: true });
24
+ // Both Squirrel.exe and Squirrel-Mono.exe shell out to rcedit.exe (via setPEVersionInfoAndIcon)
25
+ // during --releasify to stamp version info and the app icon into Setup.exe, so rcedit must live in
26
+ // the vendor dir on every host — on non-Windows it runs under wine alongside the other Win32 vendor
27
+ // exes (Setup.exe, StubExecutable.exe, …). The bundle omits rcedit, so resolve it from the
28
+ // win-codesign toolset, which already versions and caches it across platforms.
29
+ //
30
+ // getRceditBundle honors the user's `toolsets.winCodeSign` selection, so users retain a bypass if a
31
+ // newer toolset regresses: `"0.0.0"` falls back to the legacy winCodeSign-2.6.0 rcedit, a custom
32
+ // toolset object uses their own rcedit, and the default (unset/"latest") pulls rcedit-windows-2_0_0.
33
+ const rcedit = await getRceditBundle(this.packager.config.toolsets?.winCodeSign, this.packager.buildResourcesDir);
34
+ // Pick rcedit by host arch (x64 for x64/arm64, x86 only for ia32). On non-Windows it runs under wine:
35
+ // the 32-bit build fails on arm64 macOS even under Rosetta (which translates x64, not x86), so the x64
36
+ // build is required there.
37
+ const rceditExe = os.arch() === "ia32" ? rcedit.x86 : rcedit.x64;
38
+ await fs.promises.copyFile(rceditExe, path.join(tmpVendorDirectory, "rcedit.exe"));
39
+ // When building an MSI, Squirrel's createMsiPackage runs candle.exe/light.exe from the vendor dir and
40
+ // reads template.wxs there. The bundle ships neither, so merge the shared WiX toolset (the same
41
+ // candle/light electron-builder's MSI target uses) into the vendor dir, plus the Squirrel MSI template
42
+ // (authored against the v4 namespace this transitional WiX 4 requires).
43
+ if (this.options.msi) {
44
+ const wixToolset = await getWixToolsetPath();
45
+ await fs.promises.cp(wixToolset, tmpVendorDirectory, { recursive: true });
46
+ await fs.promises.copyFile(path.resolve(import.meta.dirname, "..", "template.wxs"), path.join(tmpVendorDirectory, "template.wxs"));
40
47
  }
48
+ // Squirrel.exe is the core updater binary the bundle always ships; a missing one means a broken
49
+ // vendor toolset. Fail loudly rather than skipping signing — skipping would produce a broken
50
+ // installer and bypass the forceCodeSigning enforcement inside signIf (its awaited promise rejects
51
+ // when the file can't be signed and forceCodeSigning is set).
41
52
  const files = await fs.promises.readdir(tmpVendorDirectory);
42
- const squirrelExe = files.find(f => f === "Squirrel.exe");
43
- if (squirrelExe) {
44
- const filePath = path.join(tmpVendorDirectory, squirrelExe);
45
- log.debug({ file: filePath }, "signing vendor executable");
46
- await this.packager.signIf(filePath);
47
- }
48
- else {
49
- log.warn("Squirrel.exe not found in vendor directory, skipping signing");
53
+ if (!files.includes("Squirrel.exe")) {
54
+ throw new Error(`Squirrel.exe not found in vendor directory: ${tmpVendorDirectory}`);
50
55
  }
56
+ const squirrelExePath = path.join(tmpVendorDirectory, "Squirrel.exe");
57
+ log.debug({ file: squirrelExePath }, "signing vendor executable");
58
+ await this.packager.signIf(squirrelExePath);
51
59
  return tmpVendorDirectory;
52
60
  }
53
61
  assertShellSafePath(filePath, description) {
54
- if (/[\r\n`$;&|<>]/.test(filePath)) {
62
+ if (/[\r\n\0`$;&|<>]/.test(filePath)) {
55
63
  throw new InvalidConfigurationError(`${description} contains unsafe shell characters: ${filePath}`);
56
64
  }
57
65
  }
@@ -83,7 +91,12 @@ export default class SquirrelWindowsTarget extends Target {
83
91
  }
84
92
  canonicalTargetPath = path.resolve(canonicalTargetParent, relativeFromResolvedParent);
85
93
  }
86
- catch {
94
+ catch (e) {
95
+ // Only fall back for filesystem errors (target parent not found, permission, etc.).
96
+ // Validation errors must propagate so callers get an actionable message.
97
+ if (e instanceof InvalidConfigurationError) {
98
+ throw e;
99
+ }
87
100
  canonicalTargetPath = resolvedTargetPath;
88
101
  }
89
102
  }
@@ -186,10 +199,18 @@ export default class SquirrelWindowsTarget extends Target {
186
199
  select7zipArch(vendorDirectory) {
187
200
  // https://github.com/electron/windows-installer/blob/main/script/select-7z-arch.js
188
201
  // Even if we're cross-compiling for a different arch like arm64,
189
- // we still need to use the 7-Zip executable for the host arch
202
+ // we still need to use the 7-Zip executable for the host arch.
203
+ // When arch-specific variants aren't present (vendor bundle ships a pre-selected 7z.exe),
204
+ // skip the copy — the bundle's 7z.exe is already correct.
190
205
  const resolvedArch = os.arch();
191
- fs.copyFileSync(path.join(vendorDirectory, `7z-${resolvedArch}.exe`), path.join(vendorDirectory, "7z.exe"));
192
- fs.copyFileSync(path.join(vendorDirectory, `7z-${resolvedArch}.dll`), path.join(vendorDirectory, "7z.dll"));
206
+ const archExe = path.join(vendorDirectory, `7z-${resolvedArch}.exe`);
207
+ const archDll = path.join(vendorDirectory, `7z-${resolvedArch}.dll`);
208
+ if (fs.existsSync(archExe)) {
209
+ fs.copyFileSync(archExe, path.join(vendorDirectory, "7z.exe"));
210
+ }
211
+ if (fs.existsSync(archDll)) {
212
+ fs.copyFileSync(archDll, path.join(vendorDirectory, "7z.dll"));
213
+ }
193
214
  }
194
215
  async createNuspecTemplateWithProjectUrl() {
195
216
  const templatePath = path.resolve(import.meta.dirname, "..", "template.nuspectemplate");
@@ -216,62 +237,66 @@ export default class SquirrelWindowsTarget extends Target {
216
237
  throw new InvalidConfigurationError("squirrelWindows.iconUrl is not specified, please see https://www.electron.build/squirrel-windows#SquirrelWindowsOptions-iconUrl");
217
238
  }
218
239
  }
219
- checkConflictingOptions(this.options);
240
+ normalizeSquirrelOptions(this.options);
220
241
  const appInfo = packager.appInfo;
221
- const options = {
222
- appDirectory: appDirectory,
223
- outputDirectory: outputDirectory,
224
- name: this.options.useAppIdAsId ? appInfo.id : this.appName,
225
- title: appInfo.productName || appInfo.name,
226
- version: appInfo.version,
227
- description: appInfo.description,
228
- exe: `${this.exeName}.exe`,
229
- authors: appInfo.companyName || "",
230
- nuspecTemplate: await this.createNuspecTemplateWithProjectUrl(),
231
- iconUrl,
232
- copyright: appInfo.copyright,
233
- noMsi: !this.options.msi,
234
- usePackageJson: false,
235
- };
236
- options.vendorDirectory = await this.prepareSignedVendorDirectory();
237
- this.select7zipArch(options.vendorDirectory);
238
- options.fixUpPaths = true;
239
- options.setupExe = setupFile;
240
- if (this.options.msi) {
241
- options.setupMsi = setupFile.replace(".exe", ".msi");
242
- }
243
- if (isEmptyOrSpaces(options.description)) {
244
- options.description = this.options.name || appInfo.productName;
245
- }
246
- if (options.remoteToken == null) {
247
- options.remoteToken = process.env.GH_TOKEN || process.env.GITHUB_TOKEN;
248
- }
242
+ const description = isEmptyOrSpaces(appInfo.description) ? this.options.name || appInfo.productName : appInfo.description;
243
+ let remoteReleases;
249
244
  if (this.options.remoteReleases === true) {
250
245
  const info = await packager.repositoryInfo;
251
246
  if (info == null) {
252
247
  log.warn("remoteReleases set to true, but cannot get repository info");
253
248
  }
254
249
  else {
255
- options.remoteReleases = `https://github.com/${info.user}/${info.project}`;
256
- log.info({ remoteReleases: options.remoteReleases }, `remoteReleases is set`);
250
+ remoteReleases = `https://github.com/${info.user}/${info.project}`;
251
+ log.info({ remoteReleases }, `remoteReleases is set`);
257
252
  }
258
253
  }
259
254
  else if (typeof this.options.remoteReleases === "string" && !isEmptyOrSpaces(this.options.remoteReleases)) {
260
- options.remoteReleases = this.options.remoteReleases;
255
+ remoteReleases = this.options.remoteReleases;
261
256
  }
257
+ let loadingGif;
262
258
  if (this.options.loadingGif) {
263
- options.loadingGif = path.resolve(packager.projectDir, this.options.loadingGif);
259
+ loadingGif = path.resolve(packager.projectDir, this.options.loadingGif);
264
260
  }
265
261
  else {
266
- const resourceList = await packager.resourceList;
267
- if (resourceList.includes("install-spinner.gif")) {
268
- options.loadingGif = path.join(packager.buildResourcesDir, "install-spinner.gif");
269
- }
262
+ // User-supplied buildResources gif wins; otherwise fall back to the bundled default spinner —
263
+ // parity with electron-winstaller, which always supplied resources/install-spinner.gif when none
264
+ // was configured (a fresh-install progress animation; never omitted).
265
+ loadingGif = (await packager.getResource(undefined, "install-spinner.gif")) ?? path.resolve(import.meta.dirname, "..", "install-spinner.gif");
270
266
  }
271
- return options;
267
+ const vendorDirectory = await this.prepareSignedVendorDirectory();
268
+ this.select7zipArch(vendorDirectory);
269
+ return {
270
+ appDirectory,
271
+ outputDirectory,
272
+ vendorDirectory,
273
+ name: this.options.useAppIdAsId ? appInfo.id : this.appName,
274
+ title: appInfo.productName || appInfo.name,
275
+ version: appInfo.version,
276
+ description,
277
+ exe: `${this.exeName}.exe`,
278
+ authors: appInfo.companyName || "",
279
+ nuspecTemplate: await this.createNuspecTemplateWithProjectUrl(),
280
+ iconUrl,
281
+ copyright: appInfo.copyright,
282
+ msi: this.options.msi,
283
+ fixUpPaths: true,
284
+ setupExe: setupFile,
285
+ setupMsi: this.options.msi ? setupFile.replace(/\.exe$/i, ".msi") : undefined,
286
+ loadingGif,
287
+ remoteReleases,
288
+ remoteToken: firstNonBlank(this.options.remoteToken, process.env.GH_TOKEN, process.env.GITHUB_TOKEN),
289
+ createTempDir: opts => this.packager.tempDirManager.createTempDir(opts),
290
+ };
272
291
  }
273
292
  }
274
- function checkConflictingOptions(options) {
293
+ // `remoteToken: ""` (or whitespace) in the config counts as unset: fall through to the environment
294
+ // instead of shadowing GH_TOKEN/GITHUB_TOKEN with a value SyncReleases would drop anyway.
295
+ function firstNonBlank(...values) {
296
+ const value = values.find(it => !isEmptyOrSpaces(it));
297
+ return value == null ? undefined : value.trim();
298
+ }
299
+ function normalizeSquirrelOptions(options) {
275
300
  for (const name of ["outputDirectory", "appDirectory", "exe", "fixUpPaths", "usePackageJson", "extraFileSpecs", "extraMetadataSpecs", "skipUpdateIcon", "setupExe"]) {
276
301
  if (name in options) {
277
302
  throw new InvalidConfigurationError(`Option ${name} is ignored, do not specify it.`);
@@ -1 +1 @@
1
- {"version":3,"file":"SquirrelWindowsTarget.js","sourceRoot":"","sources":["../src/SquirrelWindowsTarget.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,yBAAyB,EAAE,GAAG,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAEtF,MAAM,eAAe,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,CAAA;AAC9D,OAAO,EAAE,sBAAsB,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAClF,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AACxD,OAAO,EAAQ,aAAa,EAA0B,MAAM,EAAe,MAAM,iBAAiB,CAAA;AAClG,OAAO,KAAK,IAAI,MAAM,MAAM,CAAA;AAC5B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAA;AACxB,OAAO,KAAK,EAAE,MAAM,IAAI,CAAA;AACxB,OAAO,EAA8B,sBAAsB,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACxG,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAExD,MAAM,CAAC,OAAO,OAAO,qBAAsB,SAAQ,MAAM;IAKvD,YACmB,QAAqB,EAC7B,MAAc;QAEvB,KAAK,CAAC,UAAU,CAAC,CAAA;QAHA,aAAQ,GAAR,QAAQ,CAAa;QAC7B,WAAM,GAAN,MAAM,CAAQ;QAJzB,qBAAgB,GAAG,KAAK,CAAA;QAOtB,IAAI,CAAC,OAAO,GAAG,QAAQ,CAAC,mBAAmB,CAAyB,iBAAiB,CAAC,CAAA;IACxF,CAAC;IAEO,KAAK,CAAC,4BAA4B;QACxC,MAAM,6BAA6B,GAAG,IAAI,CAAC,OAAO,CAAC,uBAAuB,CAAA;QAC1E,MAAM,kBAAkB,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,aAAa,CAAC,EAAE,MAAM,EAAE,yBAAyB,EAAE,CAAC,CAAA;QAElH,IAAI,6BAA6B,IAAI,CAAC,MAAM,MAAM,CAAC,6BAA6B,CAAC,CAAC,EAAE,CAAC;YACnF,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,6BAA6B,EAAE,kBAAkB,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAC9F,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,eAAe,CAAC,6BAA6B,CAAC,EAAE,CAAC;gBACpD,GAAG,CAAC,IAAI,CAAC,EAAE,6BAA6B,EAAE,EAAE,2FAA2F,CAAC,CAAA;YAC1I,CAAC;YAED,MAAM,sBAAsB,GAAG,eAAe,CAAC,kCAAkC,CAAC,CAAA;YAClF,MAAM,CAAC,WAAW,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;gBACtC,sBAAsB,CAAC;oBACrB,WAAW,EAAE,wBAAwB;oBACrC,eAAe,EAAE,mCAAmC;oBACpD,SAAS,EAAE,EAAE,mCAAmC,EAAE,kEAAkE,EAAE;iBACvH,CAAC;gBACF,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,sBAAsB,CAAC,EAAE,QAAQ,CAAC,EAAE,kBAAkB,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;aACnH,CAAC,CAAA;YACF,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,qBAAqB,EAAE,QAAQ,CAAC,EAAE,kBAAkB,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QACxH,CAAC;QAED,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAA;QAC3D,MAAM,WAAW,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,cAAc,CAAC,CAAA;QACzD,IAAI,WAAW,EAAE,CAAC;YAChB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE,WAAW,CAAC,CAAA;YAC3D,GAAG,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,2BAA2B,CAAC,CAAA;YAC1D,MAAM,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;QACtC,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,IAAI,CAAC,8DAA8D,CAAC,CAAA;QAC1E,CAAC;QACD,OAAO,kBAAkB,CAAA;IAC3B,CAAC;IAEO,mBAAmB,CAAC,QAAgB,EAAE,WAAmB;QAC/D,IAAI,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YACnC,MAAM,IAAI,yBAAyB,CAAC,GAAG,WAAW,sCAAsC,QAAQ,EAAE,CAAC,CAAA;QACrG,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,gBAAgB,CAAC,OAAe,EAAE,UAAkB,EAAE,WAAmB;QACrF,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;QAC7C,MAAM,kBAAkB,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;QAEnD,IAAI,gBAAgB,GAAG,eAAe,CAAA;QACtC,IAAI,mBAAmB,GAAG,kBAAkB,CAAA;QAE5C,IAAI,CAAC;YACH,gBAAgB,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAA;QAChE,CAAC;QAAC,MAAM,CAAC;YACP,gBAAgB,GAAG,eAAe,CAAA;QACpC,CAAC;QAED,IAAI,CAAC;YACH,mBAAmB,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAA;QACtE,CAAC;QAAC,MAAM,CAAC;YACP,yFAAyF;YACzF,IAAI,CAAC;gBACH,MAAM,oBAAoB,GAAG,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAA;gBAC7D,MAAM,qBAAqB,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAA;gBAC9E,MAAM,0BAA0B,GAAG,IAAI,CAAC,QAAQ,CAAC,oBAAoB,EAAE,kBAAkB,CAAC,CAAA;gBAC1F,IACE,eAAe,CAAC,0BAA0B,CAAC;oBAC3C,IAAI,CAAC,UAAU,CAAC,0BAA0B,CAAC;oBAC3C,0BAA0B,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;oBACzD,UAAU,CAAC,IAAI,CAAC,0BAA0B,CAAC,EAC3C,CAAC;oBACD,MAAM,IAAI,yBAAyB,CAAC,GAAG,WAAW,iCAAiC,CAAC,CAAA;gBACtF,CAAC;gBACD,mBAAmB,GAAG,IAAI,CAAC,OAAO,CAAC,qBAAqB,EAAE,0BAA0B,CAAC,CAAA;YACvF,CAAC;YAAC,MAAM,CAAC;gBACP,mBAAmB,GAAG,kBAAkB,CAAA;YAC1C,CAAC;QACH,CAAC;QAED,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,CAAA;QACzE,IAAI,YAAY,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YACnE,MAAM,IAAI,yBAAyB,CAAC,GAAG,WAAW,mBAAmB,gBAAgB,EAAE,CAAC,CAAA;QAC1F,CAAC;QACD,IAAI,CAAC,mBAAmB,CAAC,mBAAmB,EAAE,WAAW,CAAC,CAAA;QAC1D,OAAO,mBAAmB,CAAA;IAC5B,CAAC;IAEO,KAAK,CAAC,yBAAyB,CAAC,SAAiB,EAAE,SAAiB;QAC1E,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC/D,MAAM,IAAI,yBAAyB,CAAC,gDAAgD,CAAC,CAAA;QACvF,CAAC;QAED,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAA;QAC3E,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,GAAG,IAAI,CAAC,OAAO,MAAM,CAAC,CAAA;QAChE,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,8CAA8C,SAAS,EAAE,CAAC,CAAA;QAC5E,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,qBAAqB,CAAC,CAAA;QACjH,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,IAAI,CAAC,OAAO,oBAAoB,CAAC,EAAE,sBAAsB,CAAC,CAAA;QAC7I,MAAM,oBAAoB,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,oBAAoB,CAAC,EAAE,wBAAwB,CAAC,CAAA;QACzI,MAAM,kBAAkB,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,qBAAqB,CAAC,EAAE,4BAA4B,CAAC,CAAA;QAE5I,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,oBAAoB,EAAE,WAAW,CAAC,CAAA;QAC7D,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAA;QACtG,MAAM,MAAM,CAAC,IAAI,CAAC,kBAAkB,EAAE,CAAC,uBAAuB,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAA;QACvF,MAAM,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;QACvC,GAAG,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,wBAAwB,CAAC,CAAA;QACvD,MAAM,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;IACtC,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,SAAiB,EAAE,IAAU;QACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAA;QAC9B,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAA;QACxC,MAAM,aAAa,GAAG,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QAEpD,MAAM,SAAS,GAAG,QAAQ,CAAC,yBAAyB,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,wCAAwC,CAAC,CAAA;QACzH,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,mBAAmB,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACxF,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,SAAS,CAAC,CAAA;QAC1D,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,QAAQ,CAAC,yBAAyB,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,wCAAwC,CAAC,CAAC,CAAA;QAE3J,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE;YACpC,MAAM,QAAQ,CAAC,wBAAwB,CAAC;gBACtC,qBAAqB,EAAE,kBAAkB;gBACzC,IAAI,EAAE,YAAY;gBAClB,IAAI;aACL,CAAC,CAAA;YACF,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,2BAA2B,CAAC,SAAS,EAAE,eAAe,EAAE,SAAS,CAAC,CAAA;YACjG,MAAM,IAAI,CAAC,yBAAyB,CAAC,SAAS,EAAE,WAAW,CAAC,eAAgB,CAAC,CAAA;YAC7E,MAAM,eAAe,CAAC,GAAG,EAAE,CAAC,sBAAsB,CAAC,WAAW,CAAC,CAAC,CAAA;YAEhE,MAAM,QAAQ,CAAC,oBAAoB,CAAC,YAAY,EAAE,IAAI,EAAE,eAAe,CAAC,CAAA;YAExE,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;gBACrB,MAAM,QAAQ,CAAC,MAAM,CAAC,eAAe,CAAC,CAAA;YACxC,CAAC;YAED,MAAM,gBAAgB,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,GAAG,aAAa,UAAU,OAAO,GAAG,aAAa,CAAC,IAAI,CAAC,IAAI,GAAG,EAAE,CAAA;YAE1G,MAAM,QAAQ,CAAC,0BAA0B,CAAC;gBACxC,IAAI,EAAE,YAAY;gBAClB,MAAM,EAAE,IAAI;gBACZ,IAAI;gBACJ,gBAAgB,EAAE,gBAAgB,CAAC,KAAK,CAAC;gBACzC,QAAQ,EAAE,IAAI,CAAC,QAAQ;aACxB,CAAC,CAAA;YAEF,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;gBACrB,MAAM,QAAQ,CAAC,mBAAmB,CAAC;oBACjC,IAAI,EAAE,eAAe;oBACrB,MAAM,EAAE,IAAI;oBACZ,IAAI;oBACJ,gBAAgB,EAAE,gBAAgB,CAAC,KAAK,CAAC;oBACzC,QAAQ,EAAE,IAAI,CAAC,QAAQ;iBACxB,CAAC,CAAA;YACJ,CAAC;YAED,MAAM,aAAa,GAAG,GAAG,IAAI,CAAC,OAAO,IAAI,cAAc,CAAC,OAAO,CAAC,GAAG,CAAA;YACnE,MAAM,QAAQ,CAAC,mBAAmB,CAAC;gBACjC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,GAAG,aAAa,YAAY,CAAC;gBAC9D,MAAM,EAAE,IAAI;gBACZ,IAAI;gBACJ,QAAQ;aACT,CAAC,CAAA;YACF,IAAI,WAAW,CAAC,cAAc,IAAI,IAAI,EAAE,CAAC;gBACvC,MAAM,QAAQ,CAAC,mBAAmB,CAAC;oBACjC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,GAAG,aAAa,aAAa,CAAC;oBAC/D,MAAM,EAAE,IAAI;oBACZ,IAAI;oBACJ,QAAQ;iBACT,CAAC,CAAA;YACJ,CAAC;YAED,MAAM,QAAQ,CAAC,mBAAmB,CAAC;gBACjC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,UAAU,CAAC;gBAC5C,MAAM,EAAE,IAAI;gBACZ,IAAI;gBACJ,QAAQ;aACT,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;QACF,OAAO,OAAO,CAAC,OAAO,EAAE,CAAA;IAC1B,CAAC;IAED,IAAY,OAAO;QACjB,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAA;IACxD,CAAC;IAED,IAAY,OAAO;QACjB,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,eAAe,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,WAAW,CAAA;QAC5G,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAA;IAC/B,CAAC;IAEO,cAAc,CAAC,eAAuB;QAC5C,mFAAmF;QACnF,iEAAiE;QACjE,8DAA8D;QAC9D,MAAM,YAAY,GAAG,EAAE,CAAC,IAAI,EAAE,CAAA;QAC9B,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,MAAM,YAAY,MAAM,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC,CAAA;QAC3G,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,MAAM,YAAY,MAAM,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC,CAAA;IAC7G,CAAC;IAEO,KAAK,CAAC,kCAAkC;QAC9C,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,yBAAyB,CAAC,CAAA;QACvF,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,iBAAiB,EAAE,CAAA;QAClE,IAAI,UAAU,IAAI,IAAI,EAAE,CAAC;YACvB,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,iBAAiB,EAAE,CAAC,CAAA;YACxH,IAAI,eAAe,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC,CAAA;YACtE,MAAM,YAAY,GAAG,yCAAyC,CAAA;YAC9D,eAAe,GAAG,eAAe,CAAC,OAAO,CAAC,YAAY,EAAE,GAAG,YAAY,qBAAqB,UAAU,eAAe,CAAC,CAAA;YACtH,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,cAAc,EAAE,eAAe,CAAC,CAAA;YAC5D,OAAO,cAAc,CAAA;QACvB,CAAC;QACD,OAAO,YAAY,CAAA;IACrB,CAAC;IAED,KAAK,CAAC,2BAA2B,CAAC,YAAoB,EAAE,eAAuB,EAAE,SAAiB;QAChG,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAA;QAC9B,IAAI,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAA;QAClC,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;YACpB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,cAAc,CAAA;YAC1C,IAAI,IAAI,IAAI,IAAI,EAAE,CAAC;gBACjB,OAAO,GAAG,sBAAsB,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,OAAO,gBAAgB,QAAQ,CAAC,6BAA6B,oBAAoB,CAAA;YACrI,CAAC;YAED,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;gBACpB,MAAM,IAAI,yBAAyB,CAAC,iIAAiI,CAAC,CAAA;YACxK,CAAC;QACH,CAAC;QAED,uBAAuB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QACrC,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAA;QAChC,MAAM,OAAO,GAAoB;YAC/B,YAAY,EAAE,YAAY;YAC1B,eAAe,EAAE,eAAe;YAChC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO;YAC3D,KAAK,EAAE,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,IAAI;YAC1C,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,MAAM;YAC1B,OAAO,EAAE,OAAO,CAAC,WAAW,IAAI,EAAE;YAClC,cAAc,EAAE,MAAM,IAAI,CAAC,kCAAkC,EAAE;YAC/D,OAAO;YACP,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,KAAK,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG;YACxB,cAAc,EAAE,KAAK;SACtB,CAAA;QAED,OAAO,CAAC,eAAe,GAAG,MAAM,IAAI,CAAC,4BAA4B,EAAE,CAAA;QACnE,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,eAAe,CAAC,CAAA;QAC5C,OAAO,CAAC,UAAU,GAAG,IAAI,CAAA;QACzB,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAA;QAC5B,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;YACrB,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QACtD,CAAC;QAED,IAAI,eAAe,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;YACzC,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,WAAW,CAAA;QAChE,CAAC;QAED,IAAI,OAAO,CAAC,WAAW,IAAI,IAAI,EAAE,CAAC;YAChC,OAAO,CAAC,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,CAAA;QACxE,CAAC;QAED,IAAI,IAAI,CAAC,OAAO,CAAC,cAAc,KAAK,IAAI,EAAE,CAAC;YACzC,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,cAAc,CAAA;YAC1C,IAAI,IAAI,IAAI,IAAI,EAAE,CAAC;gBACjB,GAAG,CAAC,IAAI,CAAC,4DAA4D,CAAC,CAAA;YACxE,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,cAAc,GAAG,sBAAsB,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,OAAO,EAAE,CAAA;gBAC1E,GAAG,CAAC,IAAI,CAAC,EAAE,cAAc,EAAE,OAAO,CAAC,cAAc,EAAE,EAAE,uBAAuB,CAAC,CAAA;YAC/E,CAAC;QACH,CAAC;aAAM,IAAI,OAAO,IAAI,CAAC,OAAO,CAAC,cAAc,KAAK,QAAQ,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC;YAC5G,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,CAAA;QACtD,CAAC;QAED,IAAI,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;YAC5B,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;QACjF,CAAC;aAAM,CAAC;YACN,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,YAAY,CAAA;YAChD,IAAI,YAAY,CAAC,QAAQ,CAAC,qBAAqB,CAAC,EAAE,CAAC;gBACjD,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,iBAAiB,EAAE,qBAAqB,CAAC,CAAA;YACnF,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAA;IAChB,CAAC;CACF;AAED,SAAS,uBAAuB,CAAC,OAAY;IAC3C,KAAK,MAAM,IAAI,IAAI,CAAC,iBAAiB,EAAE,cAAc,EAAE,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,UAAU,CAAC,EAAE,CAAC;QACpK,IAAI,IAAI,IAAI,OAAO,EAAE,CAAC;YACpB,MAAM,IAAI,yBAAyB,CAAC,UAAU,IAAI,iCAAiC,CAAC,CAAA;QACtF,CAAC;IACH,CAAC;IAED,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAA;IACvB,IAAI,GAAG,IAAI,IAAI,IAAI,OAAO,GAAG,KAAK,SAAS,EAAE,CAAC;QAC5C,MAAM,IAAI,yBAAyB,CAAC,kDAAkD,GAAG,kBAAkB,CAAC,CAAA;IAC9G,CAAC;AACH,CAAC","sourcesContent":["import { createRequire } from \"node:module\"\nimport { InvalidConfigurationError, log, isEmptyOrSpaces, exists } from \"builder-util\"\n\nconst _requireResolve = createRequire(import.meta.url).resolve\nimport { downloadBuilderToolset, withToolsetLock } from \"app-builder-lib/internal\"\nimport { sanitizeFileName } from \"builder-util/internal\"\nimport { Arch, getArchSuffix, SquirrelWindowsOptions, Target, WinPackager } from \"app-builder-lib\"\nimport * as path from \"path\"\nimport * as fs from \"fs\"\nimport * as os from \"os\"\nimport { Options as SquirrelOptions, createWindowsInstaller, convertVersion } from \"electron-winstaller\"\nimport { WineVmManager } from \"app-builder-lib/internal\"\n\nexport default class SquirrelWindowsTarget extends Target {\n readonly options: SquirrelWindowsOptions\n\n isAsyncSupported = false\n\n constructor(\n private readonly packager: WinPackager,\n readonly outDir: string\n ) {\n super(\"squirrel\")\n this.options = packager.getOptionsForTarget<SquirrelWindowsOptions>(\"squirrelWindows\")\n }\n\n private async prepareSignedVendorDirectory(): Promise<string> {\n const customSquirrelVendorDirectory = this.options.customSquirrelVendorDir\n const tmpVendorDirectory = await this.packager.tempDirManager.createTempDir({ prefix: \"squirrel-windows-vendor\" })\n\n if (customSquirrelVendorDirectory && (await exists(customSquirrelVendorDirectory))) {\n await fs.promises.cp(customSquirrelVendorDirectory, tmpVendorDirectory, { recursive: true })\n } else {\n if (!isEmptyOrSpaces(customSquirrelVendorDirectory)) {\n log.warn({ customSquirrelVendorDirectory }, \"unable to access custom Squirrel.Windows vendor directory, falling back to default vendor\")\n }\n\n const windowInstallerPackage = _requireResolve(\"electron-winstaller/package.json\")\n const [squirrelBin] = await Promise.all([\n downloadBuilderToolset({\n releaseName: \"squirrel.windows@1.0.0\",\n filenameWithExt: \"squirrel.windows-2.0.1-patched.7z\",\n checksums: { \"squirrel.windows-2.0.1-patched.7z\": \"76851f0c192eaf9bc6f8f3eecdfe325857ebe70d7833ec62ed846a1acd50c846\" },\n }),\n fs.promises.cp(path.join(path.dirname(windowInstallerPackage), \"vendor\"), tmpVendorDirectory, { recursive: true }),\n ])\n await fs.promises.cp(path.join(squirrelBin, \"electron-winstaller\", \"vendor\"), tmpVendorDirectory, { recursive: true })\n }\n\n const files = await fs.promises.readdir(tmpVendorDirectory)\n const squirrelExe = files.find(f => f === \"Squirrel.exe\")\n if (squirrelExe) {\n const filePath = path.join(tmpVendorDirectory, squirrelExe)\n log.debug({ file: filePath }, \"signing vendor executable\")\n await this.packager.signIf(filePath)\n } else {\n log.warn(\"Squirrel.exe not found in vendor directory, skipping signing\")\n }\n return tmpVendorDirectory\n }\n\n private assertShellSafePath(filePath: string, description: string): void {\n if (/[\\r\\n`$;&|<>]/.test(filePath)) {\n throw new InvalidConfigurationError(`${description} contains unsafe shell characters: ${filePath}`)\n }\n }\n\n private async ensurePathInside(baseDir: string, targetPath: string, description: string): Promise<string> {\n const resolvedBaseDir = path.resolve(baseDir)\n const resolvedTargetPath = path.resolve(targetPath)\n\n let canonicalBaseDir = resolvedBaseDir\n let canonicalTargetPath = resolvedTargetPath\n\n try {\n canonicalBaseDir = await fs.promises.realpath(resolvedBaseDir)\n } catch {\n canonicalBaseDir = resolvedBaseDir\n }\n\n try {\n canonicalTargetPath = await fs.promises.realpath(resolvedTargetPath)\n } catch {\n // Target may not exist yet; resolve the parent to handle symlinks/junctions consistently\n try {\n const resolvedTargetParent = path.dirname(resolvedTargetPath)\n const canonicalTargetParent = await fs.promises.realpath(resolvedTargetParent)\n const relativeFromResolvedParent = path.relative(resolvedTargetParent, resolvedTargetPath)\n if (\n isEmptyOrSpaces(relativeFromResolvedParent) ||\n path.isAbsolute(relativeFromResolvedParent) ||\n relativeFromResolvedParent.split(path.sep).includes(\"..\") ||\n /[\\0\\r\\n]/.test(relativeFromResolvedParent)\n ) {\n throw new InvalidConfigurationError(`${description} contains invalid path segments`)\n }\n canonicalTargetPath = path.resolve(canonicalTargetParent, relativeFromResolvedParent)\n } catch {\n canonicalTargetPath = resolvedTargetPath\n }\n }\n\n const relativePath = path.relative(canonicalBaseDir, canonicalTargetPath)\n if (relativePath.startsWith(\"..\") || path.isAbsolute(relativePath)) {\n throw new InvalidConfigurationError(`${description} must be inside ${canonicalBaseDir}`)\n }\n this.assertShellSafePath(canonicalTargetPath, description)\n return canonicalTargetPath\n }\n\n private async generateStubExecutableExe(appOutDir: string, vendorDir: string) {\n if (!path.isAbsolute(appOutDir) || !path.isAbsolute(vendorDir)) {\n throw new InvalidConfigurationError(\"appOutDir and vendorDir must be absolute paths\")\n }\n\n const files = await fs.promises.readdir(appOutDir, { withFileTypes: true })\n const appExe = files.find(f => f.name === `${this.exeName}.exe`)\n if (!appExe) {\n throw new Error(`App executable not found in app directory: ${appOutDir}`)\n }\n\n const filePath = await this.ensurePathInside(appOutDir, path.join(appOutDir, appExe.name), \"App executable path\")\n const stubExePath = await this.ensurePathInside(appOutDir, path.join(appOutDir, `${this.exeName}_ExecutionStub.exe`), \"Stub executable path\")\n const stubExecutableSource = await this.ensurePathInside(vendorDir, path.join(vendorDir, \"StubExecutable.exe\"), \"Stub executable source\")\n const writeZipToSetupExe = await this.ensurePathInside(vendorDir, path.join(vendorDir, \"WriteZipToSetup.exe\"), \"WriteZipToSetup executable\")\n\n await fs.promises.copyFile(stubExecutableSource, stubExePath)\n const wineVm = new WineVmManager(this.packager.config.toolsets?.wine, this.packager.buildResourcesDir)\n await wineVm.exec(writeZipToSetupExe, [\"--copy-stub-resources\", filePath, stubExePath])\n await this.packager.signIf(stubExePath)\n log.debug({ file: filePath }, \"signing app executable\")\n await this.packager.signIf(filePath)\n }\n\n async build(appOutDir: string, arch: Arch) {\n const packager = this.packager\n const version = packager.appInfo.version\n const sanitizedName = sanitizeFileName(this.appName)\n\n const setupFile = packager.expandArtifactNamePattern(this.options, \"exe\", arch, \"${productName} Setup ${version}.${ext}\")\n const installerOutDir = path.join(this.outDir, `squirrel-windows${getArchSuffix(arch)}`)\n const artifactPath = path.join(installerOutDir, setupFile)\n const msiArtifactPath = path.join(installerOutDir, packager.expandArtifactNamePattern(this.options, \"msi\", arch, \"${productName} Setup ${version}.${ext}\"))\n\n this.buildQueueManager.add(async () => {\n await packager.emitArtifactBuildStarted({\n targetPresentableName: \"Squirrel.Windows\",\n file: artifactPath,\n arch,\n })\n const distOptions = await this.computeEffectiveDistOptions(appOutDir, installerOutDir, setupFile)\n await this.generateStubExecutableExe(appOutDir, distOptions.vendorDirectory!)\n await withToolsetLock(() => createWindowsInstaller(distOptions))\n\n await packager.signAndEditResources(artifactPath, arch, installerOutDir)\n\n if (this.options.msi) {\n await packager.signIf(msiArtifactPath)\n }\n\n const safeArtifactName = (ext: string) => `${sanitizedName}-Setup-${version}${getArchSuffix(arch)}.${ext}`\n\n await packager.emitArtifactBuildCompleted({\n file: artifactPath,\n target: this,\n arch,\n safeArtifactName: safeArtifactName(\"exe\"),\n packager: this.packager,\n })\n\n if (this.options.msi) {\n await packager.emitArtifactCreated({\n file: msiArtifactPath,\n target: this,\n arch,\n safeArtifactName: safeArtifactName(\"msi\"),\n packager: this.packager,\n })\n }\n\n const packagePrefix = `${this.appName}-${convertVersion(version)}-`\n await packager.emitArtifactCreated({\n file: path.join(installerOutDir, `${packagePrefix}full.nupkg`),\n target: this,\n arch,\n packager,\n })\n if (distOptions.remoteReleases != null) {\n await packager.emitArtifactCreated({\n file: path.join(installerOutDir, `${packagePrefix}delta.nupkg`),\n target: this,\n arch,\n packager,\n })\n }\n\n await packager.emitArtifactCreated({\n file: path.join(installerOutDir, \"RELEASES\"),\n target: this,\n arch,\n packager,\n })\n })\n return Promise.resolve()\n }\n\n private get appName() {\n return this.options.name || this.packager.appInfo.name\n }\n\n private get exeName() {\n const name = this.packager.appInfo.productFilename || this.options.name || this.packager.appInfo.productName\n return sanitizeFileName(name)\n }\n\n private select7zipArch(vendorDirectory: string) {\n // https://github.com/electron/windows-installer/blob/main/script/select-7z-arch.js\n // Even if we're cross-compiling for a different arch like arm64,\n // we still need to use the 7-Zip executable for the host arch\n const resolvedArch = os.arch()\n fs.copyFileSync(path.join(vendorDirectory, `7z-${resolvedArch}.exe`), path.join(vendorDirectory, \"7z.exe\"))\n fs.copyFileSync(path.join(vendorDirectory, `7z-${resolvedArch}.dll`), path.join(vendorDirectory, \"7z.dll\"))\n }\n\n private async createNuspecTemplateWithProjectUrl() {\n const templatePath = path.resolve(import.meta.dirname, \"..\", \"template.nuspectemplate\")\n const projectUrl = await this.packager.appInfo.computePackageUrl()\n if (projectUrl != null) {\n const nuspecTemplate = await this.packager.tempDirManager.getTempFile({ prefix: \"template\", suffix: \".nuspectemplate\" })\n let templateContent = await fs.promises.readFile(templatePath, \"utf8\")\n const searchString = \"<copyright><%- copyright %></copyright>\"\n templateContent = templateContent.replace(searchString, `${searchString}\\n <projectUrl>${projectUrl}</projectUrl>`)\n await fs.promises.writeFile(nuspecTemplate, templateContent)\n return nuspecTemplate\n }\n return templatePath\n }\n\n async computeEffectiveDistOptions(appDirectory: string, outputDirectory: string, setupFile: string): Promise<SquirrelOptions> {\n const packager = this.packager\n let iconUrl = this.options.iconUrl\n if (iconUrl == null) {\n const info = await packager.repositoryInfo\n if (info != null) {\n iconUrl = `https://github.com/${info.user}/${info.project}/blob/master/${packager.relativeBuildResourcesDirname}/icon.ico?raw=true`\n }\n\n if (iconUrl == null) {\n throw new InvalidConfigurationError(\"squirrelWindows.iconUrl is not specified, please see https://www.electron.build/squirrel-windows#SquirrelWindowsOptions-iconUrl\")\n }\n }\n\n checkConflictingOptions(this.options)\n const appInfo = packager.appInfo\n const options: SquirrelOptions = {\n appDirectory: appDirectory,\n outputDirectory: outputDirectory,\n name: this.options.useAppIdAsId ? appInfo.id : this.appName,\n title: appInfo.productName || appInfo.name,\n version: appInfo.version,\n description: appInfo.description,\n exe: `${this.exeName}.exe`,\n authors: appInfo.companyName || \"\",\n nuspecTemplate: await this.createNuspecTemplateWithProjectUrl(),\n iconUrl,\n copyright: appInfo.copyright,\n noMsi: !this.options.msi,\n usePackageJson: false,\n }\n\n options.vendorDirectory = await this.prepareSignedVendorDirectory()\n this.select7zipArch(options.vendorDirectory)\n options.fixUpPaths = true\n options.setupExe = setupFile\n if (this.options.msi) {\n options.setupMsi = setupFile.replace(\".exe\", \".msi\")\n }\n\n if (isEmptyOrSpaces(options.description)) {\n options.description = this.options.name || appInfo.productName\n }\n\n if (options.remoteToken == null) {\n options.remoteToken = process.env.GH_TOKEN || process.env.GITHUB_TOKEN\n }\n\n if (this.options.remoteReleases === true) {\n const info = await packager.repositoryInfo\n if (info == null) {\n log.warn(\"remoteReleases set to true, but cannot get repository info\")\n } else {\n options.remoteReleases = `https://github.com/${info.user}/${info.project}`\n log.info({ remoteReleases: options.remoteReleases }, `remoteReleases is set`)\n }\n } else if (typeof this.options.remoteReleases === \"string\" && !isEmptyOrSpaces(this.options.remoteReleases)) {\n options.remoteReleases = this.options.remoteReleases\n }\n\n if (this.options.loadingGif) {\n options.loadingGif = path.resolve(packager.projectDir, this.options.loadingGif)\n } else {\n const resourceList = await packager.resourceList\n if (resourceList.includes(\"install-spinner.gif\")) {\n options.loadingGif = path.join(packager.buildResourcesDir, \"install-spinner.gif\")\n }\n }\n\n return options\n }\n}\n\nfunction checkConflictingOptions(options: any) {\n for (const name of [\"outputDirectory\", \"appDirectory\", \"exe\", \"fixUpPaths\", \"usePackageJson\", \"extraFileSpecs\", \"extraMetadataSpecs\", \"skipUpdateIcon\", \"setupExe\"]) {\n if (name in options) {\n throw new InvalidConfigurationError(`Option ${name} is ignored, do not specify it.`)\n }\n }\n\n const msi = options.msi\n if (msi != null && typeof msi !== \"boolean\") {\n throw new InvalidConfigurationError(`msi expected to be boolean value, but string '\"${msi}\"' was specified`)\n }\n}\n"]}
1
+ {"version":3,"file":"SquirrelWindowsTarget.js","sourceRoot":"","sources":["../src/SquirrelWindowsTarget.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arch, getArchSuffix, SquirrelWindowsOptions, Target, WinPackager } from \"app-builder-lib\"\nimport { getRceditBundle, withToolsetLock, WineVmManager } from \"app-builder-lib/internal\"\nimport { InvalidConfigurationError, isEmptyOrSpaces, log } from \"builder-util\"\nimport { sanitizeFileName } from \"builder-util/internal\"\nimport * as fs from \"fs\"\nimport * as os from \"os\"\nimport * as path from \"path\"\nimport { getSquirrelToolsetPath, getWixToolsetPath } from \"./toolset.js\"\nimport { InstallerOptions, convertVersion, createWindowsInstaller } from \"./windowsInstaller.js\"\n\nexport default class SquirrelWindowsTarget extends Target {\n readonly options: SquirrelWindowsOptions\n\n isAsyncSupported = false\n\n constructor(\n private readonly packager: WinPackager,\n readonly outDir: string\n ) {\n super(\"squirrel\")\n this.options = packager.getOptionsForTarget<SquirrelWindowsOptions>(\"squirrelWindows\")\n }\n\n private async prepareSignedVendorDirectory(): Promise<string> {\n const tmpVendorDirectory = await this.packager.tempDirManager.createTempDir({ prefix: \"squirrel-windows-vendor\" })\n\n // The vendor toolset comes from the maintained squirrel.windows bundle. Pin a version or supply a\n // custom/local bundle (e.g. for air-gapped builds) via `toolsets.squirrel` (a ToolsetCustom object).\n const squirrelToolset = await getSquirrelToolsetPath(this.packager.config.toolsets?.squirrel, this.packager.buildResourcesDir)\n await fs.promises.cp(path.join(squirrelToolset, \"electron-winstaller\", \"vendor\"), tmpVendorDirectory, { recursive: true })\n\n // Both Squirrel.exe and Squirrel-Mono.exe shell out to rcedit.exe (via setPEVersionInfoAndIcon)\n // during --releasify to stamp version info and the app icon into Setup.exe, so rcedit must live in\n // the vendor dir on every host — on non-Windows it runs under wine alongside the other Win32 vendor\n // exes (Setup.exe, StubExecutable.exe, …). The bundle omits rcedit, so resolve it from the\n // win-codesign toolset, which already versions and caches it across platforms.\n //\n // getRceditBundle honors the user's `toolsets.winCodeSign` selection, so users retain a bypass if a\n // newer toolset regresses: `\"0.0.0\"` falls back to the legacy winCodeSign-2.6.0 rcedit, a custom\n // toolset object uses their own rcedit, and the default (unset/\"latest\") pulls rcedit-windows-2_0_0.\n const rcedit = await getRceditBundle(this.packager.config.toolsets?.winCodeSign, this.packager.buildResourcesDir)\n // Pick rcedit by host arch (x64 for x64/arm64, x86 only for ia32). On non-Windows it runs under wine:\n // the 32-bit build fails on arm64 macOS even under Rosetta (which translates x64, not x86), so the x64\n // build is required there.\n const rceditExe = os.arch() === \"ia32\" ? rcedit.x86 : rcedit.x64\n await fs.promises.copyFile(rceditExe, path.join(tmpVendorDirectory, \"rcedit.exe\"))\n\n // When building an MSI, Squirrel's createMsiPackage runs candle.exe/light.exe from the vendor dir and\n // reads template.wxs there. The bundle ships neither, so merge the shared WiX toolset (the same\n // candle/light electron-builder's MSI target uses) into the vendor dir, plus the Squirrel MSI template\n // (authored against the v4 namespace this transitional WiX 4 requires).\n if (this.options.msi) {\n const wixToolset = await getWixToolsetPath()\n await fs.promises.cp(wixToolset, tmpVendorDirectory, { recursive: true })\n await fs.promises.copyFile(path.resolve(import.meta.dirname, \"..\", \"template.wxs\"), path.join(tmpVendorDirectory, \"template.wxs\"))\n }\n\n // Squirrel.exe is the core updater binary the bundle always ships; a missing one means a broken\n // vendor toolset. Fail loudly rather than skipping signing — skipping would produce a broken\n // installer and bypass the forceCodeSigning enforcement inside signIf (its awaited promise rejects\n // when the file can't be signed and forceCodeSigning is set).\n const files = await fs.promises.readdir(tmpVendorDirectory)\n if (!files.includes(\"Squirrel.exe\")) {\n throw new Error(`Squirrel.exe not found in vendor directory: ${tmpVendorDirectory}`)\n }\n const squirrelExePath = path.join(tmpVendorDirectory, \"Squirrel.exe\")\n log.debug({ file: squirrelExePath }, \"signing vendor executable\")\n await this.packager.signIf(squirrelExePath)\n return tmpVendorDirectory\n }\n\n private assertShellSafePath(filePath: string, description: string): void {\n if (/[\\r\\n\\0`$;&|<>]/.test(filePath)) {\n throw new InvalidConfigurationError(`${description} contains unsafe shell characters: ${filePath}`)\n }\n }\n\n private async ensurePathInside(baseDir: string, targetPath: string, description: string): Promise<string> {\n const resolvedBaseDir = path.resolve(baseDir)\n const resolvedTargetPath = path.resolve(targetPath)\n\n let canonicalBaseDir = resolvedBaseDir\n let canonicalTargetPath = resolvedTargetPath\n\n try {\n canonicalBaseDir = await fs.promises.realpath(resolvedBaseDir)\n } catch {\n canonicalBaseDir = resolvedBaseDir\n }\n\n try {\n canonicalTargetPath = await fs.promises.realpath(resolvedTargetPath)\n } catch {\n // Target may not exist yet; resolve the parent to handle symlinks/junctions consistently\n try {\n const resolvedTargetParent = path.dirname(resolvedTargetPath)\n const canonicalTargetParent = await fs.promises.realpath(resolvedTargetParent)\n const relativeFromResolvedParent = path.relative(resolvedTargetParent, resolvedTargetPath)\n if (\n isEmptyOrSpaces(relativeFromResolvedParent) ||\n path.isAbsolute(relativeFromResolvedParent) ||\n relativeFromResolvedParent.split(path.sep).includes(\"..\") ||\n /[\\0\\r\\n]/.test(relativeFromResolvedParent)\n ) {\n throw new InvalidConfigurationError(`${description} contains invalid path segments`)\n }\n canonicalTargetPath = path.resolve(canonicalTargetParent, relativeFromResolvedParent)\n } catch (e: unknown) {\n // Only fall back for filesystem errors (target parent not found, permission, etc.).\n // Validation errors must propagate so callers get an actionable message.\n if (e instanceof InvalidConfigurationError) {\n throw e\n }\n canonicalTargetPath = resolvedTargetPath\n }\n }\n\n const relativePath = path.relative(canonicalBaseDir, canonicalTargetPath)\n if (relativePath.startsWith(\"..\") || path.isAbsolute(relativePath)) {\n throw new InvalidConfigurationError(`${description} must be inside ${canonicalBaseDir}`)\n }\n this.assertShellSafePath(canonicalTargetPath, description)\n return canonicalTargetPath\n }\n\n private async generateStubExecutableExe(appOutDir: string, vendorDir: string) {\n if (!path.isAbsolute(appOutDir) || !path.isAbsolute(vendorDir)) {\n throw new InvalidConfigurationError(\"appOutDir and vendorDir must be absolute paths\")\n }\n\n const files = await fs.promises.readdir(appOutDir, { withFileTypes: true })\n const appExe = files.find(f => f.name === `${this.exeName}.exe`)\n if (!appExe) {\n throw new Error(`App executable not found in app directory: ${appOutDir}`)\n }\n\n const filePath = await this.ensurePathInside(appOutDir, path.join(appOutDir, appExe.name), \"App executable path\")\n const stubExePath = await this.ensurePathInside(appOutDir, path.join(appOutDir, `${this.exeName}_ExecutionStub.exe`), \"Stub executable path\")\n const stubExecutableSource = await this.ensurePathInside(vendorDir, path.join(vendorDir, \"StubExecutable.exe\"), \"Stub executable source\")\n const writeZipToSetupExe = await this.ensurePathInside(vendorDir, path.join(vendorDir, \"WriteZipToSetup.exe\"), \"WriteZipToSetup executable\")\n\n await fs.promises.copyFile(stubExecutableSource, stubExePath)\n const wineVm = new WineVmManager(this.packager.config.toolsets?.wine, this.packager.buildResourcesDir)\n await wineVm.exec(writeZipToSetupExe, [\"--copy-stub-resources\", filePath, stubExePath])\n await this.packager.signIf(stubExePath)\n log.debug({ file: filePath }, \"signing app executable\")\n await this.packager.signIf(filePath)\n }\n\n async build(appOutDir: string, arch: Arch) {\n const packager = this.packager\n const version = packager.appInfo.version\n const sanitizedName = sanitizeFileName(this.appName)\n\n const setupFile = packager.expandArtifactNamePattern(this.options, \"exe\", arch, \"${productName} Setup ${version}.${ext}\")\n const installerOutDir = path.join(this.outDir, `squirrel-windows${getArchSuffix(arch)}`)\n const artifactPath = path.join(installerOutDir, setupFile)\n const msiArtifactPath = path.join(installerOutDir, packager.expandArtifactNamePattern(this.options, \"msi\", arch, \"${productName} Setup ${version}.${ext}\"))\n\n this.buildQueueManager.add(async () => {\n await packager.emitArtifactBuildStarted({\n targetPresentableName: \"Squirrel.Windows\",\n file: artifactPath,\n arch,\n })\n const distOptions = await this.computeEffectiveDistOptions(appOutDir, installerOutDir, setupFile)\n await this.generateStubExecutableExe(appOutDir, distOptions.vendorDirectory)\n await withToolsetLock(() => createWindowsInstaller(distOptions))\n\n await packager.signAndEditResources(artifactPath, arch, installerOutDir)\n\n if (this.options.msi) {\n await packager.signIf(msiArtifactPath)\n }\n\n const safeArtifactName = (ext: string) => `${sanitizedName}-Setup-${version}${getArchSuffix(arch)}.${ext}`\n\n await packager.emitArtifactBuildCompleted({\n file: artifactPath,\n target: this,\n arch,\n safeArtifactName: safeArtifactName(\"exe\"),\n packager: this.packager,\n })\n\n if (this.options.msi) {\n await packager.emitArtifactCreated({\n file: msiArtifactPath,\n target: this,\n arch,\n safeArtifactName: safeArtifactName(\"msi\"),\n packager: this.packager,\n })\n }\n\n const packagePrefix = `${this.appName}-${convertVersion(version)}-`\n await packager.emitArtifactCreated({\n file: path.join(installerOutDir, `${packagePrefix}full.nupkg`),\n target: this,\n arch,\n packager,\n })\n if (distOptions.remoteReleases != null) {\n await packager.emitArtifactCreated({\n file: path.join(installerOutDir, `${packagePrefix}delta.nupkg`),\n target: this,\n arch,\n packager,\n })\n }\n\n await packager.emitArtifactCreated({\n file: path.join(installerOutDir, \"RELEASES\"),\n target: this,\n arch,\n packager,\n })\n })\n return Promise.resolve()\n }\n\n private get appName() {\n return this.options.name || this.packager.appInfo.name\n }\n\n private get exeName() {\n const name = this.packager.appInfo.productFilename || this.options.name || this.packager.appInfo.productName\n return sanitizeFileName(name)\n }\n\n private select7zipArch(vendorDirectory: string) {\n // https://github.com/electron/windows-installer/blob/main/script/select-7z-arch.js\n // Even if we're cross-compiling for a different arch like arm64,\n // we still need to use the 7-Zip executable for the host arch.\n // When arch-specific variants aren't present (vendor bundle ships a pre-selected 7z.exe),\n // skip the copy — the bundle's 7z.exe is already correct.\n const resolvedArch = os.arch()\n const archExe = path.join(vendorDirectory, `7z-${resolvedArch}.exe`)\n const archDll = path.join(vendorDirectory, `7z-${resolvedArch}.dll`)\n if (fs.existsSync(archExe)) {\n fs.copyFileSync(archExe, path.join(vendorDirectory, \"7z.exe\"))\n }\n if (fs.existsSync(archDll)) {\n fs.copyFileSync(archDll, path.join(vendorDirectory, \"7z.dll\"))\n }\n }\n\n private async createNuspecTemplateWithProjectUrl() {\n const templatePath = path.resolve(import.meta.dirname, \"..\", \"template.nuspectemplate\")\n const projectUrl = await this.packager.appInfo.computePackageUrl()\n if (projectUrl != null) {\n const nuspecTemplate = await this.packager.tempDirManager.getTempFile({ prefix: \"template\", suffix: \".nuspectemplate\" })\n let templateContent = await fs.promises.readFile(templatePath, \"utf8\")\n const searchString = \"<copyright><%- copyright %></copyright>\"\n templateContent = templateContent.replace(searchString, `${searchString}\\n <projectUrl>${projectUrl}</projectUrl>`)\n await fs.promises.writeFile(nuspecTemplate, templateContent)\n return nuspecTemplate\n }\n return templatePath\n }\n\n async computeEffectiveDistOptions(appDirectory: string, outputDirectory: string, setupFile: string): Promise<InstallerOptions> {\n const packager = this.packager\n let iconUrl = this.options.iconUrl\n if (iconUrl == null) {\n const info = await packager.repositoryInfo\n if (info != null) {\n iconUrl = `https://github.com/${info.user}/${info.project}/blob/master/${packager.relativeBuildResourcesDirname}/icon.ico?raw=true`\n }\n\n if (iconUrl == null) {\n throw new InvalidConfigurationError(\"squirrelWindows.iconUrl is not specified, please see https://www.electron.build/squirrel-windows#SquirrelWindowsOptions-iconUrl\")\n }\n }\n\n normalizeSquirrelOptions(this.options)\n const appInfo = packager.appInfo\n\n const description = isEmptyOrSpaces(appInfo.description) ? this.options.name || appInfo.productName : appInfo.description\n\n let remoteReleases: string | undefined\n if (this.options.remoteReleases === true) {\n const info = await packager.repositoryInfo\n if (info == null) {\n log.warn(\"remoteReleases set to true, but cannot get repository info\")\n } else {\n remoteReleases = `https://github.com/${info.user}/${info.project}`\n log.info({ remoteReleases }, `remoteReleases is set`)\n }\n } else if (typeof this.options.remoteReleases === \"string\" && !isEmptyOrSpaces(this.options.remoteReleases)) {\n remoteReleases = this.options.remoteReleases\n }\n\n let loadingGif: string\n if (this.options.loadingGif) {\n loadingGif = path.resolve(packager.projectDir, this.options.loadingGif)\n } else {\n // User-supplied buildResources gif wins; otherwise fall back to the bundled default spinner —\n // parity with electron-winstaller, which always supplied resources/install-spinner.gif when none\n // was configured (a fresh-install progress animation; never omitted).\n loadingGif = (await packager.getResource(undefined, \"install-spinner.gif\")) ?? path.resolve(import.meta.dirname, \"..\", \"install-spinner.gif\")\n }\n\n const vendorDirectory = await this.prepareSignedVendorDirectory()\n this.select7zipArch(vendorDirectory)\n\n return {\n appDirectory,\n outputDirectory,\n vendorDirectory,\n name: this.options.useAppIdAsId ? appInfo.id : this.appName,\n title: appInfo.productName || appInfo.name,\n version: appInfo.version,\n description,\n exe: `${this.exeName}.exe`,\n authors: appInfo.companyName || \"\",\n nuspecTemplate: await this.createNuspecTemplateWithProjectUrl(),\n iconUrl,\n copyright: appInfo.copyright,\n msi: this.options.msi,\n fixUpPaths: true,\n setupExe: setupFile,\n setupMsi: this.options.msi ? setupFile.replace(/\\.exe$/i, \".msi\") : undefined,\n loadingGif,\n remoteReleases,\n remoteToken: firstNonBlank(this.options.remoteToken, process.env.GH_TOKEN, process.env.GITHUB_TOKEN),\n createTempDir: opts => this.packager.tempDirManager.createTempDir(opts),\n }\n }\n}\n\n// `remoteToken: \"\"` (or whitespace) in the config counts as unset: fall through to the environment\n// instead of shadowing GH_TOKEN/GITHUB_TOKEN with a value SyncReleases would drop anyway.\nfunction firstNonBlank(...values: Array<string | null | undefined>): string | undefined {\n const value = values.find(it => !isEmptyOrSpaces(it))\n return value == null ? undefined : value.trim()\n}\n\nfunction normalizeSquirrelOptions(options: any) {\n for (const name of [\"outputDirectory\", \"appDirectory\", \"exe\", \"fixUpPaths\", \"usePackageJson\", \"extraFileSpecs\", \"extraMetadataSpecs\", \"skipUpdateIcon\", \"setupExe\"]) {\n if (name in options) {\n throw new InvalidConfigurationError(`Option ${name} is ignored, do not specify it.`)\n }\n }\n\n const msi = options.msi\n if (msi != null && typeof msi !== \"boolean\") {\n throw new InvalidConfigurationError(`msi expected to be boolean value, but string '\"${msi}\"' was specified`)\n }\n}\n"]}
@@ -0,0 +1,22 @@
1
+ import { ToolsetConfig } from "app-builder-lib";
2
+ export declare const squirrelWindowsChecksums: {
3
+ readonly "1.1.1": {
4
+ readonly "squirrel.windows-2.0.1-patched.zip": "77cc2c451639c3b0bd68fde67111f726a236e6750d15f521c79e606fd7119e72";
5
+ };
6
+ };
7
+ /**
8
+ * Returns the path to the squirrel.windows toolset directory. It contains an
9
+ * `electron-winstaller/vendor/` subtree with the Squirrel vendor executables (Squirrel.exe,
10
+ * nuget.exe, SyncReleases.exe, 7z, …).
11
+ *
12
+ * Honors `toolsets.squirrel`: a pinned version (or unset / `"latest"`) downloads the maintained
13
+ * electron-builder-binaries bundle; a {@link ToolsetCustom} object supplies a custom or local bundle
14
+ * (which must mirror the same `electron-winstaller/vendor/` layout).
15
+ */
16
+ export declare function getSquirrelToolsetPath(toolset: ToolsetConfig["squirrel"], resourcesDir: string): Promise<string>;
17
+ /**
18
+ * Returns the path to the WiX toolset directory (candle.exe, light.exe, WixNetFxExtension.dll, …).
19
+ * Only needed when building an MSI.
20
+ */
21
+ export declare function getWixToolsetPath(): Promise<string>;
22
+ //# sourceMappingURL=toolset.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolset.d.ts","sourceRoot":"","sources":["../src/toolset.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAO/C,eAAO,MAAM,wBAAwB;;;;CAI3B,CAAA;AAEV;;;;;;;;GAQG;AACH,wBAAsB,sBAAsB,CAAC,OAAO,EAAE,aAAa,CAAC,UAAU,CAAC,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAoBtH;AAUD;;;GAGG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC,CAMzD"}
@@ -0,0 +1,56 @@
1
+ import { downloadBuilderToolset, getCustomToolsetPath, resolveToolsetVersion } from "app-builder-lib/internal";
2
+ import { InvalidConfigurationError } from "builder-util";
3
+ // Newest squirrel.windows bundle — selected when `toolsets.squirrel` is unset / null / "latest".
4
+ const SQUIRREL_LATEST = "1.1.1";
5
+ export const squirrelWindowsChecksums = {
6
+ "1.1.1": {
7
+ "squirrel.windows-2.0.1-patched.zip": "77cc2c451639c3b0bd68fde67111f726a236e6750d15f521c79e606fd7119e72",
8
+ },
9
+ };
10
+ /**
11
+ * Returns the path to the squirrel.windows toolset directory. It contains an
12
+ * `electron-winstaller/vendor/` subtree with the Squirrel vendor executables (Squirrel.exe,
13
+ * nuget.exe, SyncReleases.exe, 7z, …).
14
+ *
15
+ * Honors `toolsets.squirrel`: a pinned version (or unset / `"latest"`) downloads the maintained
16
+ * electron-builder-binaries bundle; a {@link ToolsetCustom} object supplies a custom or local bundle
17
+ * (which must mirror the same `electron-winstaller/vendor/` layout).
18
+ */
19
+ export async function getSquirrelToolsetPath(toolset, resourcesDir) {
20
+ if (typeof toolset === "object" && toolset != null) {
21
+ return getCustomToolsetPath(toolset, resourcesDir);
22
+ }
23
+ const version = resolveToolsetVersion(toolset, SQUIRREL_LATEST);
24
+ // The `toolsets.squirrel` type and scheme.json only admit known versions, but a programmatic config
25
+ // bypasses both. Never forward an unknown version: without a checksum entry the downloader would run
26
+ // with integrity verification disabled.
27
+ const checksums = squirrelWindowsChecksums[version];
28
+ if (checksums == null) {
29
+ throw new InvalidConfigurationError(`Unknown toolsets.squirrel version "${version}". Known versions: ${Object.keys(squirrelWindowsChecksums).join(", ")} (or "latest"). ` +
30
+ `To use a custom bundle, set toolsets.squirrel to a ToolsetCustom object (url + checksum) instead.`);
31
+ }
32
+ return downloadBuilderToolset({
33
+ releaseName: `squirrel.windows@${version}`,
34
+ filenameWithExt: "squirrel.windows-2.0.1-patched.zip",
35
+ checksums,
36
+ });
37
+ }
38
+ // Squirrel's createMsiPackage (msi: true) runs candle.exe/light.exe with `-ext WixNetFxExtension` from
39
+ // its own vendor dir. The squirrel.windows bundle omits the WiX toolchain, so reuse the shared WiX
40
+ // toolset (the same candle/light electron-builder's MSI target uses) and merge it into the vendor dir.
41
+ // This is a transitional WiX 4 (4.0.0.5512): it accepts the v3-style element structure but requires the
42
+ // v4 namespace, so template.wxs is authored against http://wixtoolset.org/schemas/v4/wxs.
43
+ const WIX_TOOLSET_FILE = "wix-4.0.0.5512.2.7z";
44
+ const WIX_TOOLSET_SHA256 = "fe677fcd837b18c9b912985d91636bbd8a1e800c3b3a6a841b6f96e89624e839";
45
+ /**
46
+ * Returns the path to the WiX toolset directory (candle.exe, light.exe, WixNetFxExtension.dll, …).
47
+ * Only needed when building an MSI.
48
+ */
49
+ export async function getWixToolsetPath() {
50
+ return downloadBuilderToolset({
51
+ releaseName: "wix-4.0.0.5512.2",
52
+ filenameWithExt: WIX_TOOLSET_FILE,
53
+ checksums: { [WIX_TOOLSET_FILE]: WIX_TOOLSET_SHA256 },
54
+ });
55
+ }
56
+ //# sourceMappingURL=toolset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolset.js","sourceRoot":"","sources":["../src/toolset.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAA;AAC9G,OAAO,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAA;AAExD,iGAAiG;AACjG,MAAM,eAAe,GAAG,OAAO,CAAA;AAE/B,MAAM,CAAC,MAAM,wBAAwB,GAAG;IACtC,OAAO,EAAE;QACP,oCAAoC,EAAE,kEAAkE;KACzG;CACO,CAAA;AAEV;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,OAAkC,EAAE,YAAoB;IACnG,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;QACnD,OAAO,oBAAoB,CAAC,OAAO,EAAE,YAAY,CAAC,CAAA;IACpD,CAAC;IACD,MAAM,OAAO,GAAG,qBAAqB,CAAC,OAAO,EAAE,eAAe,CAAC,CAAA;IAC/D,oGAAoG;IACpG,qGAAqG;IACrG,wCAAwC;IACxC,MAAM,SAAS,GAAI,wBAA4E,CAAC,OAAO,CAAC,CAAA;IACxG,IAAI,SAAS,IAAI,IAAI,EAAE,CAAC;QACtB,MAAM,IAAI,yBAAyB,CACjC,sCAAsC,OAAO,sBAAsB,MAAM,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,kBAAkB;YACnI,mGAAmG,CACtG,CAAA;IACH,CAAC;IACD,OAAO,sBAAsB,CAAC;QAC5B,WAAW,EAAE,oBAAoB,OAAO,EAAE;QAC1C,eAAe,EAAE,oCAAoC;QACrD,SAAS;KACV,CAAC,CAAA;AACJ,CAAC;AAED,uGAAuG;AACvG,mGAAmG;AACnG,uGAAuG;AACvG,wGAAwG;AACxG,0FAA0F;AAC1F,MAAM,gBAAgB,GAAG,qBAAqB,CAAA;AAC9C,MAAM,kBAAkB,GAAG,kEAAkE,CAAA;AAE7F;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,OAAO,sBAAsB,CAAC;QAC5B,WAAW,EAAE,kBAAkB;QAC/B,eAAe,EAAE,gBAAgB;QACjC,SAAS,EAAE,EAAE,CAAC,gBAAgB,CAAC,EAAE,kBAAkB,EAAE;KACtD,CAAC,CAAA;AACJ,CAAC","sourcesContent":["import { ToolsetConfig } from \"app-builder-lib\"\nimport { downloadBuilderToolset, getCustomToolsetPath, resolveToolsetVersion } from \"app-builder-lib/internal\"\nimport { InvalidConfigurationError } from \"builder-util\"\n\n// Newest squirrel.windows bundle — selected when `toolsets.squirrel` is unset / null / \"latest\".\nconst SQUIRREL_LATEST = \"1.1.1\"\n\nexport const squirrelWindowsChecksums = {\n \"1.1.1\": {\n \"squirrel.windows-2.0.1-patched.zip\": \"77cc2c451639c3b0bd68fde67111f726a236e6750d15f521c79e606fd7119e72\",\n },\n} as const\n\n/**\n * Returns the path to the squirrel.windows toolset directory. It contains an\n * `electron-winstaller/vendor/` subtree with the Squirrel vendor executables (Squirrel.exe,\n * nuget.exe, SyncReleases.exe, 7z, …).\n *\n * Honors `toolsets.squirrel`: a pinned version (or unset / `\"latest\"`) downloads the maintained\n * electron-builder-binaries bundle; a {@link ToolsetCustom} object supplies a custom or local bundle\n * (which must mirror the same `electron-winstaller/vendor/` layout).\n */\nexport async function getSquirrelToolsetPath(toolset: ToolsetConfig[\"squirrel\"], resourcesDir: string): Promise<string> {\n if (typeof toolset === \"object\" && toolset != null) {\n return getCustomToolsetPath(toolset, resourcesDir)\n }\n const version = resolveToolsetVersion(toolset, SQUIRREL_LATEST)\n // The `toolsets.squirrel` type and scheme.json only admit known versions, but a programmatic config\n // bypasses both. Never forward an unknown version: without a checksum entry the downloader would run\n // with integrity verification disabled.\n const checksums = (squirrelWindowsChecksums as Partial<Record<string, Record<string, string>>>)[version]\n if (checksums == null) {\n throw new InvalidConfigurationError(\n `Unknown toolsets.squirrel version \"${version}\". Known versions: ${Object.keys(squirrelWindowsChecksums).join(\", \")} (or \"latest\"). ` +\n `To use a custom bundle, set toolsets.squirrel to a ToolsetCustom object (url + checksum) instead.`\n )\n }\n return downloadBuilderToolset({\n releaseName: `squirrel.windows@${version}`,\n filenameWithExt: \"squirrel.windows-2.0.1-patched.zip\",\n checksums,\n })\n}\n\n// Squirrel's createMsiPackage (msi: true) runs candle.exe/light.exe with `-ext WixNetFxExtension` from\n// its own vendor dir. The squirrel.windows bundle omits the WiX toolchain, so reuse the shared WiX\n// toolset (the same candle/light electron-builder's MSI target uses) and merge it into the vendor dir.\n// This is a transitional WiX 4 (4.0.0.5512): it accepts the v3-style element structure but requires the\n// v4 namespace, so template.wxs is authored against http://wixtoolset.org/schemas/v4/wxs.\nconst WIX_TOOLSET_FILE = \"wix-4.0.0.5512.2.7z\"\nconst WIX_TOOLSET_SHA256 = \"fe677fcd837b18c9b912985d91636bbd8a1e800c3b3a6a841b6f96e89624e839\"\n\n/**\n * Returns the path to the WiX toolset directory (candle.exe, light.exe, WixNetFxExtension.dll, …).\n * Only needed when building an MSI.\n */\nexport async function getWixToolsetPath(): Promise<string> {\n return downloadBuilderToolset({\n releaseName: \"wix-4.0.0.5512.2\",\n filenameWithExt: WIX_TOOLSET_FILE,\n checksums: { [WIX_TOOLSET_FILE]: WIX_TOOLSET_SHA256 },\n })\n}\n"]}
@@ -0,0 +1,31 @@
1
+ export declare function convertVersion(version: string): string;
2
+ export declare function escapeXml(value: string): string;
3
+ export declare function renderNuspecTemplate(templateContent: string, vars: Record<string, string>): string;
4
+ export declare function buildAdditionalFilesXml(appDirectory: string): Promise<string>;
5
+ export interface InstallerOptions {
6
+ appDirectory: string;
7
+ outputDirectory: string;
8
+ vendorDirectory: string;
9
+ name: string;
10
+ title?: string | null;
11
+ version: string;
12
+ description?: string | null;
13
+ exe: string;
14
+ authors: string;
15
+ owners?: string | null;
16
+ iconUrl?: string | null;
17
+ copyright?: string | null;
18
+ nuspecTemplate: string;
19
+ loadingGif?: string | null;
20
+ msi?: boolean;
21
+ remoteReleases?: string | null;
22
+ remoteToken?: string | null;
23
+ setupExe?: string | null;
24
+ setupMsi?: string | null;
25
+ fixUpPaths?: boolean;
26
+ createTempDir: (options: {
27
+ prefix: string;
28
+ }) => Promise<string>;
29
+ }
30
+ export declare function createWindowsInstaller(options: InstallerOptions): Promise<void>;
31
+ //# sourceMappingURL=windowsInstaller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windowsInstaller.d.ts","sourceRoot":"","sources":["../src/windowsInstaller.ts"],"names":[],"mappings":"AAIA,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAItD;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,wBAAgB,oBAAoB,CAAC,eAAe,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAElG;AAED,wBAAsB,uBAAuB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAiBnF;AAED,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,MAAM,CAAA;IACpB,eAAe,EAAE,MAAM,CAAA;IACvB,eAAe,EAAE,MAAM,CAAA;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,cAAc,EAAE,MAAM,CAAA;IACtB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,GAAG,CAAC,EAAE,OAAO,CAAA;IACb,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,aAAa,EAAE,CAAC,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;CAChE;AAED,wBAAsB,sBAAsB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoGrF"}
@@ -0,0 +1,108 @@
1
+ import { exec, exists, log } from "builder-util";
2
+ import * as fs from "fs/promises";
3
+ import * as path from "path";
4
+ export function convertVersion(version) {
5
+ const parts = version.split("+")[0].split("-");
6
+ const mainVersion = parts.shift();
7
+ return parts.length > 0 ? [mainVersion, parts.join("-").replace(/\./g, "")].join("-") : mainVersion;
8
+ }
9
+ export function escapeXml(value) {
10
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
11
+ }
12
+ export function renderNuspecTemplate(templateContent, vars) {
13
+ return Object.entries(vars).reduce((t, [k, v]) => t.split(`<%- ${k} %>`).join(v), templateContent);
14
+ }
15
+ export async function buildAdditionalFilesXml(appDirectory) {
16
+ const checks = [
17
+ { rel: "swiftshader", src: "swiftshader\\**", target: "lib\\net45\\swiftshader" },
18
+ { rel: "vk_swiftshader_icd.json", src: "vk_swiftshader_icd.json", target: "lib\\net45" },
19
+ ];
20
+ const lines = [];
21
+ for (const { rel, src, target } of checks) {
22
+ try {
23
+ await fs.access(path.join(appDirectory, rel));
24
+ lines.push(` <file src="${src}" target="${target}" />`);
25
+ }
26
+ catch (e) {
27
+ if (e?.code !== "ENOENT") {
28
+ throw e;
29
+ }
30
+ }
31
+ }
32
+ return lines.join("\n");
33
+ }
34
+ export async function createWindowsInstaller(options) {
35
+ const { appDirectory, outputDirectory, vendorDirectory, name, version, exe, nuspecTemplate, loadingGif, msi, remoteReleases, remoteToken, setupExe, setupMsi, fixUpPaths = false, createTempDir, } = options;
36
+ const useMono = process.platform !== "win32";
37
+ if (useMono) {
38
+ log.warn("building Squirrel.Windows on non-Windows requires mono in PATH; spawn will fail if it is missing");
39
+ }
40
+ // Squirrel.exe must live in the app directory so the nuspec can reference it
41
+ await fs.copyFile(path.join(vendorDirectory, "Squirrel.exe"), path.join(appDirectory, "Squirrel.exe"));
42
+ const nugetVersion = convertVersion(version);
43
+ const authors = options.authors || "";
44
+ const copyright = options.copyright || `Copyright © ${new Date().getFullYear()} ${authors}`;
45
+ const owners = options.owners || authors;
46
+ let additionalFilesXml = await buildAdditionalFilesXml(appDirectory);
47
+ let templateContent = await fs.readFile(nuspecTemplate, "utf8");
48
+ if (path.sep === "/") {
49
+ templateContent = templateContent.replace(/\\/g, "/");
50
+ additionalFilesXml = additionalFilesXml.replace(/\\/g, "/");
51
+ }
52
+ const nuspecContent = renderNuspecTemplate(templateContent, {
53
+ name: escapeXml(name),
54
+ title: escapeXml(options.title || name),
55
+ version: escapeXml(nugetVersion),
56
+ authors: escapeXml(authors),
57
+ owners: escapeXml(owners),
58
+ iconUrl: escapeXml(options.iconUrl || ""),
59
+ description: escapeXml(options.description || options.title || name),
60
+ copyright: escapeXml(copyright),
61
+ exe: escapeXml(exe),
62
+ additionalFilesXml,
63
+ });
64
+ const nugetOutput = await createTempDir({ prefix: "squirrel-nuget-" });
65
+ const nuspecPath = path.join(nugetOutput, `${name}.nuspec`);
66
+ await fs.writeFile(nuspecPath, nuspecContent);
67
+ const nugetExe = path.join(vendorDirectory, "nuget.exe");
68
+ const nugetArgs = ["pack", nuspecPath, "-BasePath", appDirectory, "-OutputDirectory", nugetOutput, "-NoDefaultExcludes"];
69
+ await (useMono ? exec("mono", [nugetExe, ...nugetArgs]) : exec(nugetExe, nugetArgs));
70
+ const nupkgPath = path.join(nugetOutput, `${name}.${nugetVersion}.nupkg`);
71
+ if (remoteReleases) {
72
+ const syncReleasesExe = path.join(vendorDirectory, "SyncReleases.exe");
73
+ const syncArgs = ["-u", remoteReleases, "-r", outputDirectory];
74
+ if (remoteToken) {
75
+ syncArgs.push("-t", remoteToken);
76
+ }
77
+ await (useMono ? exec("mono", [syncReleasesExe, ...syncArgs]) : exec(syncReleasesExe, syncArgs));
78
+ }
79
+ const releasifyArgs = ["--releasify", nupkgPath, "--releaseDir", outputDirectory];
80
+ if (loadingGif) {
81
+ releasifyArgs.push("--loadingGif", loadingGif);
82
+ }
83
+ if (!msi) {
84
+ releasifyArgs.push("--no-msi");
85
+ }
86
+ if (useMono) {
87
+ await exec("mono", [path.join(vendorDirectory, "Squirrel-Mono.exe"), ...releasifyArgs]);
88
+ }
89
+ else {
90
+ await exec(path.join(vendorDirectory, "Squirrel.exe"), releasifyArgs);
91
+ }
92
+ if (fixUpPaths) {
93
+ if (setupExe) {
94
+ await fs.rename(path.join(outputDirectory, "Setup.exe"), path.join(outputDirectory, setupExe));
95
+ }
96
+ if (setupMsi) {
97
+ // setupMsi is only set when MSI output was requested (msi: true), so releasify ran without
98
+ // --no-msi and Setup.msi must exist. A missing file here is a real failure, not an expected
99
+ // absence — surface it instead of silently dropping the artifact.
100
+ const setupMsiPath = path.join(outputDirectory, "Setup.msi");
101
+ if (!(await exists(setupMsiPath))) {
102
+ throw new Error(`MSI output was requested but Squirrel.Windows did not produce ${setupMsiPath}`);
103
+ }
104
+ await fs.rename(setupMsiPath, path.join(outputDirectory, setupMsi));
105
+ }
106
+ }
107
+ }
108
+ //# sourceMappingURL=windowsInstaller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windowsInstaller.js","sourceRoot":"","sources":["../src/windowsInstaller.ts"],"names":[],"mappings":"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","sourcesContent":["import { exec, exists, log } from \"builder-util\"\nimport * as fs from \"fs/promises\"\nimport * as path from \"path\"\n\nexport function convertVersion(version: string): string {\n const parts = version.split(\"+\")[0].split(\"-\")\n const mainVersion = parts.shift()\n return parts.length > 0 ? [mainVersion, parts.join(\"-\").replace(/\\./g, \"\")].join(\"-\") : mainVersion!\n}\n\nexport function escapeXml(value: string): string {\n return value.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\").replace(/\"/g, \"&quot;\").replace(/'/g, \"&apos;\")\n}\n\nexport function renderNuspecTemplate(templateContent: string, vars: Record<string, string>): string {\n return Object.entries(vars).reduce((t, [k, v]) => t.split(`<%- ${k} %>`).join(v), templateContent)\n}\n\nexport async function buildAdditionalFilesXml(appDirectory: string): Promise<string> {\n const checks: Array<{ rel: string; src: string; target: string }> = [\n { rel: \"swiftshader\", src: \"swiftshader\\\\**\", target: \"lib\\\\net45\\\\swiftshader\" },\n { rel: \"vk_swiftshader_icd.json\", src: \"vk_swiftshader_icd.json\", target: \"lib\\\\net45\" },\n ]\n const lines: string[] = []\n for (const { rel, src, target } of checks) {\n try {\n await fs.access(path.join(appDirectory, rel))\n lines.push(` <file src=\"${src}\" target=\"${target}\" />`)\n } catch (e: any) {\n if (e?.code !== \"ENOENT\") {\n throw e\n }\n }\n }\n return lines.join(\"\\n\")\n}\n\nexport interface InstallerOptions {\n appDirectory: string\n outputDirectory: string\n vendorDirectory: string\n name: string\n title?: string | null\n version: string\n description?: string | null\n exe: string\n authors: string\n owners?: string | null\n iconUrl?: string | null\n copyright?: string | null\n nuspecTemplate: string\n loadingGif?: string | null\n msi?: boolean\n remoteReleases?: string | null\n remoteToken?: string | null\n setupExe?: string | null\n setupMsi?: string | null\n fixUpPaths?: boolean\n createTempDir: (options: { prefix: string }) => Promise<string>\n}\n\nexport async function createWindowsInstaller(options: InstallerOptions): Promise<void> {\n const {\n appDirectory,\n outputDirectory,\n vendorDirectory,\n name,\n version,\n exe,\n nuspecTemplate,\n loadingGif,\n msi,\n remoteReleases,\n remoteToken,\n setupExe,\n setupMsi,\n fixUpPaths = false,\n createTempDir,\n } = options\n\n const useMono = process.platform !== \"win32\"\n if (useMono) {\n log.warn(\"building Squirrel.Windows on non-Windows requires mono in PATH; spawn will fail if it is missing\")\n }\n\n // Squirrel.exe must live in the app directory so the nuspec can reference it\n await fs.copyFile(path.join(vendorDirectory, \"Squirrel.exe\"), path.join(appDirectory, \"Squirrel.exe\"))\n\n const nugetVersion = convertVersion(version)\n const authors = options.authors || \"\"\n const copyright = options.copyright || `Copyright © ${new Date().getFullYear()} ${authors}`\n const owners = options.owners || authors\n let additionalFilesXml = await buildAdditionalFilesXml(appDirectory)\n\n let templateContent = await fs.readFile(nuspecTemplate, \"utf8\")\n if (path.sep === \"/\") {\n templateContent = templateContent.replace(/\\\\/g, \"/\")\n additionalFilesXml = additionalFilesXml.replace(/\\\\/g, \"/\")\n }\n\n const nuspecContent = renderNuspecTemplate(templateContent, {\n name: escapeXml(name),\n title: escapeXml(options.title || name),\n version: escapeXml(nugetVersion),\n authors: escapeXml(authors),\n owners: escapeXml(owners),\n iconUrl: escapeXml(options.iconUrl || \"\"),\n description: escapeXml(options.description || options.title || name),\n copyright: escapeXml(copyright),\n exe: escapeXml(exe),\n additionalFilesXml,\n })\n\n const nugetOutput = await createTempDir({ prefix: \"squirrel-nuget-\" })\n const nuspecPath = path.join(nugetOutput, `${name}.nuspec`)\n await fs.writeFile(nuspecPath, nuspecContent)\n\n const nugetExe = path.join(vendorDirectory, \"nuget.exe\")\n const nugetArgs = [\"pack\", nuspecPath, \"-BasePath\", appDirectory, \"-OutputDirectory\", nugetOutput, \"-NoDefaultExcludes\"]\n await (useMono ? exec(\"mono\", [nugetExe, ...nugetArgs]) : exec(nugetExe, nugetArgs))\n\n const nupkgPath = path.join(nugetOutput, `${name}.${nugetVersion}.nupkg`)\n\n if (remoteReleases) {\n const syncReleasesExe = path.join(vendorDirectory, \"SyncReleases.exe\")\n const syncArgs = [\"-u\", remoteReleases, \"-r\", outputDirectory]\n if (remoteToken) {\n syncArgs.push(\"-t\", remoteToken)\n }\n await (useMono ? exec(\"mono\", [syncReleasesExe, ...syncArgs]) : exec(syncReleasesExe, syncArgs))\n }\n\n const releasifyArgs = [\"--releasify\", nupkgPath, \"--releaseDir\", outputDirectory]\n if (loadingGif) {\n releasifyArgs.push(\"--loadingGif\", loadingGif)\n }\n if (!msi) {\n releasifyArgs.push(\"--no-msi\")\n }\n\n if (useMono) {\n await exec(\"mono\", [path.join(vendorDirectory, \"Squirrel-Mono.exe\"), ...releasifyArgs])\n } else {\n await exec(path.join(vendorDirectory, \"Squirrel.exe\"), releasifyArgs)\n }\n\n if (fixUpPaths) {\n if (setupExe) {\n await fs.rename(path.join(outputDirectory, \"Setup.exe\"), path.join(outputDirectory, setupExe))\n }\n if (setupMsi) {\n // setupMsi is only set when MSI output was requested (msi: true), so releasify ran without\n // --no-msi and Setup.msi must exist. A missing file here is a real failure, not an expected\n // absence — surface it instead of silently dropping the artifact.\n const setupMsiPath = path.join(outputDirectory, \"Setup.msi\")\n if (!(await exists(setupMsiPath))) {\n throw new Error(`MSI output was requested but Squirrel.Windows did not produce ${setupMsiPath}`)\n }\n await fs.rename(setupMsiPath, path.join(outputDirectory, setupMsi))\n }\n }\n}\n"]}
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "electron-builder-squirrel-windows",
3
- "version": "27.0.0-alpha.8",
3
+ "version": "27.0.0-alpha.9",
4
4
  "type": "module",
5
5
  "main": "./dist/SquirrelWindowsTarget.js",
6
6
  "exports": {
@@ -26,19 +26,16 @@
26
26
  "homepage": "https://github.com/electron-userland/electron-builder",
27
27
  "files": [
28
28
  "dist",
29
- "template.nuspectemplate"
29
+ "template.nuspectemplate",
30
+ "template.wxs",
31
+ "install-spinner.gif"
30
32
  ],
31
33
  "engines": {
32
34
  "node": ">=22.12.0"
33
35
  },
34
36
  "dependencies": {
35
- "electron-winstaller": "5.4.0",
36
- "app-builder-lib": "27.0.0-alpha.8",
37
- "builder-util": "27.0.0-alpha.8"
38
- },
39
- "devDependencies": {
40
- "@types/archiver": "5.3.1",
41
- "@types/fs-extra": "9.0.13"
37
+ "app-builder-lib": "27.0.0-alpha.9",
38
+ "builder-util": "27.0.0-alpha.9"
42
39
  },
43
40
  "types": "./dist/SquirrelWindowsTarget.d.ts",
44
41
  "scripts": {
@@ -25,8 +25,6 @@
25
25
  <file src="LICENSE.electron.txt" target="lib\net45\LICENSE.electron.txt" />
26
26
  <file src="LICENSES.chromium.html" target="lib\net45\LICENSES.chromium.html" />
27
27
  <file src="<%- exe %>" target="lib\net45\<%- exe %>" />
28
- <% additionalFiles.forEach(function(f) { %>
29
- <file src="<%- f.src %>" target="<%- f.target %>" />
30
- <% }); %>
28
+ <%- additionalFilesXml %>
31
29
  </files>
32
30
  </package>
package/template.wxs ADDED
@@ -0,0 +1,39 @@
1
+ <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
2
+ <Product Id="*" Name="{{Title}} Deployment Tool" Language="1033" Codepage="{{Codepage}}" Version="!(bind.FileVersion.{{Id}}.exe)" UpgradeCode="{{IdAsGuid1}}" Manufacturer="{{Author}}">
3
+
4
+ <Package Description="This package installs a deployment tool for {{Title}}. Not {{Title}} itself. {{Title}} is only installed if a user logs into the machine." InstallScope="perMachine" Comments="Comments" InstallerVersion="200" Compressed="yes" Platform="{{Platform}}"/>
5
+ <MajorUpgrade AllowSameVersionUpgrades="yes" DowngradeErrorMessage="A later version of this product is already installed. Setup will now exit."/>
6
+ <Media Id="1" Cabinet="contents.cab" EmbedCab="yes" CompressionLevel="high"/>
7
+
8
+ <PropertyRef Id="NETFRAMEWORK45" />
9
+
10
+ <Condition Message="This application requires .NET Framework 4.5 or higher. Please install the latest .NET Framework then run this installer again.">
11
+ <![CDATA[Installed OR NETFRAMEWORK45]]>
12
+ </Condition>
13
+
14
+ <Directory Id="TARGETDIR" Name="SourceDir">
15
+ <Directory Id="{{ProgramFilesFolder}}">
16
+ <Directory Id="APPLICATIONROOTDIRECTORY" Name="{{Title}} Deployment" />
17
+ </Directory>
18
+ </Directory>
19
+
20
+ <DirectoryRef Id="APPLICATIONROOTDIRECTORY">
21
+ <Component Id="{{Id}}.exe" Guid="{{IdAsGuid2}}" Win64="{{Win64YesNo}}">
22
+ <File Id="{{Id}}.exe" Name="{{Id}}DeploymentTool.exe" Source="./Setup.exe" KeyPath="yes"/>
23
+ </Component>
24
+ </DirectoryRef>
25
+
26
+ <DirectoryRef Id="TARGETDIR">
27
+ <Component Id="RegistryEntries" Guid="{{IdAsGuid3}}" Win64="{{Win64YesNo}}">
28
+ <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows\CurrentVersion\Run">
29
+ <RegistryValue Type="expandable" Name="{{Id}}Deployment" Value="&quot;[#{{Id}}.exe]&quot; --checkInstall" />
30
+ </RegistryKey>
31
+ </Component>
32
+ </DirectoryRef>
33
+
34
+ <Feature Id="MainApplication" Title="Main Application" Level="1">
35
+ <ComponentRef Id="{{Id}}.exe" />
36
+ <ComponentRef Id="RegistryEntries" />
37
+ </Feature>
38
+ </Product>
39
+ </Wix>