react-native-gtkx 0.1.0-alpha.3 → 0.2.0-alpha.1

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 (193) hide show
  1. package/README.md +41 -3
  2. package/dist/adw/index.d.ts +3 -0
  3. package/dist/adw/index.js +41 -0
  4. package/dist/adw/index.js.map +1 -0
  5. package/dist/adw/widgets.generated.d.ts +63 -0
  6. package/dist/adw/widgets.generated.js +125 -0
  7. package/dist/adw/widgets.generated.js.map +1 -0
  8. package/dist/animated/create-animated.js +1 -1
  9. package/dist/animated/create-animated.js.map +1 -1
  10. package/dist/animated/index.js +3 -3
  11. package/dist/animated/index.js.map +1 -1
  12. package/dist/common/content.d.ts +69 -0
  13. package/dist/common/content.js +84 -0
  14. package/dist/common/content.js.map +1 -0
  15. package/dist/common/index.d.ts +3 -0
  16. package/dist/common/index.js +19 -0
  17. package/dist/common/index.js.map +1 -0
  18. package/dist/common/navigation-stack.d.ts +84 -0
  19. package/dist/common/navigation-stack.js +313 -0
  20. package/dist/common/navigation-stack.js.map +1 -0
  21. package/dist/common/widget.d.ts +83 -0
  22. package/dist/common/widget.js +142 -0
  23. package/dist/common/widget.js.map +1 -0
  24. package/dist/components/animated.d.ts +3 -2
  25. package/dist/components/animated.js +85 -66
  26. package/dist/components/animated.js.map +1 -1
  27. package/dist/components/app-registry.d.ts +10 -1
  28. package/dist/components/app-registry.js +8 -3
  29. package/dist/components/app-registry.js.map +1 -1
  30. package/dist/components/pressable.js +109 -16
  31. package/dist/components/pressable.js.map +1 -1
  32. package/dist/components/rect-store.d.ts +11 -1
  33. package/dist/components/rect-store.js +27 -3
  34. package/dist/components/rect-store.js.map +1 -1
  35. package/dist/components/svg/animated-support.d.ts +19 -0
  36. package/dist/components/svg/animated-support.js +64 -0
  37. package/dist/components/svg/animated-support.js.map +1 -0
  38. package/dist/components/svg/context.d.ts +8 -0
  39. package/dist/components/svg/context.js +15 -0
  40. package/dist/components/svg/context.js.map +1 -0
  41. package/dist/components/svg/gradients.d.ts +31 -0
  42. package/dist/components/svg/gradients.js +93 -0
  43. package/dist/components/svg/gradients.js.map +1 -0
  44. package/dist/components/svg/group.d.ts +8 -0
  45. package/dist/components/svg/group.js +30 -0
  46. package/dist/components/svg/group.js.map +1 -0
  47. package/dist/components/svg/index.d.ts +6 -0
  48. package/dist/components/svg/index.js +5 -0
  49. package/dist/components/svg/index.js.map +1 -0
  50. package/dist/components/svg/node.d.ts +7 -0
  51. package/dist/components/svg/node.js +7 -0
  52. package/dist/components/svg/node.js.map +1 -0
  53. package/dist/components/svg/paint.d.ts +24 -0
  54. package/dist/components/svg/paint.js +57 -0
  55. package/dist/components/svg/paint.js.map +1 -0
  56. package/dist/components/svg/shapes.d.ts +47 -0
  57. package/dist/components/svg/shapes.js +51 -0
  58. package/dist/components/svg/shapes.js.map +1 -0
  59. package/dist/components/svg/svg.d.ts +14 -0
  60. package/dist/components/svg/svg.js +48 -0
  61. package/dist/components/svg/svg.js.map +1 -0
  62. package/dist/components/svg/use-shape-node.d.ts +12 -0
  63. package/dist/components/svg/use-shape-node.js +52 -0
  64. package/dist/components/svg/use-shape-node.js.map +1 -0
  65. package/dist/components/text-input.js +3 -2
  66. package/dist/components/text-input.js.map +1 -1
  67. package/dist/components/text.js +11 -2
  68. package/dist/components/text.js.map +1 -1
  69. package/dist/components/use-layout-child.js +47 -4
  70. package/dist/components/use-layout-child.js.map +1 -1
  71. package/dist/contracts.d.ts +12 -1
  72. package/dist/contracts.js +2 -3
  73. package/dist/contracts.js.map +1 -1
  74. package/dist/gtk/index.d.ts +6 -0
  75. package/dist/gtk/index.js +39 -0
  76. package/dist/gtk/index.js.map +1 -0
  77. package/dist/gtk/widgets.generated.d.ts +103 -0
  78. package/dist/gtk/widgets.generated.js +206 -0
  79. package/dist/gtk/widgets.generated.js.map +1 -0
  80. package/dist/gtkx/bridge/index.d.ts +9 -4
  81. package/dist/gtkx/bridge/index.js +41 -5
  82. package/dist/gtkx/bridge/index.js.map +1 -1
  83. package/dist/gtkx/bridge/layout-manager.d.ts +2 -1
  84. package/dist/gtkx/bridge/layout-manager.js +31 -9
  85. package/dist/gtkx/bridge/layout-manager.js.map +1 -1
  86. package/dist/gtkx/bridge/svg-node.d.ts +79 -0
  87. package/dist/gtkx/bridge/svg-node.js +367 -0
  88. package/dist/gtkx/bridge/svg-node.js.map +1 -0
  89. package/dist/gtkx/bridge/theme.js +1 -1
  90. package/dist/gtkx/bridge/theme.js.map +1 -1
  91. package/dist/gtkx/bridge/use-signal.js +21 -10
  92. package/dist/gtkx/bridge/use-signal.js.map +1 -1
  93. package/dist/gtkx/bridge/widgets.generated.d.ts +2 -0
  94. package/dist/gtkx/bridge/widgets.generated.js +14 -0
  95. package/dist/gtkx/bridge/widgets.generated.js.map +1 -0
  96. package/dist/index.js +1 -1
  97. package/dist/index.js.map +1 -1
  98. package/dist/mcp/bin.d.ts +2 -0
  99. package/dist/mcp/bin.js +17 -0
  100. package/dist/mcp/bin.js.map +1 -0
  101. package/dist/mcp/data/generated.d.ts +1282 -0
  102. package/dist/mcp/data/generated.js +1148 -0
  103. package/dist/mcp/data/generated.js.map +1 -0
  104. package/dist/mcp/index.d.ts +5 -0
  105. package/dist/mcp/index.js +9 -0
  106. package/dist/mcp/index.js.map +1 -0
  107. package/dist/mcp/list.d.ts +4 -0
  108. package/dist/mcp/list.js +56 -0
  109. package/dist/mcp/list.js.map +1 -0
  110. package/dist/mcp/resolve.d.ts +55 -0
  111. package/dist/mcp/resolve.js +151 -0
  112. package/dist/mcp/resolve.js.map +1 -0
  113. package/dist/mcp/search.d.ts +13 -0
  114. package/dist/mcp/search.js +48 -0
  115. package/dist/mcp/search.js.map +1 -0
  116. package/dist/mcp/server.d.ts +7 -0
  117. package/dist/mcp/server.js +135 -0
  118. package/dist/mcp/server.js.map +1 -0
  119. package/dist/mcp/tool.d.ts +21 -0
  120. package/dist/mcp/tool.js +36 -0
  121. package/dist/mcp/tool.js.map +1 -0
  122. package/dist/metro/index.js +10 -0
  123. package/dist/metro/index.js.map +1 -1
  124. package/dist/navigation/index.d.ts +50 -13
  125. package/dist/navigation/index.js +183 -148
  126. package/dist/navigation/index.js.map +1 -1
  127. package/dist/navigation/option-warnings.js +9 -1
  128. package/dist/navigation/option-warnings.js.map +1 -1
  129. package/dist/navigation/sidebar.d.ts +177 -9
  130. package/dist/navigation/sidebar.js +284 -10
  131. package/dist/navigation/sidebar.js.map +1 -1
  132. package/dist/runner/index.d.ts +22 -2
  133. package/dist/runner/index.js +163 -12
  134. package/dist/runner/index.js.map +1 -1
  135. package/dist/sea/assemble.d.ts +29 -0
  136. package/dist/sea/assemble.js +129 -0
  137. package/dist/sea/assemble.js.map +1 -0
  138. package/dist/sea/bundle.d.ts +61 -0
  139. package/dist/sea/bundle.js +202 -0
  140. package/dist/sea/bundle.js.map +1 -0
  141. package/dist/sea/gtkx-config-module.d.ts +18 -0
  142. package/dist/sea/gtkx-config-module.js +67 -0
  143. package/dist/sea/gtkx-config-module.js.map +1 -0
  144. package/dist/sea/native-shim.d.ts +40 -0
  145. package/dist/sea/native-shim.js +121 -0
  146. package/dist/sea/native-shim.js.map +1 -0
  147. package/dist/sea/react-anchor-plugin.d.ts +2 -0
  148. package/dist/sea/react-anchor-plugin.js +30 -0
  149. package/dist/sea/react-anchor-plugin.js.map +1 -0
  150. package/dist/style/colors.js +3 -1
  151. package/dist/style/colors.js.map +1 -1
  152. package/dist/style/index.d.ts +1 -0
  153. package/dist/style/index.js +3 -2
  154. package/dist/style/index.js.map +1 -1
  155. package/dist/style/registry.gtkx.js +1 -1
  156. package/dist/style/registry.gtkx.js.map +1 -1
  157. package/dist/style/split-style.js +3 -3
  158. package/dist/style/split-style.js.map +1 -1
  159. package/dist/style/text-align.js +1 -1
  160. package/dist/style/text-align.js.map +1 -1
  161. package/dist/style/transform.d.ts +22 -0
  162. package/dist/style/transform.js +137 -0
  163. package/dist/style/transform.js.map +1 -0
  164. package/dist/style/visual-css.js +3 -2
  165. package/dist/style/visual-css.js.map +1 -1
  166. package/dist/svg/geometry.d.ts +19 -0
  167. package/dist/svg/geometry.js +80 -0
  168. package/dist/svg/geometry.js.map +1 -0
  169. package/dist/svg/gradient-geometry.d.ts +15 -0
  170. package/dist/svg/gradient-geometry.js +18 -0
  171. package/dist/svg/gradient-geometry.js.map +1 -0
  172. package/dist/svg/transform.d.ts +22 -0
  173. package/dist/svg/transform.js +74 -0
  174. package/dist/svg/transform.js.map +1 -0
  175. package/dist/svg/view-box.d.ts +34 -0
  176. package/dist/svg/view-box.js +108 -0
  177. package/dist/svg/view-box.js.map +1 -0
  178. package/dist/svg-compat/index.d.ts +1 -0
  179. package/dist/svg-compat/index.js +16 -0
  180. package/dist/svg-compat/index.js.map +1 -0
  181. package/dist/testing/index.d.ts +14 -0
  182. package/dist/testing/index.js +14 -0
  183. package/dist/testing/index.js.map +1 -0
  184. package/dist/vite/index.d.ts +7 -3
  185. package/dist/vite/index.js +16 -3
  186. package/dist/vite/index.js.map +1 -1
  187. package/dist/vitest/index.d.ts +52 -0
  188. package/dist/vitest/index.js +58 -0
  189. package/dist/vitest/index.js.map +1 -0
  190. package/dist/vitest/setup.d.ts +4 -0
  191. package/dist/vitest/setup.js +22 -0
  192. package/dist/vitest/setup.js.map +1 -0
  193. package/package.json +47 -8
