app-builder-lib 26.11.0 → 26.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/out/binDownload.js +4 -1
  2. package/out/binDownload.js.map +1 -1
  3. package/out/codeSign/codesign.js +7 -23
  4. package/out/codeSign/codesign.js.map +1 -1
  5. package/out/configuration.d.ts +36 -2
  6. package/out/configuration.js.map +1 -1
  7. package/out/fileMatcher.d.ts +2 -1
  8. package/out/fileMatcher.js +0 -1
  9. package/out/fileMatcher.js.map +1 -1
  10. package/out/index.d.ts +1 -1
  11. package/out/index.js.map +1 -1
  12. package/out/linuxPackager.js +1 -1
  13. package/out/linuxPackager.js.map +1 -1
  14. package/out/macPackager.js +0 -12
  15. package/out/macPackager.js.map +1 -1
  16. package/out/node-module-collector/moduleManager.d.ts +1 -0
  17. package/out/node-module-collector/moduleManager.js +2 -0
  18. package/out/node-module-collector/moduleManager.js.map +1 -1
  19. package/out/node-module-collector/nodeModulesCollector.d.ts +3 -2
  20. package/out/node-module-collector/nodeModulesCollector.js +25 -5
  21. package/out/node-module-collector/nodeModulesCollector.js.map +1 -1
  22. package/out/node-module-collector/pnpmNodeModulesCollector.js +5 -1
  23. package/out/node-module-collector/pnpmNodeModulesCollector.js.map +1 -1
  24. package/out/options/SnapOptions.d.ts +415 -56
  25. package/out/options/SnapOptions.js.map +1 -1
  26. package/out/options/linuxOptions.d.ts +8 -0
  27. package/out/options/linuxOptions.js.map +1 -1
  28. package/out/platformPackager.js +1 -1
  29. package/out/platformPackager.js.map +1 -1
  30. package/out/publish/PublishManager.js +2 -2
  31. package/out/publish/PublishManager.js.map +1 -1
  32. package/out/publish/updateInfoBuilder.d.ts +4 -0
  33. package/out/publish/updateInfoBuilder.js +14 -2
  34. package/out/publish/updateInfoBuilder.js.map +1 -1
  35. package/out/targets/ArchiveTarget.js +1 -1
  36. package/out/targets/ArchiveTarget.js.map +1 -1
  37. package/out/targets/LinuxTargetHelper.d.ts +3 -0
  38. package/out/targets/LinuxTargetHelper.js +68 -0
  39. package/out/targets/LinuxTargetHelper.js.map +1 -1
  40. package/out/targets/MsiTarget.js +6 -3
  41. package/out/targets/MsiTarget.js.map +1 -1
  42. package/out/targets/archive.js +2 -6
  43. package/out/targets/archive.js.map +1 -1
  44. package/out/targets/nsis/NsisTarget.js +12 -12
  45. package/out/targets/nsis/NsisTarget.js.map +1 -1
  46. package/out/targets/nsis/nsisUtil.d.ts +0 -7
  47. package/out/targets/nsis/nsisUtil.js +5 -48
  48. package/out/targets/nsis/nsisUtil.js.map +1 -1
  49. package/out/targets/snap/SnapTarget.d.ts +36 -0
  50. package/out/targets/snap/SnapTarget.js +104 -0
  51. package/out/targets/snap/SnapTarget.js.map +1 -0
  52. package/out/targets/snap/core24.d.ts +52 -0
  53. package/out/targets/snap/core24.js +447 -0
  54. package/out/targets/snap/core24.js.map +1 -0
  55. package/out/targets/snap/coreCustom.d.ts +28 -0
  56. package/out/targets/snap/coreCustom.js +63 -0
  57. package/out/targets/snap/coreCustom.js.map +1 -0
  58. package/out/targets/snap/coreLegacy.d.ts +20 -0
  59. package/out/targets/{snap.js → snap/coreLegacy.js} +96 -155
  60. package/out/targets/snap/coreLegacy.js.map +1 -0
  61. package/out/targets/snap/snapcraftBuilder.d.ts +39 -0
  62. package/out/targets/snap/snapcraftBuilder.js +418 -0
  63. package/out/targets/snap/snapcraftBuilder.js.map +1 -0
  64. package/out/toolsets/linux.d.ts +5 -0
  65. package/out/toolsets/linux.js +55 -23
  66. package/out/toolsets/linux.js.map +1 -1
  67. package/out/toolsets/windows.d.ts +19 -0
  68. package/out/toolsets/windows.js +136 -18
  69. package/out/toolsets/windows.js.map +1 -1
  70. package/out/util/electronGet.d.ts +4 -1
  71. package/out/util/electronGet.js +19 -19
  72. package/out/util/electronGet.js.map +1 -1
  73. package/out/util/envPath.d.ts +2 -0
  74. package/out/util/envPath.js +28 -0
  75. package/out/util/envPath.js.map +1 -0
  76. package/out/util/toolsetLock.d.ts +1 -0
  77. package/out/util/toolsetLock.js +23 -0
  78. package/out/util/toolsetLock.js.map +1 -0
  79. package/out/version.d.ts +1 -1
  80. package/out/version.js +1 -1
  81. package/out/version.js.map +1 -1
  82. package/out/vm/vm.d.ts +1 -0
  83. package/out/vm/vm.js +18 -0
  84. package/out/vm/vm.js.map +1 -1
  85. package/package.json +8 -8
  86. package/scheme.json +1401 -107
  87. package/templates/nsis/multiUser.nsh +14 -12
  88. package/out/targets/snap.d.ts +0 -17
  89. package/out/targets/snap.js.map +0 -1
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SnapCore = void 0;
4
+ const builder_util_1 = require("builder-util");
5
+ const path = require("path");
6
+ const core_1 = require("../../core");
7
+ const targetUtil_1 = require("../targetUtil");
8
+ /** Abstract base for all snap build strategies (core24, legacy core18/20/22, custom pass-through). */
9
+ class SnapCore {
10
+ constructor(packager, helper, options) {
11
+ this.packager = packager;
12
+ this.helper = helper;
13
+ this.options = options;
14
+ }
15
+ }
16
+ exports.SnapCore = SnapCore;
17
+ /** Snap build target — merges `snapcraft` (preferred) and legacy `snap` config, then delegates to the appropriate `SnapCore` strategy. */
18
+ class SnapTarget extends core_1.Target {
19
+ constructor(name, packager, helper, outDir) {
20
+ var _a;
21
+ super(name);
22
+ this.packager = packager;
23
+ this.helper = helper;
24
+ this.outDir = outDir;
25
+ const { config: { snapcraft, snap }, platformSpecificBuildOptions, } = packager;
26
+ this.options = (0, builder_util_1.deepAssign)({}, platformSpecificBuildOptions, (_a = snapcraft !== null && snapcraft !== void 0 ? snapcraft : snap) !== null && _a !== void 0 ? _a : {});
27
+ }
28
+ async build(appOutDir, arch) {
29
+ const packager = this.packager;
30
+ // tslint:disable-next-line:no-invalid-template-strings
31
+ const artifactName = packager.expandArtifactNamePattern(this.options, "snap", arch, "${name}_${version}_${arch}.${ext}", false);
32
+ const artifactPath = path.join(this.outDir, artifactName);
33
+ await packager.info.emitArtifactBuildStarted({
34
+ targetPresentableName: "snap",
35
+ file: artifactPath,
36
+ arch,
37
+ });
38
+ const core = this.helper.getSnapCore();
39
+ const snap = await core.createDescriptor(arch);
40
+ builder_util_1.log.debug({ snap }, "snapcraft.yaml descriptor created");
41
+ await core.buildSnap({
42
+ snap,
43
+ appOutDir,
44
+ stageDir: await (0, targetUtil_1.createStageDirPath)(this, packager, arch),
45
+ snapArch: arch,
46
+ artifactPath,
47
+ });
48
+ const publishConfig = this.findSnapPublishConfig(packager.config);
49
+ await packager.info.emitArtifactBuildCompleted({
50
+ file: artifactPath,
51
+ safeArtifactName: packager.computeSafeArtifactName(artifactName, "snap", arch, false),
52
+ target: this,
53
+ arch,
54
+ packager,
55
+ publishConfig,
56
+ });
57
+ }
58
+ findSnapPublishConfig(config) {
59
+ var _a, _b;
60
+ const fallback = { provider: "snapStore" };
61
+ if (!config) {
62
+ return fallback;
63
+ }
64
+ const snapConfig = (_a = config.snapcraft) !== null && _a !== void 0 ? _a : config.snap;
65
+ if (snapConfig === null || snapConfig === void 0 ? void 0 : snapConfig.publish) {
66
+ return this.findSnapPublishConfigInPublishNode(snapConfig.publish);
67
+ }
68
+ if ((_b = config.linux) === null || _b === void 0 ? void 0 : _b.publish) {
69
+ const configCandidate = this.findSnapPublishConfigInPublishNode(config.linux.publish);
70
+ if (configCandidate) {
71
+ return configCandidate;
72
+ }
73
+ }
74
+ if (config.publish) {
75
+ const configCandidate = this.findSnapPublishConfigInPublishNode(config.publish);
76
+ if (configCandidate) {
77
+ return configCandidate;
78
+ }
79
+ }
80
+ return fallback;
81
+ }
82
+ findSnapPublishConfigInPublishNode(configPublishNode) {
83
+ if (!configPublishNode) {
84
+ return null;
85
+ }
86
+ if (Array.isArray(configPublishNode)) {
87
+ for (const configObj of configPublishNode) {
88
+ if (this.isSnapStoreOptions(configObj)) {
89
+ return configObj;
90
+ }
91
+ }
92
+ }
93
+ if (typeof configPublishNode === `object` && this.isSnapStoreOptions(configPublishNode)) {
94
+ return configPublishNode;
95
+ }
96
+ return null;
97
+ }
98
+ isSnapStoreOptions(configPublishNode) {
99
+ const snapStoreOptionsCandidate = configPublishNode;
100
+ return (snapStoreOptionsCandidate === null || snapStoreOptionsCandidate === void 0 ? void 0 : snapStoreOptionsCandidate.provider) === `snapStore`;
101
+ }
102
+ }
103
+ exports.default = SnapTarget;
104
+ //# sourceMappingURL=SnapTarget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SnapTarget.js","sourceRoot":"","sources":["../../../src/targets/snap/SnapTarget.ts"],"names":[],"mappings":";;;AAAA,+CAAoD;AAEpD,6BAA4B;AAE5B,qCAA4C;AAI5C,8CAAkD;AAGlD,sGAAsG;AACtG,MAAsB,QAAQ;IAG5B,YACqB,QAAuB,EACvB,MAAyB,EACzB,OAAU;QAFV,aAAQ,GAAR,QAAQ,CAAe;QACvB,WAAM,GAAN,MAAM,CAAmB;QACzB,YAAO,GAAP,OAAO,CAAG;IAC5B,CAAC;CAKL;AAZD,4BAYC;AAED,0IAA0I;AAC1I,MAAqB,UAAW,SAAQ,aAAM;IAG5C,YACE,IAAY,EACO,QAAuB,EACvB,MAAyB,EACnC,MAAc;;QAEvB,KAAK,CAAC,IAAI,CAAC,CAAA;QAJQ,aAAQ,GAAR,QAAQ,CAAe;QACvB,WAAM,GAAN,MAAM,CAAmB;QACnC,WAAM,GAAN,MAAM,CAAQ;QAIvB,MAAM,EACJ,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,EAC3B,4BAA4B,GAC7B,GAAG,QAAQ,CAAA;QAEZ,IAAI,CAAC,OAAO,GAAG,IAAA,yBAAU,EAAC,EAAE,EAAE,4BAA4B,EAAE,MAAA,SAAS,aAAT,SAAS,cAAT,SAAS,GAAI,IAAI,mCAAI,EAAE,CAAC,CAAA;IACtF,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,SAAiB,EAAE,IAAU;QACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAA;QAC9B,uDAAuD;QACvD,MAAM,YAAY,GAAG,QAAQ,CAAC,yBAAyB,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,mCAAmC,EAAE,KAAK,CAAC,CAAA;QAC/H,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,CAAA;QAEzD,MAAM,QAAQ,CAAC,IAAI,CAAC,wBAAwB,CAAC;YAC3C,qBAAqB,EAAE,MAAM;YAC7B,IAAI,EAAE,YAAY;YAClB,IAAI;SACL,CAAC,CAAA;QAEF,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAA;QAEtC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAA;QAC9C,kBAAG,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,EAAE,mCAAmC,CAAC,CAAA;QAExD,MAAM,IAAI,CAAC,SAAS,CAAC;YACnB,IAAI;YACJ,SAAS;YACT,QAAQ,EAAE,MAAM,IAAA,+BAAkB,EAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC;YACxD,QAAQ,EAAE,IAAI;YACd,YAAY;SACb,CAAC,CAAA;QAEF,MAAM,aAAa,GAAG,IAAI,CAAC,qBAAqB,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;QAEjE,MAAM,QAAQ,CAAC,IAAI,CAAC,0BAA0B,CAAC;YAC7C,IAAI,EAAE,YAAY;YAClB,gBAAgB,EAAE,QAAQ,CAAC,uBAAuB,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC;YACrF,MAAM,EAAE,IAAI;YACZ,IAAI;YACJ,QAAQ;YACR,aAAa;SACd,CAAC,CAAA;IACJ,CAAC;IAES,qBAAqB,CAAC,MAAsB;;QACpD,MAAM,QAAQ,GAAqB,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAA;QAE5D,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,QAAQ,CAAA;QACjB,CAAC;QAED,MAAM,UAAU,GAAG,MAAA,MAAM,CAAC,SAAS,mCAAI,MAAM,CAAC,IAAI,CAAA;QAClD,IAAI,UAAU,aAAV,UAAU,uBAAV,UAAU,CAAE,OAAO,EAAE,CAAC;YACxB,OAAO,IAAI,CAAC,kCAAkC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAA;QACpE,CAAC;QAED,IAAI,MAAA,MAAM,CAAC,KAAK,0CAAE,OAAO,EAAE,CAAC;YAC1B,MAAM,eAAe,GAAG,IAAI,CAAC,kCAAkC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;YAErF,IAAI,eAAe,EAAE,CAAC;gBACpB,OAAO,eAAe,CAAA;YACxB,CAAC;QACH,CAAC;QAED,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,MAAM,eAAe,GAAG,IAAI,CAAC,kCAAkC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;YAE/E,IAAI,eAAe,EAAE,CAAC;gBACpB,OAAO,eAAe,CAAA;YACxB,CAAC;QACH,CAAC;QAED,OAAO,QAAQ,CAAA;IACjB,CAAC;IAEO,kCAAkC,CAAC,iBAA0B;QACnE,IAAI,CAAC,iBAAiB,EAAE,CAAC;YACvB,OAAO,IAAI,CAAA;QACb,CAAC;QAED,IAAI,KAAK,CAAC,OAAO,CAAC,iBAAiB,CAAC,EAAE,CAAC;YACrC,KAAK,MAAM,SAAS,IAAI,iBAAiB,EAAE,CAAC;gBAC1C,IAAI,IAAI,CAAC,kBAAkB,CAAC,SAAS,CAAC,EAAE,CAAC;oBACvC,OAAO,SAAS,CAAA;gBAClB,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,OAAO,iBAAiB,KAAK,QAAQ,IAAI,IAAI,CAAC,kBAAkB,CAAC,iBAAiB,CAAC,EAAE,CAAC;YACxF,OAAO,iBAAiB,CAAA;QAC1B,CAAC;QAED,OAAO,IAAI,CAAA;IACb,CAAC;IAEO,kBAAkB,CAAC,iBAA0B;QACnD,MAAM,yBAAyB,GAAG,iBAAqC,CAAA;QACvE,OAAO,CAAA,yBAAyB,aAAzB,yBAAyB,uBAAzB,yBAAyB,CAAE,QAAQ,MAAK,WAAW,CAAA;IAC5D,CAAC;CACF;AA/GD,6BA+GC","sourcesContent":["import { Arch, deepAssign, log } from \"builder-util\"\nimport { SnapStoreOptions } from \"builder-util-runtime\"\nimport * as path from \"path\"\nimport { Configuration } from \"../../configuration\"\nimport { Publish, Target } from \"../../core\"\nimport { LinuxPackager } from \"../../linuxPackager\"\nimport { SnapcraftOptions, SnapOptions } from \"../../options/SnapOptions\"\nimport { LinuxTargetHelper } from \"../LinuxTargetHelper\"\nimport { createStageDirPath } from \"../targetUtil\"\nimport { SnapcraftYAML } from \"./snapcraft\"\n\n/** Abstract base for all snap build strategies (core24, legacy core18/20/22, custom pass-through). */\nexport abstract class SnapCore<T> {\n protected abstract defaultPlugs: Array<string>\n\n constructor(\n protected readonly packager: LinuxPackager,\n protected readonly helper: LinuxTargetHelper,\n protected readonly options: T\n ) {}\n\n abstract createDescriptor(arch: Arch): Promise<SnapcraftYAML>\n // snapArch is passed through to subclasses; SnapCoreLegacy forwards it to app-builder as --arch.\n abstract buildSnap(params: { snap: SnapcraftYAML; appOutDir: string; stageDir: string; snapArch: Arch; artifactPath: string }): Promise<void>\n}\n\n/** Snap build target — merges `snapcraft` (preferred) and legacy `snap` config, then delegates to the appropriate `SnapCore` strategy. */\nexport default class SnapTarget extends Target {\n readonly options: SnapcraftOptions | SnapOptions\n\n constructor(\n name: string,\n protected readonly packager: LinuxPackager,\n protected readonly helper: LinuxTargetHelper,\n readonly outDir: string\n ) {\n super(name)\n\n const {\n config: { snapcraft, snap },\n platformSpecificBuildOptions,\n } = packager\n\n this.options = deepAssign({}, platformSpecificBuildOptions, snapcraft ?? snap ?? {})\n }\n\n async build(appOutDir: string, arch: Arch): Promise<any> {\n const packager = this.packager\n // tslint:disable-next-line:no-invalid-template-strings\n const artifactName = packager.expandArtifactNamePattern(this.options, \"snap\", arch, \"${name}_${version}_${arch}.${ext}\", false)\n const artifactPath = path.join(this.outDir, artifactName)\n\n await packager.info.emitArtifactBuildStarted({\n targetPresentableName: \"snap\",\n file: artifactPath,\n arch,\n })\n\n const core = this.helper.getSnapCore()\n\n const snap = await core.createDescriptor(arch)\n log.debug({ snap }, \"snapcraft.yaml descriptor created\")\n\n await core.buildSnap({\n snap,\n appOutDir,\n stageDir: await createStageDirPath(this, packager, arch),\n snapArch: arch,\n artifactPath,\n })\n\n const publishConfig = this.findSnapPublishConfig(packager.config)\n\n await packager.info.emitArtifactBuildCompleted({\n file: artifactPath,\n safeArtifactName: packager.computeSafeArtifactName(artifactName, \"snap\", arch, false),\n target: this,\n arch,\n packager,\n publishConfig,\n })\n }\n\n protected findSnapPublishConfig(config?: Configuration): SnapStoreOptions | null {\n const fallback: SnapStoreOptions = { provider: \"snapStore\" }\n\n if (!config) {\n return fallback\n }\n\n const snapConfig = config.snapcraft ?? config.snap\n if (snapConfig?.publish) {\n return this.findSnapPublishConfigInPublishNode(snapConfig.publish)\n }\n\n if (config.linux?.publish) {\n const configCandidate = this.findSnapPublishConfigInPublishNode(config.linux.publish)\n\n if (configCandidate) {\n return configCandidate\n }\n }\n\n if (config.publish) {\n const configCandidate = this.findSnapPublishConfigInPublishNode(config.publish)\n\n if (configCandidate) {\n return configCandidate\n }\n }\n\n return fallback\n }\n\n private findSnapPublishConfigInPublishNode(configPublishNode: Publish): SnapStoreOptions | null {\n if (!configPublishNode) {\n return null\n }\n\n if (Array.isArray(configPublishNode)) {\n for (const configObj of configPublishNode) {\n if (this.isSnapStoreOptions(configObj)) {\n return configObj\n }\n }\n }\n\n if (typeof configPublishNode === `object` && this.isSnapStoreOptions(configPublishNode)) {\n return configPublishNode\n }\n\n return null\n }\n\n private isSnapStoreOptions(configPublishNode: Publish): configPublishNode is SnapStoreOptions {\n const snapStoreOptionsCandidate = configPublishNode as SnapStoreOptions\n return snapStoreOptionsCandidate?.provider === `snapStore`\n }\n}\n"]}
@@ -0,0 +1,52 @@
1
+ import { Arch } from "builder-util";
2
+ import { PlugDescriptor, SlotDescriptor, SnapOptions24 } from "../../options/SnapOptions";
3
+ import { SnapCore } from "./SnapTarget";
4
+ import { SnapcraftYAML } from "./snapcraft";
5
+ import { Nullish } from "builder-util-runtime";
6
+ /** Snap build strategy for core24 — generates a native snapcraft.yaml and invokes the snapcraft CLI. */
7
+ export declare class SnapCore24 extends SnapCore<SnapOptions24> {
8
+ defaultPlugs: string[];
9
+ readonly configRelativePath = "snap";
10
+ readonly guiRelativePath: string;
11
+ createDescriptor(arch: Arch): Promise<SnapcraftYAML>;
12
+ private isHostMode;
13
+ /** Writes the snapcraft.yaml, stages app files, then invokes `buildSnap()` to run the actual snapcraft build. */
14
+ buildSnap(params: {
15
+ snap: SnapcraftYAML;
16
+ appOutDir: string;
17
+ stageDir: string;
18
+ snapArch: Arch;
19
+ artifactPath: string;
20
+ }): Promise<void>;
21
+ /** Converts `SnapOptions24` into a fully resolved `SnapcraftYAML` descriptor for the given architecture. */
22
+ mapSnapOptionsToSnapcraftYAML(arch: Arch): Promise<SnapcraftYAML>;
23
+ /**
24
+ * Build environment variables with proper defaults
25
+ */
26
+ private buildEnvironment;
27
+ /**
28
+ * Build default layout for core24 with GNOME platform content snaps (non-extension mode)
29
+ * This allows the app to access libraries from the gnome-46-2404 and mesa-2404 content snaps
30
+ */
31
+ private buildDefaultLayout;
32
+ /**
33
+ * Process hooks directory into hook definitions
34
+ */
35
+ private processHooks;
36
+ /**
37
+ * Normalize assumes list (can be string or array)
38
+ */
39
+ normalizeAssumesList(assumes: Array<string> | string | Nullish): string[] | undefined;
40
+ /**
41
+ * Process plugs or slots into root-level definitions and app-level references
42
+ */
43
+ processPlugOrSlots<T extends Array<string | SlotDescriptor | PlugDescriptor> | SlotDescriptor | PlugDescriptor | null>(items: T): {
44
+ root: Record<string, unknown> | undefined;
45
+ app: string[] | undefined;
46
+ };
47
+ private isBrowserSandboxAllowed;
48
+ /**
49
+ * Expand "default" keyword in arrays of anything
50
+ */
51
+ private expandDefaultsInArray;
52
+ }
@@ -0,0 +1,447 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SnapCore24 = void 0;
4
+ const builder_util_1 = require("builder-util");
5
+ const fs_extra_1 = require("fs-extra");
6
+ const path = require("path");
7
+ const SnapTarget_1 = require("./SnapTarget");
8
+ const snapcraftBuilder_1 = require("./snapcraftBuilder");
9
+ const yaml = require("js-yaml");
10
+ /** Snap build strategy for core24 — generates a native snapcraft.yaml and invokes the snapcraft CLI. */
11
+ class SnapCore24 extends SnapTarget_1.SnapCore {
12
+ constructor() {
13
+ super(...arguments);
14
+ // browser-support is intentionally absent here; it is auto-injected in mapSnapOptionsToSnapcraftYAML
15
+ // when the user has not provided custom plugs, so it always lands in both root plugs and app plugs.
16
+ this.defaultPlugs = ["desktop", "desktop-legacy", "home", "x11", "wayland", "unity7", "network", "gsettings", "audio-playback", "pulseaudio", "opengl"];
17
+ // Snap file hierarchy:
18
+ // - snap/gui/ gets automatically copied to meta/gui/ in the final snap
19
+ // - Desktop files in meta/gui/ are used for menu integration
20
+ this.configRelativePath = "snap";
21
+ this.guiRelativePath = path.join(this.configRelativePath, "gui");
22
+ }
23
+ async createDescriptor(arch) {
24
+ return await this.mapSnapOptionsToSnapcraftYAML(arch);
25
+ }
26
+ isHostMode() {
27
+ return this.options.useDestructiveMode === true;
28
+ }
29
+ /** Writes the snapcraft.yaml, stages app files, then invokes `buildSnap()` to run the actual snapcraft build. */
30
+ async buildSnap(params) {
31
+ const { snap, appOutDir, stageDir, artifactPath } = params;
32
+ const snapDirResolved = path.resolve(stageDir, this.configRelativePath);
33
+ const snapcraftYamlPath = path.join(snapDirResolved, "snapcraft.yaml");
34
+ // Create snap/gui directory for desktop files and icons
35
+ // Snapcraft will automatically copy snap/gui/ contents to meta/gui/ in the final snap
36
+ const guiOutput = path.resolve(stageDir, this.guiRelativePath);
37
+ await (0, fs_extra_1.mkdir)(guiOutput, { recursive: true });
38
+ const yamlContent = yaml.dump(snap, snapcraftBuilder_1.SNAPCRAFT_YAML_OPTIONS);
39
+ await (0, fs_extra_1.writeFile)(snapcraftYamlPath, yamlContent, "utf8");
40
+ builder_util_1.log.debug(snap, "generated snapcraft.yaml");
41
+ // Copy icon to snap/gui/ directory
42
+ // Snapcraft will automatically copy this to meta/gui/ in the final snap
43
+ const desktopExtraProps = {};
44
+ const icon = this.helper.maxIconPath;
45
+ if (icon) {
46
+ const iconFileName = `${snap.name}${path.extname(icon)}`;
47
+ await (0, fs_extra_1.copy)(icon, path.join(guiOutput, iconFileName));
48
+ // Icon path will be available at ${SNAP}/meta/gui/<icon-file> after installation
49
+ desktopExtraProps.Icon = `\${SNAP}/meta/gui/${iconFileName}`;
50
+ }
51
+ // Create desktop file in snap/gui/ directory
52
+ // Snapcraft will automatically copy this to meta/gui/ in the final snap
53
+ const desktopFilePath = path.join(guiOutput, `${snap.name}.desktop`);
54
+ await this.helper.writeDesktopEntry(this.options, this.packager.executableName + " %U", desktopFilePath, desktopExtraProps);
55
+ // Copy app files to the project root `app` directory so `source: app`
56
+ // in the generated `snapcraft.yaml` (which is under `snap/`) can be
57
+ // resolved by snapcraft running in the build environment.
58
+ const appDir = path.resolve(stageDir, "app");
59
+ if (path.resolve(appDir) !== path.resolve(appOutDir)) {
60
+ builder_util_1.log.debug({ to: builder_util_1.log.filePath(appDir), from: builder_util_1.log.filePath(appOutDir) }, "copying app files to project root app directory");
61
+ await (0, builder_util_1.copyDir)(appOutDir, appDir);
62
+ }
63
+ // Auto-generate `organize` mapping for the app part so top-level helper
64
+ // binaries and resources are placed under `app/` inside the snap. Update
65
+ // the already-written `snapcraft.yaml` so the build sees the mapping.
66
+ try {
67
+ const appPart = snap.parts[snap.name];
68
+ if (appPart) {
69
+ const entries = (await (0, fs_extra_1.readdir)(appOutDir)).sort();
70
+ const organize = appPart.organize || {};
71
+ for (const entry of entries) {
72
+ if (!entry) {
73
+ continue;
74
+ }
75
+ if (organize[entry]) {
76
+ continue;
77
+ }
78
+ organize[entry] = `app/${entry}`;
79
+ }
80
+ appPart.organize = organize;
81
+ const updatedYaml = yaml.dump(snap, snapcraftBuilder_1.SNAPCRAFT_YAML_OPTIONS);
82
+ await (0, fs_extra_1.writeFile)(snapcraftYamlPath, updatedYaml, "utf8");
83
+ builder_util_1.log.debug({ organize }, "updated snapcraft.yaml with organize mapping");
84
+ }
85
+ }
86
+ catch (e) {
87
+ builder_util_1.log.warn({ error: e.message }, "failed to generate and update organize mapping");
88
+ }
89
+ const buildMode = {
90
+ useLXD: this.options.useLXD === true,
91
+ useMultipass: this.options.useMultipass === true,
92
+ useDestructiveMode: this.options.useDestructiveMode === true,
93
+ remoteBuild: this.options.remoteBuild || undefined,
94
+ };
95
+ if (this.packager.packagerOptions.effectiveOptionComputed != null) {
96
+ const shouldSkip = await this.packager.packagerOptions.effectiveOptionComputed({ snap, ...buildMode });
97
+ if (shouldSkip) {
98
+ return;
99
+ }
100
+ }
101
+ const rootOptions = this.packager.config.snapcraft;
102
+ await (0, snapcraftBuilder_1.buildSnap)({
103
+ snapcraftConfig: snap,
104
+ artifactPath,
105
+ stageDir,
106
+ packager: this.packager,
107
+ cscLink: rootOptions === null || rootOptions === void 0 ? void 0 : rootOptions.cscLink,
108
+ ...buildMode,
109
+ });
110
+ }
111
+ /** Converts `SnapOptions24` into a fully resolved `SnapcraftYAML` descriptor for the given architecture. */
112
+ async mapSnapOptionsToSnapcraftYAML(arch) {
113
+ var _a, _b, _c, _d;
114
+ const appInfo = this.packager.appInfo;
115
+ const appName = this.packager.executableName.toLowerCase();
116
+ const options = this.options;
117
+ // Default to ["gnome"] in normal builds; no extensions in host/destructive-mode (where the
118
+ // gnome extension is incompatible). Throw if the user explicitly includes "gnome" in host mode.
119
+ const hostMode = this.isHostMode();
120
+ const extensionsList = options.extensions != null ? [...options.extensions] : hostMode ? [] : ["gnome"];
121
+ if (hostMode && extensionsList.includes("gnome")) {
122
+ throw new builder_util_1.InvalidConfigurationError(`The "gnome" snapcraft extension is incompatible with host/destructive-mode builds.\n` +
123
+ `In this mode snapcraft cannot resolve the extension's command-chain source ` +
124
+ `(/usr/share/snapcraft/extensions/desktop/command-chain) and will fail.\n\n` +
125
+ `To resolve this, choose one of:\n` +
126
+ ` 1. Remove "gnome" from snapcraft.core24.extensions (or set it to []) and add any\n` +
127
+ ` required stage-packages manually.\n` +
128
+ ` 2. Switch to an isolated build environment by setting snapcraft.core24.useLXD: true\n` +
129
+ ` or snapcraft.core24.useMultipass: true instead of useDestructiveMode.\n\n` +
130
+ `See: https://snapcraft.io/docs/gnome-extension`);
131
+ }
132
+ const resolvedExtensions = extensionsList.length > 0 ? extensionsList : undefined;
133
+ const useGnomeExtension = extensionsList.includes("gnome");
134
+ // Create the app part
135
+ const appPart = {
136
+ plugin: "dump",
137
+ source: "app",
138
+ "build-packages": ((_a = options.buildPackages) === null || _a === void 0 ? void 0 : _a.length) ? options.buildPackages : undefined,
139
+ "stage-packages": this.expandDefaultsInArray(options.stagePackages, snapcraftBuilder_1.DEFAULT_STAGE_PACKAGES),
140
+ after: this.expandDefaultsInArray(options.after, []),
141
+ stage: ((_b = options.appPartStage) === null || _b === void 0 ? void 0 : _b.length) ? options.appPartStage : undefined,
142
+ };
143
+ // Process plugs and slots
144
+ // When using GNOME extension, we don't need to manually configure content snaps
145
+ // The extension will handle: gnome-46-2404, gtk-3-themes, icon-themes, sound-themes
146
+ let rootPlugs;
147
+ let appPlugs;
148
+ if (useGnomeExtension) {
149
+ // With GNOME extension, only process user-provided custom plugs
150
+ const result = options.plugs ? this.processPlugOrSlots(options.plugs) : { root: undefined, app: undefined };
151
+ rootPlugs = result.root;
152
+ // Extension automatically adds common plugs, so we only add custom ones
153
+ appPlugs = result.app;
154
+ }
155
+ else {
156
+ // Without GNOME extension, we need manual content snaps
157
+ const defaultRootPlugs = {
158
+ "gtk-3-themes": {
159
+ interface: "content",
160
+ target: "$SNAP/data-dir/themes",
161
+ "default-provider": "gtk-common-themes",
162
+ },
163
+ "icon-themes": {
164
+ interface: "content",
165
+ target: "$SNAP/data-dir/icons",
166
+ "default-provider": "gtk-common-themes",
167
+ },
168
+ "sound-themes": {
169
+ interface: "content",
170
+ target: "$SNAP/data-dir/sounds",
171
+ "default-provider": "gtk-common-themes",
172
+ },
173
+ "gnome-46-2404": {
174
+ interface: "content",
175
+ target: "$SNAP/gnome-platform",
176
+ "default-provider": "gnome-46-2404",
177
+ },
178
+ "gpu-2404": {
179
+ interface: "content",
180
+ target: "$SNAP/gpu-2404",
181
+ "default-provider": "mesa-2404",
182
+ },
183
+ };
184
+ const result = options.plugs
185
+ ? this.processPlugOrSlots(options.plugs)
186
+ : hostMode
187
+ ? { root: undefined, app: this.defaultPlugs }
188
+ : {
189
+ root: defaultRootPlugs,
190
+ app: this.defaultPlugs,
191
+ };
192
+ rootPlugs = result.root;
193
+ appPlugs = result.app;
194
+ }
195
+ // Always add browser-support with allow-sandbox so Chromium's internal sandbox
196
+ // can create user namespaces under strict confinement. Without allow-sandbox: true
197
+ // the app crashes immediately with "FATAL: Permission denied (13)" in credentials.cc.
198
+ // Skip the injection only when the user has explicitly provided their own plugs
199
+ // (they are responsible for including browser-support in that case).
200
+ if (!options.plugs) {
201
+ rootPlugs = { ...rootPlugs, "browser-support": { interface: "browser-support", "allow-sandbox": true } };
202
+ if (!(appPlugs === null || appPlugs === void 0 ? void 0 : appPlugs.includes("browser-support"))) {
203
+ appPlugs = [...(appPlugs !== null && appPlugs !== void 0 ? appPlugs : []), "browser-support"];
204
+ }
205
+ }
206
+ const { root: rootSlots, app: appSlots } = options.slots ? this.processPlugOrSlots(options.slots) : { root: undefined, app: undefined };
207
+ // Build the effective arg list for the snap command.
208
+ // Start with any user-supplied executableArgs, then conditionally add --no-sandbox
209
+ // if browser-support with allow-sandbox:true is not present in the resolved plugs
210
+ // (mirrors the same logic in SnapCoreLegacy.buildSnap).
211
+ const extraArgs = [...((_c = this.options.executableArgs) !== null && _c !== void 0 ? _c : [])];
212
+ if (this.options.forceX11 === true) {
213
+ if (!extraArgs.includes("--ozone-platform=x11")) {
214
+ extraArgs.push("--ozone-platform=x11");
215
+ }
216
+ }
217
+ if (this.helper.isElectronVersionGreaterOrEqualThan("5.0.0") && !this.isBrowserSandboxAllowed(rootPlugs)) {
218
+ if (!extraArgs.includes("--no-sandbox")) {
219
+ extraArgs.push("--no-sandbox");
220
+ }
221
+ }
222
+ const commandSuffix = extraArgs.length > 0 ? ` ${extraArgs.join(" ")}` : "";
223
+ // Create the app configuration
224
+ const app = {
225
+ command: `app/${this.packager.executableName}${commandSuffix}`,
226
+ "command-chain": undefined, // explicitly undefined so removeNullish strips it; extensions supply their own command-chain
227
+ plugs: appPlugs,
228
+ slots: appSlots,
229
+ autostart: options.autoStart ? `${appName}.desktop` : undefined,
230
+ desktop: `meta/gui/${appName}.desktop`,
231
+ extensions: resolvedExtensions,
232
+ };
233
+ // Icon path — build-time relative path so snapcraft can find the file in snap/gui/
234
+ await this.helper.icons;
235
+ const iconPath = this.helper.maxIconPath != null ? `snap/gui/${appName}${path.extname(this.helper.maxIconPath)}` : undefined;
236
+ // Process hooks if configured
237
+ const hooksConfig = options.hooks;
238
+ const hooks = hooksConfig ? await this.processHooks(hooksConfig) : undefined;
239
+ // Parts configuration - the extension automatically adds a gnome/sdk part
240
+ // Don't manually add desktop-launch when using the extension
241
+ const parts = {
242
+ [appName]: appPart,
243
+ };
244
+ // Note: `organize` will be generated later in `buildSnap` based on the
245
+ // actual contents of the built app directory so helper binaries and
246
+ // resources are automatically moved under `app/` in the snap.
247
+ // Build the snapcraft configuration
248
+ const snapcraft = {
249
+ // Required fields
250
+ name: appName,
251
+ base: "core24",
252
+ confinement: options.confinement || "strict",
253
+ parts: parts,
254
+ // Architecture/Platform — only needed for cross-compilation; snapcraft 8
255
+ // defaults to host arch and snapcraft 7 rejects this field entirely.
256
+ ...(arch !== (0, builder_util_1.archFromString)(process.arch)
257
+ ? {
258
+ platforms: {
259
+ [(0, builder_util_1.toLinuxArchString)(arch, "snap")]: {
260
+ "build-for": (0, builder_util_1.toLinuxArchString)(arch, "snap"),
261
+ "build-on": (0, builder_util_1.toLinuxArchString)((0, builder_util_1.archFromString)(process.arch), "snap"),
262
+ },
263
+ },
264
+ }
265
+ : {}),
266
+ // Metadata - with fallbacks from appInfo
267
+ version: appInfo.version,
268
+ summary: options.summary || appInfo.productName,
269
+ description: this.helper.getDescription(options),
270
+ grade: options.grade || "stable",
271
+ title: options.title || appInfo.productName,
272
+ icon: iconPath,
273
+ // Build configuration
274
+ compression: options.compression || undefined,
275
+ assumes: this.normalizeAssumesList(options.assumes),
276
+ // Environment
277
+ environment: this.buildEnvironment(options),
278
+ // User-supplied layout always wins. Without gnome extension and not in host mode, fall back to content-snap defaults.
279
+ layout: (_d = options.layout) !== null && _d !== void 0 ? _d : (useGnomeExtension || hostMode ? undefined : this.buildDefaultLayout(options)),
280
+ // Interfaces
281
+ plugs: rootPlugs,
282
+ slots: rootSlots,
283
+ // Hooks
284
+ hooks: hooks,
285
+ // Apps
286
+ apps: {
287
+ [appName]: app,
288
+ },
289
+ };
290
+ return (0, builder_util_1.removeNullish)(snapcraft);
291
+ }
292
+ /**
293
+ * Build environment variables with proper defaults
294
+ */
295
+ buildEnvironment(options) {
296
+ var _a;
297
+ const env = {};
298
+ // Add default TMPDIR for Electron/Chromium apps
299
+ if (!((_a = options.environment) === null || _a === void 0 ? void 0 : _a.TMPDIR)) {
300
+ env.TMPDIR = "$XDG_RUNTIME_DIR";
301
+ }
302
+ if (options.environment) {
303
+ (0, builder_util_1.deepAssign)(env, options.environment);
304
+ }
305
+ return Object.keys(env).length > 0 ? env : undefined;
306
+ }
307
+ /**
308
+ * Build default layout for core24 with GNOME platform content snaps (non-extension mode)
309
+ * This allows the app to access libraries from the gnome-46-2404 and mesa-2404 content snaps
310
+ */
311
+ buildDefaultLayout(options) {
312
+ // If user provides custom layout, use that instead
313
+ if (options.layout) {
314
+ return options.layout;
315
+ }
316
+ // Default layout for core24 Electron apps using GNOME content snaps WITHOUT extension
317
+ return {
318
+ "/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/webkit2gtk-4.0": {
319
+ bind: "$SNAP/gnome-platform/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/webkit2gtk-4.0",
320
+ },
321
+ "/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/webkit2gtk-4.1": {
322
+ bind: "$SNAP/gnome-platform/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/webkit2gtk-4.1",
323
+ },
324
+ "/usr/share/xml/iso-codes": {
325
+ bind: "$SNAP/gnome-platform/usr/share/xml/iso-codes",
326
+ },
327
+ "/usr/share/libdrm": {
328
+ bind: "$SNAP/gpu-2404/libdrm",
329
+ },
330
+ "/usr/share/drirc.d": {
331
+ symlink: "$SNAP/gpu-2404/drirc.d",
332
+ },
333
+ };
334
+ }
335
+ /**
336
+ * Process hooks directory into hook definitions
337
+ */
338
+ async processHooks(hooksPath) {
339
+ try {
340
+ const buildResourcesDir = this.packager.buildResourcesDir;
341
+ const hooksDir = path.resolve(buildResourcesDir, hooksPath);
342
+ if (!hooksDir.startsWith(buildResourcesDir + path.sep) && hooksDir !== buildResourcesDir) {
343
+ throw new builder_util_1.InvalidConfigurationError(`snapcraft.core24.hooks must resolve within the build resources directory (got "${hooksDir}")`);
344
+ }
345
+ const hookFiles = await (0, fs_extra_1.readdir)(hooksDir);
346
+ if (hookFiles.length === 0) {
347
+ return undefined;
348
+ }
349
+ const hooks = {};
350
+ for (const hookFile of hookFiles) {
351
+ const hookName = path.basename(hookFile, path.extname(hookFile));
352
+ if (!(0, builder_util_1.isValidKey)(hookName)) {
353
+ throw new builder_util_1.InvalidConfigurationError(`Invalid hook name: ${hookName}`);
354
+ }
355
+ hooks[hookName] = {
356
+ // Hook definitions will be populated by snapcraft from the files
357
+ // Just register that these hooks exist
358
+ };
359
+ }
360
+ return hooks;
361
+ }
362
+ catch (e) {
363
+ builder_util_1.log.error({ message: e.message }, "error processing Snap hooks directory");
364
+ throw e;
365
+ }
366
+ }
367
+ /**
368
+ * Normalize assumes list (can be string or array)
369
+ */
370
+ normalizeAssumesList(assumes) {
371
+ if (!assumes) {
372
+ return undefined;
373
+ }
374
+ if (typeof assumes === "string") {
375
+ return [assumes];
376
+ }
377
+ return assumes.length > 0 ? assumes : undefined;
378
+ }
379
+ /**
380
+ * Process plugs or slots into root-level definitions and app-level references
381
+ */
382
+ processPlugOrSlots(items) {
383
+ if (!items || (Array.isArray(items) && items.length === 0)) {
384
+ return { root: undefined, app: undefined };
385
+ }
386
+ const root = {};
387
+ const app = [];
388
+ // Handle single descriptor object
389
+ if (!Array.isArray(items)) {
390
+ Object.entries(items).forEach(([name, config]) => {
391
+ if (!(0, builder_util_1.isValidKey)(name)) {
392
+ throw new Error(`Invalid plug/slot name: ${name}`);
393
+ }
394
+ root[name] = config;
395
+ app.push(name);
396
+ });
397
+ return { root, app };
398
+ }
399
+ // Handle array - support "default" keyword
400
+ const processedItems = this.expandDefaultsInArray(items, this.defaultPlugs);
401
+ for (const item of processedItems !== null && processedItems !== void 0 ? processedItems : []) {
402
+ if (typeof item === "string") {
403
+ // Simple string reference
404
+ app.push(item);
405
+ }
406
+ else {
407
+ // Descriptor object with configuration
408
+ Object.entries(item).forEach(([name, config]) => {
409
+ if (!(0, builder_util_1.isValidKey)(name)) {
410
+ throw new Error(`Invalid plug/slot name: ${name}`);
411
+ }
412
+ root[name] = config;
413
+ app.push(name);
414
+ });
415
+ }
416
+ }
417
+ return { root: Object.keys(root).length > 0 ? root : undefined, app: app.length > 0 ? app : undefined };
418
+ }
419
+ isBrowserSandboxAllowed(plugs) {
420
+ if (!plugs) {
421
+ return false;
422
+ }
423
+ for (const plug of Object.values(plugs)) {
424
+ if ((plug === null || plug === void 0 ? void 0 : plug.interface) === "browser-support" && plug["allow-sandbox"] === true) {
425
+ return true;
426
+ }
427
+ }
428
+ return false;
429
+ }
430
+ /**
431
+ * Expand "default" keyword in arrays of anything
432
+ */
433
+ expandDefaultsInArray(items, defaults) {
434
+ const result = [];
435
+ for (const item of items !== null && items !== void 0 ? items : []) {
436
+ if (typeof item === "string" && item === "default") {
437
+ result.push(...defaults);
438
+ }
439
+ else {
440
+ result.push(item);
441
+ }
442
+ }
443
+ return result.length > 0 ? result : undefined;
444
+ }
445
+ }
446
+ exports.SnapCore24 = SnapCore24;
447
+ //# sourceMappingURL=core24.js.map