@gtkx/cli 1.2.2 → 1.4.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 (234) hide show
  1. package/README.md +6 -4
  2. package/dist/builder.d.ts +0 -1
  3. package/dist/builder.d.ts.map +1 -1
  4. package/dist/builder.js +6 -6
  5. package/dist/builder.js.map +1 -1
  6. package/dist/codegen/freshness.js +1 -1
  7. package/dist/codegen/freshness.js.map +1 -1
  8. package/dist/codegen/run-codegen.d.ts +2 -2
  9. package/dist/codegen/run-codegen.d.ts.map +1 -1
  10. package/dist/codegen/run-codegen.js +28 -9
  11. package/dist/codegen/run-codegen.js.map +1 -1
  12. package/dist/commands/build.d.ts +0 -4
  13. package/dist/commands/build.d.ts.map +1 -1
  14. package/dist/commands/build.js +0 -5
  15. package/dist/commands/build.js.map +1 -1
  16. package/dist/commands/codegen.d.ts.map +1 -1
  17. package/dist/commands/codegen.js +1 -3
  18. package/dist/commands/codegen.js.map +1 -1
  19. package/dist/commands/docs.d.ts.map +1 -1
  20. package/dist/commands/docs.js +3 -0
  21. package/dist/commands/docs.js.map +1 -1
  22. package/dist/deploy/depends.d.ts +2 -2
  23. package/dist/deploy/depends.d.ts.map +1 -1
  24. package/dist/deploy/depends.js +30 -15
  25. package/dist/deploy/depends.js.map +1 -1
  26. package/dist/deploy/nfpm/config.js +1 -1
  27. package/dist/deploy/nfpm/config.js.map +1 -1
  28. package/dist/deploy/node-runtime/elf.d.ts +1 -1
  29. package/dist/deploy/node-runtime/elf.d.ts.map +1 -1
  30. package/dist/deploy/node-runtime/elf.js +2 -2
  31. package/dist/deploy/node-runtime/elf.js.map +1 -1
  32. package/dist/deploy/node-runtime/index.js +2 -2
  33. package/dist/deploy/node-runtime/index.js.map +1 -1
  34. package/dist/deploy/notices/collect.d.ts +3 -1
  35. package/dist/deploy/notices/collect.d.ts.map +1 -1
  36. package/dist/deploy/notices/collect.js +2 -2
  37. package/dist/deploy/notices/collect.js.map +1 -1
  38. package/dist/deploy/notices/packages.d.ts +2 -1
  39. package/dist/deploy/notices/packages.d.ts.map +1 -1
  40. package/dist/deploy/notices/packages.js +4 -27
  41. package/dist/deploy/notices/packages.js.map +1 -1
  42. package/dist/deploy/payload/icons.d.ts +7 -3
  43. package/dist/deploy/payload/icons.d.ts.map +1 -1
  44. package/dist/deploy/payload/icons.js +46 -28
  45. package/dist/deploy/payload/icons.js.map +1 -1
  46. package/dist/deploy/payload/stage.d.ts.map +1 -1
  47. package/dist/deploy/payload/stage.js +3 -2
  48. package/dist/deploy/payload/stage.js.map +1 -1
  49. package/dist/deploy/run-deploy.d.ts.map +1 -1
  50. package/dist/deploy/run-deploy.js +63 -11
  51. package/dist/deploy/run-deploy.js.map +1 -1
  52. package/dist/deploy/settings/build-manifest.d.ts +9 -0
  53. package/dist/deploy/settings/build-manifest.d.ts.map +1 -0
  54. package/dist/deploy/settings/build-manifest.js +80 -0
  55. package/dist/deploy/settings/build-manifest.js.map +1 -0
  56. package/dist/deploy/settings/index.d.ts.map +1 -1
  57. package/dist/deploy/settings/index.js +9 -3
  58. package/dist/deploy/settings/index.js.map +1 -1
  59. package/dist/deploy/settings/libraries.d.ts +8 -0
  60. package/dist/deploy/settings/libraries.d.ts.map +1 -0
  61. package/dist/deploy/settings/libraries.js +39 -0
  62. package/dist/deploy/settings/libraries.js.map +1 -0
  63. package/dist/deploy/settings/paths.d.ts +3 -0
  64. package/dist/deploy/settings/paths.d.ts.map +1 -1
  65. package/dist/deploy/settings/paths.js +6 -32
  66. package/dist/deploy/settings/paths.js.map +1 -1
  67. package/dist/deploy/targets/appimage.d.ts.map +1 -1
  68. package/dist/deploy/targets/appimage.js +19 -13
  69. package/dist/deploy/targets/appimage.js.map +1 -1
  70. package/dist/deploy/targets/flatpak-manifest.d.ts +2 -1
  71. package/dist/deploy/targets/flatpak-manifest.d.ts.map +1 -1
  72. package/dist/deploy/targets/flatpak-manifest.js +5 -1
  73. package/dist/deploy/targets/flatpak-manifest.js.map +1 -1
  74. package/dist/deploy/targets/flatpak-pnpm.js +4 -4
  75. package/dist/deploy/targets/flatpak-pnpm.js.map +1 -1
  76. package/dist/deploy/targets/flatpak-source.d.ts.map +1 -1
  77. package/dist/deploy/targets/flatpak-source.js +9 -6
  78. package/dist/deploy/targets/flatpak-source.js.map +1 -1
  79. package/dist/deploy/types.d.ts +4 -4
  80. package/dist/deploy/types.d.ts.map +1 -1
  81. package/dist/deploy/types.js.map +1 -1
  82. package/dist/dev/icon-dir.d.ts +1 -1
  83. package/dist/dev/icon-dir.d.ts.map +1 -1
  84. package/dist/dev/icon-dir.js +20 -7
  85. package/dist/dev/icon-dir.js.map +1 -1
  86. package/dist/dev/runner-deps.d.ts.map +1 -1
  87. package/dist/dev/runner-deps.js +5 -1
  88. package/dist/dev/runner-deps.js.map +1 -1
  89. package/dist/dev/runner-main.js +4 -4
  90. package/dist/dev/runner-main.js.map +1 -1
  91. package/dist/dev/runner.d.ts +1 -1
  92. package/dist/dev/runner.d.ts.map +1 -1
  93. package/dist/dev/runner.js +1 -1
  94. package/dist/dev/runner.js.map +1 -1
  95. package/dist/dev/schema-dir.d.ts +1 -1
  96. package/dist/dev/schema-dir.d.ts.map +1 -1
  97. package/dist/dev/schema-dir.js +3 -1
  98. package/dist/dev/schema-dir.js.map +1 -1
  99. package/dist/internal/build-manifest.d.ts +20 -0
  100. package/dist/internal/build-manifest.d.ts.map +1 -0
  101. package/dist/internal/build-manifest.js +6 -0
  102. package/dist/internal/build-manifest.js.map +1 -0
  103. package/dist/internal/icon-path.d.ts +13 -0
  104. package/dist/internal/icon-path.d.ts.map +1 -0
  105. package/dist/internal/icon-path.js +86 -0
  106. package/dist/internal/icon-path.js.map +1 -0
  107. package/dist/internal/source-imports.d.ts +8 -0
  108. package/dist/internal/source-imports.d.ts.map +1 -0
  109. package/dist/internal/source-imports.js +144 -0
  110. package/dist/internal/source-imports.js.map +1 -0
  111. package/dist/mcp/widget-properties.d.ts.map +1 -1
  112. package/dist/mcp/widget-properties.js +3 -12
  113. package/dist/mcp/widget-properties.js.map +1 -1
  114. package/dist/settings/render.d.ts +7 -1
  115. package/dist/settings/render.d.ts.map +1 -1
  116. package/dist/settings/render.js +69 -20
  117. package/dist/settings/render.js.map +1 -1
  118. package/dist/settings/schema.d.ts +4 -3
  119. package/dist/settings/schema.d.ts.map +1 -1
  120. package/dist/settings/schema.js +122 -15
  121. package/dist/settings/schema.js.map +1 -1
  122. package/dist/vite-plugins/asset-emitter.d.ts +1 -1
  123. package/dist/vite-plugins/asset-emitter.d.ts.map +1 -1
  124. package/dist/vite-plugins/asset-emitter.js.map +1 -1
  125. package/dist/vite-plugins/asset-extensions.d.ts.map +1 -1
  126. package/dist/vite-plugins/asset-extensions.js +1 -0
  127. package/dist/vite-plugins/asset-extensions.js.map +1 -1
  128. package/dist/vite-plugins/asset-imports.d.ts +2 -1
  129. package/dist/vite-plugins/asset-imports.d.ts.map +1 -1
  130. package/dist/vite-plugins/asset-imports.js +37 -16
  131. package/dist/vite-plugins/asset-imports.js.map +1 -1
  132. package/dist/vite-plugins/asset-specifier.d.ts +13 -1
  133. package/dist/vite-plugins/asset-specifier.d.ts.map +1 -1
  134. package/dist/vite-plugins/asset-specifier.js +39 -1
  135. package/dist/vite-plugins/asset-specifier.js.map +1 -1
  136. package/dist/vite-plugins/build-manifest.d.ts +5 -0
  137. package/dist/vite-plugins/build-manifest.d.ts.map +1 -0
  138. package/dist/vite-plugins/{bundled-packages.js → build-manifest.js} +20 -14
  139. package/dist/vite-plugins/build-manifest.js.map +1 -0
  140. package/dist/vite-plugins/built-url.d.ts +1 -1
  141. package/dist/vite-plugins/built-url.d.ts.map +1 -1
  142. package/dist/vite-plugins/built-url.js +37 -24
  143. package/dist/vite-plugins/built-url.js.map +1 -1
  144. package/dist/vite-plugins/icons.d.ts +2 -1
  145. package/dist/vite-plugins/icons.d.ts.map +1 -1
  146. package/dist/vite-plugins/icons.js +25 -12
  147. package/dist/vite-plugins/icons.js.map +1 -1
  148. package/dist/vite-plugins/index.d.ts +2 -1
  149. package/dist/vite-plugins/index.d.ts.map +1 -1
  150. package/dist/vite-plugins/index.js +7 -5
  151. package/dist/vite-plugins/index.js.map +1 -1
  152. package/dist/vite-plugins/native.d.ts.map +1 -1
  153. package/dist/vite-plugins/native.js +23 -4
  154. package/dist/vite-plugins/native.js.map +1 -1
  155. package/dist/vite-plugins/resource-init-module.d.ts +7 -3
  156. package/dist/vite-plugins/resource-init-module.d.ts.map +1 -1
  157. package/dist/vite-plugins/resource-init-module.js +39 -14
  158. package/dist/vite-plugins/resource-init-module.js.map +1 -1
  159. package/dist/vite-plugins/resource-shared.d.ts +3 -1
  160. package/dist/vite-plugins/resource-shared.d.ts.map +1 -1
  161. package/dist/vite-plugins/resource-shared.js +3 -1
  162. package/dist/vite-plugins/resource-shared.js.map +1 -1
  163. package/dist/vite-plugins/resources.d.ts +1 -1
  164. package/dist/vite-plugins/resources.d.ts.map +1 -1
  165. package/dist/vite-plugins/resources.js +922 -86
  166. package/dist/vite-plugins/resources.js.map +1 -1
  167. package/dist/vite-plugins/settings-worker-env.d.ts.map +1 -1
  168. package/dist/vite-plugins/settings-worker-env.js +6 -3
  169. package/dist/vite-plugins/settings-worker-env.js.map +1 -1
  170. package/dist/vite-plugins/settings.d.ts +3 -1
  171. package/dist/vite-plugins/settings.d.ts.map +1 -1
  172. package/dist/vite-plugins/settings.js +63 -23
  173. package/dist/vite-plugins/settings.js.map +1 -1
  174. package/dist/vite-plugins/store-links.js +1 -1
  175. package/dist/vite-plugins/store-links.js.map +1 -1
  176. package/dist/vite-plugins/undeclared-library.d.ts.map +1 -1
  177. package/dist/vite-plugins/undeclared-library.js +25 -13
  178. package/dist/vite-plugins/undeclared-library.js.map +1 -1
  179. package/env.d.ts +11 -192
  180. package/package.json +14 -14
  181. package/src/builder.ts +6 -7
  182. package/src/codegen/freshness.ts +1 -1
  183. package/src/codegen/run-codegen.ts +33 -10
  184. package/src/commands/build.ts +0 -5
  185. package/src/commands/codegen.ts +1 -3
  186. package/src/commands/docs.ts +3 -0
  187. package/src/deploy/depends.ts +47 -18
  188. package/src/deploy/nfpm/config.ts +1 -1
  189. package/src/deploy/node-runtime/elf.ts +3 -3
  190. package/src/deploy/node-runtime/index.ts +2 -2
  191. package/src/deploy/notices/collect.ts +4 -2
  192. package/src/deploy/notices/packages.ts +5 -43
  193. package/src/deploy/payload/icons.ts +64 -34
  194. package/src/deploy/payload/stage.ts +5 -2
  195. package/src/deploy/run-deploy.ts +87 -12
  196. package/src/deploy/settings/build-manifest.ts +122 -0
  197. package/src/deploy/settings/index.ts +9 -4
  198. package/src/deploy/settings/libraries.ts +57 -0
  199. package/src/deploy/settings/paths.ts +10 -47
  200. package/src/deploy/targets/appimage.ts +32 -15
  201. package/src/deploy/targets/flatpak-manifest.ts +7 -1
  202. package/src/deploy/targets/flatpak-pnpm.ts +4 -4
  203. package/src/deploy/targets/flatpak-source.ts +9 -10
  204. package/src/deploy/types.ts +4 -4
  205. package/src/dev/icon-dir.ts +31 -7
  206. package/src/dev/runner-deps.ts +5 -1
  207. package/src/dev/runner-main.ts +4 -4
  208. package/src/dev/runner.ts +2 -2
  209. package/src/dev/schema-dir.ts +3 -1
  210. package/src/internal/build-manifest.ts +32 -0
  211. package/src/internal/icon-path.ts +127 -0
  212. package/src/internal/source-imports.ts +200 -0
  213. package/src/mcp/widget-properties.ts +3 -14
  214. package/src/settings/render.ts +99 -21
  215. package/src/settings/schema.ts +190 -17
  216. package/src/vite-plugins/asset-emitter.ts +1 -1
  217. package/src/vite-plugins/asset-extensions.ts +1 -0
  218. package/src/vite-plugins/asset-imports.ts +60 -19
  219. package/src/vite-plugins/asset-specifier.ts +73 -1
  220. package/src/vite-plugins/{bundled-packages.ts → build-manifest.ts} +30 -19
  221. package/src/vite-plugins/built-url.ts +49 -28
  222. package/src/vite-plugins/icons.ts +33 -14
  223. package/src/vite-plugins/index.ts +12 -5
  224. package/src/vite-plugins/native.ts +31 -4
  225. package/src/vite-plugins/resource-init-module.ts +44 -15
  226. package/src/vite-plugins/resource-shared.ts +4 -0
  227. package/src/vite-plugins/resources.ts +1459 -100
  228. package/src/vite-plugins/settings-worker-env.ts +7 -3
  229. package/src/vite-plugins/settings.ts +89 -21
  230. package/src/vite-plugins/store-links.ts +1 -1
  231. package/src/vite-plugins/undeclared-library.ts +31 -13
  232. package/dist/vite-plugins/bundled-packages.d.ts +0 -5
  233. package/dist/vite-plugins/bundled-packages.d.ts.map +0 -1
  234. package/dist/vite-plugins/bundled-packages.js.map +0 -1
