UNPKG

@expofp/floorplan

Version:

Interactive floor plan library for expos and events

65 lines • 3.24 kB
/** * The live-plan bookkeeping behind the one-live-plan-per-page contract * (ADR-0011). One page shows one plan at a time; a *plan swap* is * `unstable_destroy()` followed by `load()`, and the next load builds a * completely fresh event-scoped world rather than resetting the old one. * * Two things live here, and nothing else — the module is deliberately free of * store, config and DOM imports so `load()` can hold the contract without * pulling the event-scoped graph into the entry chunk: * * - the slot: `load()` claims it and refuses a second plan; `disposePlan()` * frees it, which is what makes `unstable_destroy()` idempotent; * - the teardown registry: everything the plan owns — MobX reactions, DOM * listeners, timers, the store graph itself — registers how to undo itself, * because an undisposed reaction stays subscribed to the dead instance and * pins it across the swap (spike finding, `docs/2026-08-27-plan-swap-proxy-spike-verdict.md`). * * Module-scope *data* that belongs to one event is not registered anywhere: it * is memoized on the installed config by `tools/event-scoped-cache.ts`. */ type Disposer = () => void; /** * What an embedder sees when their navigation code loads a second plan without * destroying the first. Naming the fix is the point — the alternative is a * corrupted map (ADR-0011). */ export declare const LIVE_PLAN_ERROR: string; /** Whether a plan currently owns the page. */ export declare function isPlanLive(): boolean; /** * Names the plan currently occupying the page. Bumped by every teardown, so async work started by * one plan can tell that it has come back to a different one — or to none. * * `isPlanLive()` cannot answer that question: the next `load()` claims the slot long before * `createLivePlan()` points the barrel at its graph, so a continuation resuming in that window sees * a live plan and reads a barrel that is still empty. Capture this before the `await`, compare * after, and drop the result when it no longer belongs to anyone (ADR-0011). */ export declare function planGeneration(): number; /** * Reserves the page for the plan being loaded. Called at the top of `load()`, * before anything is built, so a sequencing bug in the host's navigation * surfaces as a rejected promise rather than a half-swapped world. * * @throws when a plan is already alive; the live plan is left untouched. */ export declare function claimPlanSlot(): void; /** * Registers how to undo one thing the live plan owns. Disposers run in reverse * registration order, so whatever was built first — the store graph — is the * last thing to go. */ export declare function registerPlanDisposer(dispose: Disposer): void; /** * Tears the live plan down and frees the slot: the disposer registry runs in * reverse, then the page is empty again. Idempotent — a second call, and a * call when nothing was ever loaded, do nothing. * * @throws the first failure once every disposer has run. A disposer that * throws is a bug in that module, not a reason to strand the rest of the * teardown and leave the page half-alive. */ export declare function disposePlan(): void; export {}; //# sourceMappingURL=plan-lifecycle.d.ts.map