react-native-gtkx 0.3.0-alpha.1 → 0.4.0-alpha.2
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/README.md +1 -1
- package/dist/adw/index.d.ts +3 -2
- package/dist/adw/index.js +21 -4
- package/dist/adw/index.js.map +1 -1
- package/dist/adw/widgets.generated.d.ts +1 -1
- package/dist/adw/widgets.generated.js +2 -2
- package/dist/adw/widgets.generated.js.map +1 -1
- package/dist/animated/create-animated.d.ts +2 -0
- package/dist/animated/create-animated.js +2 -0
- package/dist/animated/create-animated.js.map +1 -1
- package/dist/animated/event.d.ts +15 -0
- package/dist/animated/event.js +80 -0
- package/dist/animated/event.js.map +1 -0
- package/dist/animated/index.d.ts +4 -0
- package/dist/animated/index.js +8 -0
- package/dist/animated/index.js.map +1 -1
- package/dist/animated/spring.d.ts +10 -0
- package/dist/animated/spring.js +20 -6
- package/dist/animated/spring.js.map +1 -1
- package/dist/animated/timing.d.ts +10 -0
- package/dist/animated/timing.js +21 -13
- package/dist/animated/timing.js.map +1 -1
- package/dist/apis/host.gtkx.js +70 -11
- package/dist/apis/host.gtkx.js.map +1 -1
- package/dist/common/navigation-stack.d.ts +6 -3
- package/dist/common/navigation-stack.js +8 -1
- package/dist/common/navigation-stack.js.map +1 -1
- package/dist/common/widget.js +2 -11
- package/dist/common/widget.js.map +1 -1
- package/dist/components/animated.d.ts +1 -0
- package/dist/components/animated.js +28 -4
- package/dist/components/animated.js.map +1 -1
- package/dist/components/app-registry.js +32 -8
- package/dist/components/app-registry.js.map +1 -1
- package/dist/components/request-animation-frame.d.ts +33 -0
- package/dist/components/request-animation-frame.js +83 -0
- package/dist/components/request-animation-frame.js.map +1 -0
- package/dist/components/scroll-view.js +60 -2
- package/dist/components/scroll-view.js.map +1 -1
- package/dist/components/virtualized-list.js +1 -4
- package/dist/components/virtualized-list.js.map +1 -1
- package/dist/dnd/autoscroll.d.ts +44 -0
- package/dist/dnd/autoscroll.js +176 -0
- package/dist/dnd/autoscroll.js.map +1 -0
- package/dist/dnd/grid-order.d.ts +45 -0
- package/dist/dnd/grid-order.js +151 -0
- package/dist/dnd/grid-order.js.map +1 -0
- package/dist/dnd/grid.d.ts +44 -0
- package/dist/dnd/grid.js +397 -0
- package/dist/dnd/grid.js.map +1 -0
- package/dist/dnd/gtk-controllers.d.ts +16 -2
- package/dist/dnd/gtk-controllers.js +23 -3
- package/dist/dnd/gtk-controllers.js.map +1 -1
- package/dist/dnd/index.d.ts +4 -2
- package/dist/dnd/index.js +9 -2
- package/dist/dnd/index.js.map +1 -1
- package/dist/dnd/order-state.d.ts +14 -0
- package/dist/dnd/order-state.js +55 -0
- package/dist/dnd/order-state.js.map +1 -0
- package/dist/dnd/order.d.ts +19 -0
- package/dist/dnd/order.js +19 -0
- package/dist/dnd/order.js.map +1 -1
- package/dist/dnd/sortable.d.ts +29 -4
- package/dist/dnd/sortable.js +308 -115
- package/dist/dnd/sortable.js.map +1 -1
- package/dist/dnd/types.d.ts +236 -14
- package/dist/dnd/types.js +30 -0
- package/dist/dnd/types.js.map +1 -1
- package/dist/gesture-handler-compat/attach-context.d.ts +29 -0
- package/dist/gesture-handler-compat/attach-context.js +90 -0
- package/dist/gesture-handler-compat/attach-context.js.map +1 -0
- package/dist/gesture-handler-compat/detector-runtime.d.ts +14 -3
- package/dist/gesture-handler-compat/detector-runtime.js +15 -5
- package/dist/gesture-handler-compat/detector-runtime.js.map +1 -1
- package/dist/gesture-handler-compat/detector.js +57 -2
- package/dist/gesture-handler-compat/detector.js.map +1 -1
- package/dist/gesture-handler-compat/gesture-state-manager.d.ts +5 -0
- package/dist/gesture-handler-compat/gesture-state-manager.js +77 -0
- package/dist/gesture-handler-compat/gesture-state-manager.js.map +1 -0
- package/dist/gesture-handler-compat/index.d.ts +2 -2
- package/dist/gesture-handler-compat/index.js +38 -33
- package/dist/gesture-handler-compat/index.js.map +1 -1
- package/dist/gesture-handler-compat/recognizer.d.ts +12 -1
- package/dist/gesture-handler-compat/recognizer.js +23 -9
- package/dist/gesture-handler-compat/recognizer.js.map +1 -1
- package/dist/gesture-handler-compat/tag-registry.d.ts +14 -0
- package/dist/gesture-handler-compat/tag-registry.js +19 -0
- package/dist/gesture-handler-compat/tag-registry.js.map +1 -0
- package/dist/globals/index.d.ts +47 -0
- package/dist/globals/index.js +181 -0
- package/dist/globals/index.js.map +1 -0
- package/dist/globals/install.d.ts +1 -0
- package/dist/globals/install.js +14 -0
- package/dist/globals/install.js.map +1 -0
- package/dist/gtkx/bridge/adw-namespace.d.ts +2 -0
- package/dist/gtkx/bridge/adw-namespace.js +26 -0
- package/dist/gtkx/bridge/adw-namespace.js.map +1 -0
- package/dist/gtkx/bridge/adw.d.ts +23 -0
- package/dist/gtkx/bridge/adw.js +93 -0
- package/dist/gtkx/bridge/adw.js.map +1 -0
- package/dist/gtkx/bridge/color-scheme-parse.d.ts +11 -0
- package/dist/gtkx/bridge/color-scheme-parse.js +42 -0
- package/dist/gtkx/bridge/color-scheme-parse.js.map +1 -0
- package/dist/gtkx/bridge/color-scheme-portal.d.ts +24 -0
- package/dist/gtkx/bridge/color-scheme-portal.js +172 -0
- package/dist/gtkx/bridge/color-scheme-portal.js.map +1 -0
- package/dist/gtkx/bridge/core.d.ts +25 -0
- package/dist/gtkx/bridge/core.js +69 -0
- package/dist/gtkx/bridge/core.js.map +1 -0
- package/dist/gtkx/bridge/drag-layer.d.ts +27 -0
- package/dist/gtkx/bridge/drag-layer.js +177 -0
- package/dist/gtkx/bridge/drag-layer.js.map +1 -0
- package/dist/gtkx/bridge/index.d.ts +1 -27
- package/dist/gtkx/bridge/index.js +12 -71
- package/dist/gtkx/bridge/index.js.map +1 -1
- package/dist/gtkx/bridge/widgets.generated.adw.d.ts +1 -0
- package/dist/gtkx/bridge/widgets.generated.adw.js +16 -0
- package/dist/gtkx/bridge/widgets.generated.adw.js.map +1 -0
- package/dist/gtkx/bridge/widgets.generated.d.ts +0 -1
- package/dist/gtkx/bridge/widgets.generated.js +3 -3
- package/dist/gtkx/bridge/widgets.generated.js.map +1 -1
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp/data/generated.d.ts +41 -20
- package/dist/mcp/data/generated.js +46 -20
- package/dist/mcp/data/generated.js.map +1 -1
- package/dist/metro/index.d.ts +1 -0
- package/dist/metro/index.js +12 -0
- package/dist/metro/index.js.map +1 -1
- package/dist/navigation/sidebar.js +2 -45
- package/dist/navigation/sidebar.js.map +1 -1
- package/dist/reanimated-compat/animatable-value.d.ts +158 -0
- package/dist/reanimated-compat/animatable-value.js +316 -0
- package/dist/reanimated-compat/animatable-value.js.map +1 -0
- package/dist/reanimated-compat/animation.d.ts +34 -13
- package/dist/reanimated-compat/animation.js +97 -25
- package/dist/reanimated-compat/animation.js.map +1 -1
- package/dist/reanimated-compat/mutable.js +6 -6
- package/dist/reanimated-compat/mutable.js.map +1 -1
- package/dist/reanimated-compat/updater-animations.js +32 -12
- package/dist/reanimated-compat/updater-animations.js.map +1 -1
- package/dist/runner/host-dev.js +5 -1
- package/dist/runner/host-dev.js.map +1 -1
- package/dist/runner/host.js +9 -1
- package/dist/runner/host.js.map +1 -1
- package/dist/vite/index.js +130 -0
- package/dist/vite/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/gtkx/bridge/theme.d.ts +0 -4
- package/dist/gtkx/bridge/theme.js +0 -5
- package/dist/gtkx/bridge/theme.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"updater-animations.js","sourceRoot":"","sources":["../../src/reanimated-compat/updater-animations.ts"],"names":[],"mappings":"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","sourcesContent":["// An animation returned FROM a style or props updater, which is the shape the\n// documentation of `useAnimatedStyle` is written in:\n//\n// const style = useAnimatedStyle(() => ({\n// height: withSpring(open.value ? 320 : 0),\n// }))\n//\n// Assigning an animation to a shared value has always worked here\n// (mutable.ts). Returning one from an updater did not, and it failed the way\n// this repo likes least: silently. `with*` builders return a MARKED DESCRIPTOR\n// outside the initial run (animation.ts), the style layer's leaf test is\n// `typeof value === \"number\"`, and a descriptor is an object — so the property\n// was neither driven nor written nor warned about. It simply sat in the style\n// as `{kind: \"spring\", toValue: 543.4, …}`.\n//\n// Found by `spike/core-exports`, not by reading: `@gorhom/bottom-sheet` bounds\n// its scrollable with `height: animate({point: …})` from `useAnimatedStyle`,\n// and the probe's report that the height \"is not reaching the Yoga node\" was\n// true for a reason one layer earlier than layout — the height was never a\n// number on this platform at all. docs/research/animated-size.md §9.\n//\n// WHAT THIS MODULE IS. One running animation per key, on the platform's own\n// `Animated.Value` and the platform's one frame scheduler — the same\n// `buildAnimation` a shared value uses, so `withTiming`, `withSpring`,\n// `withDelay`, `withSequence`, `withRepeat`, `withDecay` and `withClamp` all\n// arrive here already implemented. The updater's object is republished with\n// each animated key replaced by the number its animation is currently at, and\n// a frame of a running animation costs no React render — it goes down exactly\n// the path a shared value written every frame goes down.\n//\n// THREE RULES, and all three are upstream's — every one of them read out of\n// `hook/useAnimatedStyle.ts`'s `styleUpdater`/`prepareAnimation` rather than\n// inferred from behaviour:\n//\n// - A key APPEARING for the first time is seeded at the animation's target\n// rather than animated to it. There is nothing to animate from, and it is\n// the same collapse `initialUpdaterRun` performs on the updater's first\n// run. Upstream reaches the same place from the other direction: its\n// `prepareAnimation` starts at `oldValues[key]`, which for a key that was\n// not in the last result is `undefined` and leaves the animation's own\n// `current` — its target — standing.\n// - A key whose previous result held a PLAIN NUMBER animates from that\n// number. `oldValues` is `state.last`, the whole previous updater result\n// kept raw, and `prepareAnimation`'s last branch is one line with the\n// comment already on it: `// previously it was a plain value, just set it\n// as starting point`. So `height: open.value ? withTiming(200) : 100` runs\n// 100 → 200, and the idiom people actually write — snap shut, open\n// smoothly — animates. It did not here: the key was dropped when it held a\n// number and re-seeded when it next held an animation, so the seed went\n// straight to 200 and the animation never played at all. Silently, which\n// is the failure this repo ranks worst.\n// - A re-run that produces an EQUIVALENT animation does not restart it. A\n// mapper re-runs whenever anything it read changed, which for a real app is\n// many times a second, and rebuilding the spring each time would leave it\n// crawling. Equivalence is the descriptor's target and shape\n// (`animationSignature`), not object identity — every run builds a fresh\n// object.\n//\n// AND THE REVERSE DIRECTION, animation → plain number, which is upstream's\n// too and is not the mirror image of the second rule: `styleUpdater`'s\n// non-animated branch does `delete animations[key]` and pushes the value\n// through `updateProps` in the SAME run, so the animation is cancelled — no\n// callback, no settle — and the number lands at once. It does not ease back.\n// The only thing this platform has to add is the render a refused property\n// needs to land at all, because \"at once\" through React is still a render (see\n// `onLanding`).\n//\n// WHERE THIS DIFFERS FROM UPSTREAM, said out loud: a restart picks the\n// animation up at the value it is currently at, with the velocity the new\n// descriptor asks for, where upstream also carries the previous animation's\n// VELOCITY across. For a target that moves once that is the same animation;\n// for a target that moves every frame ours is slightly more damped.\n//\n// AND THE CADENCE, the one rule here that is ours rather than upstream's — see\n// LANDING_INTERVAL_MS. It exists because none of the above is enough for a\n// property whose frames this platform refuses to write: for those, the value\n// only exists on screen at whatever the last React render committed, and \"the\n// render at the settle\" turned out to be arbitrarily far away.\nimport type { AnimatedValue, CompositeAnimation } from \"../animated/index\"\nimport {\n animationSignature,\n buildAnimation,\n isAnimationSpec,\n targetOf,\n type AnimationEngine,\n type AnimationSpec,\n} from \"./animation\"\n\n/** What an updater returns: a style object, or a props object. */\nexport type UpdaterObject = Record<string, unknown>\n\n// How far behind its own animation a property this platform will not drive at\n// frame rate is allowed to fall.\n//\n// The settle alone is not an answer, and `@gorhom/bottom-sheet` MOUNTING is\n// the measurement that says so. Its content mask is bounded by an animated\n// `height` whose target is derived from the sheet's own POSITION, so every\n// frame of the opening spring re-aims it — 37 re-aims over 673 ms, each\n// cancelling the last, so not one of them a settle — and then a further\n// 677 ms for the final spring to converge. Measured on the gallery's\n// `upstream-bottom-sheet` screen: the seed was 95.9 px (gorhom's\n// `animatedContentHeightMax` was still 0 on the mapper run that first\n// produced a `height` at all, and the real 832 px arrived 27 ms later, by\n// which time the key already had an entry and a moving target is an animation\n// rather than a seed), and `height` reached Yoga exactly TWICE in the whole\n// mount: 95.9 px at once, 954.6 px 1378 ms later. For 1.38 s the mask was a\n// tenth of its size, the list inside it had no bounded parent, and it mounted\n// zero of its 18 rows. Correct by the settle rule and plainly wrong to\n// anybody opening the screen.\n//\n// So the value lands on a cadence as well. 100 ms because that is the bound\n// under which a change still reads as immediate, and because it bounds the\n// cost by the CLOCK rather than by the animation: at most ten renders a\n// second per animated key, against sixty frames. The same mount now lands the\n// mask at 266 → 546 → 649 → 731 → 792 → 832 → 896 → 939 → 951 → 954 px before\n// settling at 954.6 — the shape the animation has, at a tenth of its rate —\n// with the first at ~100 ms rather than 1.38 s.\n//\n// What it costs, both halves measured in one `spike/core-exports` run on the\n// same machine: 4 settles and 4 renders against 290 refused-property frames\n// before, 4 settles + 38 landings and 42 renders against 294 after. Still an\n// order of magnitude under the per-frame layout write the refusal exists to\n// avoid, and no longer a promise that may never come due.\n// docs/research/animated-size.md §10.\nconst LANDING_INTERVAL_MS = 100\n\n// A landing that cannot move a widget is a render for nothing: GTK allocates\n// whole pixels, so a sub-pixel step changes no committed geometry. It is what\n// keeps a long animation over a short distance from spending ten renders a\n// second to travel one pixel — gorhom's `paddingBottom` crosses 26 px over the\n// same 1.38 s and lands 8 times, not 13.\nconst LANDING_EPSILON = 1\n\ntype Entry = {\n driver: AnimatedValue\n listenerId: string\n signature: string\n running: CompositeAnimation | null\n // The value React was last given for this key, and the moment it was given\n // — the two the cadence is measured against. They survive a restart on\n // purpose: what matters is how stale REACT's copy is, not how far the\n // animation currently in flight has come.\n landedValue: number\n landedAt: number\n}\n\nexport type UpdaterAnimations = {\n /**\n * Resolves `source`'s animations and publishes the result. Called from the\n * mapper, so `source` is a fresh object every time.\n */\n run(source: UpdaterObject): void\n dispose(): void\n}\n\n/**\n * @param publish Receives the updater's object with every animated key\n * replaced by a number. Called once per mapper run and once per animation\n * frame.\n * @param onSettled Called when an animation on `key` reaches its target on its\n * own (never when it is cancelled or replaced). The style layer uses it for\n * the properties it refuses to drive at frame rate, whose contract is that\n * the value lands on the next React render — without it, that promise is\n * only kept when something else happens to re-render.\n * @param onLanding Called when `key`'s current value has to reach React\n * without its animation having reached a target. Two occasions: while an\n * animation runs, at most once per `LANDING_INTERVAL_MS` and only when the\n * value has moved far enough to change a committed layout (the cadence); and\n * when a plain number REPLACES a running animation, where upstream cancels\n * and snaps and a refused property cannot snap without a render. The snap is\n * deliberately not rate-limited — it is a state change rather than a step of\n * one, it happens once per mapper run that flips the key rather than once per\n * frame, and upstream pushes exactly the same number of `updateProps` for it.\n * Same job as `onSettled` and the same handling at the call site; it is a\n * separate callback because a settle and a value that has merely got to be\n * published are different claims, and only the first one is a promise kept.\n * Omit it and both cost nothing at all — a caller with no refused properties\n * (`useAnimatedProps`) does.\n */\nexport const createUpdaterAnimations = (\n engine: AnimationEngine,\n publish: (resolved: UpdaterObject) => void,\n onSettled?: (key: string) => void,\n onLanding?: (key: string) => void,\n): UpdaterAnimations => {\n const entries = new Map<string, Entry>()\n // The clock the animations themselves run on, never `Date` — the whole\n // layer is driven by one injected scheduler so a test can take it\n // (components/frame-scheduler.ts). A driver that only has frame stamps and\n // no off-frame `now` cannot have a cadence, and falls back to the settle.\n const hasClock = engine.scheduler.now !== undefined\n const now = (): number => engine.scheduler.now?.() ?? 0\n let lastSource: UpdaterObject | null = null\n // A frame of one key's animation republishes the WHOLE object, which\n // re-enters `resolve`. The guard keeps that from restarting anything: the\n // run in progress publishes the final state itself.\n let resolving = false\n\n /**\n * @param replacement The plain value that took the key over, or `undefined`\n * when the key left the updater's result altogether.\n *\n * A number here owes the caller a render, and `landedValue` is what decides\n * it: that field is this module's whole model of what REACT holds for the\n * key, and everything since the last landing or settle went to the widget\n * without passing through React. So a plain number that differs from it has\n * to be published or it never arrives — on a refused property the snap IS\n * a render, and neither the cadence nor a settle is ever going to come for\n * it. Compared without the cadence's one-pixel epsilon and for the same\n * reason a settle ignores it: this is a resting value rather than a step\n * towards one, and there is nothing after it to correct a skipped render.\n *\n * Not asked for otherwise. A key that VANISHED, or one replaced by a\n * percentage or a colour, changes the style's SHAPE, and the caller already\n * pays exactly one render for that (hooks.ts); a value equal to the one\n * React already has is a render for nothing.\n */\n const drop = (key: string, replacement: unknown): void => {\n const entry = entries.get(key)\n if (entry === undefined) {\n return\n }\n entries.delete(key)\n entry.running?.stop()\n entry.driver.removeListener(entry.listenerId)\n if (\n typeof replacement === \"number\" &&\n !Object.is(replacement, entry.landedValue)\n ) {\n onLanding?.(key)\n }\n }\n\n const republish = (): void => {\n if (resolving || lastSource === null) {\n return\n }\n // No previous result on a frame: nothing can START an animation here — the\n // source has not changed — so there is nothing to look a starting point up\n // for.\n publish(resolve(lastSource, null))\n }\n\n /**\n * Records that `key`'s current value is the one React now holds. Called\n * wherever a render is asked for, so the cadence is measured from the last\n * value React was actually given rather than from the last frame.\n */\n const markLanded = (entry: Entry): void => {\n entry.landedValue = entry.driver.__getValue()\n entry.landedAt = now()\n }\n\n /** The cadence: see LANDING_INTERVAL_MS. */\n const considerLanding = (key: string, value: number): void => {\n if (onLanding === undefined || !hasClock) {\n return\n }\n const entry = entries.get(key)\n if (entry === undefined) {\n return\n }\n if (now() - entry.landedAt < LANDING_INTERVAL_MS) {\n return\n }\n if (Math.abs(value - entry.landedValue) < LANDING_EPSILON) {\n return\n }\n markLanded(entry)\n onLanding(key)\n }\n\n /** Aims `entry`'s driver at `spec`, replacing whatever it was running. */\n const start = (\n key: string,\n entry: Entry,\n spec: AnimationSpec,\n signature: string,\n ): Entry => {\n entry.signature = signature\n entry.running?.stop()\n const animation = buildAnimation(engine, entry.driver, spec)\n entry.running = animation\n animation.start((result) => {\n if (entry.running === animation) {\n entry.running = null\n }\n // `finished` only: a restart stops the previous animation, and reporting\n // that as a settle would publish through React on every frame the target\n // moves, which is the cost the refusal exists to avoid. A restart is\n // still covered — the cadence above is what carries a target that keeps\n // moving, and it does not care whose animation the frames belong to.\n if (result.finished) {\n markLanded(entry)\n onSettled?.(key)\n }\n })\n return entry\n }\n\n /**\n * Where an animation that is starting has to start FROM, for a key that was\n * not animating a moment ago: the value the PREVIOUS updater result held for\n * it, and only when that is a real number.\n *\n * This is `prepareAnimation(…, oldValues[key])` and nothing more —\n * `oldValues` is `state.last`, upstream's copy of the whole previous updater\n * result — so the second of the header's three rules costs no bookkeeping at\n * all. The previous result is an object this module was already holding for\n * `republish`; reading one key out of it is the entire mechanism, and the\n * entry does not have to carry a value across runs or outlive its animation.\n *\n * Numbers only, and `undefined` for everything else, which lines up with\n * upstream at both ends: a key that was absent has no starting point (its\n * `oldValues[key]` is `undefined`, and the animation's own `current` — the\n * target — stands), and a percentage string or a colour is not something the\n * numeric drivers here can start at.\n */\n const startingPoint = (\n previous: UpdaterObject | null,\n key: string,\n ): number | undefined => {\n const value = previous?.[key]\n return typeof value === \"number\" && Number.isFinite(value)\n ? value\n : undefined\n }\n\n const ensure = (\n key: string,\n spec: AnimationSpec,\n previous: UpdaterObject | null,\n ): Entry => {\n const signature = animationSignature(spec)\n const existing = entries.get(key)\n if (existing !== undefined) {\n return existing.signature === signature\n ? existing\n : start(key, existing, spec, signature)\n }\n const from = startingPoint(previous, key)\n // The driver is seeded before anything is built on purpose: a spring reads\n // its origin off the value it is given (animation.ts), so this IS where\n // \"animate from the old number\" happens.\n const driver = new engine.api.Value(from ?? targetOf(spec) ?? 0)\n const entry: Entry = {\n driver,\n listenerId: driver.addListener(({ value }) => {\n republish()\n considerLanding(key, value)\n }),\n signature,\n running: null,\n // Whichever branch follows, React's copy of this key is the value the\n // driver starts at: a seed changes the style's SHAPE and the caller\n // already pays one render for that (hooks.ts), and a starting point that\n // came out of the previous result is a number React was already handed.\n // So the cadence starts here either way.\n landedValue: driver.__getValue(),\n landedAt: now(),\n }\n entries.set(key, entry)\n // Nothing to animate from: seeded at the target and not started at all,\n // which is the first of the header's three rules.\n return from === undefined ? entry : start(key, entry, spec, signature)\n }\n\n const resolve = (\n source: UpdaterObject,\n previous: UpdaterObject | null,\n ): UpdaterObject => {\n resolving = true\n try {\n let resolved: UpdaterObject | null = null\n for (const key of Object.keys(source)) {\n const value = source[key]\n if (!isAnimationSpec(value)) {\n // A plain value replacing an animation cancels it and snaps, exactly\n // as an assignment to a shared value does and exactly as upstream's\n // `delete animations[key]` + `updateProps` in the same run does. The\n // number itself is published below, by identity.\n drop(key, value)\n continue\n }\n resolved ??= { ...source }\n resolved[key] = ensure(key, value, previous).driver.__getValue()\n }\n for (const key of [...entries.keys()]) {\n if (!(key in source)) {\n drop(key, undefined)\n }\n }\n return resolved ?? source\n } finally {\n resolving = false\n }\n }\n\n return {\n run(source) {\n // `state.last`, upstream's name for it: the result this run's animations\n // measure themselves against. Held for one run only, and it was already\n // being held.\n const previous = lastSource\n lastSource = source\n publish(resolve(source, previous))\n },\n dispose() {\n for (const key of [...entries.keys()]) {\n // Nothing is owed a render: the component is going away.\n drop(key, undefined)\n }\n lastSource = null\n },\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"updater-animations.js","sourceRoot":"","sources":["../../src/reanimated-compat/updater-animations.ts"],"names":[],"mappings":"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","sourcesContent":["// An animation returned FROM a style or props updater, which is the shape the\n// documentation of `useAnimatedStyle` is written in:\n//\n// const style = useAnimatedStyle(() => ({\n// height: withSpring(open.value ? 320 : 0),\n// }))\n//\n// Assigning an animation to a shared value has always worked here\n// (mutable.ts). Returning one from an updater did not, and it failed the way\n// this repo likes least: silently. `with*` builders return a MARKED DESCRIPTOR\n// outside the initial run (animation.ts), the style layer's leaf test is\n// `typeof value === \"number\"`, and a descriptor is an object — so the property\n// was neither driven nor written nor warned about. It simply sat in the style\n// as `{kind: \"spring\", toValue: 543.4, …}`.\n//\n// Found by `spike/core-exports`, not by reading: `@gorhom/bottom-sheet` bounds\n// its scrollable with `height: animate({point: …})` from `useAnimatedStyle`,\n// and the probe's report that the height \"is not reaching the Yoga node\" was\n// true for a reason one layer earlier than layout — the height was never a\n// number on this platform at all. docs/research/animated-size.md §9.\n//\n// WHAT THIS MODULE IS. One running animation per key, on the platform's own\n// `Animated.Value` and the platform's one frame scheduler — the same\n// `buildAnimation` a shared value uses, so `withTiming`, `withSpring`,\n// `withDelay`, `withSequence`, `withRepeat`, `withDecay` and `withClamp` all\n// arrive here already implemented. The updater's object is republished with\n// each animated key replaced by the number its animation is currently at, and\n// a frame of a running animation costs no React render — it goes down exactly\n// the path a shared value written every frame goes down.\n//\n// THREE RULES, and all three are upstream's — every one of them read out of\n// `hook/useAnimatedStyle.ts`'s `styleUpdater`/`prepareAnimation` rather than\n// inferred from behaviour:\n//\n// - A key APPEARING for the first time is seeded at the animation's target\n// rather than animated to it. There is nothing to animate from, and it is\n// the same collapse `initialUpdaterRun` performs on the updater's first\n// run. Upstream reaches the same place from the other direction: its\n// `prepareAnimation` starts at `oldValues[key]`, which for a key that was\n// not in the last result is `undefined` and leaves the animation's own\n// `current` — its target — standing.\n// - A key whose previous result held a PLAIN NUMBER animates from that\n// number. `oldValues` is `state.last`, the whole previous updater result\n// kept raw, and `prepareAnimation`'s last branch is one line with the\n// comment already on it: `// previously it was a plain value, just set it\n// as starting point`. So `height: open.value ? withTiming(200) : 100` runs\n// 100 → 200, and the idiom people actually write — snap shut, open\n// smoothly — animates. It did not here: the key was dropped when it held a\n// number and re-seeded when it next held an animation, so the seed went\n// straight to 200 and the animation never played at all. Silently, which\n// is the failure this repo ranks worst.\n// - A re-run that produces an EQUIVALENT animation does not restart it. A\n// mapper re-runs whenever anything it read changed, which for a real app is\n// many times a second, and rebuilding the spring each time would leave it\n// crawling. Equivalence is the descriptor's target and shape\n// (`animationSignature`), not object identity — every run builds a fresh\n// object.\n//\n// AND THE REVERSE DIRECTION, animation → plain number, which is upstream's\n// too and is not the mirror image of the second rule: `styleUpdater`'s\n// non-animated branch does `delete animations[key]` and pushes the value\n// through `updateProps` in the SAME run, so the animation is cancelled — no\n// callback, no settle — and the number lands at once. It does not ease back.\n// The only thing this platform has to add is the render a refused property\n// needs to land at all, because \"at once\" through React is still a render (see\n// `onLanding`).\n//\n// WHERE THIS DIFFERS FROM UPSTREAM, said out loud: a restart picks the\n// animation up at the value it is currently at, with the velocity the new\n// descriptor asks for, where upstream also carries the previous animation's\n// VELOCITY across. For a target that moves once that is the same animation;\n// for a target that moves every frame ours is slightly more damped.\n//\n// AND THE CADENCE, the one rule here that is ours rather than upstream's — see\n// LANDING_INTERVAL_MS. It exists because none of the above is enough for a\n// property whose frames this platform refuses to write: for those, the value\n// only exists on screen at whatever the last React render committed, and \"the\n// render at the settle\" turned out to be arbitrarily far away.\nimport type { CompositeAnimation } from \"../animated/index\"\nimport {\n isAnimatableValue,\n maxAnimatableLeafDelta,\n sameAnimatableValue,\n type AnimatableValue,\n} from \"./animatable-value\"\nimport {\n animationSignature,\n buildAnimation,\n isAnimationSpec,\n makeAnimationDriver,\n targetOf,\n type AnimationDriver,\n type AnimationEngine,\n type AnimationSpec,\n} from \"./animation\"\n\n/** What an updater returns: a style object, or a props object. */\nexport type UpdaterObject = Record<string, unknown>\n\n// How far behind its own animation a property this platform will not drive at\n// frame rate is allowed to fall.\n//\n// The settle alone is not an answer, and `@gorhom/bottom-sheet` MOUNTING is\n// the measurement that says so. Its content mask is bounded by an animated\n// `height` whose target is derived from the sheet's own POSITION, so every\n// frame of the opening spring re-aims it — 37 re-aims over 673 ms, each\n// cancelling the last, so not one of them a settle — and then a further\n// 677 ms for the final spring to converge. Measured on the gallery's\n// `upstream-bottom-sheet` screen: the seed was 95.9 px (gorhom's\n// `animatedContentHeightMax` was still 0 on the mapper run that first\n// produced a `height` at all, and the real 832 px arrived 27 ms later, by\n// which time the key already had an entry and a moving target is an animation\n// rather than a seed), and `height` reached Yoga exactly TWICE in the whole\n// mount: 95.9 px at once, 954.6 px 1378 ms later. For 1.38 s the mask was a\n// tenth of its size, the list inside it had no bounded parent, and it mounted\n// zero of its 18 rows. Correct by the settle rule and plainly wrong to\n// anybody opening the screen.\n//\n// So the value lands on a cadence as well. 100 ms because that is the bound\n// under which a change still reads as immediate, and because it bounds the\n// cost by the CLOCK rather than by the animation: at most ten renders a\n// second per animated key, against sixty frames. The same mount now lands the\n// mask at 266 → 546 → 649 → 731 → 792 → 832 → 896 → 939 → 951 → 954 px before\n// settling at 954.6 — the shape the animation has, at a tenth of its rate —\n// with the first at ~100 ms rather than 1.38 s.\n//\n// What it costs, both halves measured in one `spike/core-exports` run on the\n// same machine: 4 settles and 4 renders against 290 refused-property frames\n// before, 4 settles + 38 landings and 42 renders against 294 after. Still an\n// order of magnitude under the per-frame layout write the refusal exists to\n// avoid, and no longer a promise that may never come due.\n// docs/research/animated-size.md §10.\nconst LANDING_INTERVAL_MS = 100\n\n// A landing that cannot move a widget is a render for nothing: GTK allocates\n// whole pixels, so a sub-pixel step changes no committed geometry. It is what\n// keeps a long animation over a short distance from spending ten renders a\n// second to travel one pixel — gorhom's `paddingBottom` crosses 26 px over the\n// same 1.38 s and lands 8 times, not 13.\nconst LANDING_EPSILON = 1\n\ntype Entry = {\n driver: AnimationDriver\n listenerId: string\n signature: string\n running: CompositeAnimation | null\n // The value React was last given for this key, and the moment it was given\n // — the two the cadence is measured against. They survive a restart on\n // purpose: what matters is how stale REACT's copy is, not how far the\n // animation currently in flight has come. A number for a scalar key, an\n // object/array for a shape one (AnimatableValue, animatable-value.ts).\n landedValue: AnimatableValue\n landedAt: number\n}\n\nexport type UpdaterAnimations = {\n /**\n * Resolves `source`'s animations and publishes the result. Called from the\n * mapper, so `source` is a fresh object every time.\n */\n run(source: UpdaterObject): void\n dispose(): void\n}\n\n/**\n * @param publish Receives the updater's object with every animated key\n * replaced by a number. Called once per mapper run and once per animation\n * frame.\n * @param onSettled Called when an animation on `key` reaches its target on its\n * own (never when it is cancelled or replaced). The style layer uses it for\n * the properties it refuses to drive at frame rate, whose contract is that\n * the value lands on the next React render — without it, that promise is\n * only kept when something else happens to re-render.\n * @param onLanding Called when `key`'s current value has to reach React\n * without its animation having reached a target. Two occasions: while an\n * animation runs, at most once per `LANDING_INTERVAL_MS` and only when the\n * value has moved far enough to change a committed layout (the cadence); and\n * when a plain number REPLACES a running animation, where upstream cancels\n * and snaps and a refused property cannot snap without a render. The snap is\n * deliberately not rate-limited — it is a state change rather than a step of\n * one, it happens once per mapper run that flips the key rather than once per\n * frame, and upstream pushes exactly the same number of `updateProps` for it.\n * Same job as `onSettled` and the same handling at the call site; it is a\n * separate callback because a settle and a value that has merely got to be\n * published are different claims, and only the first one is a promise kept.\n * Omit it and both cost nothing at all — a caller with no refused properties\n * (`useAnimatedProps`) does.\n */\nexport const createUpdaterAnimations = (\n engine: AnimationEngine,\n publish: (resolved: UpdaterObject) => void,\n onSettled?: (key: string) => void,\n onLanding?: (key: string) => void,\n): UpdaterAnimations => {\n const entries = new Map<string, Entry>()\n // The clock the animations themselves run on, never `Date` — the whole\n // layer is driven by one injected scheduler so a test can take it\n // (components/frame-scheduler.ts). A driver that only has frame stamps and\n // no off-frame `now` cannot have a cadence, and falls back to the settle.\n const hasClock = engine.scheduler.now !== undefined\n const now = (): number => engine.scheduler.now?.() ?? 0\n let lastSource: UpdaterObject | null = null\n // A frame of one key's animation republishes the WHOLE object, which\n // re-enters `resolve`. The guard keeps that from restarting anything: the\n // run in progress publishes the final state itself.\n let resolving = false\n\n /**\n * @param replacement The plain value that took the key over, or `undefined`\n * when the key left the updater's result altogether.\n *\n * A number here owes the caller a render, and `landedValue` is what decides\n * it: that field is this module's whole model of what REACT holds for the\n * key, and everything since the last landing or settle went to the widget\n * without passing through React. So a plain number that differs from it has\n * to be published or it never arrives — on a refused property the snap IS\n * a render, and neither the cadence nor a settle is ever going to come for\n * it. Compared without the cadence's one-pixel epsilon and for the same\n * reason a settle ignores it: this is a resting value rather than a step\n * towards one, and there is nothing after it to correct a skipped render.\n *\n * Not asked for otherwise. A key that VANISHED, or one replaced by a\n * percentage or a colour, changes the style's SHAPE, and the caller already\n * pays exactly one render for that (hooks.ts); a value equal to the one\n * React already has is a render for nothing.\n */\n const drop = (key: string, replacement: unknown): void => {\n const entry = entries.get(key)\n if (entry === undefined) {\n return\n }\n entries.delete(key)\n entry.running?.stop()\n entry.driver.removeListener(entry.listenerId)\n // A number originally; now also an object/array of numbers — either way\n // a resting AnimatableValue owes the caller a render if it differs from\n // what React was last given. `sameAnimatableValue` replaces the original\n // `Object.is`: a merged object is rebuilt fresh every frame\n // (rebuildAnimatableValue), so it is never the SAME reference as the\n // landed value even when every leaf agrees.\n if (\n isAnimatableValue(replacement) &&\n !sameAnimatableValue(replacement, entry.landedValue)\n ) {\n onLanding?.(key)\n }\n }\n\n const republish = (): void => {\n if (resolving || lastSource === null) {\n return\n }\n // No previous result on a frame: nothing can START an animation here — the\n // source has not changed — so there is nothing to look a starting point up\n // for.\n publish(resolve(lastSource, null))\n }\n\n /**\n * Records that `key`'s current value is the one React now holds. Called\n * wherever a render is asked for, so the cadence is measured from the last\n * value React was actually given rather than from the last frame.\n */\n const markLanded = (entry: Entry): void => {\n entry.landedValue = entry.driver.__getValue()\n entry.landedAt = now()\n }\n\n /**\n * The cadence: see LANDING_INTERVAL_MS. For a shape key (`{x, y}`, …) \"far\n * enough to change a committed layout\" is ANY leaf crossing the epsilon —\n * `maxAnimatableLeafDelta` is the largest single-leaf change, not a sum, so\n * a diagonal move is not double-counted into landing twice as often.\n */\n const considerLanding = (key: string, value: AnimatableValue): void => {\n if (onLanding === undefined || !hasClock) {\n return\n }\n const entry = entries.get(key)\n if (entry === undefined) {\n return\n }\n if (now() - entry.landedAt < LANDING_INTERVAL_MS) {\n return\n }\n if (maxAnimatableLeafDelta(value, entry.landedValue) < LANDING_EPSILON) {\n return\n }\n markLanded(entry)\n onLanding(key)\n }\n\n /** Aims `entry`'s driver at `spec`, replacing whatever it was running. */\n const start = (\n key: string,\n entry: Entry,\n spec: AnimationSpec,\n signature: string,\n ): Entry => {\n entry.signature = signature\n entry.running?.stop()\n const animation = buildAnimation(engine, entry.driver, spec)\n entry.running = animation\n animation.start((result) => {\n if (entry.running === animation) {\n entry.running = null\n }\n // `finished` only: a restart stops the previous animation, and reporting\n // that as a settle would publish through React on every frame the target\n // moves, which is the cost the refusal exists to avoid. A restart is\n // still covered — the cadence above is what carries a target that keeps\n // moving, and it does not care whose animation the frames belong to.\n if (result.finished) {\n markLanded(entry)\n onSettled?.(key)\n }\n })\n return entry\n }\n\n /**\n * Where an animation that is starting has to start FROM, for a key that was\n * not animating a moment ago: the value the PREVIOUS updater result held for\n * it, and only when that is a real number.\n *\n * This is `prepareAnimation(…, oldValues[key])` and nothing more —\n * `oldValues` is `state.last`, upstream's copy of the whole previous updater\n * result — so the second of the header's three rules costs no bookkeeping at\n * all. The previous result is an object this module was already holding for\n * `republish`; reading one key out of it is the entire mechanism, and the\n * entry does not have to carry a value across runs or outlive its animation.\n *\n * Numbers only, and `undefined` for everything else — which, now that a key\n * can hold an OBJECT too, is worth stating precisely: a plain object\n * (`{x: 5, y: 10}`) does NOT carry over here, on purpose, and it is\n * upstream's own rule, not a gap in this one. `prepareAnimation`'s branches\n * are `typeof lastValue === \"object\"` → was it a shared value (`.value`) or\n * an animation node (`.onFrame`)? Neither matches a plain data object, so\n * `value` is left at its default — the animation's own target. A key whose\n * previous value was a plain OBJECT is therefore seeded at the target\n * exactly like a key that was absent, and only a plain NUMBER ever carries\n * over as a starting point. This function already implemented that rule by\n * accident, before objects were legal at all; nothing here changed.\n */\n const startingPoint = (\n previous: UpdaterObject | null,\n key: string,\n ): number | undefined => {\n const value = previous?.[key]\n return typeof value === \"number\" && Number.isFinite(value)\n ? value\n : undefined\n }\n\n const ensure = (\n key: string,\n spec: AnimationSpec,\n previous: UpdaterObject | null,\n ): Entry => {\n const signature = animationSignature(spec)\n const existing = entries.get(key)\n if (existing !== undefined) {\n return existing.signature === signature\n ? existing\n : start(key, existing, spec, signature)\n }\n const from = startingPoint(previous, key)\n // The driver is seeded before anything is built on purpose: a spring reads\n // its origin off the value it is given (animation.ts), so this IS where\n // \"animate from the old number\" happens. makeAnimationDriver picks the\n // right driver kind for the seed — a number for a scalar key, a shape\n // (animatable-value.ts) for an object/array one.\n const driver = makeAnimationDriver(\n engine.api,\n from ?? targetOf(spec) ?? 0,\n `the \"${key}\" key of an updater's result`,\n )\n const entry: Entry = {\n driver,\n listenerId: driver.addListener(({ value }) => {\n republish()\n considerLanding(key, value)\n }),\n signature,\n running: null,\n // Whichever branch follows, React's copy of this key is the value the\n // driver starts at: a seed changes the style's SHAPE and the caller\n // already pays one render for that (hooks.ts), and a starting point that\n // came out of the previous result is a number React was already handed.\n // So the cadence starts here either way.\n landedValue: driver.__getValue(),\n landedAt: now(),\n }\n entries.set(key, entry)\n // Nothing to animate from: seeded at the target and not started at all,\n // which is the first of the header's three rules.\n return from === undefined ? entry : start(key, entry, spec, signature)\n }\n\n const resolve = (\n source: UpdaterObject,\n previous: UpdaterObject | null,\n ): UpdaterObject => {\n resolving = true\n try {\n let resolved: UpdaterObject | null = null\n for (const key of Object.keys(source)) {\n const value = source[key]\n if (!isAnimationSpec(value)) {\n // A plain value replacing an animation cancels it and snaps, exactly\n // as an assignment to a shared value does and exactly as upstream's\n // `delete animations[key]` + `updateProps` in the same run does. The\n // number itself is published below, by identity.\n drop(key, value)\n continue\n }\n resolved ??= { ...source }\n resolved[key] = ensure(key, value, previous).driver.__getValue()\n }\n for (const key of [...entries.keys()]) {\n if (!(key in source)) {\n drop(key, undefined)\n }\n }\n return resolved ?? source\n } finally {\n resolving = false\n }\n }\n\n return {\n run(source) {\n // `state.last`, upstream's name for it: the result this run's animations\n // measure themselves against. Held for one run only, and it was already\n // being held.\n const previous = lastSource\n lastSource = source\n publish(resolve(source, previous))\n },\n dispose() {\n for (const key of [...entries.keys()]) {\n // Nothing is owed a render: the component is going away.\n drop(key, undefined)\n }\n lastSource = null\n },\n }\n}\n"]}
|
package/dist/runner/host-dev.js
CHANGED
|
@@ -16,7 +16,7 @@ import { createRequire, registerHooks } from "node:module";
|
|
|
16
16
|
import { join } from "node:path";
|
|
17
17
|
import { pathToFileURL } from "node:url";
|
|
18
18
|
import vm from "node:vm";
|
|
19
|
-
import { HOST_MODULE_EXTERNALS } from "react-native-gtkx/metro";
|
|
19
|
+
import { HOST_MODULE_EXTERNALS, OPTIONAL_HOST_MODULE_EXTERNALS, } from "react-native-gtkx/metro";
|
|
20
20
|
const fail = (message) => {
|
|
21
21
|
console.error(`[react-native-gtkx] ${message}`);
|
|
22
22
|
process.exit(1);
|
|
@@ -109,6 +109,10 @@ for (const name of HOST_MODULE_EXTERNALS) {
|
|
|
109
109
|
globalThis.__hostModules[name] = await load(name);
|
|
110
110
|
}
|
|
111
111
|
catch (error) {
|
|
112
|
+
if (OPTIONAL_HOST_MODULE_EXTERNALS.has(name)) {
|
|
113
|
+
// See host.ts's identical guard — expected on the plain-GTK profile.
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
112
116
|
fail(`failed to load host module "${name}" — is the codegen store in ` +
|
|
113
117
|
`place (npx gtkx codegen) and GTK4/libadwaita installed?\n${String(error)}`);
|
|
114
118
|
}
|
|
@@ -1 +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 >= 24.`,\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 and same module shape as the\n// release host — see host.ts for why each export is needed).\nconst CONFIG_REQUIRED =\n \"gtkx.config.ts with an applicationId is required in the app root \" +\n '(export default defineConfig({ applicationId: \"...\", libraries: [...] })).'\nconst { createConfigLoader } = await import(\n pathToFileURL(fromPackage.resolve(\"@gtkx/config/internal\")).href\n)\nconst gtkxConfig = await createConfigLoader()\n .resolve(process.cwd())\n .catch((error: unknown) => fail(`${CONFIG_REQUIRED}\\n${String(error)}`))\nif (!gtkxConfig.applicationId) {\n fail(CONFIG_REQUIRED)\n}\nif (gtkxConfig.elements !== null) {\n fail(\n \"gtkx.config.ts `elements.behaviors` is not supported on the linux \" +\n \"platform — react-native-gtkx owns element behaviors.\",\n )\n}\nconst configModuleUrl = new URL(\"./__virtual-gtkx-config.mjs\", import.meta.url)\n .href\nconst lazyElements = Object.fromEntries(\n gtkxConfig.lazyElements.map((type: string) => [type, { isLazy: true }]),\n)\nconst configModuleSource = [\n `export * from \"@gtkx/jsx/metadata\";`,\n `export const applicationId = ${JSON.stringify(gtkxConfig.applicationId)};`,\n `export const userEventSignals = ${JSON.stringify(gtkxConfig.userEventSignals)};`,\n `export const elements = ${JSON.stringify(lazyElements)};`,\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"]}
|
|
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 {\n HOST_MODULE_EXTERNALS,\n OPTIONAL_HOST_MODULE_EXTERNALS,\n} 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 >= 24.`,\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 and same module shape as the\n// release host — see host.ts for why each export is needed).\nconst CONFIG_REQUIRED =\n \"gtkx.config.ts with an applicationId is required in the app root \" +\n '(export default defineConfig({ applicationId: \"...\", libraries: [...] })).'\nconst { createConfigLoader } = await import(\n pathToFileURL(fromPackage.resolve(\"@gtkx/config/internal\")).href\n)\nconst gtkxConfig = await createConfigLoader()\n .resolve(process.cwd())\n .catch((error: unknown) => fail(`${CONFIG_REQUIRED}\\n${String(error)}`))\nif (!gtkxConfig.applicationId) {\n fail(CONFIG_REQUIRED)\n}\nif (gtkxConfig.elements !== null) {\n fail(\n \"gtkx.config.ts `elements.behaviors` is not supported on the linux \" +\n \"platform — react-native-gtkx owns element behaviors.\",\n )\n}\nconst configModuleUrl = new URL(\"./__virtual-gtkx-config.mjs\", import.meta.url)\n .href\nconst lazyElements = Object.fromEntries(\n gtkxConfig.lazyElements.map((type: string) => [type, { isLazy: true }]),\n)\nconst configModuleSource = [\n `export * from \"@gtkx/jsx/metadata\";`,\n `export const applicationId = ${JSON.stringify(gtkxConfig.applicationId)};`,\n `export const userEventSignals = ${JSON.stringify(gtkxConfig.userEventSignals)};`,\n `export const elements = ${JSON.stringify(lazyElements)};`,\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 if (OPTIONAL_HOST_MODULE_EXTERNALS.has(name)) {\n // See host.ts's identical guard — expected on the plain-GTK profile.\n continue\n }\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"]}
|
package/dist/runner/host.js
CHANGED
|
@@ -10,7 +10,7 @@ import { readFileSync } from "node:fs";
|
|
|
10
10
|
import { createRequire, registerHooks } from "node:module";
|
|
11
11
|
import { pathToFileURL } from "node:url";
|
|
12
12
|
import vm from "node:vm";
|
|
13
|
-
import { HOST_MODULE_EXTERNALS } from "react-native-gtkx/metro";
|
|
13
|
+
import { HOST_MODULE_EXTERNALS, OPTIONAL_HOST_MODULE_EXTERNALS, } from "react-native-gtkx/metro";
|
|
14
14
|
const fail = (message) => {
|
|
15
15
|
console.error(`[react-native-gtkx] ${message}`);
|
|
16
16
|
process.exit(1);
|
|
@@ -96,6 +96,14 @@ for (const name of HOST_MODULE_EXTERNALS) {
|
|
|
96
96
|
globalThis.__hostModules[name] = await load(name);
|
|
97
97
|
}
|
|
98
98
|
catch (error) {
|
|
99
|
+
if (OPTIONAL_HOST_MODULE_EXTERNALS.has(name)) {
|
|
100
|
+
// Expected and fine: this app's gtkx.config.ts never declared the GIR
|
|
101
|
+
// library this module binds (e.g. "Adw-1" — the plain-GTK profile,
|
|
102
|
+
// see .claude/epics/adw-optional/001.md). Left unset in
|
|
103
|
+
// __hostModules; a feature that actually needs it throws its own
|
|
104
|
+
// named error when it is reached, not here at startup.
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
99
107
|
fail(`failed to load host module "${name}" — is the codegen store in ` +
|
|
100
108
|
`place (npx gtkx codegen) and GTK4/libadwaita installed?\n${String(error)}`);
|
|
101
109
|
}
|
package/dist/runner/host.js.map
CHANGED
|
@@ -1 +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 >= 24.`,\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 plus the values\n// resolved from gtkx.config.ts (applicationId for the GApplication, the\n// userEventSignals suppressed during commits and the elements config the\n// reconciler registry is primed with). In the vite path the gtkx CLI plugin\n// serves it; replicate it with a loader hook, mirroring @gtkx/config's own\n// renderConfigModule. The fake module URL is anchored inside this package so\n// the re-exported bare specifier resolves through node_modules.\nconst CONFIG_REQUIRED =\n \"gtkx.config.ts with an applicationId is required in the app root \" +\n '(export default defineConfig({ applicationId: \"...\", libraries: [...] })).'\nconst { createConfigLoader } = await import(\"@gtkx/config/internal\")\n// The loader validates the config, so a missing or malformed one throws.\n// rc.3 turned the loader from a bare function into `{ load, resolve }`;\n// `resolve` is the runtime projection this module needs.\nconst gtkxConfig = await createConfigLoader()\n .resolve(process.cwd())\n .catch((error: unknown) => fail(`${CONFIG_REQUIRED}\\n${String(error)}`))\nif (!gtkxConfig.applicationId) {\n fail(CONFIG_REQUIRED)\n}\n// A behaviors module would have to be bundled and merged through\n// @gtkx/react/config; the react-native surface owns element behaviors, so no\n// app declares one — refuse rather than silently drop it.\nif (gtkxConfig.elements !== null) {\n fail(\n \"gtkx.config.ts `elements.behaviors` is not supported on the linux \" +\n \"platform — react-native-gtkx owns element behaviors.\",\n )\n}\nconst configModuleUrl = new URL(\"./__virtual-gtkx-config.mjs\", import.meta.url)\n .href\nconst lazyElements = Object.fromEntries(\n gtkxConfig.lazyElements.map((type) => [type, { isLazy: true }]),\n)\nconst configModuleSource = [\n `export * from \"@gtkx/jsx/metadata\";`,\n `export const applicationId = ${JSON.stringify(gtkxConfig.applicationId)};`,\n `export const userEventSignals = ${JSON.stringify(gtkxConfig.userEventSignals)};`,\n `export const elements = ${JSON.stringify(lazyElements)};`,\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"]}
|
|
1
|
+
{"version":3,"file":"host.js","sourceRoot":"","sources":["../../src/runner/host.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,gDAAgD;AAChD,yEAAyE;AACzE,iDAAiD;AACjD,EAAE;AACF,0EAA0E;AAC1E,sEAAsE;AACtE,qDAAqD;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,EACL,qBAAqB,EACrB,8BAA8B,GAC/B,MAAM,yBAAyB,CAAA;AAIhC,MAAM,IAAI,GAAG,CAAC,OAAe,EAAS,EAAE;IACtC,OAAO,CAAC,KAAK,CAAC,uBAAuB,OAAO,EAAE,CAAC,CAAA;IAC/C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC,CAAA;AAED,IAAI,OAAO,aAAa,KAAK,UAAU,EAAE,CAAC;IACxC,IAAI,CACF,QAAQ,OAAO,CAAC,OAAO,gEAAgE,CACxF,CAAA;AACH,CAAC;AAED,yEAAyE;AACzE,sEAAsE;AACtE,yEAAyE;AACzE,0EAA0E;AAC1E,MAAM,WAAW,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAClD,MAAM,aAAa,GAAG,aAAa,CAAC,WAAW,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAA;AAEvE,MAAM,eAAe,GAAG,CAAC,IAAY,EAAU,EAAE,CAC/C,IAAI,KAAK,OAAO,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;IAC3C,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC;IAC7B,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;AAE/B,mEAAmE;AACnE,8DAA8D;AAC9D,MAAM,IAAI,GAAG,KAAK,EAAE,IAAY,EAAuB,EAAE;IACvD,MAAM,SAAS,GAAe,MAAM,MAAM,CACxC,aAAa,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAC1C,CAAA;IACD,MAAM,MAAM,GAAe,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,SAAS,EAAE,CAAA;IAC7D,IAAI,CAAC,CAAC,SAAS,IAAI,SAAS,CAAC,EAAE,CAAC;QAC9B,MAAM,CAAC,OAAO,GAAG,SAAS,CAAA;IAC5B,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC,CAAA;AAED,2EAA2E;AAC3E,wEAAwE;AACxE,yEAAyE;AACzE,4EAA4E;AAC5E,2EAA2E;AAC3E,6EAA6E;AAC7E,gEAAgE;AAChE,MAAM,eAAe,GACnB,mEAAmE;IACnE,4EAA4E,CAAA;AAC9E,MAAM,EAAE,kBAAkB,EAAE,GAAG,MAAM,MAAM,CAAC,uBAAuB,CAAC,CAAA;AACpE,yEAAyE;AACzE,wEAAwE;AACxE,yDAAyD;AACzD,MAAM,UAAU,GAAG,MAAM,kBAAkB,EAAE;KAC1C,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;KACtB,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,eAAe,KAAK,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAA;AAC1E,IAAI,CAAC,UAAU,CAAC,aAAa,EAAE,CAAC;IAC9B,IAAI,CAAC,eAAe,CAAC,CAAA;AACvB,CAAC;AACD,iEAAiE;AACjE,6EAA6E;AAC7E,0DAA0D;AAC1D,IAAI,UAAU,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;IACjC,IAAI,CACF,oEAAoE;QAClE,sDAAsD,CACzD,CAAA;AACH,CAAC;AACD,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,6BAA6B,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;KAC5E,IAAI,CAAA;AACP,MAAM,YAAY,GAAG,MAAM,CAAC,WAAW,CACrC,UAAU,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAChE,CAAA;AACD,MAAM,kBAAkB,GAAG;IACzB,qCAAqC;IACrC,gCAAgC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,aAAa,CAAC,GAAG;IAC3E,mCAAmC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,gBAAgB,CAAC,GAAG;IACjF,2BAA2B,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,GAAG;CAC3D,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACZ,aAAa,CAAC;IACZ,OAAO,CAAC,SAAS,EAAE,OAAO,EAAE,WAAW;QACrC,IAAI,SAAS,KAAK,qBAAqB,EAAE,CAAC;YACxC,OAAO,EAAE,GAAG,EAAE,eAAe,EAAE,YAAY,EAAE,IAAI,EAAE,CAAA;QACrD,CAAC;QACD,OAAO,WAAW,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;IACxC,CAAC;IACD,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,QAAQ;QACzB,IAAI,GAAG,KAAK,eAAe,EAAE,CAAC;YAC5B,OAAO;gBACL,MAAM,EAAE,QAAQ;gBAChB,MAAM,EAAE,kBAAkB;gBAC1B,YAAY,EAAE,IAAI;aACnB,CAAA;QACH,CAAC;QACD,OAAO,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;IAC/B,CAAC;CACF,CAAC,CAAA;AAEF,UAAU,CAAC,aAAa,GAAG,EAAE,CAAA;AAC7B,KAAK,MAAM,IAAI,IAAI,qBAAqB,EAAE,CAAC;IACzC,IAAI,CAAC;QACH,UAAU,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,CAAA;IACnD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,8BAA8B,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7C,sEAAsE;YACtE,mEAAmE;YACnE,wDAAwD;YACxD,iEAAiE;YACjE,uDAAuD;YACvD,SAAQ;QACV,CAAC;QACD,IAAI,CACF,+BAA+B,IAAI,8BAA8B;YAC/D,4DAA4D,MAAM,CAAC,KAAK,CAAC,EAAE,CAC9E,CAAA;IACH,CAAC;AACH,CAAC;AACD,sEAAsE;AACtE,UAAU,CAAC,aAAa,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAEzD,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AAClC,IAAI,CAAC,UAAU,EAAE,CAAC;IAChB,IAAI,CAAC,6CAA6C,CAAC,CAAA;AACrD,CAAC;AACD,IAAI,MAAc,CAAA;AAClB,IAAI,CAAC;IACH,MAAM,GAAG,YAAY,CAAC,UAAW,EAAE,MAAM,CAAC,CAAA;AAC5C,CAAC;AAAC,MAAM,CAAC;IACP,IAAI,CAAC,uBAAuB,UAAU,gCAAgC,CAAC,CAAA;IACvE,MAAM,IAAI,KAAK,CAAC,aAAa,CAAC,CAAA;AAChC,CAAC;AACD,0EAA0E;AAC1E,mEAAmE;AACnE,EAAE,CAAC,gBAAgB,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAA","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 {\n HOST_MODULE_EXTERNALS,\n OPTIONAL_HOST_MODULE_EXTERNALS,\n} 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 >= 24.`,\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 plus the values\n// resolved from gtkx.config.ts (applicationId for the GApplication, the\n// userEventSignals suppressed during commits and the elements config the\n// reconciler registry is primed with). In the vite path the gtkx CLI plugin\n// serves it; replicate it with a loader hook, mirroring @gtkx/config's own\n// renderConfigModule. The fake module URL is anchored inside this package so\n// the re-exported bare specifier resolves through node_modules.\nconst CONFIG_REQUIRED =\n \"gtkx.config.ts with an applicationId is required in the app root \" +\n '(export default defineConfig({ applicationId: \"...\", libraries: [...] })).'\nconst { createConfigLoader } = await import(\"@gtkx/config/internal\")\n// The loader validates the config, so a missing or malformed one throws.\n// rc.3 turned the loader from a bare function into `{ load, resolve }`;\n// `resolve` is the runtime projection this module needs.\nconst gtkxConfig = await createConfigLoader()\n .resolve(process.cwd())\n .catch((error: unknown) => fail(`${CONFIG_REQUIRED}\\n${String(error)}`))\nif (!gtkxConfig.applicationId) {\n fail(CONFIG_REQUIRED)\n}\n// A behaviors module would have to be bundled and merged through\n// @gtkx/react/config; the react-native surface owns element behaviors, so no\n// app declares one — refuse rather than silently drop it.\nif (gtkxConfig.elements !== null) {\n fail(\n \"gtkx.config.ts `elements.behaviors` is not supported on the linux \" +\n \"platform — react-native-gtkx owns element behaviors.\",\n )\n}\nconst configModuleUrl = new URL(\"./__virtual-gtkx-config.mjs\", import.meta.url)\n .href\nconst lazyElements = Object.fromEntries(\n gtkxConfig.lazyElements.map((type) => [type, { isLazy: true }]),\n)\nconst configModuleSource = [\n `export * from \"@gtkx/jsx/metadata\";`,\n `export const applicationId = ${JSON.stringify(gtkxConfig.applicationId)};`,\n `export const userEventSignals = ${JSON.stringify(gtkxConfig.userEventSignals)};`,\n `export const elements = ${JSON.stringify(lazyElements)};`,\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 if (OPTIONAL_HOST_MODULE_EXTERNALS.has(name)) {\n // Expected and fine: this app's gtkx.config.ts never declared the GIR\n // library this module binds (e.g. \"Adw-1\" — the plain-GTK profile,\n // see .claude/epics/adw-optional/001.md). Left unset in\n // __hostModules; a feature that actually needs it throws its own\n // named error when it is reached, not here at startup.\n continue\n }\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"]}
|
package/dist/vite/index.js
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
// — the pure resolution helpers live here rather than in a sibling module,
|
|
10
10
|
// and the one import that does cross a file boundary spells out its `.js`.
|
|
11
11
|
import { existsSync } from "node:fs";
|
|
12
|
+
import { createRequire } from "node:module";
|
|
12
13
|
import { dirname, extname, isAbsolute, resolve } from "node:path";
|
|
13
14
|
import { applyAliases, compileAliases, DEFAULT_ALIAS_TABLE, } from "../aliases/index.js";
|
|
14
15
|
// Re-exported so an app configuring `aliases` never has to reach past the
|
|
@@ -98,6 +99,92 @@ export const resolvePlatformSpecifier = (source, importer, exists, options = {})
|
|
|
98
99
|
}
|
|
99
100
|
return null;
|
|
100
101
|
};
|
|
102
|
+
// The bridge's Adw probe (gtkx/bridge/adw.ts) needs to know, AT BUILD TIME,
|
|
103
|
+
// whether this app's codegen store actually generated Adwaita bindings —
|
|
104
|
+
// see the epic's own regression notes (.claude/epics/adw-optional/006). A
|
|
105
|
+
// runtime-only check (a bare specifier assembled from string parts, so
|
|
106
|
+
// Rollup's build-time graph walk never reaches it) is invisible to the
|
|
107
|
+
// STATIC machinery every other gtkx import gets for free: `resolve.dedupe`
|
|
108
|
+
// (RC4-WORKAROUND(runtime-dedupe) above) and `gtkx build`'s own asset
|
|
109
|
+
// pipeline for the native addon (`@gtkx/cli`'s `gtkx:native` plugin, which
|
|
110
|
+
// rewrites every STATICALLY reachable `@gtkx/native` import onto the single
|
|
111
|
+
// `dist/gtkx.node` it emits) both only ever see specifiers Rollup's graph
|
|
112
|
+
// walk actually visits. A second, independently-resolved copy of the native
|
|
113
|
+
// addon double-initializes the gtkx runtime and aborts the process
|
|
114
|
+
// (`g_log_set_writer_func() called multiple times`) — the exact failure
|
|
115
|
+
// `runtime-dedupe` exists for, reached through a path dedupe cannot see.
|
|
116
|
+
//
|
|
117
|
+
// The fix: make the specifier a literal wherever Adw genuinely exists, so
|
|
118
|
+
// it gets the SAME static treatment as every other gtkx import — and prune
|
|
119
|
+
// it entirely wherever it does not, so `gtkx:undeclared-library` never
|
|
120
|
+
// throws on the plain-GTK profile. `__GTKX_ADW_AVAILABLE__` is that lever:
|
|
121
|
+
// a `define`d boolean CONSTANT (like `__DEV__` above), true only when this
|
|
122
|
+
// app's OWN codegen store actually has an "adw" entry. The bridge guards
|
|
123
|
+
// its probe on it; when the guard folds to a literal `false`, esbuild's
|
|
124
|
+
// dead-code elimination removes the whole probe body — literal specifiers
|
|
125
|
+
// and all — before Rollup's build ever walks the module graph, so the
|
|
126
|
+
// undeclared-library plugin never sees them either.
|
|
127
|
+
//
|
|
128
|
+
// require.resolve, not a static/dynamic import: this file is a vite CONFIG
|
|
129
|
+
// module (not part of the app's own bundle), so nothing here is subject to
|
|
130
|
+
// the eslint bridge fence or Rollup's build-time graph at all — it is a
|
|
131
|
+
// plain Node path lookup, run once while vite starts, mirroring exactly
|
|
132
|
+
// what `gtkx:undeclared-library`'s own resolveId does with `this.resolve`.
|
|
133
|
+
const hasAdwStore = (root) => {
|
|
134
|
+
try {
|
|
135
|
+
createRequire(resolve(root, "package.json")).resolve(["@gtkx", "gi", "adw"].join("/"));
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
// The two raw specifiers every Adw-dependent file in the bridge imports as a
|
|
143
|
+
// LITERAL (gtkx/bridge/adw.ts's own probe, gtkx/bridge/adw-namespace.ts,
|
|
144
|
+
// gtkx/bridge/widgets.generated.adw.ts) — needed as literals so `gtkx
|
|
145
|
+
// build`'s real Rollup graph gives them the same static treatment as every
|
|
146
|
+
// other gtkx import (see the doc above and .claude/epics/adw-optional/006.md).
|
|
147
|
+
// That literal-ness has a cost `gtkx build` never pays but `gtkx dev` and
|
|
148
|
+
// vitest do: both run every file through Vite's SSR module runner, which
|
|
149
|
+
// resolves every import() call it can find in a file's text — including one
|
|
150
|
+
// inside a dead `if (__GTKX_ADW_AVAILABLE__ === false)` branch — as part of
|
|
151
|
+
// loading that FILE, before any of the file's own code (the runtime guard,
|
|
152
|
+
// the try/catch around it) ever executes. `esbuild`'s dead-code elimination
|
|
153
|
+
// is what makes the literal safe for `gtkx build`, and it is a real BUNDLE
|
|
154
|
+
// optimization, not something the dev server or vitest's request-based
|
|
155
|
+
// transform ever performs — so on a store with no "Adw-1" declared, every
|
|
156
|
+
// one of those three files failed to even LOAD (a raw "'./adw' is not
|
|
157
|
+
// exported" resolver error out of Vite's own builtin:vite-resolve, not any
|
|
158
|
+
// message this package writes), which took the ENTIRE package down with it:
|
|
159
|
+
// gtkx/bridge/adw.ts is an ordinary dependency of apis/host.gtkx.ts,
|
|
160
|
+
// components/app-registry.tsx and common/navigation-stack.tsx, so nothing
|
|
161
|
+
// that reaches any of those — which is most of the surface — could load
|
|
162
|
+
// either. Found writing .claude/epics/adw-optional/005.md's own guard
|
|
163
|
+
// tests: spike/plain-gtk's PRE-EXISTING alert/appearance GTK tests (003.md,
|
|
164
|
+
// 004.md) failed the exact same way.
|
|
165
|
+
//
|
|
166
|
+
// Fixed the same way `gtkx:undeclared-library` itself is a resolveId hook,
|
|
167
|
+
// not a source change: intercept these two specifiers HERE, before Vite's
|
|
168
|
+
// own resolver (or gtkx's) ever sees them, whenever this app's store
|
|
169
|
+
// genuinely lacks Adw — resolving them to a tiny virtual module that THROWS
|
|
170
|
+
// ONLY WHEN ACTUALLY EVALUATED (i.e. lazily, exactly when something really
|
|
171
|
+
// awaits the dynamic import, or — for the two eager importers above — when
|
|
172
|
+
// something actually loads react-native-gtkx/adw). That is late enough for
|
|
173
|
+
// gtkx/bridge/adw.ts's own `try { ... } catch { return null }` to catch it
|
|
174
|
+
// as a genuine rejected promise, same as it always could for a specifier
|
|
175
|
+
// Node's own loader could not find; for the two EAGER importers, it turns
|
|
176
|
+
// what used to be a generic third-party resolver error into this package's
|
|
177
|
+
// own named, actionable throw (the ONE message text below, since neither
|
|
178
|
+
// eager importer has a call-site "feature" name available to it the way
|
|
179
|
+
// requireAdwGi/requireAdwJsx's callers do — see gtkx/bridge/adw.ts). When
|
|
180
|
+
// the store DOES have Adw, `hasAdwStore` is true and this hook falls
|
|
181
|
+
// through to real resolution, unchanged: `gtkx build`'s dedupe and native-
|
|
182
|
+
// asset rewrite still see a real, literal specifier.
|
|
183
|
+
const ADW_ONLY_SPECIFIERS = new Set(["@gtkx/gi/adw", "@gtkx/jsx/adw"]);
|
|
184
|
+
const ADW_UNAVAILABLE_PREFIX = "\0gtkx-adw-unavailable:";
|
|
185
|
+
const adwUnavailableMessage = (specifier) => `[react-native-gtkx] "${specifier}" requires "Adw-1" in this app's ` +
|
|
186
|
+
"gtkx.config.ts `libraries` — see docs/api.md (the plain-GTK profile) " +
|
|
187
|
+
"for what needs Adw unconditionally and what falls back without it.";
|
|
101
188
|
/**
|
|
102
189
|
* Vite plugin: aliases `react-native` (and subpaths) to `react-native-gtkx`
|
|
103
190
|
* and resolves Metro-style platform extensions
|
|
@@ -126,6 +213,11 @@ export const reactNativeGtkx = (options = {}) => {
|
|
|
126
213
|
// `gtkx build` in production, which is exactly the distinction RN draws.
|
|
127
214
|
define: {
|
|
128
215
|
__DEV__: JSON.stringify(env.mode !== "production"),
|
|
216
|
+
// See hasAdwStore's doc above — process.cwd(), not _config.root:
|
|
217
|
+
// `gtkx dev`/`gtkx build` always run from the app's own directory
|
|
218
|
+
// (root defaults there too), and this must be resolvable before the
|
|
219
|
+
// rest of the merged config is settled.
|
|
220
|
+
__GTKX_ADW_AVAILABLE__: JSON.stringify(hasAdwStore(process.cwd())),
|
|
129
221
|
},
|
|
130
222
|
ssr: {
|
|
131
223
|
// `gtkx dev` runs vite with ssr.external: true, which would hand
|
|
@@ -200,8 +292,39 @@ export const reactNativeGtkx = (options = {}) => {
|
|
|
200
292
|
"react",
|
|
201
293
|
],
|
|
202
294
|
},
|
|
295
|
+
build: {
|
|
296
|
+
rolldownOptions: {
|
|
297
|
+
output: {
|
|
298
|
+
// A literal, code-split dynamic import (the Adw seam,
|
|
299
|
+
// gtkx/bridge/adw.ts — see its own doc and 006 above) lands its
|
|
300
|
+
// chunk under the Rolldown default `assets/[name]-[hash].js`
|
|
301
|
+
// UNLESS told otherwise. `@gtkx/cli`'s own `gtkx:native` plugin
|
|
302
|
+
// rewrites every reachable `@gtkx/native` import into
|
|
303
|
+
// `require("./gtkx.node")` — a path RELATIVE TO WHATEVER FILE
|
|
304
|
+
// THE REWRITE LANDS IN, correct only when that file sits next to
|
|
305
|
+
// the emitted `dist/gtkx.node` asset. The entry chunk is pinned
|
|
306
|
+
// there already (`entryFileNames: "bundle.js"`, set by
|
|
307
|
+
// `@gtkx/cli`'s own builder); a chunk placed one level down in
|
|
308
|
+
// `assets/` breaks the SAME relative path
|
|
309
|
+
// ("Cannot find module './gtkx.node'" — reproduced building
|
|
310
|
+
// examples/gallery with the Adw seam's dynamic import made
|
|
311
|
+
// literal). Keeping every chunk in `dist/` alongside the entry
|
|
312
|
+
// and the addon sidesteps the mismatch instead of guessing at
|
|
313
|
+
// gtkx's own relative-path assumption.
|
|
314
|
+
chunkFileNames: "[name]-[hash].js",
|
|
315
|
+
},
|
|
316
|
+
},
|
|
317
|
+
},
|
|
203
318
|
}),
|
|
204
319
|
async resolveId(source, importer) {
|
|
320
|
+
// See ADW_ONLY_SPECIFIERS' own doc above: on a store with no "Adw-1",
|
|
321
|
+
// resolving either of these for real fails the whole file that
|
|
322
|
+
// imports them, before that file's own code (a runtime guard, a
|
|
323
|
+
// try/catch) ever runs. Checked first, ahead of the alias table below
|
|
324
|
+
// (neither specifier is in it).
|
|
325
|
+
if (ADW_ONLY_SPECIFIERS.has(source) && !hasAdwStore(process.cwd())) {
|
|
326
|
+
return ADW_UNAVAILABLE_PREFIX + source;
|
|
327
|
+
}
|
|
205
328
|
// The app's table, not the default one: a package dropped with `false`
|
|
206
329
|
// falls through to vite's own resolution and the real package loads.
|
|
207
330
|
const aliased = applyAliases(aliases, source);
|
|
@@ -213,6 +336,13 @@ export const reactNativeGtkx = (options = {}) => {
|
|
|
213
336
|
}
|
|
214
337
|
return resolvePlatformSpecifier(source, importer, existsSync, options);
|
|
215
338
|
},
|
|
339
|
+
load(id) {
|
|
340
|
+
if (!id.startsWith(ADW_UNAVAILABLE_PREFIX)) {
|
|
341
|
+
return null;
|
|
342
|
+
}
|
|
343
|
+
const specifier = id.slice(ADW_UNAVAILABLE_PREFIX.length);
|
|
344
|
+
return `throw new Error(${JSON.stringify(adwUnavailableMessage(specifier))})`;
|
|
345
|
+
},
|
|
216
346
|
};
|
|
217
347
|
};
|
|
218
348
|
export default reactNativeGtkx;
|