@@ -0,0 +1,122 @@
1
+ import { isRecord, sortStrings } from "@gtkx/utils";
2
+ import { existsSync, readFileSync, statSync } from "node:fs";
3
+ import { isAbsolute, join, relative, resolve, sep } from "node:path";
4
+ import type { DeploySettings } from "../types.js";
5
+ import {
6
+ BUILD_MANIFEST_FILENAME,
7
+ BUILD_MANIFEST_FORMAT_VERSION,
8
+ BUILD_MANIFEST_GENERATOR,
9
+ type BuildManifest,
10
+ type RecordedPackage,
11
+ } from "../../internal/build-manifest.js";
12
+ import {
13
+ assertUniqueSchemaBasenames,
14
+ projectRelativeSchemaPath,
15
+ SCHEMA_SUFFIX,
16
+ } from "../../settings/schema.js";
17
+
18
+ type ResolvedBuildManifest = {
19
+ packages: RecordedPackage[];
20
+ schemaFiles: string[];
21
+ };
22
+
23
+ const invalidManifest = (path: string): Error =>
24
+ new Error(`Cannot deploy: ${path} is not a valid GTKX build manifest. Run \`gtkx build\` again.`);
25
+
26
+ const recordedSchemas = (value: unknown[], path: string): string[] =>
27
+ value.map((entry) => {
28
+ if (typeof entry !== "string") {
29
+ throw invalidManifest(path);
30
+ }
31
+
32
+ return entry;
33
+ });
34
+
35
+ const recordedPackage = (value: unknown, path: string): RecordedPackage => {
36
+ if (
37
+ !isRecord(value) ||
38
+ typeof value.name !== "string" ||
39
+ typeof value.dir !== "string" ||
40
+ isAbsolute(value.dir) ||
41
+ (value.version !== null && typeof value.version !== "string")
42
+ ) {
43
+ throw invalidManifest(path);
44
+ }
45
+
46
+ return { name: value.name, version: value.version, dir: value.dir };
47
+ };
48
+
49
+ const parseBuildManifest = (value: unknown, path: string): BuildManifest => {
50
+ if (
51
+ !isRecord(value) ||
52
+ value.generator !== BUILD_MANIFEST_GENERATOR ||
53
+ value.formatVersion !== BUILD_MANIFEST_FORMAT_VERSION ||
54
+ !Array.isArray(value.schemas) ||
55
+ !Array.isArray(value.packages)
56
+ ) {
57
+ throw invalidManifest(path);
58
+ }
59
+
60
+ const packages: unknown[] = value.packages;
61
+
62
+ return {
63
+ generator: BUILD_MANIFEST_GENERATOR,
64
+ formatVersion: BUILD_MANIFEST_FORMAT_VERSION,
65
+ schemas: recordedSchemas(value.schemas, path),
66
+ packages: packages.map((entry) => recordedPackage(entry, path)),
67
+ };
68
+ };
69
+
70
+ const isFile = (path: string): boolean => {
71
+ try {
72
+ return statSync(path, { throwIfNoEntry: false })?.isFile() === true;
73
+ } catch {
74
+ return false;
75
+ }
76
+ };
77
+
78
+ const isInsideProject = (root: string, filePath: string): boolean => {
79
+ const rel = relative(root, filePath);
80
+
81
+ return rel.length > 0 && rel !== ".." && !rel.startsWith(`..${sep}`) && !isAbsolute(rel);
82
+ };
83
+
84
+ const resolveRecordedSchema = (root: string, manifestPath: string, entry: string): string => {
85
+ if (isAbsolute(entry) || !entry.endsWith(SCHEMA_SUFFIX)) {
86
+ throw new Error(`Cannot deploy: ${manifestPath} records an invalid GSettings schema path.`);
87
+ }
88
+
89
+ const filePath = resolve(root, entry);
90
+
91
+ if (!isInsideProject(root, filePath)) {
92
+ throw new Error(`Cannot deploy: ${manifestPath} records a GSettings schema outside the project.`);
93
+ }
94
+
95
+ if (!isFile(filePath)) {
96
+ throw new Error(`Cannot deploy: the recorded GSettings schema ${filePath} is missing.`);
97
+ }
98
+
99
+ if (projectRelativeSchemaPath(root, filePath) === null) {
100
+ throw new Error(`Cannot deploy: ${manifestPath} records a GSettings schema outside the project.`);
101
+ }
102
+
103
+ return filePath;
104
+ };
105
+
106
+ const readBuildManifest = (settings: DeploySettings): ResolvedBuildManifest => {
107
+ const manifestPath = join(settings.paths.dist, BUILD_MANIFEST_FILENAME);
108
+
109
+ if (!existsSync(manifestPath)) {
110
+ throw new Error(`Cannot deploy: ${manifestPath} is missing. Run \`gtkx build\` first.`);
111
+ }
112
+
113
+ const parsed: unknown = JSON.parse(readFileSync(manifestPath, "utf8"));
114
+ const manifest = parseBuildManifest(parsed, manifestPath);
115
+ const files = manifest.schemas.map((entry) => resolveRecordedSchema(settings.paths.root, manifestPath, entry));
116
+ const unique = sortStrings(new Set(files));
117
+ assertUniqueSchemaBasenames(unique);
118
+
119
+ return { packages: manifest.packages, schemaFiles: unique };
120
+ };
121
+
122
+ export { readBuildManifest };
@@ -22,6 +22,7 @@ import {
22
22
  resolveSummary,
23
23
  resolveVersionString,
24
24
  } from "./identity.js";
