@expofp/floorplan
Version:
Interactive floor plan library for expos and events
65 lines • 3.24 kB
TypeScript
/**
* 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