react-native-gtkx 0.1.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.
- package/LICENSE +21 -0
- package/README.md +73 -0
- package/dist/animated/composite.d.ts +5 -0
- package/dist/animated/composite.js +132 -0
- package/dist/animated/composite.js.map +1 -0
- package/dist/animated/create-animated.d.ts +12 -0
- package/dist/animated/create-animated.js +17 -0
- package/dist/animated/create-animated.js.map +1 -0
- package/dist/animated/easing.d.ts +11 -0
- package/dist/animated/easing.js +91 -0
- package/dist/animated/easing.js.map +1 -0
- package/dist/animated/frame-loop.d.ts +6 -0
- package/dist/animated/frame-loop.js +25 -0
- package/dist/animated/frame-loop.js.map +1 -0
- package/dist/animated/index.d.ts +6 -0
- package/dist/animated/index.js +7 -0
- package/dist/animated/index.js.map +1 -0
- package/dist/animated/interpolate.d.ts +2 -0
- package/dist/animated/interpolate.js +90 -0
- package/dist/animated/interpolate.js.map +1 -0
- package/dist/animated/native-driver.d.ts +1 -0
- package/dist/animated/native-driver.js +17 -0
- package/dist/animated/native-driver.js.map +1 -0
- package/dist/animated/spring.d.ts +3 -0
- package/dist/animated/spring.js +67 -0
- package/dist/animated/spring.js.map +1 -0
- package/dist/animated/timing.d.ts +3 -0
- package/dist/animated/timing.js +30 -0
- package/dist/animated/timing.js.map +1 -0
- package/dist/animated/types.d.ts +51 -0
- package/dist/animated/types.js +6 -0
- package/dist/animated/types.js.map +1 -0
- package/dist/animated/value-animation.d.ts +9 -0
- package/dist/animated/value-animation.js +65 -0
- package/dist/animated/value-animation.js.map +1 -0
- package/dist/animated/value.d.ts +46 -0
- package/dist/animated/value.js +130 -0
- package/dist/animated/value.js.map +1 -0
- package/dist/apis/alert.d.ts +16 -0
- package/dist/apis/alert.js +33 -0
- package/dist/apis/alert.js.map +1 -0
- package/dist/apis/app-state.d.ts +11 -0
- package/dist/apis/app-state.js +54 -0
- package/dist/apis/app-state.js.map +1 -0
- package/dist/apis/appearance.d.ts +12 -0
- package/dist/apis/appearance.js +33 -0
- package/dist/apis/appearance.js.map +1 -0
- package/dist/apis/dev-settings.d.ts +9 -0
- package/dist/apis/dev-settings.js +25 -0
- package/dist/apis/dev-settings.js.map +1 -0
- package/dist/apis/dimensions.d.ts +14 -0
- package/dist/apis/dimensions.js +80 -0
- package/dist/apis/dimensions.js.map +1 -0
- package/dist/apis/emitter.d.ts +8 -0
- package/dist/apis/emitter.js +35 -0
- package/dist/apis/emitter.js.map +1 -0
- package/dist/apis/hooks.d.ts +11 -0
- package/dist/apis/hooks.js +29 -0
- package/dist/apis/hooks.js.map +1 -0
- package/dist/apis/host.d.ts +45 -0
- package/dist/apis/host.gtkx.d.ts +2 -0
- package/dist/apis/host.gtkx.js +301 -0
- package/dist/apis/host.gtkx.js.map +1 -0
- package/dist/apis/host.js +6 -0
- package/dist/apis/host.js.map +1 -0
- package/dist/apis/index.d.ts +39 -0
- package/dist/apis/index.js +21 -0
- package/dist/apis/index.js.map +1 -0
- package/dist/apis/linking.d.ts +7 -0
- package/dist/apis/linking.js +28 -0
- package/dist/apis/linking.js.map +1 -0
- package/dist/apis/platform.d.ts +14 -0
- package/dist/apis/platform.js +23 -0
- package/dist/apis/platform.js.map +1 -0
- package/dist/components/activity-indicator.d.ts +10 -0
- package/dist/components/activity-indicator.js +21 -0
- package/dist/components/activity-indicator.js.map +1 -0
- package/dist/components/animated.d.ts +34 -0
- package/dist/components/animated.js +152 -0
- package/dist/components/animated.js.map +1 -0
- package/dist/components/app-registry.d.ts +14 -0
- package/dist/components/app-registry.js +61 -0
- package/dist/components/app-registry.js.map +1 -0
- package/dist/components/flat-list.d.ts +48 -0
- package/dist/components/flat-list.js +23 -0
- package/dist/components/flat-list.js.map +1 -0
- package/dist/components/host-node.d.ts +10 -0
- package/dist/components/host-node.js +10 -0
- package/dist/components/host-node.js.map +1 -0
- package/dist/components/image-loader.d.ts +17 -0
- package/dist/components/image-loader.js +54 -0
- package/dist/components/image-loader.js.map +1 -0
- package/dist/components/image.d.ts +19 -0
- package/dist/components/image.js +73 -0
- package/dist/components/image.js.map +1 -0
- package/dist/components/index.d.ts +14 -0
- package/dist/components/index.js +14 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/modal.d.ts +12 -0
- package/dist/components/modal.js +18 -0
- package/dist/components/modal.js.map +1 -0
- package/dist/components/pressable.d.ts +33 -0
- package/dist/components/pressable.js +116 -0
- package/dist/components/pressable.js.map +1 -0
- package/dist/components/rect-store.d.ts +17 -0
- package/dist/components/rect-store.js +40 -0
- package/dist/components/rect-store.js.map +1 -0
- package/dist/components/root.d.ts +8 -0
- package/dist/components/root.js +59 -0
- package/dist/components/root.js.map +1 -0
- package/dist/components/scroll-view.d.ts +56 -0
- package/dist/components/scroll-view.js +324 -0
- package/dist/components/scroll-view.js.map +1 -0
- package/dist/components/switch.d.ts +11 -0
- package/dist/components/switch.js +20 -0
- package/dist/components/switch.js.map +1 -0
- package/dist/components/text-input.d.ts +23 -0
- package/dist/components/text-input.js +151 -0
- package/dist/components/text-input.js.map +1 -0
- package/dist/components/text.d.ts +11 -0
- package/dist/components/text.js +100 -0
- package/dist/components/text.js.map +1 -0
- package/dist/components/use-layout-child.d.ts +36 -0
- package/dist/components/use-layout-child.js +177 -0
- package/dist/components/use-layout-child.js.map +1 -0
- package/dist/components/view.d.ts +13 -0
- package/dist/components/view.js +60 -0
- package/dist/components/view.js.map +1 -0
- package/dist/components/virtualized-list.d.ts +67 -0
- package/dist/components/virtualized-list.js +519 -0
- package/dist/components/virtualized-list.js.map +1 -0
- package/dist/contracts.d.ts +119 -0
- package/dist/contracts.js +5 -0
- package/dist/contracts.js.map +1 -0
- package/dist/gtkx/bridge/index.d.ts +16 -0
- package/dist/gtkx/bridge/index.js +25 -0
- package/dist/gtkx/bridge/index.js.map +1 -0
- package/dist/gtkx/bridge/layout-manager.d.ts +11 -0
- package/dist/gtkx/bridge/layout-manager.js +87 -0
- package/dist/gtkx/bridge/layout-manager.js.map +1 -0
- package/dist/gtkx/bridge/measure.d.ts +9 -0
- package/dist/gtkx/bridge/measure.js +20 -0
- package/dist/gtkx/bridge/measure.js.map +1 -0
- package/dist/gtkx/bridge/theme.d.ts +4 -0
- package/dist/gtkx/bridge/theme.js +5 -0
- package/dist/gtkx/bridge/theme.js.map +1 -0
- package/dist/gtkx/bridge/view-box.d.ts +7 -0
- package/dist/gtkx/bridge/view-box.js +40 -0
- package/dist/gtkx/bridge/view-box.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/layout/apply-style.d.ts +4 -0
- package/dist/layout/apply-style.js +148 -0
- package/dist/layout/apply-style.js.map +1 -0
- package/dist/layout/engine.d.ts +22 -0
- package/dist/layout/engine.js +90 -0
- package/dist/layout/engine.js.map +1 -0
- package/dist/layout/index.d.ts +3 -0
- package/dist/layout/index.js +4 -0
- package/dist/layout/index.js.map +1 -0
- package/dist/layout/node.d.ts +33 -0
- package/dist/layout/node.js +151 -0
- package/dist/layout/node.js.map +1 -0
- package/dist/layout/yoga.d.ts +13 -0
- package/dist/layout/yoga.js +52 -0
- package/dist/layout/yoga.js.map +1 -0
- package/dist/metro/index.d.ts +42 -0
- package/dist/metro/index.js +119 -0
- package/dist/metro/index.js.map +1 -0
- package/dist/runner/host-dev.d.ts +1 -0
- package/dist/runner/host-dev.js +208 -0
- package/dist/runner/host-dev.js.map +1 -0
- package/dist/runner/host.d.ts +1 -0
- package/dist/runner/host.js +101 -0
- package/dist/runner/host.js.map +1 -0
- package/dist/runner/index.d.ts +26 -0
- package/dist/runner/index.js +179 -0
- package/dist/runner/index.js.map +1 -0
- package/dist/style/colors.d.ts +17 -0
- package/dist/style/colors.js +375 -0
- package/dist/style/colors.js.map +1 -0
- package/dist/style/dev-warning.d.ts +2 -0
- package/dist/style/dev-warning.js +18 -0
- package/dist/style/dev-warning.js.map +1 -0
- package/dist/style/index.d.ts +7 -0
- package/dist/style/index.js +14 -0
- package/dist/style/index.js.map +1 -0
- package/dist/style/registry.d.ts +12 -0
- package/dist/style/registry.gtkx.d.ts +2 -0
- package/dist/style/registry.gtkx.js +9 -0
- package/dist/style/registry.gtkx.js.map +1 -0
- package/dist/style/registry.js +23 -0
- package/dist/style/registry.js.map +1 -0
- package/dist/style/split-style.d.ts +6 -0
- package/dist/style/split-style.js +107 -0
- package/dist/style/split-style.js.map +1 -0
- package/dist/style/style-sheet.d.ts +43 -0
- package/dist/style/style-sheet.js +57 -0
- package/dist/style/style-sheet.js.map +1 -0
- package/dist/style/text-align.d.ts +7 -0
- package/dist/style/text-align.js +22 -0
- package/dist/style/text-align.js.map +1 -0
- package/dist/style/visual-css.d.ts +6 -0
- package/dist/style/visual-css.js +133 -0
- package/dist/style/visual-css.js.map +1 -0
- package/dist/vite/index.d.ts +53 -0
- package/dist/vite/index.js +127 -0
- package/dist/vite/index.js.map +1 -0
- package/package.json +88 -0
- package/react-native.config.js +21 -0
- package/types.d.ts +43 -0
- package/types.js +4 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
// Metro preset for the linux out-of-tree platform: wrap the app's Metro
|
|
2
|
+
// config with `withLinuxPlatform` and the standard RN toolchain bundles for
|
|
3
|
+
// `--platform linux`.
|
|
4
|
+
//
|
|
5
|
+
// What it does on top of RN defaults (validated by spike/rn-platform):
|
|
6
|
+
//
|
|
7
|
+
// 1. Adds "linux" to resolver.platforms (`.linux.tsx` extensions and
|
|
8
|
+
// Platform.OS come along with it).
|
|
9
|
+
// 2. Redirects `react-native` (and subpaths) to `react-native-gtkx` — the
|
|
10
|
+
// out-of-tree npmPackageName declaration alone does not alias imports
|
|
11
|
+
// for `bundle`, the resolver has to.
|
|
12
|
+
// 3. EXTERNALIZES host-side singletons. Unlike react-native-windows, whose
|
|
13
|
+
// native side lives outside the JS bundle by construction, our "native"
|
|
14
|
+
// is Node modules with NAPI bindings (@gtkx/*) plus yoga-layout's WASM —
|
|
15
|
+
// Metro cannot bundle those. react (and its jsx runtimes) must also stay
|
|
16
|
+
// host-side: the reconciler inside @gtkx/react and the app have to share
|
|
17
|
+
// one React instance. Every external resolves to a generated proxy that
|
|
18
|
+
// reads the real module from global.__hostModules — the run-linux host
|
|
19
|
+
// injects them before executing the bundle.
|
|
20
|
+
// 4. Proxies Node builtins through the host's require: apps on this
|
|
21
|
+
// platform may use the whole Node API, it is a platform feature.
|
|
22
|
+
// 5. Drops InitializeCore (RN's mobile environment polyfills): the runtime
|
|
23
|
+
// environment IS Node, the host provides everything.
|
|
24
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
25
|
+
import { builtinModules, isBuiltin } from "node:module";
|
|
26
|
+
import { join } from "node:path";
|
|
27
|
+
/** Modules the run-linux host provides to the bundle at runtime. */
|
|
28
|
+
export const HOST_MODULE_EXTERNALS = [
|
|
29
|
+
"@gtkx/css",
|
|
30
|
+
"@gtkx/gi/adw",
|
|
31
|
+
"@gtkx/gi/gdk",
|
|
32
|
+
"@gtkx/gi/gio",
|
|
33
|
+
"@gtkx/gi/glib",
|
|
34
|
+
"@gtkx/gi/graphene",
|
|
35
|
+
"@gtkx/gi/gsk",
|
|
36
|
+
"@gtkx/gi/gtk",
|
|
37
|
+
"@gtkx/gi/pango",
|
|
38
|
+
"@gtkx/jsx/gtk",
|
|
39
|
+
"@gtkx/react",
|
|
40
|
+
"@gtkx/runtime",
|
|
41
|
+
"react",
|
|
42
|
+
"react/jsx-runtime",
|
|
43
|
+
"react/jsx-dev-runtime",
|
|
44
|
+
"yoga-layout",
|
|
45
|
+
];
|
|
46
|
+
export const LINUX_PLATFORM = "linux";
|
|
47
|
+
const sanitize = (name) => name.replace(/[@/:]/g, "_") + ".js";
|
|
48
|
+
const hostModuleProxy = (name) =>
|
|
49
|
+
// The run-linux host guarantees __hostModules before executing the bundle.
|
|
50
|
+
`module.exports = global.__hostModules[${JSON.stringify(name)}]\n`;
|
|
51
|
+
const builtinProxy = (name) => `module.exports = global.__hostRequire(${JSON.stringify(name)})\n`;
|
|
52
|
+
// Every proxy is generated eagerly when the config loads: Metro crawls the
|
|
53
|
+
// file map before transforming, and files that appear mid-build lose the
|
|
54
|
+
// race ("Failed to get the SHA-1"). The builtin list is finite, so the
|
|
55
|
+
// whole proxy set can exist up front.
|
|
56
|
+
const generateProxies = (dir, externals) => {
|
|
57
|
+
mkdirSync(dir, { recursive: true });
|
|
58
|
+
for (const name of externals) {
|
|
59
|
+
writeFileSync(join(dir, sanitize(name)), hostModuleProxy(name));
|
|
60
|
+
}
|
|
61
|
+
for (const bare of builtinModules) {
|
|
62
|
+
writeFileSync(join(dir, sanitize(bare)), builtinProxy(bare));
|
|
63
|
+
writeFileSync(join(dir, sanitize(`node:${bare}`)), builtinProxy(`node:${bare}`));
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Wraps a Metro config (RN's getDefaultConfig output) with everything the
|
|
68
|
+
* linux platform needs. Composes with an existing custom resolveRequest —
|
|
69
|
+
* non-linux platforms fall through to it untouched.
|
|
70
|
+
*/
|
|
71
|
+
export const withLinuxPlatform = (config, options = {}) => {
|
|
72
|
+
const externals = new Set([
|
|
73
|
+
...HOST_MODULE_EXTERNALS,
|
|
74
|
+
...(options.externals ?? []),
|
|
75
|
+
]);
|
|
76
|
+
const proxyDir = options.proxyDir ??
|
|
77
|
+
join(config.projectRoot ?? process.cwd(), "node_modules", ".react-native-gtkx", "metro-externals");
|
|
78
|
+
generateProxies(proxyDir, externals);
|
|
79
|
+
const previousResolve = config.resolver?.resolveRequest ?? null;
|
|
80
|
+
const fallback = (context, moduleName, platform) => previousResolve
|
|
81
|
+
? previousResolve(context, moduleName, platform)
|
|
82
|
+
: context.resolveRequest(context, moduleName, platform);
|
|
83
|
+
const resolveRequest = (context, moduleName, platform) => {
|
|
84
|
+
if (platform !== LINUX_PLATFORM) {
|
|
85
|
+
return fallback(context, moduleName, platform);
|
|
86
|
+
}
|
|
87
|
+
if (externals.has(moduleName) || isBuiltin(moduleName)) {
|
|
88
|
+
return {
|
|
89
|
+
type: "sourceFile",
|
|
90
|
+
filePath: join(proxyDir, sanitize(moduleName)),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
if (moduleName === "react-native" ||
|
|
94
|
+
moduleName.startsWith("react-native/")) {
|
|
95
|
+
return fallback(context, moduleName.replace(/^react-native/, "react-native-gtkx"), platform);
|
|
96
|
+
}
|
|
97
|
+
return fallback(context, moduleName, platform);
|
|
98
|
+
};
|
|
99
|
+
// The cast: T may carry narrower resolver/serializer types than the ones
|
|
100
|
+
// rebuilt here — the runtime shape is a strict superset of both.
|
|
101
|
+
return {
|
|
102
|
+
...config,
|
|
103
|
+
resolver: {
|
|
104
|
+
...config.resolver,
|
|
105
|
+
platforms: [
|
|
106
|
+
...new Set([...(config.resolver?.platforms ?? []), LINUX_PLATFORM]),
|
|
107
|
+
],
|
|
108
|
+
resolveRequest,
|
|
109
|
+
},
|
|
110
|
+
serializer: {
|
|
111
|
+
...config.serializer,
|
|
112
|
+
// RN prepends InitializeCore (Hermes Promise, nativeLoggingHook
|
|
113
|
+
// console...). Our runtime environment IS Node — nothing to
|
|
114
|
+
// initialize inside the bundle.
|
|
115
|
+
getModulesRunBeforeMainModule: () => [],
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
};
|
|
119
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/metro/index.ts"],"names":[],"mappings":"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","sourcesContent":["// Metro preset for the linux out-of-tree platform: wrap the app's Metro\n// config with `withLinuxPlatform` and the standard RN toolchain bundles for\n// `--platform linux`.\n//\n// What it does on top of RN defaults (validated by spike/rn-platform):\n//\n// 1. Adds \"linux\" to resolver.platforms (`.linux.tsx` extensions and\n// Platform.OS come along with it).\n// 2. Redirects `react-native` (and subpaths) to `react-native-gtkx` — the\n// out-of-tree npmPackageName declaration alone does not alias imports\n// for `bundle`, the resolver has to.\n// 3. EXTERNALIZES host-side singletons. Unlike react-native-windows, whose\n// native side lives outside the JS bundle by construction, our \"native\"\n// is Node modules with NAPI bindings (@gtkx/*) plus yoga-layout's WASM —\n// Metro cannot bundle those. react (and its jsx runtimes) must also stay\n// host-side: the reconciler inside @gtkx/react and the app have to share\n// one React instance. Every external resolves to a generated proxy that\n// reads the real module from global.__hostModules — the run-linux host\n// injects them before executing the bundle.\n// 4. Proxies Node builtins through the host's require: apps on this\n// platform may use the whole Node API, it is a platform feature.\n// 5. Drops InitializeCore (RN's mobile environment polyfills): the runtime\n// environment IS Node, the host provides everything.\nimport { mkdirSync, writeFileSync } from \"node:fs\"\nimport { builtinModules, isBuiltin } from \"node:module\"\nimport { join } from \"node:path\"\n\n/** Modules the run-linux host provides to the bundle at runtime. */\nexport const HOST_MODULE_EXTERNALS = [\n \"@gtkx/css\",\n \"@gtkx/gi/adw\",\n \"@gtkx/gi/gdk\",\n \"@gtkx/gi/gio\",\n \"@gtkx/gi/glib\",\n \"@gtkx/gi/graphene\",\n \"@gtkx/gi/gsk\",\n \"@gtkx/gi/gtk\",\n \"@gtkx/gi/pango\",\n \"@gtkx/jsx/gtk\",\n \"@gtkx/react\",\n \"@gtkx/runtime\",\n \"react\",\n \"react/jsx-runtime\",\n \"react/jsx-dev-runtime\",\n \"yoga-layout\",\n]\n\nexport const LINUX_PLATFORM = \"linux\"\n\n// Structural slices of Metro's config/resolution types: Metro is the app's\n// dependency, not ours — depending on its types here would pin versions.\nexport type MetroResolutionContext = {\n resolveRequest: MetroResolver\n}\nexport type MetroResolution = { type: string; filePath?: string }\nexport type MetroResolver = (\n context: MetroResolutionContext,\n moduleName: string,\n platform: string | null,\n) => MetroResolution\n\nexport type MetroLikeConfig = {\n projectRoot?: string\n resolver?: {\n platforms?: readonly string[]\n resolveRequest?: MetroResolver | null\n }\n serializer?: {\n getModulesRunBeforeMainModule?: (entryFilePath: string) => string[]\n }\n}\n\nexport type LinuxPlatformOptions = {\n /** Extra host-provided modules to keep out of the bundle. */\n externals?: readonly string[]\n /** Proxy directory override (default: node_modules/.react-native-gtkx). */\n proxyDir?: string\n}\n\nconst sanitize = (name: string): string => name.replace(/[@/:]/g, \"_\") + \".js\"\n\nconst hostModuleProxy = (name: string): string =>\n // The run-linux host guarantees __hostModules before executing the bundle.\n `module.exports = global.__hostModules[${JSON.stringify(name)}]\\n`\n\nconst builtinProxy = (name: string): string =>\n `module.exports = global.__hostRequire(${JSON.stringify(name)})\\n`\n\n// Every proxy is generated eagerly when the config loads: Metro crawls the\n// file map before transforming, and files that appear mid-build lose the\n// race (\"Failed to get the SHA-1\"). The builtin list is finite, so the\n// whole proxy set can exist up front.\nconst generateProxies = (dir: string, externals: Set<string>): void => {\n mkdirSync(dir, { recursive: true })\n for (const name of externals) {\n writeFileSync(join(dir, sanitize(name)), hostModuleProxy(name))\n }\n for (const bare of builtinModules) {\n writeFileSync(join(dir, sanitize(bare)), builtinProxy(bare))\n writeFileSync(\n join(dir, sanitize(`node:${bare}`)),\n builtinProxy(`node:${bare}`),\n )\n }\n}\n\nexport type LinuxPlatformConfig<T extends MetroLikeConfig> = T & {\n resolver: {\n platforms: string[]\n resolveRequest: MetroResolver\n }\n serializer: {\n getModulesRunBeforeMainModule: (entryFilePath: string) => string[]\n }\n}\n\n/**\n * Wraps a Metro config (RN's getDefaultConfig output) with everything the\n * linux platform needs. Composes with an existing custom resolveRequest —\n * non-linux platforms fall through to it untouched.\n */\nexport const withLinuxPlatform = <T extends MetroLikeConfig>(\n config: T,\n options: LinuxPlatformOptions = {},\n): LinuxPlatformConfig<T> => {\n const externals = new Set([\n ...HOST_MODULE_EXTERNALS,\n ...(options.externals ?? []),\n ])\n const proxyDir =\n options.proxyDir ??\n join(\n config.projectRoot ?? process.cwd(),\n \"node_modules\",\n \".react-native-gtkx\",\n \"metro-externals\",\n )\n generateProxies(proxyDir, externals)\n const previousResolve = config.resolver?.resolveRequest ?? null\n\n const fallback: MetroResolver = (context, moduleName, platform) =>\n previousResolve\n ? previousResolve(context, moduleName, platform)\n : context.resolveRequest(context, moduleName, platform)\n\n const resolveRequest: MetroResolver = (context, moduleName, platform) => {\n if (platform !== LINUX_PLATFORM) {\n return fallback(context, moduleName, platform)\n }\n if (externals.has(moduleName) || isBuiltin(moduleName)) {\n return {\n type: \"sourceFile\",\n filePath: join(proxyDir, sanitize(moduleName)),\n }\n }\n if (\n moduleName === \"react-native\" ||\n moduleName.startsWith(\"react-native/\")\n ) {\n return fallback(\n context,\n moduleName.replace(/^react-native/, \"react-native-gtkx\"),\n platform,\n )\n }\n return fallback(context, moduleName, platform)\n }\n\n // The cast: T may carry narrower resolver/serializer types than the ones\n // rebuilt here — the runtime shape is a strict superset of both.\n return {\n ...config,\n resolver: {\n ...config.resolver,\n platforms: [\n ...new Set([...(config.resolver?.platforms ?? []), LINUX_PLATFORM]),\n ],\n resolveRequest,\n },\n serializer: {\n ...config.serializer,\n // RN prepends InitializeCore (Hermes Promise, nativeLoggingHook\n // console...). Our runtime environment IS Node — nothing to\n // initialize inside the bundle.\n getModulesRunBeforeMainModule: () => [],\n },\n } as LinuxPlatformConfig<T>\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
// The DEV host: fetch the dev bundle from a Metro dev server, execute it,
|
|
2
|
+
// subscribe to HMR updates and let react-refresh re-render through the
|
|
3
|
+
// @gtkx/react reconciler with component state preserved. Spawned by
|
|
4
|
+
// `run-linux --dev` as `node dist/runner/host-dev.js <bundle-url>`; exits
|
|
5
|
+
// with code 65 when a full refresh is required — the supervisor restarts.
|
|
6
|
+
//
|
|
7
|
+
// Division of labor (validated by spike/rn-platform, FINDINGS-dev.md):
|
|
8
|
+
// metro-runtime's dev require scopes the react-refresh registration per
|
|
9
|
+
// module and applies hot updates once global.__ReactRefresh exists; its
|
|
10
|
+
// HMRClient speaks the /hot websocket protocol verbatim over Node's
|
|
11
|
+
// global WebSocket. This file only adds the dev pieces on top of the
|
|
12
|
+
// release host (./host.ts — deliberately self-contained twins: both must
|
|
13
|
+
// stay runnable under bare Node, so they cannot share a relative
|
|
14
|
+
// extensionless import).
|
|
15
|
+
import { createRequire, registerHooks } from "node:module";
|
|
16
|
+
import { join } from "node:path";
|
|
17
|
+
import { pathToFileURL } from "node:url";
|
|
18
|
+
import vm from "node:vm";
|
|
19
|
+
import { HOST_MODULE_EXTERNALS } from "react-native-gtkx/metro";
|
|
20
|
+
const fail = (message) => {
|
|
21
|
+
console.error(`[react-native-gtkx] ${message}`);
|
|
22
|
+
process.exit(1);
|
|
23
|
+
};
|
|
24
|
+
if (typeof registerHooks !== "function") {
|
|
25
|
+
fail(`Node ${process.version} lacks module.registerHooks — the linux host needs Node >= 22.15.`);
|
|
26
|
+
}
|
|
27
|
+
// react and the reconciler must run their DEV builds for react-refresh.
|
|
28
|
+
process.env.NODE_ENV = process.env.NODE_ENV ?? "development";
|
|
29
|
+
const bundleUrl = process.argv[2];
|
|
30
|
+
if (!bundleUrl) {
|
|
31
|
+
fail("usage: node host-dev.js <metro-dev-bundle-url>");
|
|
32
|
+
}
|
|
33
|
+
// Resolution anchors: react-refresh and metro-runtime ship with the APP's
|
|
34
|
+
// react-native; @gtkx/* resolve as this package's dependencies; react must
|
|
35
|
+
// be the exact instance the reconciler sees (see host.ts).
|
|
36
|
+
const fromApp = createRequire(join(process.cwd(), "package.json"));
|
|
37
|
+
const fromPackage = createRequire(import.meta.url);
|
|
38
|
+
const fromGtkxReact = createRequire(fromPackage.resolve("@gtkx/react"));
|
|
39
|
+
// --- react-refresh: inject BEFORE @gtkx/react loads (the reconciler
|
|
40
|
+
// registers into the patched devtools hook).
|
|
41
|
+
const RefreshRuntime = fromApp("react-refresh/runtime");
|
|
42
|
+
RefreshRuntime.injectIntoGlobalHook(globalThis);
|
|
43
|
+
globalThis.$RefreshReg$ = () => { };
|
|
44
|
+
globalThis.$RefreshSig$ = () => (type) => type;
|
|
45
|
+
globalThis.__ReactRefresh = {
|
|
46
|
+
...RefreshRuntime,
|
|
47
|
+
performFullRefresh(reason) {
|
|
48
|
+
console.warn(`[react-native-gtkx] full refresh required (${reason}) — restarting`);
|
|
49
|
+
process.exit(65);
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
// --- virtual:gtkx-config (same mechanism as the release host).
|
|
53
|
+
const { loadConfig } = await import(pathToFileURL(fromPackage.resolve("@gtkx/config")).href);
|
|
54
|
+
const { config: gtkxConfig } = await loadConfig(process.cwd());
|
|
55
|
+
if (!gtkxConfig.applicationId) {
|
|
56
|
+
fail("gtkx.config.ts with an applicationId is required in the app root " +
|
|
57
|
+
'(export default defineConfig({ applicationId: "...", libraries: [...] })).');
|
|
58
|
+
}
|
|
59
|
+
const configModuleUrl = new URL("./__virtual-gtkx-config.mjs", import.meta.url)
|
|
60
|
+
.href;
|
|
61
|
+
const configModuleSource = [
|
|
62
|
+
`export * from "@gtkx/jsx/metadata";`,
|
|
63
|
+
`export const applicationId = ${JSON.stringify(gtkxConfig.applicationId)};`,
|
|
64
|
+
].join("\n");
|
|
65
|
+
registerHooks({
|
|
66
|
+
resolve(specifier, context, nextResolve) {
|
|
67
|
+
if (specifier === "virtual:gtkx-config") {
|
|
68
|
+
return { url: configModuleUrl, shortCircuit: true };
|
|
69
|
+
}
|
|
70
|
+
return nextResolve(specifier, context);
|
|
71
|
+
},
|
|
72
|
+
load(url, context, nextLoad) {
|
|
73
|
+
if (url === configModuleUrl) {
|
|
74
|
+
return {
|
|
75
|
+
format: "module",
|
|
76
|
+
source: configModuleSource,
|
|
77
|
+
shortCircuit: true,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
return nextLoad(url, context);
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
// --- host modules (same interop merging as the release host).
|
|
84
|
+
const resolveExternal = (name) => name === "react" || name.startsWith("react/")
|
|
85
|
+
? fromGtkxReact.resolve(name)
|
|
86
|
+
: fromPackage.resolve(name);
|
|
87
|
+
const load = async (name) => {
|
|
88
|
+
const namespace = await import(pathToFileURL(resolveExternal(name)).href);
|
|
89
|
+
const merged = { __esModule: true, ...namespace };
|
|
90
|
+
if (!("default" in namespace)) {
|
|
91
|
+
merged.default = namespace;
|
|
92
|
+
}
|
|
93
|
+
return merged;
|
|
94
|
+
};
|
|
95
|
+
globalThis.__hostModules = {};
|
|
96
|
+
for (const name of HOST_MODULE_EXTERNALS) {
|
|
97
|
+
try {
|
|
98
|
+
globalThis.__hostModules[name] = await load(name);
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
fail(`failed to load host module "${name}" — is the codegen store in ` +
|
|
102
|
+
`place (npx gtkx codegen) and GTK4/libadwaita installed?\n${String(error)}`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
globalThis.__hostRequire = createRequire(import.meta.url);
|
|
106
|
+
// --- Dev Menu (Ctrl+Shift+D, the react-native-windows precedent).
|
|
107
|
+
// Installed before the bundle runs so DevSettings.reload works from app
|
|
108
|
+
// code; the key controller attaches once the app window exists.
|
|
109
|
+
const requestReload = (reason) => {
|
|
110
|
+
console.warn(`[react-native-gtkx] reload requested${reason ? ` (${reason})` : ""} — restarting`);
|
|
111
|
+
return process.exit(65);
|
|
112
|
+
};
|
|
113
|
+
globalThis.__rnGtkxDevHost = { reload: requestReload };
|
|
114
|
+
const installDevMenu = () => {
|
|
115
|
+
const gtk = globalThis.__hostModules["@gtkx/gi/gtk"];
|
|
116
|
+
const gdk = globalThis.__hostModules["@gtkx/gi/gdk"];
|
|
117
|
+
const adw = globalThis.__hostModules["@gtkx/gi/adw"];
|
|
118
|
+
const gio = globalThis.__hostModules["@gtkx/gi/gio"];
|
|
119
|
+
// GDK keysyms for latin letters equal their ASCII codes.
|
|
120
|
+
const KEY_UPPER_D = 0x44;
|
|
121
|
+
const KEY_LOWER_D = 0x64;
|
|
122
|
+
let menuOpen = false;
|
|
123
|
+
const openDevMenu = async (window) => {
|
|
124
|
+
if (menuOpen) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
menuOpen = true;
|
|
128
|
+
try {
|
|
129
|
+
const items = globalThis.__rnGtkxDevMenuItems ?? [];
|
|
130
|
+
const dialog = new adw.AlertDialog();
|
|
131
|
+
dialog.setHeading("React Native Dev Menu");
|
|
132
|
+
dialog.setBody(bundleUrl);
|
|
133
|
+
dialog.addResponse("cancel", "Cancel");
|
|
134
|
+
items.forEach((item, index) => {
|
|
135
|
+
dialog.addResponse(`custom-${index}`, item.title);
|
|
136
|
+
});
|
|
137
|
+
dialog.addResponse("reload", "Reload");
|
|
138
|
+
dialog.setResponseAppearance("reload", adw.ResponseAppearance.SUGGESTED);
|
|
139
|
+
dialog.setDefaultResponse("reload");
|
|
140
|
+
dialog.setCloseResponse("cancel");
|
|
141
|
+
const response = await dialog.choose(window);
|
|
142
|
+
if (response === "reload") {
|
|
143
|
+
requestReload();
|
|
144
|
+
}
|
|
145
|
+
const custom = /^custom-(\d+)$/.exec(response);
|
|
146
|
+
if (custom) {
|
|
147
|
+
items[Number(custom[1])]?.handler();
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
console.error(`[react-native-gtkx] dev menu failed: ${String(error)}`);
|
|
152
|
+
}
|
|
153
|
+
finally {
|
|
154
|
+
menuOpen = false;
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
const attach = () => {
|
|
158
|
+
const window = gio.Application.getDefault()?.getActiveWindow?.();
|
|
159
|
+
if (!window) {
|
|
160
|
+
// The bundle opens the window asynchronously (application activate).
|
|
161
|
+
setTimeout(attach, 200);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
const controller = new gtk.EventControllerKey();
|
|
165
|
+
controller.on("key-pressed", (keyval, _keycode, state) => {
|
|
166
|
+
const modifiers = state;
|
|
167
|
+
const wanted = (modifiers & gdk.ModifierType.CONTROL_MASK) !== 0 &&
|
|
168
|
+
(modifiers & gdk.ModifierType.SHIFT_MASK) !== 0 &&
|
|
169
|
+
(keyval === KEY_UPPER_D || keyval === KEY_LOWER_D);
|
|
170
|
+
if (wanted) {
|
|
171
|
+
void openDevMenu(window);
|
|
172
|
+
return true;
|
|
173
|
+
}
|
|
174
|
+
return false;
|
|
175
|
+
});
|
|
176
|
+
window.addController(controller);
|
|
177
|
+
console.warn("[react-native-gtkx] dev menu ready (Ctrl+Shift+D)");
|
|
178
|
+
};
|
|
179
|
+
attach();
|
|
180
|
+
};
|
|
181
|
+
// --- fetch and run the dev bundle.
|
|
182
|
+
let response;
|
|
183
|
+
try {
|
|
184
|
+
response = await fetch(bundleUrl);
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
fail(`Metro dev server is not reachable (${bundleUrl}).`);
|
|
188
|
+
throw new Error("unreachable");
|
|
189
|
+
}
|
|
190
|
+
if (!response.ok) {
|
|
191
|
+
fail(`Metro returned ${response.status} for the dev bundle:\n${await response.text()}`);
|
|
192
|
+
}
|
|
193
|
+
vm.runInThisContext(await response.text(), { filename: bundleUrl });
|
|
194
|
+
installDevMenu();
|
|
195
|
+
const HMRClient = fromApp("metro-runtime/src/modules/HMRClient");
|
|
196
|
+
const client = new HMRClient(bundleUrl.replace(/^http/, "ws").replace(/\/[^/]*$/, "/hot"));
|
|
197
|
+
client.send(JSON.stringify({ type: "register-entrypoints", entryPoints: [bundleUrl] }));
|
|
198
|
+
client.enable();
|
|
199
|
+
client.on("update-done", () => {
|
|
200
|
+
console.warn("[react-native-gtkx] hot update applied");
|
|
201
|
+
});
|
|
202
|
+
client.on("error", (body) => {
|
|
203
|
+
console.error(`[react-native-gtkx] Metro error (${body?.type ?? "unknown"}):\n${body?.message ?? ""}`);
|
|
204
|
+
});
|
|
205
|
+
client.on("close", () => {
|
|
206
|
+
console.warn("[react-native-gtkx] HMR connection closed (the window keeps running without hot updates)");
|
|
207
|
+
});
|
|
208
|
+
//# sourceMappingURL=host-dev.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host-dev.js","sourceRoot":"","sources":["../../src/runner/host-dev.ts"],"names":[],"mappings":"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","sourcesContent":["// The DEV host: fetch the dev bundle from a Metro dev server, execute it,\n// subscribe to HMR updates and let react-refresh re-render through the\n// @gtkx/react reconciler with component state preserved. Spawned by\n// `run-linux --dev` as `node dist/runner/host-dev.js <bundle-url>`; exits\n// with code 65 when a full refresh is required — the supervisor restarts.\n//\n// Division of labor (validated by spike/rn-platform, FINDINGS-dev.md):\n// metro-runtime's dev require scopes the react-refresh registration per\n// module and applies hot updates once global.__ReactRefresh exists; its\n// HMRClient speaks the /hot websocket protocol verbatim over Node's\n// global WebSocket. This file only adds the dev pieces on top of the\n// release host (./host.ts — deliberately self-contained twins: both must\n// stay runnable under bare Node, so they cannot share a relative\n// extensionless import).\nimport { createRequire, registerHooks } from \"node:module\"\nimport { join } from \"node:path\"\nimport { pathToFileURL } from \"node:url\"\nimport vm from \"node:vm\"\nimport { HOST_MODULE_EXTERNALS } from \"react-native-gtkx/metro\"\n\ntype HostModule = Record<string, unknown>\n\nconst fail = (message: string): never => {\n console.error(`[react-native-gtkx] ${message}`)\n process.exit(1)\n}\n\nif (typeof registerHooks !== \"function\") {\n fail(\n `Node ${process.version} lacks module.registerHooks — the linux host needs Node >= 22.15.`,\n )\n}\n\n// react and the reconciler must run their DEV builds for react-refresh.\nprocess.env.NODE_ENV = process.env.NODE_ENV ?? \"development\"\n\nconst bundleUrl = process.argv[2]\nif (!bundleUrl) {\n fail(\"usage: node host-dev.js <metro-dev-bundle-url>\")\n}\n\n// Resolution anchors: react-refresh and metro-runtime ship with the APP's\n// react-native; @gtkx/* resolve as this package's dependencies; react must\n// be the exact instance the reconciler sees (see host.ts).\nconst fromApp = createRequire(join(process.cwd(), \"package.json\"))\nconst fromPackage = createRequire(import.meta.url)\nconst fromGtkxReact = createRequire(fromPackage.resolve(\"@gtkx/react\"))\n\n// --- react-refresh: inject BEFORE @gtkx/react loads (the reconciler\n// registers into the patched devtools hook).\nconst RefreshRuntime = fromApp(\"react-refresh/runtime\") as Record<\n string,\n unknown\n> & { injectIntoGlobalHook(target: unknown): void }\nRefreshRuntime.injectIntoGlobalHook(globalThis)\nglobalThis.$RefreshReg$ = () => {}\nglobalThis.$RefreshSig$ = () => (type: unknown) => type\nglobalThis.__ReactRefresh = {\n ...RefreshRuntime,\n performFullRefresh(reason: string) {\n console.warn(\n `[react-native-gtkx] full refresh required (${reason}) — restarting`,\n )\n process.exit(65)\n },\n}\n\n// --- virtual:gtkx-config (same mechanism as the release host).\nconst { loadConfig } = await import(\n pathToFileURL(fromPackage.resolve(\"@gtkx/config\")).href\n)\nconst { config: gtkxConfig } = await loadConfig(process.cwd())\nif (!gtkxConfig.applicationId) {\n fail(\n \"gtkx.config.ts with an applicationId is required in the app root \" +\n '(export default defineConfig({ applicationId: \"...\", libraries: [...] })).',\n )\n}\nconst configModuleUrl = new URL(\"./__virtual-gtkx-config.mjs\", import.meta.url)\n .href\nconst configModuleSource = [\n `export * from \"@gtkx/jsx/metadata\";`,\n `export const applicationId = ${JSON.stringify(gtkxConfig.applicationId)};`,\n].join(\"\\n\")\nregisterHooks({\n resolve(specifier, context, nextResolve) {\n if (specifier === \"virtual:gtkx-config\") {\n return { url: configModuleUrl, shortCircuit: true }\n }\n return nextResolve(specifier, context)\n },\n load(url, context, nextLoad) {\n if (url === configModuleUrl) {\n return {\n format: \"module\",\n source: configModuleSource,\n shortCircuit: true,\n }\n }\n return nextLoad(url, context)\n },\n})\n\n// --- host modules (same interop merging as the release host).\nconst resolveExternal = (name: string): string =>\n name === \"react\" || name.startsWith(\"react/\")\n ? fromGtkxReact.resolve(name)\n : fromPackage.resolve(name)\n\nconst load = async (name: string): Promise<HostModule> => {\n const namespace: HostModule = await import(\n pathToFileURL(resolveExternal(name)).href\n )\n const merged: HostModule = { __esModule: true, ...namespace }\n if (!(\"default\" in namespace)) {\n merged.default = namespace\n }\n return merged\n}\n\nglobalThis.__hostModules = {}\nfor (const name of HOST_MODULE_EXTERNALS) {\n try {\n globalThis.__hostModules[name] = await load(name)\n } catch (error) {\n fail(\n `failed to load host module \"${name}\" — is the codegen store in ` +\n `place (npx gtkx codegen) and GTK4/libadwaita installed?\\n${String(error)}`,\n )\n }\n}\nglobalThis.__hostRequire = createRequire(import.meta.url)\n\n// --- Dev Menu (Ctrl+Shift+D, the react-native-windows precedent).\n// Installed before the bundle runs so DevSettings.reload works from app\n// code; the key controller attaches once the app window exists.\nconst requestReload = (reason?: string): never => {\n console.warn(\n `[react-native-gtkx] reload requested${reason ? ` (${reason})` : \"\"} — restarting`,\n )\n return process.exit(65)\n}\nglobalThis.__rnGtkxDevHost = { reload: requestReload }\n\n// Structural slices of the GTK wrappers the menu touches — the host talks\n// to codegen namespaces through __hostModules, untyped by design.\ntype DevMenuWindow = { addController(controller: unknown): void }\ntype DevMenuDialog = {\n setHeading(heading: string): void\n setBody(body: string): void\n addResponse(id: string, label: string): void\n setResponseAppearance(id: string, appearance: unknown): void\n setDefaultResponse(id: string): void\n setCloseResponse(id: string): void\n choose(parent: DevMenuWindow): Promise<string>\n}\n\nconst installDevMenu = (): void => {\n const gtk = globalThis.__hostModules[\"@gtkx/gi/gtk\"] as {\n EventControllerKey: new () => {\n on(signal: string, handler: (...args: unknown[]) => unknown): void\n }\n }\n const gdk = globalThis.__hostModules[\"@gtkx/gi/gdk\"] as {\n ModifierType: { CONTROL_MASK: number; SHIFT_MASK: number }\n }\n const adw = globalThis.__hostModules[\"@gtkx/gi/adw\"] as {\n AlertDialog: new () => DevMenuDialog\n ResponseAppearance: { SUGGESTED: unknown }\n }\n const gio = globalThis.__hostModules[\"@gtkx/gi/gio\"] as {\n Application: {\n getDefault():\n { getActiveWindow?: () => DevMenuWindow | null } | null | undefined\n }\n }\n // GDK keysyms for latin letters equal their ASCII codes.\n const KEY_UPPER_D = 0x44\n const KEY_LOWER_D = 0x64\n\n let menuOpen = false\n const openDevMenu = async (window: DevMenuWindow): Promise<void> => {\n if (menuOpen) {\n return\n }\n menuOpen = true\n try {\n const items = globalThis.__rnGtkxDevMenuItems ?? []\n const dialog = new adw.AlertDialog()\n dialog.setHeading(\"React Native Dev Menu\")\n dialog.setBody(bundleUrl!)\n dialog.addResponse(\"cancel\", \"Cancel\")\n items.forEach((item, index) => {\n dialog.addResponse(`custom-${index}`, item.title)\n })\n dialog.addResponse(\"reload\", \"Reload\")\n dialog.setResponseAppearance(\"reload\", adw.ResponseAppearance.SUGGESTED)\n dialog.setDefaultResponse(\"reload\")\n dialog.setCloseResponse(\"cancel\")\n const response = await dialog.choose(window)\n if (response === \"reload\") {\n requestReload()\n }\n const custom = /^custom-(\\d+)$/.exec(response)\n if (custom) {\n items[Number(custom[1])]?.handler()\n }\n } catch (error) {\n console.error(`[react-native-gtkx] dev menu failed: ${String(error)}`)\n } finally {\n menuOpen = false\n }\n }\n\n const attach = (): void => {\n const window = gio.Application.getDefault()?.getActiveWindow?.()\n if (!window) {\n // The bundle opens the window asynchronously (application activate).\n setTimeout(attach, 200)\n return\n }\n const controller = new gtk.EventControllerKey()\n controller.on(\"key-pressed\", (keyval, _keycode, state) => {\n const modifiers = state as number\n const wanted =\n (modifiers & gdk.ModifierType.CONTROL_MASK) !== 0 &&\n (modifiers & gdk.ModifierType.SHIFT_MASK) !== 0 &&\n (keyval === KEY_UPPER_D || keyval === KEY_LOWER_D)\n if (wanted) {\n void openDevMenu(window)\n return true\n }\n return false\n })\n window.addController(controller)\n console.warn(\"[react-native-gtkx] dev menu ready (Ctrl+Shift+D)\")\n }\n attach()\n}\n\n// --- fetch and run the dev bundle.\nlet response: Response\ntry {\n response = await fetch(bundleUrl!)\n} catch {\n fail(`Metro dev server is not reachable (${bundleUrl}).`)\n throw new Error(\"unreachable\")\n}\nif (!response.ok) {\n fail(\n `Metro returned ${response.status} for the dev bundle:\\n${await response.text()}`,\n )\n}\nvm.runInThisContext(await response.text(), { filename: bundleUrl })\ninstallDevMenu()\n\n// --- HMR: metro-runtime's own client (ships with react-native).\ntype HmrErrorBody = { type?: string; message?: string }\ntype HmrClient = {\n send(message: string): void\n enable(): void\n on(event: string, listener: (body?: HmrErrorBody) => void): void\n}\nconst HMRClient = fromApp(\"metro-runtime/src/modules/HMRClient\") as new (\n url: string,\n) => HmrClient\nconst client = new HMRClient(\n bundleUrl!.replace(/^http/, \"ws\").replace(/\\/[^/]*$/, \"/hot\"),\n)\nclient.send(\n JSON.stringify({ type: \"register-entrypoints\", entryPoints: [bundleUrl] }),\n)\nclient.enable()\nclient.on(\"update-done\", () => {\n console.warn(\"[react-native-gtkx] hot update applied\")\n})\nclient.on(\"error\", (body) => {\n console.error(\n `[react-native-gtkx] Metro error (${body?.type ?? \"unknown\"}):\\n${body?.message ?? \"\"}`,\n )\n})\nclient.on(\"close\", () => {\n console.warn(\n \"[react-native-gtkx] HMR connection closed (the window keeps running without hot updates)\",\n )\n})\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// The Node+GTK host: executes a Metro jsbundle built for the linux
|
|
2
|
+
// platform. Spawned by the run-linux command as
|
|
3
|
+
// `node dist/runner/host.js <bundle>`; the bundle's externalized proxies
|
|
4
|
+
// (see ../metro) read the modules injected here.
|
|
5
|
+
//
|
|
6
|
+
// This file must stay runnable under BARE Node: no extensionless relative
|
|
7
|
+
// imports — only builtins, bare dependency specifiers and the package
|
|
8
|
+
// self-reference (resolved through the exports map).
|
|
9
|
+
import { readFileSync } from "node:fs";
|
|
10
|
+
import { createRequire, registerHooks } from "node:module";
|
|
11
|
+
import { pathToFileURL } from "node:url";
|
|
12
|
+
import vm from "node:vm";
|
|
13
|
+
import { HOST_MODULE_EXTERNALS } from "react-native-gtkx/metro";
|
|
14
|
+
const fail = (message) => {
|
|
15
|
+
console.error(`[react-native-gtkx] ${message}`);
|
|
16
|
+
process.exit(1);
|
|
17
|
+
};
|
|
18
|
+
if (typeof registerHooks !== "function") {
|
|
19
|
+
fail(`Node ${process.version} lacks module.registerHooks — the linux host needs Node >= 22.15.`);
|
|
20
|
+
}
|
|
21
|
+
// Resolution anchors. @gtkx/* and @gtkx/config resolve as THIS package's
|
|
22
|
+
// dependencies; react resolves FROM @gtkx/react's real location — the
|
|
23
|
+
// reconciler and the app must share one React instance, and anchoring at
|
|
24
|
+
// the app could pick up a second copy installed by npm peer auto-install.
|
|
25
|
+
const fromPackage = createRequire(import.meta.url);
|
|
26
|
+
const fromGtkxReact = createRequire(fromPackage.resolve("@gtkx/react"));
|
|
27
|
+
const resolveExternal = (name) => name === "react" || name.startsWith("react/")
|
|
28
|
+
? fromGtkxReact.resolve(name)
|
|
29
|
+
: fromPackage.resolve(name);
|
|
30
|
+
// import() handles both ESM and CJS; merge a `default` for Babel's
|
|
31
|
+
// default-import interop when the module has none of its own.
|
|
32
|
+
const load = async (name) => {
|
|
33
|
+
const namespace = await import(pathToFileURL(resolveExternal(name)).href);
|
|
34
|
+
const merged = { __esModule: true, ...namespace };
|
|
35
|
+
if (!("default" in namespace)) {
|
|
36
|
+
merged.default = namespace;
|
|
37
|
+
}
|
|
38
|
+
return merged;
|
|
39
|
+
};
|
|
40
|
+
// @gtkx/react imports `virtual:gtkx-config` (JSX metadata + the resolved
|
|
41
|
+
// applicationId); in the vite path the gtkx CLI plugin serves it. Replicate
|
|
42
|
+
// it with a loader hook. The fake module URL is anchored inside this
|
|
43
|
+
// package so the re-exported bare specifier resolves through node_modules.
|
|
44
|
+
const { loadConfig } = await import("@gtkx/config");
|
|
45
|
+
const { config: gtkxConfig } = await loadConfig(process.cwd());
|
|
46
|
+
if (!gtkxConfig.applicationId) {
|
|
47
|
+
fail("gtkx.config.ts with an applicationId is required in the app root " +
|
|
48
|
+
'(export default defineConfig({ applicationId: "...", libraries: [...] })).');
|
|
49
|
+
}
|
|
50
|
+
const configModuleUrl = new URL("./__virtual-gtkx-config.mjs", import.meta.url)
|
|
51
|
+
.href;
|
|
52
|
+
const configModuleSource = [
|
|
53
|
+
`export * from "@gtkx/jsx/metadata";`,
|
|
54
|
+
`export const applicationId = ${JSON.stringify(gtkxConfig.applicationId)};`,
|
|
55
|
+
].join("\n");
|
|
56
|
+
registerHooks({
|
|
57
|
+
resolve(specifier, context, nextResolve) {
|
|
58
|
+
if (specifier === "virtual:gtkx-config") {
|
|
59
|
+
return { url: configModuleUrl, shortCircuit: true };
|
|
60
|
+
}
|
|
61
|
+
return nextResolve(specifier, context);
|
|
62
|
+
},
|
|
63
|
+
load(url, context, nextLoad) {
|
|
64
|
+
if (url === configModuleUrl) {
|
|
65
|
+
return {
|
|
66
|
+
format: "module",
|
|
67
|
+
source: configModuleSource,
|
|
68
|
+
shortCircuit: true,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return nextLoad(url, context);
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
globalThis.__hostModules = {};
|
|
75
|
+
for (const name of HOST_MODULE_EXTERNALS) {
|
|
76
|
+
try {
|
|
77
|
+
globalThis.__hostModules[name] = await load(name);
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
fail(`failed to load host module "${name}" — is the codegen store in ` +
|
|
81
|
+
`place (npx gtkx codegen) and GTK4/libadwaita installed?\n${String(error)}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// Node builtin proxies resolve lazily through the host's own require.
|
|
85
|
+
globalThis.__hostRequire = createRequire(import.meta.url);
|
|
86
|
+
const bundlePath = process.argv[2];
|
|
87
|
+
if (!bundlePath) {
|
|
88
|
+
fail("usage: node host.js <path/to/main.jsbundle>");
|
|
89
|
+
}
|
|
90
|
+
let source;
|
|
91
|
+
try {
|
|
92
|
+
source = readFileSync(bundlePath, "utf8");
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
fail(`bundle not found at ${bundlePath} — run react-native run-linux.`);
|
|
96
|
+
throw new Error("unreachable");
|
|
97
|
+
}
|
|
98
|
+
// The entry calls AppRegistry.runApplication itself (the react-native-web
|
|
99
|
+
// pattern); the GLib main loop keeps the process alive afterwards.
|
|
100
|
+
vm.runInThisContext(source, { filename: bundlePath });
|
|
101
|
+
//# sourceMappingURL=host.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host.js","sourceRoot":"","sources":["../../src/runner/host.ts"],"names":[],"mappings":"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","sourcesContent":["// The Node+GTK host: executes a Metro jsbundle built for the linux\n// platform. Spawned by the run-linux command as\n// `node dist/runner/host.js <bundle>`; the bundle's externalized proxies\n// (see ../metro) read the modules injected here.\n//\n// This file must stay runnable under BARE Node: no extensionless relative\n// imports — only builtins, bare dependency specifiers and the package\n// self-reference (resolved through the exports map).\nimport { readFileSync } from \"node:fs\"\nimport { createRequire, registerHooks } from \"node:module\"\nimport { pathToFileURL } from \"node:url\"\nimport vm from \"node:vm\"\nimport { HOST_MODULE_EXTERNALS } from \"react-native-gtkx/metro\"\n\ntype HostModule = Record<string, unknown>\n\nconst fail = (message: string): never => {\n console.error(`[react-native-gtkx] ${message}`)\n process.exit(1)\n}\n\nif (typeof registerHooks !== \"function\") {\n fail(\n `Node ${process.version} lacks module.registerHooks — the linux host needs Node >= 22.15.`,\n )\n}\n\n// Resolution anchors. @gtkx/* and @gtkx/config resolve as THIS package's\n// dependencies; react resolves FROM @gtkx/react's real location — the\n// reconciler and the app must share one React instance, and anchoring at\n// the app could pick up a second copy installed by npm peer auto-install.\nconst fromPackage = createRequire(import.meta.url)\nconst fromGtkxReact = createRequire(fromPackage.resolve(\"@gtkx/react\"))\n\nconst resolveExternal = (name: string): string =>\n name === \"react\" || name.startsWith(\"react/\")\n ? fromGtkxReact.resolve(name)\n : fromPackage.resolve(name)\n\n// import() handles both ESM and CJS; merge a `default` for Babel's\n// default-import interop when the module has none of its own.\nconst load = async (name: string): Promise<HostModule> => {\n const namespace: HostModule = await import(\n pathToFileURL(resolveExternal(name)).href\n )\n const merged: HostModule = { __esModule: true, ...namespace }\n if (!(\"default\" in namespace)) {\n merged.default = namespace\n }\n return merged\n}\n\n// @gtkx/react imports `virtual:gtkx-config` (JSX metadata + the resolved\n// applicationId); in the vite path the gtkx CLI plugin serves it. Replicate\n// it with a loader hook. The fake module URL is anchored inside this\n// package so the re-exported bare specifier resolves through node_modules.\nconst { loadConfig } = await import(\"@gtkx/config\")\nconst { config: gtkxConfig } = await loadConfig(process.cwd())\nif (!gtkxConfig.applicationId) {\n fail(\n \"gtkx.config.ts with an applicationId is required in the app root \" +\n '(export default defineConfig({ applicationId: \"...\", libraries: [...] })).',\n )\n}\nconst configModuleUrl = new URL(\"./__virtual-gtkx-config.mjs\", import.meta.url)\n .href\nconst configModuleSource = [\n `export * from \"@gtkx/jsx/metadata\";`,\n `export const applicationId = ${JSON.stringify(gtkxConfig.applicationId)};`,\n].join(\"\\n\")\nregisterHooks({\n resolve(specifier, context, nextResolve) {\n if (specifier === \"virtual:gtkx-config\") {\n return { url: configModuleUrl, shortCircuit: true }\n }\n return nextResolve(specifier, context)\n },\n load(url, context, nextLoad) {\n if (url === configModuleUrl) {\n return {\n format: \"module\",\n source: configModuleSource,\n shortCircuit: true,\n }\n }\n return nextLoad(url, context)\n },\n})\n\nglobalThis.__hostModules = {}\nfor (const name of HOST_MODULE_EXTERNALS) {\n try {\n globalThis.__hostModules[name] = await load(name)\n } catch (error) {\n fail(\n `failed to load host module \"${name}\" — is the codegen store in ` +\n `place (npx gtkx codegen) and GTK4/libadwaita installed?\\n${String(error)}`,\n )\n }\n}\n// Node builtin proxies resolve lazily through the host's own require.\nglobalThis.__hostRequire = createRequire(import.meta.url)\n\nconst bundlePath = process.argv[2]\nif (!bundlePath) {\n fail(\"usage: node host.js <path/to/main.jsbundle>\")\n}\nlet source: string\ntry {\n source = readFileSync(bundlePath!, \"utf8\")\n} catch {\n fail(`bundle not found at ${bundlePath} — run react-native run-linux.`)\n throw new Error(\"unreachable\")\n}\n// The entry calls AppRegistry.runApplication itself (the react-native-web\n// pattern); the GLib main loop keeps the process alive afterwards.\nvm.runInThisContext(source, { filename: bundlePath })\n"]}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
type CliConfig = {
|
|
2
|
+
root: string;
|
|
3
|
+
};
|
|
4
|
+
type RunLinuxArgs = {
|
|
5
|
+
entryFile: string;
|
|
6
|
+
bundleOutput?: string;
|
|
7
|
+
skipBundling?: boolean;
|
|
8
|
+
dev?: boolean;
|
|
9
|
+
port?: string;
|
|
10
|
+
};
|
|
11
|
+
/** Commands contributed to the RN CLI by the package's react-native.config.js. */
|
|
12
|
+
export declare const commands: {
|
|
13
|
+
name: string;
|
|
14
|
+
description: string;
|
|
15
|
+
options: ({
|
|
16
|
+
name: string;
|
|
17
|
+
description: string;
|
|
18
|
+
default: string;
|
|
19
|
+
} | {
|
|
20
|
+
name: string;
|
|
21
|
+
description: string;
|
|
22
|
+
default?: undefined;
|
|
23
|
+
})[];
|
|
24
|
+
func: (_argv: string[], config: CliConfig, args: RunLinuxArgs) => Promise<void>;
|
|
25
|
+
}[];
|
|
26
|
+
export {};
|