| 1 | import * as Layer from "effect/Layer"; |
| 2 | import { Atom, AtomRegistry, Reactivity } from "effect/reactivity"; |
| 3 | |
| 4 | export interface AcceptingHotModule { |
| 5 | readonly accept: (callback?: () => void) => void; |
| 6 | } |
| 7 | |
| 8 | interface HotAtomRuntimeEntry { |
| 9 | readonly layerAtom: Atom.Writable< |
| 10 | Layer.Layer<unknown, unknown, AtomRegistry.AtomRegistry | Reactivity.Reactivity> |
| 11 | >; |
| 12 | readonly runtime: Atom.AtomRuntime<unknown, unknown>; |
| 13 | } |
| 14 | |
| 15 | const hotAtomRuntimesKey = Symbol.for("t3.mobile.hot-atom-runtimes"); |
| 16 | |
| 17 | type HotAtomRuntimeGlobal = typeof globalThis & { |
| 18 | [hotAtomRuntimesKey]?: Map<string, HotAtomRuntimeEntry>; |
| 19 | }; |
| 20 | |
| 21 | function hotAtomRuntimes(): Map<string, HotAtomRuntimeEntry> { |
| 22 | const runtimeGlobal = globalThis as HotAtomRuntimeGlobal; |
| 23 | return (runtimeGlobal[hotAtomRuntimesKey] ??= new Map()); |
| 24 | } |
| 25 | |
| 26 | export function hotSwappableAtomRuntime<R, E>(options: { |
| 27 | readonly id: string; |
| 28 | readonly hotModule: AcceptingHotModule | undefined; |
| 29 | readonly registry: AtomRegistry.AtomRegistry; |
| 30 | readonly layer: Layer.Layer<R, E, AtomRegistry.AtomRegistry | Reactivity.Reactivity>; |
| 31 | }): Atom.AtomRuntime<R, E> { |
| 32 | if (options.hotModule === undefined || typeof __DEV__ === "undefined" || !__DEV__) { |
| 33 | return Atom.runtime(options.layer); |
| 34 | } |
| 35 | |
| 36 | const runtimes = hotAtomRuntimes(); |
| 37 | const existing = runtimes.get(options.id); |
| 38 | let entry: HotAtomRuntimeEntry; |
| 39 | |
| 40 | if (existing === undefined) { |
| 41 | const layerAtom = Atom.make(options.layer); |
| 42 | entry = { |
| 43 | layerAtom: layerAtom as HotAtomRuntimeEntry["layerAtom"], |
| 44 | runtime: Atom.runtime((get) => get(layerAtom)) as HotAtomRuntimeEntry["runtime"], |
| 45 | }; |
| 46 | runtimes.set(options.id, entry); |
| 47 | } else { |
| 48 | entry = existing; |
| 49 | options.registry.set( |
| 50 | entry.layerAtom, |
| 51 | options.layer as Layer.Layer< |
| 52 | unknown, |
| 53 | unknown, |
| 54 | AtomRegistry.AtomRegistry | Reactivity.Reactivity |
| 55 | >, |
| 56 | ); |
| 57 | } |
| 58 | |
| 59 | // This is a real HMR boundary: importers retain the stable AtomRuntime while |
| 60 | // this module evaluation installs the freshly constructed Layer above. |
| 61 | options.hotModule.accept(); |
| 62 | return entry.runtime as Atom.AtomRuntime<R, E>; |
| 63 | } |