25
+ import { resolveLibraries } from "./libraries.js";
25
26
  import { readPackageManifest } from "./package-manifest.js";
26
27
  import { resolvePaths } from "./paths.js";
27
28
  import { resolveScreenshots } from "./screenshots.js";
@@ -113,8 +114,6 @@ const resolveDesktopActions = (deploy: DeployConfig): DeployDesktopAction[] =>
113
114
  icon: action.icon ?? null,
114
115
  }));
115
116
 
116
- const resolveLibraries = (config: Config): string[] => (Array.isArray(config.libraries) ? config.libraries : []);
117
-
118
117
  const identitySlice = ({ identity, developer, date }: ResolvedCore): IdentitySlice => ({
119
118
  applicationId: identity.applicationId,
120
119
  binaryName: resolveBinaryName(identity),
@@ -181,8 +180,14 @@ const resolveDeploySettings = (request: SettingsRequest): DeploySettings => {
181
180
  extraFiles: resolveExtraFiles(deploy),
182
181
  versions: core.versions,
183
182
  arch: resolveArch(),
184
- paths: resolvePaths({ root: request.root, deploy, outDirOverride: request.outDirOverride }),
185
- libraries: resolveLibraries(request.config),
183
+ paths: resolvePaths({
184
+ root: request.root,
185
+ deploy,
186
+ applicationIcon: request.config.applicationIcon,
187
+ applicationId: request.config.applicationId,
188
+ outDirOverride: request.outDirOverride,
189
+ }),
190
+ ...resolveLibraries(request.root, request.config),
186
191
  deploy,
187
192
  };
188
193
  };
@@ -0,0 +1,57 @@
1
+ import type { Config } from "@gtkx/config";
2
+ import {
3
+ resolveLibraries as expandLibraries,
4
+ type GeneratedLibraries,
5
+ readGeneratedLibraries,
6
+ resolveGirPath,
7
+ resolveStore,
8
+ } from "@gtkx/codegen";
9
+
10
+ type ResolvedLibraries = {
11
+ libraries: string[];
12
+ minimumLibraryVersions: Record<string, string>;
13
+ };
14
+
15
+ const DEFAULT_LIBRARY = "Gtk-4.0";
16
+ const DEFAULT_LIBRARY_PREFIX = "Gtk-";
17
+
18
+ const generatedLibraries = (root: string): GeneratedLibraries | null => {
19
+ try {
20
+ return readGeneratedLibraries(resolveStore(root).gi.storeDir);
21
+ } catch {
22
+ return null;
23
+ }
24
+ };
25
+
26
+ const discoveredLibraries = (config: Config): string[] | null => {
27
+ try {
28
+ return expandLibraries(config.libraries, resolveGirPath(config.girPath));
29
+ } catch {
30
+ return null;
31
+ }
32
+ };
33
+
34
+ const configLibraries = (config: Config): string[] => {
35
+ const libraries = config.libraries;
36
+
37
+ if (!Array.isArray(libraries)) {
38
+ return discoveredLibraries(config) ?? [DEFAULT_LIBRARY];
39
+ }
40
+
41
+ return libraries.some((library) => library.startsWith(DEFAULT_LIBRARY_PREFIX))
42
+ ? [...libraries]
43
+ : [DEFAULT_LIBRARY, ...libraries];
44
+ };
45
+
46
+ const resolveLibraries = (root: string, config: Config): ResolvedLibraries => {
47
+ const generated = generatedLibraries(root);
48
+ const libraries = generated?.libraries ?? configLibraries(config);
49
+ const deploy = config.deploy ?? {};
50
+
51
+ return {
52
+ libraries,
53
+ minimumLibraryVersions: deploy.minimumLibraryVersions ?? {},
54
+ };
55
+ };
56
+
57
+ export { resolveLibraries };
@@ -1,23 +1,19 @@
1
- import { type Stats, statSync } from "node:fs";
1
+ import type { Config } from "@gtkx/config";
2
+ import { statSync } from "node:fs";
2
3
  import { isAbsolute, join, relative, resolve } from "node:path";
3
4
  import type { DeployConfig, DeployPaths } from "../types.js";
4
- import { resolveDataDir } from "../../internal/data-dir.js";
5
- import { findSchemaFiles } from "../../settings/schema.js";
5
+ import { resolveApplicationIcon } from "../../internal/icon-path.js";
6
6
 
7
7
  type PathsRequest = {
8
8
  root: string;
9
9
  deploy: DeployConfig;
10
+ applicationIcon: Config["applicationIcon"];
11
+ applicationId: Config["applicationId"];
10
12
  outDirOverride: string | undefined;
11
13
  };
12
14
 
13
- type ResolvedIcons = {
14
- iconsDir: string | null;
15
- iconFile: string | null;
16
- };
17
-
18
15
  const DEFAULT_OUT_DIR = "build";
19
16
  const DIST_DIR = "dist";
20
- const ICONS_DIR = "icons";
21
17
  const LICENSE_CANDIDATES = ["LICENSE", "LICENSE.md", "LICENSE.txt", "COPYING", "COPYING.md"];
22
18
 
23
19
  const isInside = (parent: string, candidate: string): boolean => {
@@ -37,17 +33,14 @@ const resolveOutDir = ({ root, deploy, outDirOverride }: PathsRequest): string =
37
33
  return outDir;
38
34
  };
39
35
 
40
- const getStats = (path: string): Stats | undefined => {
36
+ const existingFile = (path: string): string | null => {
41
37
  try {
42
- return statSync(path, { throwIfNoEntry: false });
38
+ return statSync(path, { throwIfNoEntry: false })?.isFile() === true ? path : null;
43
39
  } catch {
44
- return undefined;
40
+ return null;
45
41
  }
46
42
  };
47
43
 
48
- const existingFile = (path: string): string | null => (getStats(path)?.isFile() === true ? path : null);
49
- const existingDir = (path: string): string | null => (getStats(path)?.isDirectory() === true ? path : null);
50
-
51
44
  const resolveLicenseFile = (root: string, configured: string | undefined): string | null => {
52
45
  if (configured !== undefined) {
53
46
  const path = resolve(root, configured);
@@ -62,37 +55,9 @@ const resolveLicenseFile = (root: string, configured: string | undefined): strin
62
55
  return LICENSE_CANDIDATES.map((name) => existingFile(join(root, name))).find((path) => path !== null) ?? null;
63
56
  };
64
57
 
65
- const configuredIcons = (root: string, configured: string): ResolvedIcons => {
66
- const path = resolve(root, configured);
67
-
68
- if (!isInside(root, path)) {
69
- throw new Error(`Cannot use "${configured}" as the icon path: it is outside ${root}`);
70
- }
71
-
72
- if (existingDir(path) !== null) {
73
- return { iconsDir: path, iconFile: null };
74
- }
75
-
76
- if (existingFile(path) === null) {
77
- throw new Error(`Cannot read the icon path "${configured}": no such file or directory under ${root}`);
78
- }
79
-
80
- return { iconsDir: null, iconFile: path };
81
- };
82
-
83
- const defaultIcons = (root: string, dataDir: string | null): ResolvedIcons => ({
84
- iconsDir: dataDir === null ? null : existingDir(join(root, dataDir, ICONS_DIR)),
85
- iconFile: null,
86
- });
87
-
88
- const resolveIcons = (root: string, dataDir: string | null, configured: string | undefined): ResolvedIcons =>
89
- configured === undefined ? defaultIcons(root, dataDir) : configuredIcons(root, configured);
90
-
91
58
  const resolvePaths = (request: PathsRequest): DeployPaths => {
92
59
  const { root, deploy } = request;
93
60
  const outDir = resolveOutDir(request);
94
- const dataDir = resolveDataDir(root);
95
- const { iconsDir, iconFile } = resolveIcons(root, dataDir, deploy.icons);
96
61
 
97
62
  return {
98
63
  root,
@@ -104,11 +69,9 @@ const resolvePaths = (request: PathsRequest): DeployPaths => {
104
69
  overlay: join(outDir, "overlay"),
105
70
  targets: join(outDir, "targets"),
106
71
  output: join(outDir, "out"),
107
- dataDir,
108
- iconsDir,
109
- iconFile,
72
+ applicationIcon: resolveApplicationIcon(root, request.applicationId, request.applicationIcon),
110
73
  licenseFile: resolveLicenseFile(root, deploy.licenseFile),
111
- schemaFiles: dataDir === null ? [] : findSchemaFiles(join(root, dataDir)),
74
+ schemaFiles: [],
112
75
  };
113
76
  };
114
77
 
@@ -1,5 +1,5 @@
1
1
  import { existsSync, mkdirSync, rmSync, statSync } from "node:fs";
2
- import { join } from "node:path";
2
+ import { basename, join } from "node:path";
3
3
  import type {
4
4
  DeployArtifact,
5
5
  DeployManifest,
@@ -10,18 +10,21 @@ import type {
10
10
  } from "../types.js";
11
11
  import { runCliTool } from "../../internal/run-cli-tool.js";
12
12
  import { copyInto, copyTree, EXECUTABLE_MODE, writeInto } from "../payload/copy-tree.js";
13
- import { getIconSize } from "../payload/icons.js";
13
+ import { type ApplicationIconVariant, classifyApplicationIcon } from "../payload/icons.js";
14
14
  import { FILE_TOOL } from "../tools.js";
15
15
  import { resolveAppimageTooling } from "../vendored/appimagetool.js";
16
16
 
17
+ type RankedIcon = {
18
+ file: StagedFile;
19
+ variant: ApplicationIconVariant;
20
+ };
21
+
17
22
  const PREFIX = "/usr";
18
23
  const TARGET_DIR = "appimage";
19
24
  const APPRUN_FILENAME = "AppRun";
20
25
  const APPDIR_NAME = "AppDir";
21
26
  const USR_DIR = "usr";
22
- const ICON_EXTENSIONS = [".svg", ".png", ".xpm"];
23
27
  const EXTRACT_AND_RUN = "APPIMAGE_EXTRACT_AND_RUN";
24
- const SCALABLE_RANK = Number.MAX_SAFE_INTEGER;
25
28
 
26
29
  const appimageTarget: DeployTarget = {
27
30
  name: "appimage",
@@ -50,31 +53,45 @@ const renderManifests = (payload: DeployPayload): DeployManifest[] => [
50
53
  { path: appRunPathFor(payload.settings), contents: renderAppRun(payload.settings) },
51
54
  ];
52
55
 
53
- const iconRank = (file: StagedFile): number =>
54
- file.rel.endsWith(".svg") ? SCALABLE_RANK : (getIconSize(file.rel) ?? 0);
56
+ const rankedIcon = (applicationId: string, file: StagedFile): RankedIcon | null => {
57
+ const variant = classifyApplicationIcon(applicationId, file.rel);
58
+
59
+ return variant === null ? null : { file, variant };
60
+ };
61
+
62
+ const isLargerIcon = (candidate: RankedIcon, best: RankedIcon): boolean =>
63
+ candidate.variant.scalable === best.variant.scalable
64
+ ? candidate.variant.effectivePixels > best.variant.effectivePixels
65
+ : candidate.variant.scalable;
66
+
67
+ const largerIcon = (best: RankedIcon | undefined, candidate: RankedIcon): RankedIcon =>
68
+ best === undefined || isLargerIcon(candidate, best) ? candidate : best;
55
69
 
56
- const largestIcon = (icons: StagedFile[]): StagedFile | undefined => {
57
- let best: StagedFile | undefined;
70
+ const largestIcon = (applicationId: string, files: StagedFile[]): StagedFile | undefined => {
71
+ let best: RankedIcon | undefined;
58
72
 
59
- for (const file of icons) {
60
- if (best === undefined || iconRank(file) > iconRank(best)) {
61
- best = file;
73
+ for (const file of files) {
74
+ const candidate = rankedIcon(applicationId, file);
75
+
76
+ if (candidate === null) {
77
+ continue;
62
78
  }
79
+
80
+ best = largerIcon(best, candidate);
63
81
  }
64
82
 
65
- return best;
83
+ return best?.file;
66
84
  };
67
85
 
68
86
  const rootIconFor = (payload: DeployPayload): { rel: string; abs: string } => {
69
87
  const { applicationId } = payload.settings;
70
- const names = new Set(ICON_EXTENSIONS.map((extension) => `${applicationId}${extension}`));
71
- const icon = largestIcon(payload.stage.filter((file) => names.has(file.rel.split("/").at(-1) ?? "")));
88
+ const icon = largestIcon(applicationId, payload.stage);
72
89
 
73
90
  if (icon === undefined) {
74
91
  throw new Error(`Cannot build an AppImage without a ${applicationId} icon in the staged icon tree`);
75
92
  }
76
93
 
77
- return { rel: icon.rel.split("/").at(-1) ?? "", abs: icon.abs };
94
+ return { rel: basename(icon.rel), abs: icon.abs };
78
95
  };
79
96
 
80
97
  const buildAppDir = (payload: DeployPayload): string => {
@@ -110,6 +110,12 @@ const runtimeKeys = (settings: DeploySettings): FlatpakManifest => {
110
110
  };
111
111
  };
112
112
 
113
+ const runtimeLabelFor = (settings: DeploySettings): string => {
114
+ const flatpak = settings.deploy.flatpak ?? {};
115
+
116
+ return `${flatpak.runtime ?? DEFAULT_RUNTIME}//${flatpak.runtimeVersion ?? DEFAULT_RUNTIME_VERSION}`;
117
+ };
118
+
113
119
  const renderFlatpakManifest = (payload: DeployPayload): FlatpakManifest => {
114
120
  const settings = payload.settings;
115
121
 
@@ -123,4 +129,4 @@ const renderFlatpakManifest = (payload: DeployPayload): FlatpakManifest => {
123
129
  };
124
130
  };
125
131
 
126
- export { branchFor, finishArgsFor, hasDisplaySocket, renderFlatpakManifest };
132
+ export { branchFor, finishArgsFor, hasDisplaySocket, renderFlatpakManifest, runtimeLabelFor };
@@ -9,12 +9,12 @@ type PnpmPin = {
9
9
  sha512: string;
10
10
  };
11
11
 
12
- const PNPM_VERSION = "11.21.0";
12
+ const PNPM_VERSION = "11.22.0";
13
13
  const PNPM_MAJOR = 11;
14
- const PNPM_MINOR = 21;
14
+ const PNPM_MINOR = 22;
15
15
 
16
- const PNPM_SHA512 = "521705bce689924eac72f5a3587122f362689ef6571e55ba80076fd637c11132ecffada26" +
17
- "fad4ea79c485bfddbfd3d5a2a5b05805a77e893de71ec8a6cca3bb1";
16
+ const PNPM_SHA512 = "1ff870c4c6133dfd88fb2afc46dd13d47f09c9794b438c6fdb47ca98caf3bc16381ee0be9" +
17
+ "3a091b8e3824cf01f889f46d7d9e20910fb0be1ab0fb5baa80dd621";
18
18
 
19
19
  const PNPM_DIR = "flatpak-pnpm";
20
20
  const PNPM_COMMAND = "pnpm";
@@ -120,12 +120,11 @@ const metadataInstallCommands = (settings: DeploySettings): string[] => [
120
120
  const schemaInstallCommands = (settings: DeploySettings): string[] =>
121
121
  settings.paths.schemaFiles.map((file) => {
122
122
  const name = posix.basename(file);
123
+ const source = projectRelative(settings, file);
124
+ const destination = `${DESTINATION}/share/glib-2.0/schemas/${shellArgument(name)}`;
125
+ assertInsideProject(settings, { destination, source, resolved: file });
123
126
 
124
- return installCommand(
125
- projectRelative(settings, file),
126
- `${DESTINATION}/share/glib-2.0/schemas/${shellArgument(name)}`,
127
- "m644",
128
- );
127
+ return installCommand(source, destination, "m644");
129
128
  });
130
129
 
131
130
  const iconInstallCommand = (settings: DeploySettings, source: string, rel: string): string =>
@@ -136,17 +135,17 @@ const iconInstallCommand = (settings: DeploySettings, source: string, rel: strin
136
135
  );
137
136
 
138
137
  const iconInstallCommands = (settings: DeploySettings): string[] => {
139
- const { iconsDir, iconFile } = settings.paths;
138
+ const source = settings.paths.applicationIcon;
140
139
 
141
- if (iconFile !== null) {
142
- return [iconInstallCommand(settings, iconFile, iconPathFor(settings, iconFile))];
140
+ if (source.kind === "file") {
141
+ return [iconInstallCommand(settings, source.path, iconPathFor(settings, source.path))];
143
142
  }
144
143
 
145
- if (iconsDir === null) {
144
+ if (source.kind === "none") {
146
145
  return [];
147
146
  }
148
147
 
149
- return listFilesRecursive(iconsDir).map((icon) => iconInstallCommand(settings, icon.absPath, icon.rel));
148
+ return listFilesRecursive(source.path).map((icon) => iconInstallCommand(settings, icon.absPath, icon.rel));
150
149
  };
151
150
 
152
151
  const assertInsideProject = (settings: DeploySettings, installed: InstalledFile): void => {
@@ -1,4 +1,5 @@
1
1
  import type { Config } from "@gtkx/config";
2
+ import type { ResolvedApplicationIcon } from "../internal/icon-path.js";
2
3
 
3
4
  type DeployConfig = NonNullable<Config["deploy"]>;
4
5
  type DeployTargetName = NonNullable<DeployConfig["targets"]>[number];
@@ -21,7 +22,7 @@ type NodeRuntime = {
21
22
  path: string;
22
23
  licenseFile: string | null;
23
24
  version: string;
24
- glibcFloor: string | null;
25
+ glibcMinimum: string | null;
25
26
  isStripped: boolean;
26
27
  };
27
28
 
@@ -106,9 +107,7 @@ type DeployPaths = {
106
107
  overlay: string;
107
108
  targets: string;
108
109
  output: string;
109
- dataDir: string | null;
110
- iconsDir: string | null;
111
- iconFile: string | null;
110
+ applicationIcon: ResolvedApplicationIcon;
112
111
  licenseFile: string | null;
113
112
  schemaFiles: string[];
114
113
  };
@@ -145,6 +144,7 @@ type DeploySettings = {
145
144
  arch: DeployArch;
146
145
  paths: DeployPaths;
147
146
  libraries: string[];
147
+ minimumLibraryVersions: Record<string, string>;
148
148
  deploy: DeployConfig;
149
149
  };
150
150
 
@@ -1,18 +1,42 @@
1
- import { existsSync } from "node:fs";
2
- import { join } from "node:path";
1
+ import { mkdirSync, symlinkSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+ import {
4
+ relativeIconPath,
5
+ resolveApplicationIcon,
6
+ type ResolvedApplicationIcon,
7
+ } from "../internal/icon-path.js";
8
+ import { createRetainedStagingDir } from "../internal/staging-dir.js";
3
9
  import { prependXdgDataDir } from "../internal/xdg-data-dirs.js";
4
10
 
5
- const prepareDevIconDir = (root: string, dataDir: string | null): string | null => {
6
- if (dataDir === null) {
7
- return null;
11
+ const stageIconSource = (shareDir: string, applicationId: string, source: ResolvedApplicationIcon): void => {
12
+ if (source.kind === "theme") {
13
+ symlinkSync(source.path, join(shareDir, "icons"), "dir");
14
+
15
+ return;
16
+ }
17
+
18
+ if (source.kind === "none") {
19
+ return;
8
20
  }
9
21
 
10
- const shareDir = join(root, dataDir);
22
+ const target = join(shareDir, "icons", relativeIconPath(applicationId, source.path));
23
+ mkdirSync(dirname(target), { recursive: true });
24
+ symlinkSync(source.path, target, "file");
25
+ };
26
+
27
+ const prepareDevIconDir = (
28
+ root: string,
29
+ applicationId: string,
30
+ configured: string | undefined,
31
+ ): string | null => {
32
+ const source = resolveApplicationIcon(root, applicationId, configured);
11
33
 
12
- if (!existsSync(join(shareDir, "icons"))) {
34
+ if (source.kind === "none") {
13
35
  return null;
14
36
  }
15
37
 
38
+ const shareDir = createRetainedStagingDir("icons").retain();
39
+ stageIconSource(shareDir, applicationId, source);
16
40
  process.env.XDG_DATA_DIRS = prependXdgDataDir(shareDir, process.env.XDG_DATA_DIRS);
17
41
 
18
42
  return shareDir;
@@ -86,7 +86,11 @@ const defaultDevRunnerDeps = (): DevRunnerDeps => ({
86
86
  isRefreshBoundary,
87
87
  staleExportName,
88
88
  readFileRevision,
89
- plugins: () => [...gtkxVitePlugins(DEV_MODE), ...gtkxFastRefresh(), gtkxReactDomPrebundle()],
89
+ plugins: (entryPath) => [
90
+ ...gtkxVitePlugins(DEV_MODE, entryPath),
91
+ ...gtkxFastRefresh(),
92
+ gtkxReactDomPrebundle(),
93
+ ],
90
94
  log: info,
91
95
  exit: (code: number): never => process.exit(code),
92
96
  });
@@ -1,6 +1,6 @@
1
+ import { loadConfig } from "@gtkx/config";
1
2
  import { error } from "@gtkx/utils";
2
3
  import { resolve } from "node:path";
3
- import { resolveDataDir } from "../internal/data-dir.js";
4
4
  import { DEV_ENTRY_ENV } from "./entry-env.js";
5
5
  import { prepareDevIconDir } from "./icon-dir.js";
6
6
  import { createDevRunner } from "./runner.js";
@@ -21,9 +21,9 @@ const main = async (): Promise<void> => {
21
21
  process.exit(1);
22
22
  }
23
23
 
24
- const dataDir = resolveDataDir(cwd);
25
- prepareDevSchemaDir(cwd, dataDir);
26
- prepareDevIconDir(cwd, dataDir);
24
+ const { config, root } = await loadConfig(cwd, { mode: "development" });
25
+ prepareDevSchemaDir(root, config.future?.v2ResourceImports === true);
26
+ prepareDevIconDir(root, config.applicationId, config.applicationIcon);
27
27
  const entryPath = resolve(cwd, entryArg);
28
28
  const { defaultDevRunnerDeps } = await import("./runner-deps.js");
29
29
  const runner = createDevRunner(defaultDevRunnerDeps());
package/src/dev/runner.ts CHANGED
@@ -32,7 +32,7 @@ type DevRunnerDeps = {
32
32
  isRefreshBoundary(module: Record<string, unknown>): boolean;
33
33
  staleExportName(previous: Record<string, unknown>, current: Record<string, unknown>): string | null;
34
34
  readFileRevision(path: string): Promise<string>;
35
- plugins(): Plugin[];
35
+ plugins(entryPath: string): Plugin[];
36
36
  log(message: string): void;
37
37
  exit(code: number): never;
38
38
  };
@@ -602,7 +602,7 @@ const createSession = (server: DevServer, deps: DevRunnerDeps): DevSession => {
602
602
 
603
603
  const createDevRunner = (deps: DevRunnerDeps): DevRunner => ({
604
604
  async run(entryPath: string): Promise<void> {
605
- const server = await deps.createServer(createDevServerConfig(process.cwd(), deps.plugins()));
605
+ const server = await deps.createServer(createDevServerConfig(process.cwd(), deps.plugins(entryPath)));
606
606
  const session = createSession(server, deps);
607
607
  deps.installShutdownHandlers(onShutdownSignal(session));
608
608
 
@@ -1,6 +1,8 @@
1
+ import { resolveDataDir } from "../internal/data-dir.js";
1
2
  import { prependSchemaDir, stageAndCompileProjectSchemas } from "../settings/schema.js";
2
3
 
3
- const prepareDevSchemaDir = (root: string, dataDir: string | null): string | null => {
4
+ const prepareDevSchemaDir = (root: string, isV2ResourceImports: boolean): string | null => {
5
+ const dataDir = isV2ResourceImports ? null : resolveDataDir(root);
4
6
  const dir = stageAndCompileProjectSchemas(root, dataDir);
5
7
 
6
8
  if (dir === null) {
@@ -0,0 +1,32 @@
1
+ type RecordedPackage = {
2
+ name: string;
3
+ version: string | null;
4
+ dir: string;
5
+ };
6
+
7
+ type BuildManifest = {
8
+ generator: typeof BUILD_MANIFEST_GENERATOR;
9
+ formatVersion: typeof BUILD_MANIFEST_FORMAT_VERSION;
10
+ schemas: string[];
11
+ packages: RecordedPackage[];
12
+ };
13
+
14
+ type BuildManifestCollector = {
15
+ schemas: string[];
16
+ };
17
+
18
+ const BUILD_MANIFEST_FILENAME = "gtkx-schemas.json";
19
+ const BUILD_MANIFEST_GENERATOR = "gtkx-build";
20
+ const BUILD_MANIFEST_FORMAT_VERSION = 1;
21
+
22
+ const createBuildManifestCollector = (): BuildManifestCollector => ({ schemas: [] });
23
+
24
+ export {
25
+ BUILD_MANIFEST_FILENAME,
26
+ BUILD_MANIFEST_FORMAT_VERSION,
27
+ BUILD_MANIFEST_GENERATOR,
28
+ createBuildManifestCollector,
29
+ type BuildManifest,
30
+ type BuildManifestCollector,
31
+ type RecordedPackage,
32
+ };