@@ -13,7 +13,6 @@ import { mkdirSync } from "node:fs";
13
13
  import { createRequire } from "node:module";
14
14
  import { basename, dirname, extname, join } from "node:path";
15
15
  import { fileURLToPath } from "node:url";
16
- const fromPackage = createRequire(import.meta.url);
17
16
  /** Exit code host-dev.ts uses to request a supervisor restart. */
18
17
  const FULL_REFRESH_EXIT_CODE = 65;
19
18
  const run = (command, args, cwd) => {
@@ -30,19 +29,70 @@ const binOf = (requireFrom, packageName, binName) => {
30
29
  }
31
30
  return join(dirname(packageJsonPath), bin);
32
31
  };
33
- // The codegen store lives in the node_modules that hosts the @gtkx
34
- // packages — run the gtkx CLI from the project that OWNS that node_modules:
35
- // with cwd inside node_modules itself the CLI reports "up to date" without
36
- // ever creating the store.
37
- const ensureCodegenStore = () => {
38
- const hostingNodeModules = dirname(dirname(dirname(fromPackage.resolve("@gtkx/react/package.json"))));
39
- const gtkxRoot = dirname(hostingNodeModules);
32
+ /** The `@gtkx/react` subpath exports (its own `exports` map, minus `.` and `./package.json`). */
33
+ const reactSubexportsOf = (manifest) => Object.keys(manifest.exports ?? {})
34
+ .filter((key) => key.startsWith("./") && key !== "./package.json")
35
+ .map((key) => key.slice(2));
36
+ // @gtkx/cli is meant for apps: its `codegen` command resolves gtkx.config.ts
37
+ // from a cwd and trusts a freshness stamp, which is what the RC2-WORKAROUND
38
+ // this replaced was dodging (running from a reconstructed "project that owns
39
+ // the hosting node_modules" purely to keep that cwd resolution honest — see
40
+ // gtkx-org/gtkx#468, #470). A library generating bindings on a consumer's
41
+ // behalf should use the programmatic @gtkx/codegen API instead: it takes the
42
+ // GIR libraries and store paths directly, so there is no cwd to get wrong and
43
+ // no stamp to misread — and it runs its own fingerprint-based freshness
44
+ // check in-process, so a missing/pruned store is regenerated rather than
45
+ // misreported as "up to date".
46
+ //
47
+ // `root` (the app's real project root, resolved by the react-native CLI, not
48
+ // us) is the right place to resolve gtkx.config.ts from, but NOT necessarily
49
+ // where @gtkx/* actually lives on disk: in a workspace, npm hoists them to an
50
+ // ancestor's node_modules, so `root/node_modules` can be a directory with no
51
+ // @gtkx/* in it at all (confirmed against this repo's own examples/, which
52
+ // are workspace members with nothing hoisted locally). The store — and the
53
+ // @gtkx/gi and @gtkx/jsx links every other @gtkx/* package resolves through
54
+ // its OWN up-the-tree lookup — must live in whichever node_modules actually
55
+ // hosts @gtkx/runtime, so that's resolved rather than assumed.
56
+ const ensureCodegenStore = async (root) => {
40
57
  console.warn("[react-native-gtkx] ensuring gtkx codegen store…");
41
- const status = run(process.execPath, [binOf(fromPackage, "@gtkx/cli", "gtkx"), "codegen"], gtkxRoot);
42
- if (status !== 0) {
58
+ try {
59
+ const [{ runCodegen, resolveGirPath, resolveLibraries }, { loadConfig }] = await Promise.all([import("@gtkx/codegen"), import("@gtkx/config")]);
60
+ const { config } = await loadConfig(root);
61
+ if (config.codegen === false) {
62
+ console.warn("[react-native-gtkx] codegen: disabled for this project (gtkx.config.ts)");
63
+ return;
64
+ }
65
+ const girPath = resolveGirPath(config.girPath);
66
+ const libraries = resolveLibraries(config.libraries, girPath);
67
+ const appRequire = createRequire(join(root, "package.json"));
68
+ const runtimePackageJsonPath = appRequire.resolve("@gtkx/runtime/package.json");
69
+ const nodeModules = dirname(dirname(dirname(runtimePackageJsonPath)));
70
+ const runtime = appRequire(runtimePackageJsonPath);
71
+ const react = appRequire("@gtkx/react/package.json");
72
+ const result = await runCodegen({
73
+ libraries,
74
+ girPath,
75
+ gi: {
76
+ storeDir: join(nodeModules, ".gtkx", "gi"),
77
+ linkDir: join(nodeModules, "@gtkx", "gi"),
78
+ version: runtime.version,
79
+ },
80
+ jsx: {
81
+ storeDir: join(nodeModules, ".gtkx", "jsx"),
82
+ linkDir: join(nodeModules, "@gtkx", "jsx"),
83
+ version: react.version,
84
+ },
85
+ reactSubexports: reactSubexportsOf(react),
86
+ });
87
+ console.warn(result.regenerated
88
+ ? "[react-native-gtkx] codegen: regenerated stale bindings"
89
+ : "[react-native-gtkx] codegen: bindings up to date");
90
+ }
91
+ catch (error) {
43
92
  console.error("[react-native-gtkx] gtkx codegen failed — are GTK4/libadwaita " +
44
93
  "development files installed?");
45
- process.exit(status);
94
+ console.error(error);
95
+ process.exit(1);
46
96
  }
47
97
  };
48
98
  const bundle = (root, entryFile, output) => {
@@ -136,7 +186,7 @@ const runLinuxDev = async (config, args) => {
136
186
  }
137
187
  };
138
188
  const runLinux = async (_argv, config, args) => {
139
- ensureCodegenStore();
189
+ await ensureCodegenStore(config.root);
140
190
  if (args.dev) {
141
191
  await runLinuxDev(config, args);
142
192
  return;
@@ -150,6 +200,75 @@ const runLinux = async (_argv, config, args) => {
150
200
  const status = await spawnHost("./host.js", output, config.root);
151
201
  process.exit(status);
152
202
  };
203
+ /**
204
+ * The executable name a `--sea` build defaults to: the app's package name
205
+ * without its scope, so the artifact is `dist/hn-app`, not `dist/app`.
206
+ */
207
+ const appBinaryName = (root) => {
208
+ try {
209
+ const manifest = createRequire(join(root, "package.json"))("./package.json");
210
+ const name = manifest.name?.split("/").pop();
211
+ return name && /^[\w.-]+$/.test(name) ? name : "app";
212
+ }
213
+ catch {
214
+ return "app";
215
+ }
216
+ };
217
+ // The android/ios counterpart to run-linux's dev-only bundling: bundle for
218
+ // distribution and stop, the way a release APK/IPA build does not launch
219
+ // the app it produces. Deliberately skips ensureCodegenStore() — codegen
220
+ // generates the @gtkx/gi bindings host.js imports to talk to GTK at RUN
221
+ // time; bundling never touches them (Metro only reads/transforms JS, and
222
+ // the GTK/react/yoga modules are proxied rather than imported — see
223
+ // ../metro's HOST_MODULE_EXTERNALS). A machine that only builds never needs
224
+ // GTK dev headers installed.
225
+ //
226
+ // --standalone and --sea are the exception: both inline
227
+ // "virtual:gtkx-config", which re-exports @gtkx/jsx/metadata — a codegen
228
+ // product — so they DO need the store, and therefore GTK dev headers.
229
+ // Only those paths ensure it.
230
+ //
231
+ // The three artifacts, cheapest to heaviest, are deliberately one command
232
+ // with flags rather than three commands: they share the Metro bundle step,
233
+ // and the choice between them is a distribution question, not a different
234
+ // build.
235
+ // (default) main.jsbundle + a runtime node_modules + a system node
236
+ // --standalone one .cjs file, no node_modules, + a system node
237
+ // --sea one executable, nothing preinstalled at all
238
+ const buildLinux = async (_argv, config, args) => {
239
+ if (args.sea || args.standalone) {
240
+ await ensureCodegenStore(config.root);
241
+ }
242
+ const output = args.bundleOutput ?? join(config.root, "dist", "main.jsbundle");
243
+ mkdirSync(dirname(output), { recursive: true });
244
+ bundle(config.root, args.entryFile, output);
245
+ console.warn(`[react-native-gtkx] wrote the release bundle to ${output}`);
246
+ if (!args.sea && !args.standalone) {
247
+ return;
248
+ }
249
+ const name = appBinaryName(config.root);
250
+ const seaOutput = args.seaOutput ?? join(config.root, "dist", args.sea ? name : `${name}.cjs`);
251
+ // Dynamically imported so the bundler is never loaded on the ordinary
252
+ // jsbundle path.
253
+ const { assembleSea, bundleStandalone } = await import("../sea/assemble.js");
254
+ const bytes = args.sea
255
+ ? await assembleSea({
256
+ appRoot: config.root,
257
+ jsbundlePath: output,
258
+ outFile: seaOutput,
259
+ })
260
+ : await bundleStandalone({
261
+ appRoot: config.root,
262
+ jsbundlePath: output,
263
+ outFile: seaOutput,
264
+ });
265
+ const megabytes = (bytes / 1024 / 1024).toFixed(0);
266
+ console.warn(args.sea
267
+ ? `[react-native-gtkx] wrote the single executable to ${seaOutput} ` +
268
+ `(${megabytes} MB — Node itself is most of it)`
269
+ : `[react-native-gtkx] wrote the standalone script to ${seaOutput} ` +
270
+ `(${megabytes} MB — run it with \`node ${seaOutput}\`)`);
271
+ };
153
272
  /** Commands contributed to the RN CLI by the package's react-native.config.js. */
154
273
  export const commands = [
155
274
  {
@@ -180,5 +299,37 @@ export const commands = [
180
299
  ],
181
300
  func: runLinux,
182
301
  },
302
+ {
303
+ name: "build-linux",
304
+ description: "Bundle the app with Metro for the linux platform for distribution, without running it",
305
+ options: [
306
+ {
307
+ name: "--entry-file <path>",
308
+ description: "Path to the app entry file",
309
+ default: "index.js",
310
+ },
311
+ {
312
+ name: "--bundle-output <path>",
313
+ description: "Where to write the release jsbundle (default: dist/main.jsbundle)",
314
+ },
315
+ {
316
+ name: "--standalone",
317
+ description: "Also produce one self-contained .cjs — no node_modules, run it " +
318
+ "with a system node (dist/<package name>.cjs)",
319
+ },
320
+ {
321
+ name: "--sea",
322
+ description: "Also produce a single executable (Node SEA): one file that runs " +
323
+ "with no node_modules and no system Node — at the cost of " +
324
+ "carrying a whole Node binary (~120 MB)",
325
+ },
326
+ {
327
+ name: "--sea-output <path>",
328
+ description: "Where to write the --sea / --standalone artifact " +
329
+ "(default: dist/<package name>[.cjs])",
330
+ },
331
+ ],
332
+ func: buildLinux,
333
+ },
183
334
  ];
184
335
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/runner/index.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,2EAA2E;AAC3E,yEAAyE;AACzE,uEAAuE;AACvE,oEAAoE;AACpE,uEAAuE;AACvE,4CAA4C;AAC5C,EAAE;AACF,kEAAkE;AAClE,qCAAqC;AACrC,OAAO,EAAE,KAAK,EAAE,SAAS,EAAqB,MAAM,oBAAoB,CAAA;AACxE,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAExC,MAAM,WAAW,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAWlD,kEAAkE;AAClE,MAAM,sBAAsB,GAAG,EAAE,CAAA;AAEjC,MAAM,GAAG,GAAG,CAAC,OAAe,EAAE,IAAc,EAAE,GAAW,EAAU,EAAE;IACnE,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAA;IAClE,OAAO,MAAM,CAAC,MAAM,IAAI,CAAC,CAAA;AAC3B,CAAC,CAAA;AAED,wEAAwE;AACxE,MAAM,KAAK,GAAG,CACZ,WAA2B,EAC3B,WAAmB,EACnB,OAAe,EACP,EAAE;IACV,MAAM,eAAe,GAAG,WAAW,CAAC,OAAO,CAAC,GAAG,WAAW,eAAe,CAAC,CAAA;IAC1E,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,WAAW,eAAe,CAEzD,CAAA;IACD,MAAM,GAAG,GACP,OAAO,QAAQ,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,CAAA;IAC3E,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CAAC,GAAG,WAAW,uBAAuB,OAAO,UAAU,CAAC,CAAA;IACzE,CAAC;IACD,OAAO,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,GAAG,CAAC,CAAA;AAC5C,CAAC,CAAA;AAED,mEAAmE;AACnE,4EAA4E;AAC5E,2EAA2E;AAC3E,2BAA2B;AAC3B,MAAM,kBAAkB,GAAG,GAAS,EAAE;IACpC,MAAM,kBAAkB,GAAG,OAAO,CAChC,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,0BAA0B,CAAC,CAAC,CAAC,CAClE,CAAA;IACD,MAAM,QAAQ,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAA;IAC5C,OAAO,CAAC,IAAI,CAAC,kDAAkD,CAAC,CAAA;IAChE,MAAM,MAAM,GAAG,GAAG,CAChB,OAAO,CAAC,QAAQ,EAChB,CAAC,KAAK,CAAC,WAAW,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE,SAAS,CAAC,EACpD,QAAQ,CACT,CAAA;IACD,IAAI,MAAM,KAAK,CAAC,EAAE,CAAC;QACjB,OAAO,CAAC,KAAK,CACX,gEAAgE;YAC9D,8BAA8B,CACjC,CAAA;QACD,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IACtB,CAAC;AACH,CAAC,CAAA;AAED,MAAM,MAAM,GAAG,CAAC,IAAY,EAAE,SAAiB,EAAE,MAAc,EAAQ,EAAE;IACvE,MAAM,UAAU,GAAG,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC,CAAA;IAC5D,MAAM,MAAM,GAAG,GAAG,CAChB,OAAO,CAAC,QAAQ,EAChB;QACE,KAAK,CAAC,UAAU,EAAE,cAAc,EAAE,cAAc,CAAC;QACjD,QAAQ;QACR,YAAY;QACZ,OAAO;QACP,OAAO;QACP,OAAO;QACP,cAAc;QACd,SAAS;QACT,iBAAiB;QACjB,MAAM;KACP,EACD,IAAI,CACL,CAAA;IACD,IAAI,MAAM,KAAK,CAAC,EAAE,CAAC;QACjB,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IACtB,CAAC;AACH,CAAC,CAAA;AAED,MAAM,cAAc,GAAG,KAAK,EAAE,MAAc,EAAoB,EAAE;IAChE,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,SAAS,CAAC,CAAA;QAChD,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,yBAAyB,CAAC,CAAA;IACpE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC,CAAA;AAED,MAAM,YAAY,GAAG,KAAK,EAAE,MAAc,EAAiB,EAAE;IAC3D,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,GAAG,EAAE,OAAO,IAAI,CAAC,EAAE,CAAC;QAClD,IAAI,MAAM,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC;YACjC,OAAM;QACR,CAAC;QACD,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAA;IAC1D,CAAC;IACD,OAAO,CAAC,KAAK,CACX,uDAAuD,MAAM,IAAI,CAClE,CAAA;IACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC,CAAA;AAED,IAAI,UAAU,GAAwB,IAAI,CAAA;AAE1C,MAAM,SAAS,GAAG,CAChB,MAAc,EACd,QAAgB,EAChB,GAAW,EACM,EAAE,CACnB,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;IACtB,uEAAuE;IACvE,wEAAwE;IACxE,wDAAwD;IACxD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAA;IACtE,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE;QAC1D,GAAG;QACH,KAAK,EAAE,SAAS;KACjB,CAAC,CAAA;IACF,UAAU,GAAG,KAAK,CAAA;IAClB,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;QACxB,UAAU,GAAG,IAAI,CAAA;QACjB,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC,CAAA;IACpB,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEJ,MAAM,WAAW,GAAG,KAAK,EACvB,MAAiB,EACjB,IAAkB,EACF,EAAE;IAClB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,MAAM,CAAA;IAChC,MAAM,MAAM,GAAG,oBAAoB,IAAI,EAAE,CAAA;IACzC,IAAI,KAAK,GAAwB,IAAI,CAAA;IACrC,IAAI,MAAM,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC;QACjC,OAAO,CAAC,IAAI,CACV,uDAAuD,MAAM,EAAE,CAChE,CAAA;IACH,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,IAAI,CACV,wDAAwD,MAAM,GAAG,CAClE,CAAA;QACD,MAAM,UAAU,GAAG,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC,CAAA;QACnE,KAAK,GAAG,KAAK,CACX,OAAO,CAAC,QAAQ,EAChB;YACE,KAAK,CAAC,UAAU,EAAE,cAAc,EAAE,cAAc,CAAC;YACjD,OAAO;YACP,QAAQ;YACR,IAAI;SACL,EACD,EAAE,GAAG,EAAE,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,CACvC,CAAA;QACD,MAAM,YAAY,CAAC,MAAM,CAAC,CAAA;IAC5B,CAAC;IACD,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAA;IAC/D,MAAM,SAAS,GAAG,GAAG,MAAM,IAAI,KAAK,8CAA8C,CAAA;IAClF,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAS,EAAE;QACvC,UAAU,EAAE,IAAI,EAAE,CAAA;QAClB,KAAK,EAAE,IAAI,EAAE,CAAA;QACb,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACpB,CAAC,CAAA;IACD,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAA;IACvC,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAA;IACxC,uEAAuE;IACvE,kEAAkE;IAClE,SAAS,CAAC;QACR,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,eAAe,EAAE,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,CAAA;QACrE,IAAI,IAAI,KAAK,sBAAsB,EAAE,CAAC;YACpC,QAAQ,CAAC,IAAI,CAAC,CAAA;QAChB,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,8DAA8D,CAAC,CAAA;IAC9E,CAAC;AACH,CAAC,CAAA;AAED,MAAM,QAAQ,GAAG,KAAK,EACpB,KAAe,EACf,MAAiB,EACjB,IAAkB,EACH,EAAE;IACjB,kBAAkB,EAAE,CAAA;IACpB,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;QACb,MAAM,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;QAC/B,OAAM;IACR,CAAC;IACD,MAAM,MAAM,GACV,IAAI,CAAC,YAAY;QACjB,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,cAAc,EAAE,oBAAoB,EAAE,eAAe,CAAC,CAAA;IAC1E,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;QACvB,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAC/C,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAA;IAC7C,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAA;IAChE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;AACtB,CAAC,CAAA;AAED,kFAAkF;AAClF,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB;QACE,IAAI,EAAE,WAAW;QACjB,WAAW,EACT,kFAAkF;QACpF,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,qBAAqB;gBAC3B,WAAW,EAAE,4BAA4B;gBACzC,OAAO,EAAE,UAAU;aACpB;YACD;gBACE,IAAI,EAAE,wBAAwB;gBAC9B,WAAW,EACT,sFAAsF;aACzF;YACD;gBACE,IAAI,EAAE,iBAAiB;gBACvB,WAAW,EAAE,8CAA8C;aAC5D;YACD;gBACE,IAAI,EAAE,OAAO;gBACb,WAAW,EACT,oFAAoF;aACvF;YACD;gBACE,IAAI,EAAE,iBAAiB;gBACvB,WAAW,EAAE,iDAAiD;aAC/D;SACF;QACD,IAAI,EAAE,QAAQ;KACf;CACF,CAAA","sourcesContent":["// The `run-linux` CLI command (registered through the package's\n// react-native.config.js, the react-native-windows model): ensure the gtkx\n// codegen store, then either build a release jsbundle with Metro and run\n// it in the Node+GTK host (./host.ts), or — with --dev — start/reuse a\n// Metro dev server and supervise the DEV host (./host-dev.ts): Fast\n// Refresh applies edits to the live window, and a full-refresh request\n// (exit code 65) restarts the host process.\n//\n// Like the hosts, this module must stay runnable under bare Node:\n// builtins and bare specifiers only.\nimport { spawn, spawnSync, type ChildProcess } from \"node:child_process\"\nimport { mkdirSync } from \"node:fs\"\nimport { createRequire } from \"node:module\"\nimport { basename, dirname, extname, join } from \"node:path\"\nimport { fileURLToPath } from \"node:url\"\n\nconst fromPackage = createRequire(import.meta.url)\n\ntype CliConfig = { root: string }\ntype RunLinuxArgs = {\n entryFile: string\n bundleOutput?: string\n skipBundling?: boolean\n dev?: boolean\n port?: string\n}\n\n/** Exit code host-dev.ts uses to request a supervisor restart. */\nconst FULL_REFRESH_EXIT_CODE = 65\n\nconst run = (command: string, args: string[], cwd: string): number => {\n const result = spawnSync(command, args, { cwd, stdio: \"inherit\" })\n return result.status ?? 1\n}\n\n/** Resolve an executable script shipped by a dependency's bin field. */\nconst binOf = (\n requireFrom: NodeJS.Require,\n packageName: string,\n binName: string,\n): string => {\n const packageJsonPath = requireFrom.resolve(`${packageName}/package.json`)\n const manifest = requireFrom(`${packageName}/package.json`) as {\n bin?: string | Record<string, string>\n }\n const bin =\n typeof manifest.bin === \"string\" ? manifest.bin : manifest.bin?.[binName]\n if (!bin) {\n throw new Error(`${packageName} does not expose a \"${binName}\" binary`)\n }\n return join(dirname(packageJsonPath), bin)\n}\n\n// The codegen store lives in the node_modules that hosts the @gtkx\n// packages — run the gtkx CLI from the project that OWNS that node_modules:\n// with cwd inside node_modules itself the CLI reports \"up to date\" without\n// ever creating the store.\nconst ensureCodegenStore = (): void => {\n const hostingNodeModules = dirname(\n dirname(dirname(fromPackage.resolve(\"@gtkx/react/package.json\"))),\n )\n const gtkxRoot = dirname(hostingNodeModules)\n console.warn(\"[react-native-gtkx] ensuring gtkx codegen store…\")\n const status = run(\n process.execPath,\n [binOf(fromPackage, \"@gtkx/cli\", \"gtkx\"), \"codegen\"],\n gtkxRoot,\n )\n if (status !== 0) {\n console.error(\n \"[react-native-gtkx] gtkx codegen failed — are GTK4/libadwaita \" +\n \"development files installed?\",\n )\n process.exit(status)\n }\n}\n\nconst bundle = (root: string, entryFile: string, output: string): void => {\n const appRequire = createRequire(join(root, \"package.json\"))\n const status = run(\n process.execPath,\n [\n binOf(appRequire, \"react-native\", \"react-native\"),\n \"bundle\",\n \"--platform\",\n \"linux\",\n \"--dev\",\n \"false\",\n \"--entry-file\",\n entryFile,\n \"--bundle-output\",\n output,\n ],\n root,\n )\n if (status !== 0) {\n process.exit(status)\n }\n}\n\nconst isMetroRunning = async (server: string): Promise<boolean> => {\n try {\n const response = await fetch(`${server}/status`)\n return (await response.text()).includes(\"packager-status:running\")\n } catch {\n return false\n }\n}\n\nconst waitForMetro = async (server: string): Promise<void> => {\n for (let attempt = 0; attempt < 120; attempt += 1) {\n if (await isMetroRunning(server)) {\n return\n }\n await new Promise((resolve) => setTimeout(resolve, 500))\n }\n console.error(\n `[react-native-gtkx] Metro dev server never came up (${server}).`,\n )\n process.exit(1)\n}\n\nlet activeHost: ChildProcess | null = null\n\nconst spawnHost = (\n script: string,\n argument: string,\n cwd: string,\n): Promise<number> =>\n new Promise((resolve) => {\n // join over `new URL(script, import.meta.url)`: the global URL and the\n // node:url URL come from different type copies when the dependency tree\n // splits @types/node, and the two structurally diverge.\n const hostPath = join(dirname(fileURLToPath(import.meta.url)), script)\n const child = spawn(process.execPath, [hostPath, argument], {\n cwd,\n stdio: \"inherit\",\n })\n activeHost = child\n child.on(\"exit\", (code) => {\n activeHost = null\n resolve(code ?? 1)\n })\n })\n\nconst runLinuxDev = async (\n config: CliConfig,\n args: RunLinuxArgs,\n): Promise<never> => {\n const port = args.port ?? \"8081\"\n const server = `http://localhost:${port}`\n let metro: ChildProcess | null = null\n if (await isMetroRunning(server)) {\n console.warn(\n `[react-native-gtkx] reusing the Metro dev server at ${server}`,\n )\n } else {\n console.warn(\n `[react-native-gtkx] starting the Metro dev server at ${server}…`,\n )\n const appRequire = createRequire(join(config.root, \"package.json\"))\n metro = spawn(\n process.execPath,\n [\n binOf(appRequire, \"react-native\", \"react-native\"),\n \"start\",\n \"--port\",\n port,\n ],\n { cwd: config.root, stdio: \"inherit\" },\n )\n await waitForMetro(server)\n }\n const entry = basename(args.entryFile, extname(args.entryFile))\n const bundleUrl = `${server}/${entry}.bundle?platform=linux&dev=true&minify=false`\n const shutdown = (code: number): never => {\n activeHost?.kill()\n metro?.kill()\n process.exit(code)\n }\n process.on(\"SIGINT\", () => shutdown(0))\n process.on(\"SIGTERM\", () => shutdown(0))\n // Supervisor: a full-refresh request restarts the host with the window\n // reopening on the fresh bundle; any other exit ends the session.\n for (;;) {\n const code = await spawnHost(\"./host-dev.js\", bundleUrl, config.root)\n if (code !== FULL_REFRESH_EXIT_CODE) {\n shutdown(code)\n }\n console.warn(\"[react-native-gtkx] restarting the app after a full refresh…\")\n }\n}\n\nconst runLinux = async (\n _argv: string[],\n config: CliConfig,\n args: RunLinuxArgs,\n): Promise<void> => {\n ensureCodegenStore()\n if (args.dev) {\n await runLinuxDev(config, args)\n return\n }\n const output =\n args.bundleOutput ??\n join(config.root, \"node_modules\", \".react-native-gtkx\", \"main.jsbundle\")\n if (!args.skipBundling) {\n mkdirSync(dirname(output), { recursive: true })\n bundle(config.root, args.entryFile, output)\n }\n const status = await spawnHost(\"./host.js\", output, config.root)\n process.exit(status)\n}\n\n/** Commands contributed to the RN CLI by the package's react-native.config.js. */\nexport const commands = [\n {\n name: \"run-linux\",\n description:\n \"Bundle the app with Metro for the linux platform and run it in the Node+GTK host\",\n options: [\n {\n name: \"--entry-file <path>\",\n description: \"Path to the app entry file\",\n default: \"index.js\",\n },\n {\n name: \"--bundle-output <path>\",\n description:\n \"Where to write the jsbundle (default: node_modules/.react-native-gtkx/main.jsbundle)\",\n },\n {\n name: \"--skip-bundling\",\n description: \"Reuse the existing bundle at --bundle-output\",\n },\n {\n name: \"--dev\",\n description:\n \"Development mode: Metro dev server + Fast Refresh (edits apply to the live window)\",\n },\n {\n name: \"--port <number>\",\n description: \"Metro dev server port for --dev (default: 8081)\",\n },\n ],\n func: runLinux,\n },\n]\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/runner/index.ts"],"names":[],"mappings":"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","sourcesContent":["// The `run-linux` CLI command (registered through the package's\n// react-native.config.js, the react-native-windows model): ensure the gtkx\n// codegen store, then either build a release jsbundle with Metro and run\n// it in the Node+GTK host (./host.ts), or — with --dev — start/reuse a\n// Metro dev server and supervise the DEV host (./host-dev.ts): Fast\n// Refresh applies edits to the live window, and a full-refresh request\n// (exit code 65) restarts the host process.\n//\n// Like the hosts, this module must stay runnable under bare Node:\n// builtins and bare specifiers only.\nimport { spawn, spawnSync, type ChildProcess } from \"node:child_process\"\nimport { mkdirSync } from \"node:fs\"\nimport { createRequire } from \"node:module\"\nimport { basename, dirname, extname, join } from \"node:path\"\nimport { fileURLToPath } from \"node:url\"\n\ntype CliConfig = { root: string }\ntype RunLinuxArgs = {\n entryFile: string\n bundleOutput?: string\n skipBundling?: boolean\n dev?: boolean\n port?: string\n}\ntype BuildLinuxArgs = {\n entryFile: string\n bundleOutput?: string\n standalone?: boolean\n sea?: boolean\n seaOutput?: string\n}\n\n/** Exit code host-dev.ts uses to request a supervisor restart. */\nconst FULL_REFRESH_EXIT_CODE = 65\n\nconst run = (command: string, args: string[], cwd: string): number => {\n const result = spawnSync(command, args, { cwd, stdio: \"inherit\" })\n return result.status ?? 1\n}\n\n/** Resolve an executable script shipped by a dependency's bin field. */\nconst binOf = (\n requireFrom: NodeJS.Require,\n packageName: string,\n binName: string,\n): string => {\n const packageJsonPath = requireFrom.resolve(`${packageName}/package.json`)\n const manifest = requireFrom(`${packageName}/package.json`) as {\n bin?: string | Record<string, string>\n }\n const bin =\n typeof manifest.bin === \"string\" ? manifest.bin : manifest.bin?.[binName]\n if (!bin) {\n throw new Error(`${packageName} does not expose a \"${binName}\" binary`)\n }\n return join(dirname(packageJsonPath), bin)\n}\n\ntype PackageManifest = { version: string; exports?: Record<string, unknown> }\n\n/** The `@gtkx/react` subpath exports (its own `exports` map, minus `.` and `./package.json`). */\nconst reactSubexportsOf = (manifest: PackageManifest): string[] =>\n Object.keys(manifest.exports ?? {})\n .filter((key) => key.startsWith(\"./\") && key !== \"./package.json\")\n .map((key) => key.slice(2))\n\n// @gtkx/cli is meant for apps: its `codegen` command resolves gtkx.config.ts\n// from a cwd and trusts a freshness stamp, which is what the RC2-WORKAROUND\n// this replaced was dodging (running from a reconstructed \"project that owns\n// the hosting node_modules\" purely to keep that cwd resolution honest — see\n// gtkx-org/gtkx#468, #470). A library generating bindings on a consumer's\n// behalf should use the programmatic @gtkx/codegen API instead: it takes the\n// GIR libraries and store paths directly, so there is no cwd to get wrong and\n// no stamp to misread — and it runs its own fingerprint-based freshness\n// check in-process, so a missing/pruned store is regenerated rather than\n// misreported as \"up to date\".\n//\n// `root` (the app's real project root, resolved by the react-native CLI, not\n// us) is the right place to resolve gtkx.config.ts from, but NOT necessarily\n// where @gtkx/* actually lives on disk: in a workspace, npm hoists them to an\n// ancestor's node_modules, so `root/node_modules` can be a directory with no\n// @gtkx/* in it at all (confirmed against this repo's own examples/, which\n// are workspace members with nothing hoisted locally). The store — and the\n// @gtkx/gi and @gtkx/jsx links every other @gtkx/* package resolves through\n// its OWN up-the-tree lookup — must live in whichever node_modules actually\n// hosts @gtkx/runtime, so that's resolved rather than assumed.\nconst ensureCodegenStore = async (root: string): Promise<void> => {\n console.warn(\"[react-native-gtkx] ensuring gtkx codegen store…\")\n try {\n const [{ runCodegen, resolveGirPath, resolveLibraries }, { loadConfig }] =\n await Promise.all([import(\"@gtkx/codegen\"), import(\"@gtkx/config\")])\n const { config } = await loadConfig(root)\n if (config.codegen === false) {\n console.warn(\n \"[react-native-gtkx] codegen: disabled for this project (gtkx.config.ts)\",\n )\n return\n }\n const girPath = resolveGirPath(config.girPath)\n const libraries = resolveLibraries(config.libraries, girPath)\n const appRequire = createRequire(join(root, \"package.json\"))\n const runtimePackageJsonPath = appRequire.resolve(\n \"@gtkx/runtime/package.json\",\n )\n const nodeModules = dirname(dirname(dirname(runtimePackageJsonPath)))\n const runtime = appRequire(runtimePackageJsonPath) as PackageManifest\n const react = appRequire(\"@gtkx/react/package.json\") as PackageManifest\n const result = await runCodegen({\n libraries,\n girPath,\n gi: {\n storeDir: join(nodeModules, \".gtkx\", \"gi\"),\n linkDir: join(nodeModules, \"@gtkx\", \"gi\"),\n version: runtime.version,\n },\n jsx: {\n storeDir: join(nodeModules, \".gtkx\", \"jsx\"),\n linkDir: join(nodeModules, \"@gtkx\", \"jsx\"),\n version: react.version,\n },\n reactSubexports: reactSubexportsOf(react),\n })\n console.warn(\n result.regenerated\n ? \"[react-native-gtkx] codegen: regenerated stale bindings\"\n : \"[react-native-gtkx] codegen: bindings up to date\",\n )\n } catch (error) {\n console.error(\n \"[react-native-gtkx] gtkx codegen failed — are GTK4/libadwaita \" +\n \"development files installed?\",\n )\n console.error(error)\n process.exit(1)\n }\n}\n\nconst bundle = (root: string, entryFile: string, output: string): void => {\n const appRequire = createRequire(join(root, \"package.json\"))\n const status = run(\n process.execPath,\n [\n binOf(appRequire, \"react-native\", \"react-native\"),\n \"bundle\",\n \"--platform\",\n \"linux\",\n \"--dev\",\n \"false\",\n \"--entry-file\",\n entryFile,\n \"--bundle-output\",\n output,\n ],\n root,\n )\n if (status !== 0) {\n process.exit(status)\n }\n}\n\nconst isMetroRunning = async (server: string): Promise<boolean> => {\n try {\n const response = await fetch(`${server}/status`)\n return (await response.text()).includes(\"packager-status:running\")\n } catch {\n return false\n }\n}\n\nconst waitForMetro = async (server: string): Promise<void> => {\n for (let attempt = 0; attempt < 120; attempt += 1) {\n if (await isMetroRunning(server)) {\n return\n }\n await new Promise((resolve) => setTimeout(resolve, 500))\n }\n console.error(\n `[react-native-gtkx] Metro dev server never came up (${server}).`,\n )\n process.exit(1)\n}\n\nlet activeHost: ChildProcess | null = null\n\nconst spawnHost = (\n script: string,\n argument: string,\n cwd: string,\n): Promise<number> =>\n new Promise((resolve) => {\n // join over `new URL(script, import.meta.url)`: the global URL and the\n // node:url URL come from different type copies when the dependency tree\n // splits @types/node, and the two structurally diverge.\n const hostPath = join(dirname(fileURLToPath(import.meta.url)), script)\n const child = spawn(process.execPath, [hostPath, argument], {\n cwd,\n stdio: \"inherit\",\n })\n activeHost = child\n child.on(\"exit\", (code) => {\n activeHost = null\n resolve(code ?? 1)\n })\n })\n\nconst runLinuxDev = async (\n config: CliConfig,\n args: RunLinuxArgs,\n): Promise<never> => {\n const port = args.port ?? \"8081\"\n const server = `http://localhost:${port}`\n let metro: ChildProcess | null = null\n if (await isMetroRunning(server)) {\n console.warn(\n `[react-native-gtkx] reusing the Metro dev server at ${server}`,\n )\n } else {\n console.warn(\n `[react-native-gtkx] starting the Metro dev server at ${server}…`,\n )\n const appRequire = createRequire(join(config.root, \"package.json\"))\n metro = spawn(\n process.execPath,\n [\n binOf(appRequire, \"react-native\", \"react-native\"),\n \"start\",\n \"--port\",\n port,\n ],\n { cwd: config.root, stdio: \"inherit\" },\n )\n await waitForMetro(server)\n }\n const entry = basename(args.entryFile, extname(args.entryFile))\n const bundleUrl = `${server}/${entry}.bundle?platform=linux&dev=true&minify=false`\n const shutdown = (code: number): never => {\n activeHost?.kill()\n metro?.kill()\n process.exit(code)\n }\n process.on(\"SIGINT\", () => shutdown(0))\n process.on(\"SIGTERM\", () => shutdown(0))\n // Supervisor: a full-refresh request restarts the host with the window\n // reopening on the fresh bundle; any other exit ends the session.\n for (;;) {\n const code = await spawnHost(\"./host-dev.js\", bundleUrl, config.root)\n if (code !== FULL_REFRESH_EXIT_CODE) {\n shutdown(code)\n }\n console.warn(\"[react-native-gtkx] restarting the app after a full refresh…\")\n }\n}\n\nconst runLinux = async (\n _argv: string[],\n config: CliConfig,\n args: RunLinuxArgs,\n): Promise<void> => {\n await ensureCodegenStore(config.root)\n if (args.dev) {\n await runLinuxDev(config, args)\n return\n }\n const output =\n args.bundleOutput ??\n join(config.root, \"node_modules\", \".react-native-gtkx\", \"main.jsbundle\")\n if (!args.skipBundling) {\n mkdirSync(dirname(output), { recursive: true })\n bundle(config.root, args.entryFile, output)\n }\n const status = await spawnHost(\"./host.js\", output, config.root)\n process.exit(status)\n}\n\n/**\n * The executable name a `--sea` build defaults to: the app's package name\n * without its scope, so the artifact is `dist/hn-app`, not `dist/app`.\n */\nconst appBinaryName = (root: string): string => {\n try {\n const manifest = createRequire(join(root, \"package.json\"))(\n \"./package.json\",\n ) as { name?: string }\n const name = manifest.name?.split(\"/\").pop()\n return name && /^[\\w.-]+$/.test(name) ? name : \"app\"\n } catch {\n return \"app\"\n }\n}\n\n// The android/ios counterpart to run-linux's dev-only bundling: bundle for\n// distribution and stop, the way a release APK/IPA build does not launch\n// the app it produces. Deliberately skips ensureCodegenStore() — codegen\n// generates the @gtkx/gi bindings host.js imports to talk to GTK at RUN\n// time; bundling never touches them (Metro only reads/transforms JS, and\n// the GTK/react/yoga modules are proxied rather than imported — see\n// ../metro's HOST_MODULE_EXTERNALS). A machine that only builds never needs\n// GTK dev headers installed.\n//\n// --standalone and --sea are the exception: both inline\n// \"virtual:gtkx-config\", which re-exports @gtkx/jsx/metadata — a codegen\n// product — so they DO need the store, and therefore GTK dev headers.\n// Only those paths ensure it.\n//\n// The three artifacts, cheapest to heaviest, are deliberately one command\n// with flags rather than three commands: they share the Metro bundle step,\n// and the choice between them is a distribution question, not a different\n// build.\n// (default) main.jsbundle + a runtime node_modules + a system node\n// --standalone one .cjs file, no node_modules, + a system node\n// --sea one executable, nothing preinstalled at all\nconst buildLinux = async (\n _argv: string[],\n config: CliConfig,\n args: BuildLinuxArgs,\n): Promise<void> => {\n if (args.sea || args.standalone) {\n await ensureCodegenStore(config.root)\n }\n const output = args.bundleOutput ?? join(config.root, \"dist\", \"main.jsbundle\")\n mkdirSync(dirname(output), { recursive: true })\n bundle(config.root, args.entryFile, output)\n console.warn(`[react-native-gtkx] wrote the release bundle to ${output}`)\n if (!args.sea && !args.standalone) {\n return\n }\n const name = appBinaryName(config.root)\n const seaOutput =\n args.seaOutput ?? join(config.root, \"dist\", args.sea ? name : `${name}.cjs`)\n // Dynamically imported so the bundler is never loaded on the ordinary\n // jsbundle path.\n const { assembleSea, bundleStandalone } = await import(\"../sea/assemble.js\")\n const bytes = args.sea\n ? await assembleSea({\n appRoot: config.root,\n jsbundlePath: output,\n outFile: seaOutput,\n })\n : await bundleStandalone({\n appRoot: config.root,\n jsbundlePath: output,\n outFile: seaOutput,\n })\n const megabytes = (bytes / 1024 / 1024).toFixed(0)\n console.warn(\n args.sea\n ? `[react-native-gtkx] wrote the single executable to ${seaOutput} ` +\n `(${megabytes} MB — Node itself is most of it)`\n : `[react-native-gtkx] wrote the standalone script to ${seaOutput} ` +\n `(${megabytes} MB — run it with \\`node ${seaOutput}\\`)`,\n )\n}\n\n/** Commands contributed to the RN CLI by the package's react-native.config.js. */\nexport const commands = [\n {\n name: \"run-linux\",\n description:\n \"Bundle the app with Metro for the linux platform and run it in the Node+GTK host\",\n options: [\n {\n name: \"--entry-file <path>\",\n description: \"Path to the app entry file\",\n default: \"index.js\",\n },\n {\n name: \"--bundle-output <path>\",\n description:\n \"Where to write the jsbundle (default: node_modules/.react-native-gtkx/main.jsbundle)\",\n },\n {\n name: \"--skip-bundling\",\n description: \"Reuse the existing bundle at --bundle-output\",\n },\n {\n name: \"--dev\",\n description:\n \"Development mode: Metro dev server + Fast Refresh (edits apply to the live window)\",\n },\n {\n name: \"--port <number>\",\n description: \"Metro dev server port for --dev (default: 8081)\",\n },\n ],\n func: runLinux,\n },\n {\n name: \"build-linux\",\n description:\n \"Bundle the app with Metro for the linux platform for distribution, without running it\",\n options: [\n {\n name: \"--entry-file <path>\",\n description: \"Path to the app entry file\",\n default: \"index.js\",\n },\n {\n name: \"--bundle-output <path>\",\n description:\n \"Where to write the release jsbundle (default: dist/main.jsbundle)\",\n },\n {\n name: \"--standalone\",\n description:\n \"Also produce one self-contained .cjs — no node_modules, run it \" +\n \"with a system node (dist/<package name>.cjs)\",\n },\n {\n name: \"--sea\",\n description:\n \"Also produce a single executable (Node SEA): one file that runs \" +\n \"with no node_modules and no system Node — at the cost of \" +\n \"carrying a whole Node binary (~120 MB)\",\n },\n {\n name: \"--sea-output <path>\",\n description:\n \"Where to write the --sea / --standalone artifact \" +\n \"(default: dist/<package name>[.cjs])\",\n },\n ],\n func: buildLinux,\n },\n]\n"]}
@@ -0,0 +1,29 @@
1
+ export type AssembleSeaOptions = {
2
+ /** The app root — where gtkx.config.ts and package.json live. */
3
+ appRoot: string;
4
+ /** The release jsbundle `build-linux` just wrote. */
5
+ jsbundlePath: string;
6
+ /** Where the finished executable is written. */
7
+ outFile: string;
8
+ /** Scratch directory for the intermediate CJS bundle, the SEA config and
9
+ * the prep blob (default: alongside the jsbundle). */
10
+ workDir?: string;
11
+ };
12
+ /**
13
+ * Produces the middle artifact: one self-contained CJS file with the app,
14
+ * its whole node_modules closure and the native addon inlined, run by a
15
+ * system `node`. Everything the SEA is except the embedded Node runtime —
16
+ * so ~120 MB smaller, at the cost of a `nodejs` dependency to declare.
17
+ * Returns its size in bytes.
18
+ */
19
+ export declare const bundleStandalone: (options: {
20
+ appRoot: string;
21
+ jsbundlePath: string;
22
+ outFile: string;
23
+ }) => Promise<number>;
24
+ /**
25
+ * Produces a single executable at {@link AssembleSeaOptions.outFile} and
26
+ * returns its size in bytes. Requires network access on first run unless
27
+ * postject is already in the npx cache.
28
+ */
29
+ export declare const assembleSea: (options: AssembleSeaOptions) => Promise<number>;
@@ -0,0 +1,129 @@
1
+ // Turns a Metro-built app into ONE executable file: bundle everything into
2
+ // a CJS entry (./bundle.ts), generate a SEA blob from it, then inject that
3
+ // blob into a copy of the `node` binary. This is the whole of what "SEA"
4
+ // means — Node's Single Executable Application format is literally a copy
5
+ // of the node binary with a V8 code-cache blob appended, which is why the
6
+ // result necessarily carries Node's own weight (~117 MB on linux-arm64,
7
+ // against <7 MB for the app code and its native addon).
8
+ //
9
+ // Follows gtkx's own tutorial (gtkx-org/gtkx examples/tutorial/scripts/
10
+ // build-sea.sh) for these mechanics; ./bundle.ts's header documents where
11
+ // the bundling half deliberately diverges.
12
+ //
13
+ // Kept out of ../runner/index.ts and reached through a dynamic import so
14
+ // the bundler is only loaded when a SEA is actually asked for; the
15
+ // ordinary `build-linux` path never touches it.
16
+ import { spawnSync } from "node:child_process";
17
+ import { chmodSync, copyFileSync, mkdirSync, statSync, writeFileSync, } from "node:fs";
18
+ import { dirname, join } from "node:path";
19
+ import { bundleMetroSea } from "./bundle.js";
20
+ /** The fuse postject looks for inside the node binary to place the blob. */
21
+ const SENTINEL_FUSE = "NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2";
22
+ /** Pinned: postject has no stable release, and the SEA docs name this one. */
23
+ const POSTJECT = "postject@1.0.0-alpha.6";
24
+ const run = (command, args) => {
25
+ const result = spawnSync(command, args, { stdio: "inherit" });
26
+ if (result.error) {
27
+ throw result.error;
28
+ }
29
+ if (result.status !== 0) {
30
+ throw new Error(`${command} ${args.join(" ")} exited with ${result.status}`);
31
+ }
32
+ };
33
+ /**
34
+ * Drops the debug symbols from the copied Node binary. Worth a step of its
35
+ * own because the saving is not marginal: the `node` binary distributed by
36
+ * NodeSource for Ubuntu ships `with debug_info, not stripped` — measured at
37
+ * 117 MB, and 98 MB after `strip --strip-all`. Nothing in a SEA needs those
38
+ * symbols; the only cost is that a crash inside Node's own C++ produces an
39
+ * unsymbolicated backtrace.
40
+ *
41
+ * Runs BEFORE postject, never after: `--strip-all` removes non-allocated
42
+ * sections, which is exactly what the injected NODE_SEA_BLOB is.
43
+ *
44
+ * Best-effort — a build machine without binutils still produces a working
45
+ * (larger) executable rather than failing, so this cannot become a new
46
+ * install requirement for a build that worked yesterday.
47
+ */
48
+ const stripSymbols = (file) => {
49
+ const before = statSync(file).size;
50
+ const result = spawnSync("strip", ["--strip-all", file], {
51
+ stdio: ["ignore", "ignore", "pipe"],
52
+ });
53
+ if (result.error || result.status !== 0) {
54
+ console.warn("[react-native-gtkx] skipped stripping symbols (no usable `strip`) — " +
55
+ "the executable will be tens of MB larger than it needs to be");
56
+ return;
57
+ }
58
+ const saved = (before - statSync(file).size) / 1024 / 1024;
59
+ console.warn(`[react-native-gtkx] stripped debug symbols (-${saved.toFixed(0)} MB)`);
60
+ };
61
+ /**
62
+ * Produces the middle artifact: one self-contained CJS file with the app,
63
+ * its whole node_modules closure and the native addon inlined, run by a
64
+ * system `node`. Everything the SEA is except the embedded Node runtime —
65
+ * so ~120 MB smaller, at the cost of a `nodejs` dependency to declare.
66
+ * Returns its size in bytes.
67
+ */
68
+ export const bundleStandalone = async (options) => {
69
+ const { appRoot, jsbundlePath, outFile } = options;
70
+ mkdirSync(dirname(outFile), { recursive: true });
71
+ console.warn("[react-native-gtkx] bundling a standalone script…");
72
+ await bundleMetroSea({
73
+ appRoot,
74
+ jsbundlePath,
75
+ outFile,
76
+ nativeAddonSource: "inline",
77
+ });
78
+ return statSync(outFile).size;
79
+ };
80
+ /**
81
+ * Produces a single executable at {@link AssembleSeaOptions.outFile} and
82
+ * returns its size in bytes. Requires network access on first run unless
83
+ * postject is already in the npx cache.
84
+ */
85
+ export const assembleSea = async (options) => {
86
+ const { appRoot, jsbundlePath, outFile } = options;
87
+ const workDir = options.workDir ?? dirname(jsbundlePath);
88
+ mkdirSync(workDir, { recursive: true });
89
+ mkdirSync(dirname(outFile), { recursive: true });
90
+ console.warn("[react-native-gtkx] bundling for a single executable…");
91
+ const bundlePath = join(workDir, "sea-bundle.cjs");
92
+ const nativeAddon = await bundleMetroSea({
93
+ appRoot,
94
+ jsbundlePath,
95
+ outFile: bundlePath,
96
+ });
97
+ console.warn(`[react-native-gtkx] native addon: ${nativeAddon.path}`);
98
+ const configPath = join(workDir, "sea-config.json");
99
+ writeFileSync(configPath, `${JSON.stringify({
100
+ main: bundlePath,
101
+ output: join(workDir, "sea-prep.blob"),
102
+ disableExperimentalSEAWarning: true,
103
+ assets: { [nativeAddon.key]: nativeAddon.path },
104
+ }, null, 2)}\n`);
105
+ console.warn("[react-native-gtkx] generating the SEA blob…");
106
+ run(process.execPath, ["--experimental-sea-config", configPath]);
107
+ console.warn("[react-native-gtkx] copying the node binary…");
108
+ copyFileSync(process.execPath, outFile);
109
+ if (process.platform === "darwin") {
110
+ // The copy inherits a signature that no longer matches once the blob
111
+ // is injected; macOS refuses to exec it until the signature is gone.
112
+ run("codesign", ["--remove-signature", outFile]);
113
+ }
114
+ stripSymbols(outFile);
115
+ console.warn("[react-native-gtkx] injecting the SEA blob…");
116
+ run("npx", [
117
+ "--yes",
118
+ "--ignore-scripts",
119
+ POSTJECT,
120
+ outFile,
121
+ "NODE_SEA_BLOB",
122
+ join(workDir, "sea-prep.blob"),
123
+ "--sentinel-fuse",
124
+ SENTINEL_FUSE,
125
+ ]);
126
+ chmodSync(outFile, 0o755);
127
+ return statSync(outFile).size;
128
+ };
129
+ //# sourceMappingURL=assemble.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assemble.js","sourceRoot":"","sources":["../../src/sea/assemble.ts"],"names":[],"mappings":"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","sourcesContent":["// Turns a Metro-built app into ONE executable file: bundle everything into\n// a CJS entry (./bundle.ts), generate a SEA blob from it, then inject that\n// blob into a copy of the `node` binary. This is the whole of what \"SEA\"\n// means — Node's Single Executable Application format is literally a copy\n// of the node binary with a V8 code-cache blob appended, which is why the\n// result necessarily carries Node's own weight (~117 MB on linux-arm64,\n// against <7 MB for the app code and its native addon).\n//\n// Follows gtkx's own tutorial (gtkx-org/gtkx examples/tutorial/scripts/\n// build-sea.sh) for these mechanics; ./bundle.ts's header documents where\n// the bundling half deliberately diverges.\n//\n// Kept out of ../runner/index.ts and reached through a dynamic import so\n// the bundler is only loaded when a SEA is actually asked for; the\n// ordinary `build-linux` path never touches it.\nimport { spawnSync } from \"node:child_process\"\nimport {\n chmodSync,\n copyFileSync,\n mkdirSync,\n statSync,\n writeFileSync,\n} from \"node:fs\"\nimport { dirname, join } from \"node:path\"\nimport { bundleMetroSea } from \"./bundle.js\"\n\n/** The fuse postject looks for inside the node binary to place the blob. */\nconst SENTINEL_FUSE = \"NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2\"\n\n/** Pinned: postject has no stable release, and the SEA docs name this one. */\nconst POSTJECT = \"postject@1.0.0-alpha.6\"\n\nexport type AssembleSeaOptions = {\n /** The app root — where gtkx.config.ts and package.json live. */\n appRoot: string\n /** The release jsbundle `build-linux` just wrote. */\n jsbundlePath: string\n /** Where the finished executable is written. */\n outFile: string\n /** Scratch directory for the intermediate CJS bundle, the SEA config and\n * the prep blob (default: alongside the jsbundle). */\n workDir?: string\n}\n\nconst run = (command: string, args: string[]): void => {\n const result = spawnSync(command, args, { stdio: \"inherit\" })\n if (result.error) {\n throw result.error\n }\n if (result.status !== 0) {\n throw new Error(`${command} ${args.join(\" \")} exited with ${result.status}`)\n }\n}\n\n/**\n * Drops the debug symbols from the copied Node binary. Worth a step of its\n * own because the saving is not marginal: the `node` binary distributed by\n * NodeSource for Ubuntu ships `with debug_info, not stripped` — measured at\n * 117 MB, and 98 MB after `strip --strip-all`. Nothing in a SEA needs those\n * symbols; the only cost is that a crash inside Node's own C++ produces an\n * unsymbolicated backtrace.\n *\n * Runs BEFORE postject, never after: `--strip-all` removes non-allocated\n * sections, which is exactly what the injected NODE_SEA_BLOB is.\n *\n * Best-effort — a build machine without binutils still produces a working\n * (larger) executable rather than failing, so this cannot become a new\n * install requirement for a build that worked yesterday.\n */\nconst stripSymbols = (file: string): void => {\n const before = statSync(file).size\n const result = spawnSync(\"strip\", [\"--strip-all\", file], {\n stdio: [\"ignore\", \"ignore\", \"pipe\"],\n })\n if (result.error || result.status !== 0) {\n console.warn(\n \"[react-native-gtkx] skipped stripping symbols (no usable `strip`) — \" +\n \"the executable will be tens of MB larger than it needs to be\",\n )\n return\n }\n const saved = (before - statSync(file).size) / 1024 / 1024\n console.warn(\n `[react-native-gtkx] stripped debug symbols (-${saved.toFixed(0)} MB)`,\n )\n}\n\n/**\n * Produces the middle artifact: one self-contained CJS file with the app,\n * its whole node_modules closure and the native addon inlined, run by a\n * system `node`. Everything the SEA is except the embedded Node runtime —\n * so ~120 MB smaller, at the cost of a `nodejs` dependency to declare.\n * Returns its size in bytes.\n */\nexport const bundleStandalone = async (options: {\n appRoot: string\n jsbundlePath: string\n outFile: string\n}): Promise<number> => {\n const { appRoot, jsbundlePath, outFile } = options\n mkdirSync(dirname(outFile), { recursive: true })\n console.warn(\"[react-native-gtkx] bundling a standalone script…\")\n await bundleMetroSea({\n appRoot,\n jsbundlePath,\n outFile,\n nativeAddonSource: \"inline\",\n })\n return statSync(outFile).size\n}\n\n/**\n * Produces a single executable at {@link AssembleSeaOptions.outFile} and\n * returns its size in bytes. Requires network access on first run unless\n * postject is already in the npx cache.\n */\nexport const assembleSea = async (\n options: AssembleSeaOptions,\n): Promise<number> => {\n const { appRoot, jsbundlePath, outFile } = options\n const workDir = options.workDir ?? dirname(jsbundlePath)\n mkdirSync(workDir, { recursive: true })\n mkdirSync(dirname(outFile), { recursive: true })\n\n console.warn(\"[react-native-gtkx] bundling for a single executable…\")\n const bundlePath = join(workDir, \"sea-bundle.cjs\")\n const nativeAddon = await bundleMetroSea({\n appRoot,\n jsbundlePath,\n outFile: bundlePath,\n })\n console.warn(`[react-native-gtkx] native addon: ${nativeAddon.path}`)\n\n const configPath = join(workDir, \"sea-config.json\")\n writeFileSync(\n configPath,\n `${JSON.stringify(\n {\n main: bundlePath,\n output: join(workDir, \"sea-prep.blob\"),\n disableExperimentalSEAWarning: true,\n assets: { [nativeAddon.key]: nativeAddon.path },\n },\n null,\n 2,\n )}\\n`,\n )\n\n console.warn(\"[react-native-gtkx] generating the SEA blob…\")\n run(process.execPath, [\"--experimental-sea-config\", configPath])\n\n console.warn(\"[react-native-gtkx] copying the node binary…\")\n copyFileSync(process.execPath, outFile)\n if (process.platform === \"darwin\") {\n // The copy inherits a signature that no longer matches once the blob\n // is injected; macOS refuses to exec it until the signature is gone.\n run(\"codesign\", [\"--remove-signature\", outFile])\n }\n stripSymbols(outFile)\n\n console.warn(\"[react-native-gtkx] injecting the SEA blob…\")\n run(\"npx\", [\n \"--yes\",\n \"--ignore-scripts\",\n POSTJECT,\n outFile,\n \"NODE_SEA_BLOB\",\n join(workDir, \"sea-prep.blob\"),\n \"--sentinel-fuse\",\n SENTINEL_FUSE,\n ])\n\n chmodSync(outFile, 0o755)\n return statSync(outFile).size\n}\n"]}
@@ -0,0 +1,61 @@
1
+ import { type NativeAddonSource } from "./native-shim.js";
2
+ export type MetroSeaBundleOptions = {
3
+ /** The app root — where gtkx.config.ts lives and package.json resolves
4
+ * HOST_MODULE_EXTERNALS' bare specifiers (react, @gtkx/*, ...) from. */
5
+ appRoot: string;
6
+ /** Path to the release jsbundle produced by `build-linux`. */
7
+ jsbundlePath: string;
8
+ /** Where to write the bundled CJS entry (e.g. dist/bundle.cjs). */
9
+ outFile: string;
10
+ /** Where the native addon's bytes come from at runtime — "sea-asset"
11
+ * for a real single executable, "inline" for a self-contained .cjs run
12
+ * by a system Node (default: "sea-asset"). */
13
+ nativeAddonSource?: NativeAddonSource;
14
+ };
15
+ export type NativeAddonAsset = {
16
+ /** Absolute path to the platform's @gtkx/native-<platform>-<libc>.node
17
+ * that npm installed for this machine. */
18
+ path: string;
19
+ /** The SEA asset key it must be embedded under. */
20
+ key: string;
21
+ };
22
+ /**
23
+ * Locates the ONE native addon file npm installed for this machine.
24
+ * @gtkx/native picks exactly one optionalDependency per platform/libc at
25
+ * install time (see @gtkx/native/index.js's NAPI-RS-generated loader) —
26
+ * failing loudly on anything other than exactly one match matters here:
27
+ * silently picking the wrong one would embed an addon for the wrong
28
+ * architecture with no error until the app actually launches.
29
+ */
30
+ export declare const resolveNativeAddon: (appRoot: string) => NativeAddonAsset;
31
+ /**
32
+ * Builds the synthetic SEA entry source: every HOST_MODULE_EXTERNALS name
33
+ * loaded through a dynamic `import()` (mirroring runner/host.ts's own
34
+ * `load()`, which does the same against a real node_modules at runtime),
35
+ * assembled into globalThis.__hostModules, then the jsbundle text executed
36
+ * the same way host.ts does.
37
+ *
38
+ * Dynamic import, not static, throughout: a Node SEA's main script is
39
+ * CommonJS only — confirmed empirically, Node 24 executes the embedded
40
+ * main as CJS regardless of a "type": "module" field in sea-config.json
41
+ * or an .mjs extension — and top-level await is a hard error under a "cjs"
42
+ * output format REGARDLESS of whether the module is reached via a static
43
+ * or dynamic import (the restriction is format-wide, not per-module —
44
+ * verified: switching yoga-layout's static import to a dynamic one alone
45
+ * did not clear the error). yoga-layout's own entry point has exactly this
46
+ * top-level await (it loads its WASM binary asynchronously — see
47
+ * node_modules/yoga-layout/dist/src/index.js: `const Yoga =
48
+ * wrapAssembly(await loadYoga())` at module scope). The actual fix: import
49
+ * "yoga-layout/load" instead, which exports the same `await`, just inside
50
+ * an async FUNCTION (`export async function loadYoga()`), not at the
51
+ * file's top level — bundleable, and awaited here like everything else.
52
+ */
53
+ export declare const buildEntrySource: (jsbundlePath: string) => string;
54
+ /**
55
+ * Produces `outFile`, a single CJS file with the jsbundle, its
56
+ * HOST_MODULE_EXTERNALS and gtkx.config.ts's resolved values all inlined,
57
+ * and the native addon import redirected to the SEA-asset extraction
58
+ * shim. Returns the native addon that must be embedded as a SEA asset
59
+ * under {@link NativeAddonAsset.key} for the result to run.
60
+ */
61
+ export declare const bundleMetroSea: (options: MetroSeaBundleOptions) => Promise<NativeAddonAsset>;