Instances
Internal instance anatomy and orchestration boundaries.
Anatomy at a glance
createInstance({ map, document? }) first validates the consumer-injected map, then normalises input via normaliseInstanceDocument(...), then delegates the resulting canonical InstanceDocument to createInstanceCore(map, ...), which assembles one runtime core for one injected map.
Key components:
| Component | Responsibility |
|---|---|
src/entry.js | Factory entry: map duck-type validation, document normalisation, deep-clone, runtime creation. |
src/document/instanceDocument.js | Canonical InstanceDocument shape, normalisation, serialisation, and validation. |
src/runtime/createInstanceCore.js | Runtime core orchestration, lifecycle, public API assembly, registry behaviour, destroy flow. |
src/runtime/runtimeRegistry.js | Internal WeakMap runtime storage keyed by the consumer map (get/set/delete). |
src/runtime/createInstanceEvents.js | Container event bus (on/off/once/emit); events are dispatched on map.getContainer(). |
src/runtime/state/createInstanceState.js | Canonical runtime-state store (getSnapshot, dispatch, subscribe) and scoped/global state-event emission. |
src/config/resolveConfig.js | Runtime config resolution (debug) over defaultConfig. |
src/geojson/* | GeoJSON overlay internals — type-based render plans (createGeoJSONModule.js), feature interaction events (createFeatureInteractionModule.js). Documented in docs/5.data.md. |
Internal orchestration boundaries
- Public boundary:
createInstance({ map, document? })insrc/entry.jsreturnsWaymarkInstancePublicApionly. - Runtime boundary: lifecycle phase, registry entries, and event-wiring handles stay internal.
- InstanceDocument boundary:
toJSON()is canonical serialisable output; it is separate from runtime lifecycle state.
Map injection details are documented separately:
core.modules boundary
core.modules in createInstanceCore(...) groups teardown-capable internals:
geoJSON(source/layer lifecycle, type-based render planning, feature interaction viacreateFeatureInteractionModule.js)debug(console event logging)
This grouping is internal lifecycle wiring, not part of the consumer API.
Module state boundaries
- Runtime mutable state lives in
core.runtimeState(state module snapshot + dispatch) and coversdebugand type visibility only. core.baselinekeeps stable authored/default intent (debug,types) for delta generation.- Serialisation emits a stable
configbaseline and a minimalstatedelta intoJSON()(unchanged branches omitted), using runtime-state snapshots as the current source. There is no map/camera/basemap slice. - Internal mutators (for example,
runtimeState.dispatch(...)) are runtime wiring and not public API. - The
geoJSONmodule owns a nestedfeatureInteractionmodule that observes Waymark-owned layers and emits feature interaction events. It is not part of the public API surface: consumers receivewaymark:feature.*events andcore.modules.geoJSON.destroy()detaches its listeners.
Lifecycle order
Create flow:
- Validate the injected map (
src/entry.js) and normalise the incoming document. - Check the
WeakMapregistry insrc/runtime/runtimeRegistry.js; if the map already has a runtime, throw. - Resolve config (debug) and install the event bus on
map.getContainer(). - Create the GeoJSON module: build render plans, register
load/style.loadmount handlers, and wire the feature interaction module (click/mousemove/mouseout). - Create runtime state (
createInstanceState(...)) with initial debug and type-visibility state. - Build the InstanceDocument adapter and public API.
- Register the runtime against the map in the
WeakMapand emitwaymark:instance.createdon the map container.
Destroy flow:
- Mark lifecycle destroyed and emit
waymark:instance.destroyed. - Run
geoJSON.destroy()(remove Waymark-owned layers/sources, detachload/style.load, destroy the feature interaction module and detach itsclick/mousemove/mouseouthandlers) anddebug.destroy(). - Delete the runtime registry entry for the map.
The consumer's map and container are never removed or modified by Waymark.
Extension notes
When adding internals to createInstanceCore(...):
- Keep dependencies explicit.
- Keep teardown deterministic.
- Keep ID-scoped names collision-safe.
- Keep the public API stable unless intentionally documented and tested.
For module-level behaviour, update these docs alongside runtime changes:
docs/4.map.md