apps/mobile/src/lib/hot-swappable-atom-runtime.ts

import * as Layer from "effect/Layer";
import { Atom, AtomRegistry, Reactivity } from "effect/reactivity";

export interface AcceptingHotModule {
  readonly accept: (callback?: () => void) => void;
}

interface HotAtomRuntimeEntry {
  readonly layerAtom: Atom.Writable<
    Layer.Layer<unknown, unknown, AtomRegistry.AtomRegistry | Reactivity.Reactivity>
  >;
  readonly runtime: Atom.AtomRuntime<unknown, unknown>;
}

const hotAtomRuntimesKey = Symbol.for("t3.mobile.hot-atom-runtimes");

type HotAtomRuntimeGlobal = typeof globalThis & {
  [hotAtomRuntimesKey]?: Map<string, HotAtomRuntimeEntry>;
};

function hotAtomRuntimes(): Map<string, HotAtomRuntimeEntry> {
  const runtimeGlobal = globalThis as HotAtomRuntimeGlobal;
  return (runtimeGlobal[hotAtomRuntimesKey] ??= new Map());
}

export function hotSwappableAtomRuntime<R, E>(options: {
  readonly id: string;
  readonly hotModule: AcceptingHotModule | undefined;
  readonly registry: AtomRegistry.AtomRegistry;
  readonly layer: Layer.Layer<R, E, AtomRegistry.AtomRegistry | Reactivity.Reactivity>;
}): Atom.AtomRuntime<R, E> {
  if (options.hotModule === undefined || typeof __DEV__ === "undefined" || !__DEV__) {
    return Atom.runtime(options.layer);
  }

  const runtimes = hotAtomRuntimes();
  const existing = runtimes.get(options.id);
  let entry: HotAtomRuntimeEntry;

  if (existing === undefined) {
    const layerAtom = Atom.make(options.layer);
    entry = {
      layerAtom: layerAtom as HotAtomRuntimeEntry["layerAtom"],
      runtime: Atom.runtime((get) => get(layerAtom)) as HotAtomRuntimeEntry["runtime"],
    };
    runtimes.set(options.id, entry);
  } else {
    entry = existing;
    options.registry.set(
      entry.layerAtom,
      options.layer as Layer.Layer<
        unknown,
        unknown,
        AtomRegistry.AtomRegistry | Reactivity.Reactivity
      >,
    );
  }

  // This is a real HMR boundary: importers retain the stable AtomRuntime while
  // this module evaluation installs the freshly constructed Layer above.
  options.hotModule.accept();
  return entry.runtime as Atom.AtomRuntime<R, E>;
}