@yoltra/core 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.es.md +127 -11
- package/README.md +126 -12
- package/dist/types/index.d.ts +2 -1
- package/dist/types/persistence/persist.d.ts +2 -2
- package/dist/types/store/Store.d.ts +368 -14
- package/dist/types/store/fingerprint.d.ts +62 -0
- package/dist/types/types.d.ts +524 -14
- package/dist/yoltra.cjs +2 -2
- package/dist/yoltra.cjs.map +1 -1
- package/dist/yoltra.mjs +1668 -880
- package/dist/yoltra.mjs.map +1 -1
- package/dist/yoltra.umd.js +2 -2
- package/dist/yoltra.umd.js.map +1 -1
- package/package.json +3 -2
package/dist/yoltra.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"yoltra.mjs","sources":["../src/eventBus/EventBus.ts","../src/eventBus/LooseEventBus.ts","../src/reducer/Reducer.ts","../src/utils/detectChangedProps.ts","../src/utils/immutability.ts","../src/store/rejection.ts","../src/store/call.ts","../src/store/callQueue.ts","../src/store/performCall.ts","../src/store/paths.ts","../src/store/matching.ts","../src/store/Store.ts","../src/types.ts","../src/entity/entityAdapter.ts","../src/serialize/codec.ts","../src/persistence/persist.ts","../src/persistence/adapters.ts"],"sourcesContent":["/**\n * @module @yoltra/core\n */\n\nimport type { Event, EventMapBase } from \"../types\";\n\n/**\n * Minimal, synchronous pub/sub event bus keyed by **channel** and **type**.\n *\n * @typeParam EM - Event map shape:\n * ```ts\n * type EventMapBase = Record<string, Record<string, unknown>>;\n * // Example:\n * type EM = {\n * ui: { toggle: boolean };\n * data: { loaded: { items: string[] } };\n * };\n * ```\n *\n * @remarks\n * - Handlers are stored per `(channel, type)` and invoked **synchronously** in subscription order.\n * - Exceptions thrown by a handler are **caught and logged**, and do **not** stop other handlers.\n * - Intended for in-memory, single-process usage (no cross-tab/process broadcasting).\n *\n * @example\n * ```ts\n * type EM = {\n * ui: { toggle: boolean };\n * data: { loaded: { items: string[] } };\n * };\n *\n * const bus = new EventBus<EM>();\n *\n * // Subscribe\n * const off = bus.on('ui', 'toggle', (on) => {\n * console.log('UI toggled:', on);\n * });\n *\n * // Emit\n * bus.emit('ui', 'toggle', true); // logs: \"UI toggled: true\"\n *\n * // Unsubscribe\n * off();\n * ```\n *\n * @public\n */\nexport class EventBus<EM extends EventMapBase> {\n /**\n * Internal registry: `channel → type → Set<handler>`.\n * @internal\n */\n private handlers: Map<string, Map<string, Set<(payload: any, event?: any) => void>>> = new Map();\n\n /**\n * Subscribes a handler to an exact `(channel, type)`.\n *\n * @typeParam C - Channel key (must be a string key of `EM`).\n * @typeParam T - Type key within channel `C` (must be a string key of `EM[C]`).\n * @param channel - Channel name to subscribe to.\n * @param type - Event type within the channel.\n * @param handler - Function invoked with the payload type `EM[C][T]`. It optionally\n * receives the **source event** as a second argument when the emitter supplies one, so\n * subscribers can read the true `id` (and any `meta`) instead of reconstructing an event\n * from the payload alone. Handlers that declare only `payload` remain valid.\n * @returns An **unsubscribe** function that removes this handler.\n *\n * @example\n * ```ts\n * const off = bus.on('data', 'loaded', ({ items }) => {\n * console.log('Loaded', items.length, 'items');\n * });\n *\n * // Later, stop listening:\n * off();\n * ```\n *\n * @example Reading the source event\n * ```ts\n * bus.on('data', 'loaded', (payload, event) => {\n * console.log('event id:', event?.id);\n * });\n * ```\n *\n * @public\n */\n public on<C extends keyof EM & string, T extends keyof EM[C] & string>(\n channel: C,\n type: T,\n handler: (payload: EM[C][T], event?: Event<EM, C, T>) => void,\n ): () => void {\n let byType = this.handlers.get(channel);\n if (!byType) {\n byType = new Map();\n this.handlers.set(channel, byType);\n }\n\n let set = byType.get(type);\n if (!set) {\n set = new Set();\n byType.set(type, set);\n }\n\n set.add(handler as any);\n\n return () => this.off(channel, type, handler);\n }\n\n /**\n * Removes a specific handler previously added with {@link EventBus.on | `on`}.\n *\n * @typeParam C - Channel key (string key of `EM`).\n * @typeParam T - Type key within channel `C` (string key of `EM[C]`).\n * @param channel - Channel name of the subscription to remove.\n * @param type - Event type of the subscription to remove.\n * @param handler - The same handler reference that was passed to `on`.\n *\n * @example\n * ```ts\n * const h = (n: number) => console.log('inc', n);\n * bus.on('math', 'inc', h);\n *\n * // Explicitly remove this handler:\n * bus.off('math', 'inc', h);\n * ```\n *\n * @public\n */\n public off<C extends keyof EM & string, T extends keyof EM[C] & string>(\n channel: C,\n type: T,\n handler: (payload: EM[C][T], event?: Event<EM, C, T>) => void,\n ): void {\n const byType = this.handlers.get(channel);\n if (!byType) return;\n\n const set = byType.get(type);\n if (!set) return;\n\n set.delete(handler as any);\n\n if (set.size === 0) byType.delete(type);\n if (byType.size === 0) this.handlers.delete(channel);\n }\n\n /**\n * Emits an event to all subscribers of the exact `(channel, type)`.\n *\n * Handlers are invoked **synchronously**. Any exception thrown by a handler is\n * caught and logged, and other handlers still run.\n *\n * @typeParam C - Channel key (string key of `EM`).\n * @typeParam T - Type key within channel `C` (string key of `EM[C]`).\n * @param channel - Channel name to emit on.\n * @param type - Event type to emit.\n * @param payload - Payload matching `EM[C][T]`.\n * @param event - Optional **source event**, forwarded to handlers as a second argument.\n * Supply it whenever the caller already holds the real event so subscribers observe its\n * true `id` rather than reconstructing one; omitting it keeps the original behaviour.\n *\n * @example\n * ```ts\n * bus.emit('ui', 'toggle', false);\n * ```\n *\n * @public\n */\n public emit<C extends keyof EM & string, T extends keyof EM[C] & string>(\n channel: C,\n type: T,\n payload: EM[C][T],\n event?: Event<EM, C, T>,\n ): void {\n const byType = this.handlers.get(channel);\n if (!byType) return;\n\n const set = byType.get(type);\n if (!set || set.size === 0) return;\n\n for (const h of [...set]) {\n try {\n (h as any)(payload, event);\n } catch (err) {\n console.error(\"EventBus handler error:\", err);\n }\n }\n }\n\n /**\n * Clears **all** listeners across all channels/types.\n *\n * Useful for tests or during HMR teardown to avoid duplicate handlers.\n *\n * @example\n * ```ts\n * // In a test teardown:\n * afterEach(() => bus.clear());\n * ```\n *\n * @public\n */\n public clear(): void {\n this.handlers.clear();\n }\n}","/**\n * @module @yoltra/core\n */\n\n/**\n * Flexible, synchronous pub/sub bus that supports **exact** and **pattern** event subscriptions.\n *\n * @typeParam C - Channel name type (defaults to `string`).\n * @typeParam T - Event type name type (defaults to `string`). Types are treated as **dot-separated paths** (e.g. `\"a.b.c\"`).\n * @typeParam P - Payload type for all events (defaults to `any`).\n *\n * @remarks\n * - **Exact handlers** subscribe to a specific `(channel, type)` pair. Type keys are **normalized** by stripping a single leading dot (`\".foo\"` → `\"foo\"`).\n * - **Pattern handlers** subscribe using wildcards over dot-separated segments:\n * - `*` matches **one** segment.\n * - `**` matches **zero or more** segments (greedy).\n * - On {@link LooseEventBus.emit | `emit`}, exact handlers fire first, then any matching pattern handlers.\n * - Handlers are **de-duplicated**: if the same function is both exact and pattern-registered, it is called **once**.\n * - Handler invocation is **synchronous**. Exceptions are caught and logged; remaining handlers still run.\n *\n * @example\n * ```ts\n * type C = 'ui' | 'data';\n * type T = string;\n * type P = unknown;\n *\n * const bus = new LooseEventBus<C, T, P>();\n *\n * // Exact\n * const offA = bus.on('ui', 'panel.open', () => console.log('panel opened'));\n *\n * // Patterns\n * const offB = bus.on('ui', 'panel.*', () => console.log('any single sub-event under panel'));\n * const offC = bus.on('ui', 'panel.**', () => console.log('any depth under panel'));\n *\n * bus.emit('ui', 'panel.open', null);\n * // => exact fires, then 'panel.*', then 'panel.**'\n *\n * offA(); offB(); offC(); // unsubscribe\n * ```\n *\n * @public\n */\n/**\n * One registered pattern, kept pre-split.\n * @internal\n */\ninterface PatternEntry {\n readonly pattern: string;\n readonly segments: readonly string[];\n}\n\n/**\n * The patterns on one channel, arranged by what a subject's first segment can match.\n * @internal\n */\ninterface PatternIndex {\n /** Keyed by a literal first segment. */\n readonly byHead: Map<string, PatternEntry[]>;\n /** Patterns beginning with `*` or `**`, which every subject has to test. */\n readonly anyHead: PatternEntry[];\n}\n\nexport class LooseEventBus<C extends string = string, T extends string = string, P = any> {\n /**\n * Exact handlers: `channel → type → [handlers]`.\n * @internal\n */\n private handlers = new Map<C, Map<T, Array<(p: P) => void>>>();\n\n /**\n * Pattern handlers with `*` and `**`: `channel → pattern(string) → [handlers]`.\n * @internal\n */\n private patternHandlers = new Map<C, Map<string, Array<(p: P) => void>>>();\n\n /**\n * Patterns bucketed by their first segment, so an emit tests only what could match.\n *\n * @remarks\n * Delivery used to walk every pattern registered on the channel and run the full segment\n * matcher against each. That is linear in the number of patterns rather than in the number\n * that match, and it re-split both the pattern and the subject on every test — for a thousand\n * patterns, two thousand string splits to deliver one event.\n *\n * A subject's first segment can only be matched by a pattern whose first segment is that same\n * literal, or is `*` or `**`. Bucketing on that turns the common shape — distinct event\n * families like `panel.*` and `order.**` — from a scan of everything into a map lookup plus\n * the handful that begin with a wildcard.\n *\n * It buys nothing for a channel where every pattern starts with `**`, since all of those must\n * still be tested. That is the honest worst case, and it is unchanged rather than worsened.\n */\n private patternIndex = new Map<C, PatternIndex>();\n\n /**\n * Subscribes a handler to either an **exact** type or a **pattern**.\n *\n * @param channel - Channel to subscribe on.\n * @param type - Exact event type (e.g. `\"a.b\"`) or pattern (contains `*`/`**`).\n * @param handler - Function invoked with the emitted payload.\n * @returns An **unsubscribe** function that removes this handler.\n *\n * @remarks\n * - Exact subscriptions are stored under a **normalized** key (leading `.` removed).\n * - Pattern subscriptions are stored **as provided**; matching normalizes the subject.\n *\n * @example Exact subscription\n * ```ts\n * const off = bus.on('data', 'items.loaded', ({ count }) => {\n * console.log('Loaded', count);\n * });\n * // Later\n * off();\n * ```\n *\n * @example Pattern subscription\n * ```ts\n * // Match any single sub-event: 'panel.open', 'panel.close', etc.\n * const offStar = bus.on('ui', 'panel.*', () => {});\n *\n * // Match any depth: 'panel.open', 'panel.items.add', 'panel', etc.\n * const offGlob = bus.on('ui', 'panel.**', () => {});\n * ```\n *\n * @public\n */\n on(channel: C, type: T, handler: (payload: P) => void): () => void {\n const typeStr = String(type);\n if (!this.isPattern(typeStr)) {\n // Exact subscription with normalized key (strip leading dot)\n const key = this.normalizeTypeKey(typeStr) as T;\n\n if (!this.handlers.has(channel)) this.handlers.set(channel, new Map());\n const map = this.handlers.get(channel)!;\n\n if (!map.has(key)) map.set(key, []);\n map.get(key)!.push(handler);\n\n // capture normalized key for off()\n return () => this.offExactNormalized(channel, key, handler);\n } else {\n // Pattern subscription (stored as provided; matcher handles normalization)\n const pattern = typeStr;\n\n if (!this.patternHandlers.has(channel)) this.patternHandlers.set(channel, new Map());\n const pmap = this.patternHandlers.get(channel)!;\n\n if (!pmap.has(pattern)) {\n pmap.set(pattern, []);\n // Split once here rather than on every emit, and file it under the segment that decides\n // whether it is even a candidate.\n this.indexPattern(channel, pattern);\n }\n pmap.get(pattern)!.push(handler);\n\n return () => this.offPattern(channel, pattern, handler);\n }\n }\n\n /**\n * Unsubscribes an **exact** handler. The `type` key is normalized internally,\n * so callers can pass `\"foo\"` or `\".foo\"` interchangeably.\n *\n * @param channel - Channel name.\n * @param type - Exact event type key to remove (normalization applied).\n * @param handler - The same handler reference previously passed to {@link LooseEventBus.on | `on`}.\n *\n * @example\n * ```ts\n * const h = () => {};\n * bus.on('ui', 'panel.open', h);\n * // Remove it (with or without leading dot)\n * bus.off('ui', '.panel.open', h);\n * ```\n *\n * @public\n */\n off(channel: C, type: T, handler: (payload: P) => void): void {\n const key = this.normalizeTypeKey(String(type)) as T;\n this.offExactNormalized(channel, key, handler);\n }\n\n /**\n * Internal exact unsubscription using an already **normalized** type key.\n *\n * @param channel - Channel name.\n * @param normalizedType - Event type key with leading dot removed.\n * @param handler - Handler to remove.\n * @internal\n */\n private offExactNormalized(\n channel: C,\n normalizedType: T,\n handler: (payload: P) => void,\n ): void {\n const cMap = this.handlers.get(channel);\n if (!cMap) return;\n const list = cMap.get(normalizedType);\n if (!list) return;\n\n const i = list.indexOf(handler);\n if (i !== -1) list.splice(i, 1);\n\n // cleanup empties\n if (list.length === 0) cMap.delete(normalizedType);\n if (cMap.size === 0) this.handlers.delete(channel);\n }\n\n /**\n * Internal removal for a **pattern** subscription. No-ops if missing.\n *\n * @param channel - Channel name.\n * @param pattern - Pattern string as originally subscribed.\n * @param handler - Handler to remove.\n * @internal\n */\n private offPattern(channel: C, pattern: string, handler: (payload: P) => void): void {\n const pMap = this.patternHandlers.get(channel);\n if (!pMap) return;\n\n const list = pMap.get(pattern);\n if (!list) return;\n\n const i = list.indexOf(handler);\n if (i !== -1) list.splice(i, 1);\n\n // cleanup empties\n if (list.length === 0) {\n pMap.delete(pattern);\n this.unindexPattern(channel, pattern);\n }\n if (pMap.size === 0) {\n this.patternHandlers.delete(channel);\n this.patternIndex.delete(channel);\n }\n }\n\n /**\n * Emits an event to all exact subscribers first, then to **matching pattern** subscribers.\n * Duplicate handler references are called **once** (de-duped).\n *\n * @param channel - Channel to emit on.\n * @param type - Event type (subject). A leading dot is ignored for matching.\n * @param payload - Payload delivered to handlers.\n *\n * @example\n * ```ts\n * // Suppose:\n * // - on('ui', 'panel.open', h)\n * // - on('ui', 'panel.*', h) // same handler ref!\n * // - on('ui', 'panel.**', other)\n * bus.emit('ui', 'panel.open', { id: 1 });\n * // => 'h' runs once (de-duped), then 'other'\n * ```\n *\n * @public\n */\n emit(channel: C, type: T, payload: P): void {\n const typeStr = String(type);\n const normalizedType = this.normalizeTypeKey(typeStr) as T;\n\n // Exact delivery (normalized)\n const exactList = this.handlers.get(channel)?.get(normalizedType) ?? [];\n\n // Pattern delivery (normalize subject before matching)\n const patternLists = this.matchingPatternHandlers(channel, typeStr);\n\n const called = new Set<(p: P) => void>();\n const deliver = (arr: Array<(p: P) => void>) => {\n for (const h of [...arr]) {\n if (called.has(h)) continue;\n\n called.add(h);\n\n try {\n h(payload);\n } catch (exc) {\n console.error(exc);\n continue;\n }\n }\n };\n\n deliver(exactList);\n for (const list of patternLists) deliver(list);\n }\n\n /**\n * Emits a payload that is only built if somebody is listening.\n *\n * @param channel - Channel to emit on.\n * @param type - Concrete event type.\n * @param make - Builds the payload. Called at most once, and only when a handler matched.\n *\n * @remarks\n * Same matching as {@link LooseEventBus.emit}; the difference is *when* the payload exists.\n * The store's change notification carries the old and new value at a path, and reading those\n * means walking the state tree twice per path. Doing that eagerly meant a slice nobody had\n * subscribed to paid the full cost of describing changes to an audience of nobody — the\n * matching work was already being done to discover there were no handlers.\n *\n * @public\n */\n emitWith(channel: C, type: T, make: () => P): void {\n const typeStr = String(type);\n const normalizedType = this.normalizeTypeKey(typeStr) as T;\n\n const exactList = this.handlers.get(channel)?.get(normalizedType) ?? [];\n\n const patternLists = this.matchingPatternHandlers(channel, typeStr);\n\n if (exactList.length === 0 && patternLists.length === 0) return;\n\n // Exactly one construction, shared by every handler — the same guarantee `emit` gives.\n const payload = make();\n\n const called = new Set<(p: P) => void>();\n const deliver = (arr: Array<(p: P) => void>) => {\n for (const h of [...arr]) {\n if (called.has(h)) continue;\n called.add(h);\n try {\n h(payload);\n } catch (exc) {\n console.error(exc);\n continue;\n }\n }\n };\n\n deliver(exactList);\n for (const list of patternLists) deliver(list);\n }\n\n /**\n * Determines if a string is a **pattern** (contains `*`).\n * @param s - Event type or pattern string.\n * @returns `true` if it contains at least one `*`, else `false`.\n * @internal\n */\n private isPattern(s: string): boolean {\n return s.includes(\"*\");\n }\n\n /**\n * Normalizes event type keys for exact matching by stripping a **single** leading dot.\n *\n * @param s - Event type key.\n * @returns Normalized key without a leading dot.\n * @example\n * ```ts\n * normalizeTypeKey('.a.b') // 'a.b'\n * normalizeTypeKey('a.b') // 'a.b'\n * ```\n * @internal\n */\n private normalizeTypeKey(s: string): string {\n return s.replace(/^\\./, \"\");\n }\n\n /**\n * Splits a path into dot-separated segments after normalization and removes empties.\n * @param p - Event type or pattern string.\n * @internal\n */\n private splitPath(p: string): string[] {\n return this.normalizeTypeKey(p).split(\".\").filter(Boolean);\n }\n\n /**\n * Files a pattern under the first segment that could select it.\n * @internal\n */\n private indexPattern(channel: C, pattern: string): void {\n let index = this.patternIndex.get(channel);\n if (index === undefined) {\n index = { byHead: new Map(), anyHead: [] };\n this.patternIndex.set(channel, index);\n }\n const segments = this.splitPath(pattern);\n const entry: PatternEntry = { pattern, segments };\n const head = segments[0];\n // A pattern with no segments at all, or one starting with a wildcard, cannot be narrowed by\n // the subject's first segment — so it goes in the list every emit walks.\n if (head === undefined || head === \"*\" || head === \"**\") {\n index.anyHead.push(entry);\n return;\n }\n const bucket = index.byHead.get(head);\n if (bucket === undefined) index.byHead.set(head, [entry]);\n else bucket.push(entry);\n }\n\n /**\n * Removes a pattern from the index. Paired with {@link LooseEventBus.offPattern}.\n * @internal\n */\n private unindexPattern(channel: C, pattern: string): void {\n const index = this.patternIndex.get(channel);\n if (index === undefined) return;\n const head = this.splitPath(pattern)[0];\n const bucket =\n head === undefined || head === \"*\" || head === \"**\"\n ? index.anyHead\n : index.byHead.get(head);\n if (bucket === undefined) return;\n const at = bucket.findIndex((e) => e.pattern === pattern);\n if (at !== -1) bucket.splice(at, 1);\n if (bucket.length === 0 && bucket !== index.anyHead && head !== undefined) {\n index.byHead.delete(head);\n }\n }\n\n /**\n * The handler lists of every pattern matching this subject.\n *\n * @remarks\n * Shared by `emit` and `emitWith` so the two cannot drift on what \"matching\" means — which\n * they could, being two copies of the same walk before.\n *\n * The subject is split once here rather than once per pattern tested.\n *\n * @internal\n */\n private matchingPatternHandlers(channel: C, typeStr: string): Array<Array<(p: P) => void>> {\n const patternMap = this.patternHandlers.get(channel);\n const index = this.patternIndex.get(channel);\n if (patternMap === undefined || patternMap.size === 0 || index === undefined) return [];\n\n const subject = this.splitPath(typeStr);\n const lists: Array<Array<(p: P) => void>> = [];\n\n const test = (entries: readonly PatternEntry[]): void => {\n for (const entry of entries) {\n if (!this.matchSegments(entry.segments, subject)) continue;\n const handlers = patternMap.get(entry.pattern);\n if (handlers !== undefined) lists.push(handlers);\n }\n };\n\n const head = subject[0];\n if (head !== undefined) {\n const bucket = index.byHead.get(head);\n if (bucket !== undefined) test(bucket);\n }\n test(index.anyHead);\n\n return lists;\n }\n\n /**\n * Pattern matcher over dot-separated segments, which arrive already split.\n *\n * Rules:\n * - **literal**: exact match.\n * - `*` : matches exactly **one** segment.\n * - `**` : matches **zero or more** remaining segments (including empty).\n *\n * @remarks\n * Takes segments rather than strings so delivery can split each pattern once at registration\n * and the subject once per emit, instead of both once per test. Re-splitting per test was most\n * of what made wildcard delivery expensive: a thousand patterns meant two thousand string\n * splits to deliver one event.\n *\n * @param pSegs - Pattern segments (may include `*`/`**`).\n * @param sSegs - Subject segments to test.\n * @returns `true` if the pattern matches; otherwise `false`.\n *\n * @example\n * ```ts\n * matchSegments(['a', '*'], ['a', 'b']) // true\n * matchSegments(['a', '*'], ['a', 'b', 'c']) // false\n * matchSegments(['a', '**'], ['a']) // true\n * matchSegments(['**', 'end'], ['x', 'y', 'end']) // true\n * ```\n *\n * @internal\n */\n private matchSegments(pSegs: readonly string[], sSegs: readonly string[]): boolean {\n\n // Iterative segment glob with backtracking — no per-suffix recursion or\n // string re-joining. `*` matches exactly one segment; `**` matches zero or\n // more. Standard wildcard algorithm (`*`≈`?`, `**`≈`*`).\n let i = 0; // pattern index\n let j = 0; // subject index\n let star = -1; // pSegs index of the most recent '**' seen\n let matchIdx = 0; // sSegs index captured when that '**' was seen\n\n while (j < sSegs.length) {\n if (i < pSegs.length && (pSegs[i] === \"*\" || pSegs[i] === sSegs[j])) {\n i++;\n j++;\n } else if (i < pSegs.length && pSegs[i] === \"**\") {\n // '**' initially absorbs zero segments; remember it for backtracking.\n star = i;\n matchIdx = j;\n i++;\n } else if (star !== -1) {\n // Backtrack: let the last '**' absorb one more subject segment.\n i = star + 1;\n j = ++matchIdx;\n } else {\n return false;\n }\n }\n\n // Any leftover pattern tokens must all be '**' (each matching zero segments).\n while (i < pSegs.length && pSegs[i] === \"**\") i++;\n return i === pSegs.length;\n }\n\n /**\n * Removes **all** listeners (exact and pattern). Useful for tests/HMR teardown.\n *\n * @example\n * ```ts\n * afterEach(() => bus.clear());\n * ```\n *\n * @public\n */\n clear(): void {\n this.handlers.clear();\n this.patternHandlers.clear();\n // The index is derived state; leaving it behind would re-register a pattern twice on the\n // next `on()` and hold every cleared pattern string alive for the life of the bus.\n this.patternIndex.clear();\n }\n\n /**\n * Returns a snapshot of all registered subscriptions for DevTools introspection.\n *\n * @returns An array of `{ channel, type, count }` entries for each distinct\n * (channel, type/pattern) pair with at least one handler.\n *\n * @internal\n */\n __introspect(): Array<{ channel: string; type: string; count: number }> {\n const result: Array<{ channel: string; type: string; count: number }> = [];\n for (const [channel, map] of this.handlers) {\n for (const [type, list] of map) {\n if (list.length > 0) {\n result.push({ channel: channel as string, type: type as string, count: list.length });\n }\n }\n }\n for (const [channel, map] of this.patternHandlers) {\n for (const [pattern, list] of map) {\n if (list.length > 0) {\n result.push({ channel: channel as string, type: pattern, count: list.length });\n }\n }\n }\n return result;\n }\n}","/**\n * @module @yoltra/core\n */\n\nimport type { EventMapBase, EventUnion, ReducerFunction } from \"../types\";\nimport type { Rejection } from \"../store/rejection\";\n\n/**\n * Thin wrapper around a pure reducer function (stateful event consumer):\n * given a state `S` and an event (from {@link EventUnion | `EventUnion<EM>`}),\n * returns the next state `S`.\n *\n * @typeParam S - State shape handled by this reducer.\n * @typeParam EM - Event map describing the valid event keys and payload types.\n *\n * @remarks\n * - The reducer function is expected to be **pure** and **side-effect free**.\n * - Use this class when you want to pass a reducer around as a value, or to\n * unify the reducer interface across the core API.\n *\n * @example Basic counter\n * ```ts\n * type State = { count: number };\n * type EM = { math: { add: number; set: number } };\n *\n * const rf: ReducerFunction<State, EM> = (s, evt) => {\n * if (evt.channel === 'math' && evt.type === 'add') {\n * return { count: s.count + evt.payload };\n * }\n * if (evt.channel === 'math' && evt.type === 'set') {\n * return { count: evt.payload };\n * }\n * return s;\n * };\n *\n * const r = new Reducer<State, EM>(rf);\n *\n * const s0 = { count: 0 };\n * const s1 = r.reduce(s0, {\n * channel: 'math',\n * type: 'add',\n * payload: 2,\n * id: crypto.randomUUID()\n * } as EventUnion<EM>);\n * // s1.count === 2\n * ```\n *\n * @public\n */\nexport class Reducer<S, EM extends EventMapBase = EventMapBase> {\n /**\n * The underlying pure reducer function.\n * @internal\n */\n private readonly _reduce: ReducerFunction<S, EM>;\n\n /**\n * Creates a new {@link Reducer} from a pure reducer function.\n *\n * @param reduce - A function `(state, event) => nextState` that implements your update logic.\n *\n * @example\n * ```ts\n * const reducer = new Reducer<MyState, MyEM>((state, event) => {\n * // implement your transitions here\n * return state;\n * });\n * ```\n *\n * @public\n */\n constructor(reduce: ReducerFunction<S, EM>) {\n this._reduce = reduce;\n }\n\n /**\n * Applies the reducer to produce the next state.\n *\n * @param state - Current state.\n * @param event - An event drawn from {@link EventUnion | `EventUnion<EM>`}.\n * @returns The next state, or a {@link Rejection} if the reducer refused the write.\n *\n * @example\n * ```ts\n * const next = reducer.reduce(curr, someEvent as EventUnion<MyEM>);\n * ```\n *\n * @public\n */\n reduce(state: S, event: EventUnion<EM>): S | Rejection {\n return this._reduce(state, event);\n }\n}","/**\n * @module @yoltra/core\n */\n\n/**\n * Keys already warned about, so a hot path does not turn into a log.\n *\n * @internal\n */\nconst warnedDottedKeys = new Set<string>();\n\n/** @internal */\nfunction warnDottedKey(path: string, key: string): void {\n const full = path ? `${path}.${key}` : key;\n if (warnedDottedKeys.has(full)) return;\n warnedDottedKeys.add(full);\n console.warn(\n `[yoltra] State key \"${key}\"${path ? ` under \"${path}\"` : \"\"} contains a dot. Paths are ` +\n `dotted, so this key is indistinguishable from nested objects of the same name: a ` +\n `subscription to \"${full}\" may match the wrong value, and DevTools patches for it will ` +\n `address the wrong node. Rename the key, or nest it.`,\n );\n}\n\n\n/**\n * Computes the list of **dotted leaf paths** that changed between two values.\n *\n * The algorithm performs a deep structural comparison with special handling for:\n * - **Primitives / null** → treated as leafs (change = current `path`; two `NaN`s are equal)\n * - **Date** → compares `getTime()`\n * - **RegExp** → compares `source` and `flags`\n * - **Arrays** → if lengths differ, the whole array path is marked changed; otherwise compares\n * element-by-element producing paths like `\"items.0.title\"`\n * - **Objects** → compares by the **union of keys**, recursing into shared keys and marking\n * added/removed keys as changed at their **full path**\n *\n * Cycles are handled by tracking the `(old, new)` pairs currently on the **recursion path**\n * (added on entry, removed on unwind). A pair is skipped only when it is a genuine ancestor of\n * itself (a real cycle) — a pair that merely appears again at a *sibling* path (legitimate\n * aliasing, e.g. the same object referenced from two keys) is still diffed, so real changes at\n * the second site are never dropped.\n *\n * @param oldState - Previous value to diff.\n * @param newState - Next value to diff.\n * @param path - Current dotted path (callers pass `\"\"` for root; recursion appends segments).\n * @param ancestors - (Advanced) Pairs on the current recursion path, for cycle detection. You\n * generally never pass this.\n * @returns An array of **dotted leaf paths** that changed. Paths use `\".\"` as a separator and\n * indices for arrays (e.g., `\"todos.0.title\"`). If nothing changed, returns `[]`.\n *\n * @example Basic object leaf\n * ```ts\n * detectChangedProps(\n * { user: { name: 'Ada', age: 37 } },\n * { user: { name: 'Grace', age: 37 } }\n * );\n * // => ['user.name']\n * ```\n *\n * @example Array element change\n * ```ts\n * detectChangedProps(\n * { items: [{ title: 'A' }, { title: 'B' }] },\n * { items: [{ title: 'A+' }, { title: 'B' }] }\n * );\n * // => ['items.0.title']\n * ```\n *\n * @example Array length change (marks the array path)\n * ```ts\n * detectChangedProps({ nums: [1,2] }, { nums: [1,2,3] });\n * // => ['nums']\n * ```\n *\n * @example Dates & RegExps\n * ```ts\n * detectChangedProps(new Date(0), new Date(0), 'createdAt'); // => []\n * detectChangedProps(new Date(0), new Date(1), 'createdAt'); // => ['createdAt']\n * detectChangedProps(/a/i, /a/i, 'pattern'); // => []\n * detectChangedProps(/a/i, /a/g, 'pattern'); // => ['pattern']\n * ```\n *\n * @remarks\n * - If `oldState === newState` (same reference), returns `[]` immediately.\n * - A change at the **root** — the values themselves differ and neither is a walkable object,\n * as for a primitive, a `Map`/`Set`, or two `Date`s — is reported at the `path` given, which\n * is `\"\"` for the default root call. `[\"\"]` therefore means *\"the whole value changed\"*, and\n * is emphatically **not** the same as `[]`. Callers must not filter it out for falsiness:\n * doing so is indistinguishable from \"nothing changed\", which is how a store slice holding a\n * primitive once silently refused every update it was given.\n * - For objects, only **own enumerable** keys are compared (via `Object.keys`).\n * - Returned paths are **leaf paths** where a primitive/terminal difference was detected; for arrays,\n * a length change is treated as a leaf change at the array path.\n *\n * @public\n */\nexport function detectChangedProps(\n oldState: any,\n newState: any,\n path = \"\",\n ancestors: Map<object, Set<object>> = new Map(),\n): string[] {\n const out: string[] = [];\n walk(oldState, newState, path, ancestors, out);\n return out;\n}\n\n/**\n * The recursion, writing into one array rather than returning a new one per node.\n *\n * @remarks\n * Every node used to allocate its own `string[]` and every parent spread its children's back in.\n * On a thousand-entity normalised map that is roughly four thousand short-lived arrays per diff,\n * for a result that is usually a single path — the allocation dwarfed the comparison it existed\n * to report.\n *\n * @internal\n */\nfunction walk(\n oldState: any,\n newState: any,\n path: string,\n ancestors: Map<object, Set<object>>,\n out: string[],\n): void {\n if (oldState === newState) return;\n\n if (\n typeof oldState !== \"object\" ||\n typeof newState !== \"object\" ||\n oldState === null ||\n newState === null\n ) {\n // Two NaNs are never `===` but represent no change — don't report a spurious diff.\n if (typeof oldState === \"number\" && Number.isNaN(oldState) && Number.isNaN(newState as number)) {\n return;\n }\n out.push(path);\n return;\n }\n\n if (oldState instanceof Date && newState instanceof Date) {\n if (oldState.getTime() !== newState.getTime()) out.push(path);\n return;\n }\n\n if (oldState instanceof RegExp && newState instanceof RegExp) {\n if (oldState.source !== newState.source || newState.flags !== oldState.flags) out.push(path);\n return;\n }\n\n // `Map` and `Set` keep their contents outside own enumerable keys, so the key-walk below sees\n // two empty objects and reports no change at all. The store treats \"no changed paths\" as a\n // no-op and skips the commit entirely, so a reducer returning a new Map produced no state\n // update, no subscriber notification and no error — the update simply vanished.\n //\n // Reported at this path rather than diffed internally: the references differ, which under the\n // immutability contract means the value changed. Reactivity for such a value is therefore\n // reference-level, not per-entry.\n if (oldState instanceof Map || newState instanceof Map) {\n out.push(path);\n return;\n }\n if (oldState instanceof Set || newState instanceof Set) {\n out.push(path);\n return;\n }\n\n const oldObj = oldState as object;\n const newObj = newState as object;\n\n // Cycle guard: skip a pair only when it is currently an ANCESTOR on this\n // recursion path (a genuine cycle). A pair seen earlier at a sibling path is\n // legitimate aliasing and must still be diffed.\n const active = ancestors.get(oldObj);\n if (active?.has(newObj)) return;\n const onPath = active ?? new Set<object>();\n onPath.add(newObj);\n if (!active) ancestors.set(oldObj, onPath);\n\n try {\n const isArrOld = Array.isArray(oldState);\n const isArrNew = Array.isArray(newState);\n if (isArrOld !== isArrNew) {\n out.push(path);\n return;\n }\n\n if (isArrOld) {\n const a = oldState;\n const b = newState as any[];\n\n // A length change reports the array path — the array's own identity changed, so a\n // subscriber watching `items` must hear about it — and then keeps going. Returning early\n // here used to be the whole story, which meant an `unshift` or `splice` notified `items`\n // and nothing beneath it: a component subscribed to the exact path `items.0.title`, the\n // very example the documentation leads with, kept rendering the previous row's title.\n // Guarded rather than filtered afterwards: at the root there is no path to report, and an\n // empty string in the output would read downstream as \"the whole slice\".\n if (a.length !== b.length && path) out.push(path);\n\n // Overlapping indices are compared as usual. With positional paths a shift genuinely\n // changes the value at nearly every index, so this is honest rather than noisy — the\n // remedy for that cost is identity-keyed state, not a diff that stays quiet.\n // The identity check happens *before* the path is built. `walk` would short-circuit on it\n // a line later anyway, but only after this frame had already concatenated a string for a\n // child that turns out to be unchanged — which for the overwhelmingly common shape of an\n // update (one element of many) is one allocation per element that nobody reads.\n const overlap = Math.min(a.length, b.length);\n for (let i = 0; i < overlap; i++) {\n if (a[i] === b[i]) continue;\n walk(a[i], b[i], path ? `${path}.${i}` : `${i}`, ancestors, out);\n }\n\n // Indices present in only one of the two: the element as a whole appeared or vanished,\n // which is the same treatment an added or removed object key gets below.\n for (let i = overlap; i < Math.max(a.length, b.length); i++) {\n out.push(path ? `${path}.${i}` : `${i}`);\n }\n\n return;\n }\n\n const oldKeys = Object.keys(oldState);\n const newKeys = Object.keys(newState);\n\n // Two distinct references with nothing enumerable to compare: any class instance holding its\n // state in private fields or behind accessors lands here. Assume changed rather than equal —\n // the alternative is the silent no-op that `Map` and `Set` used to produce, and a false\n // \"changed\" costs a render while a false \"unchanged\" costs correctness.\n if (oldKeys.length === 0 && newKeys.length === 0) {\n out.push(path);\n return;\n }\n\n // Whether both sides carry exactly the same keys, which is the overwhelmingly common case:\n // an update changes values, not shape. Equal counts plus one-way containment is enough to\n // conclude it — a key of `newState` missing from `oldState` would have to be balanced by a\n // key of `oldState` missing from `newState`, and the counts forbid that.\n //\n // Worth establishing because the alternative is materialising the union, and that union used\n // to be built unconditionally: two key arrays and a `Set` per object, at every level of the\n // tree. On a thousand-entity normalised map — the exact shape `createEntityAdapter` steers\n // people toward — that allocation was most of the diff's cost.\n let sameKeys = oldKeys.length === newKeys.length;\n if (sameKeys) {\n for (let i = 0; i < newKeys.length; i++) {\n if (!Object.prototype.hasOwnProperty.call(oldState, newKeys[i]!)) {\n sameKeys = false;\n break;\n }\n }\n }\n\n if (sameKeys) {\n for (const key of newKeys) {\n // Skip before building a path. `walk` would short-circuit on this identity a line later\n // anyway, but only after this frame had already concatenated a string for a child that\n // turns out to be unchanged — one allocation per key that nobody reads, which for the\n // common shape of an update (one field of many) is nearly all of them.\n if (oldState[key] === newState[key]) continue;\n // A key containing a dot cannot survive the join: `{ \"a.b\": 1 }` and `{ a: { b: 1 } }`\n // both produce \"a.b\", so a subscription and a devtools patch pointing at one silently\n // address the other. Nothing downstream can recover the difference from the string, which\n // is why this is said here, where the key is still intact.\n if (process.env.NODE_ENV !== \"production\" && key.includes(\".\")) warnDottedKey(path, key);\n walk(oldState[key], newState[key], path ? `${path}.${key}` : key, ancestors, out);\n }\n return;\n }\n\n // The shapes differ, so both sides have to be visited — but still without materialising a\n // union. Two passes over the key lists find additions and removals directly; building a\n // `Set` of every key on both sides to iterate once costs more than walking each list.\n for (const key of newKeys) {\n const hasOld = Object.prototype.hasOwnProperty.call(oldState, key);\n // Only compare values once presence is established: with differing shapes, `oldState[key]`\n // and `newState[key]` both read `undefined` for a key genuinely absent from one side, and\n // that is a change rather than a match.\n if (hasOld && oldState[key] === newState[key]) continue;\n if (process.env.NODE_ENV !== \"production\" && key.includes(\".\")) warnDottedKey(path, key);\n const nextPath = path ? `${path}.${key}` : key;\n if (!hasOld) {\n out.push(nextPath);\n continue;\n }\n walk(oldState[key], newState[key], nextPath, ancestors, out);\n }\n\n for (const key of oldKeys) {\n if (Object.prototype.hasOwnProperty.call(newState, key)) continue;\n if (process.env.NODE_ENV !== \"production\" && key.includes(\".\")) warnDottedKey(path, key);\n out.push(path ? `${path}.${key}` : key);\n }\n } finally {\n // Unwind: leave the current recursion path so sibling branches can revisit\n // this pair (legitimate aliasing) without being suppressed as a cycle.\n onPath.delete(newObj);\n if (onPath.size === 0) ancestors.delete(oldObj);\n }\n}\n","/**\n * @module @yoltra/core\n */\n\nimport type { DeepReadonly } from \"../types\";\n\n/**\n * Deep-freezes a value **in place** and returns it as {@link DeepReadonly | `DeepReadonly<T>`}.\n *\n * @typeParam T - The input value type to freeze.\n * @param obj - Any value; objects and arrays are frozen recursively.\n * @param seen - (Advanced) A `WeakSet` used to track visited objects for cycle/alias safety.\n * @returns The **same** reference as `obj`, but frozen and typed as `DeepReadonly<T>`.\n *\n * @remarks\n * - **In-place**: this function mutates the input by freezing it and its children, then returns it.\n * - **Early exits**:\n * - Primitives and `null` are returned as-is.\n * - Already-frozen objects (`Object.isFrozen(obj)`) are returned as-is.\n * - Previously seen objects (by identity) are returned as-is to avoid infinite recursion on cycles.\n * - **Arrays**: freezes each element, then `Object.freeze(array)`. Length/property descriptors are not rewritten.\n * - **Objects**: iterates **own** string and symbol keys. Only **data properties** are recursed (getters/setters are skipped).\n * - **Strict mode**: Mutating a frozen object throws; in non-strict mode it is a no-op (per JS semantics).\n *\n * @example Basic usage\n * ```ts\n * const state = { user: { name: 'Ada' }, items: [1, { id: 1 }] };\n * const frozen = freezeState(state);\n *\n * Object.isFrozen(frozen); // true\n * Object.isFrozen(frozen.user); // true\n * Object.isFrozen(frozen.items); // true\n * Object.isFrozen(frozen.items[1]); // true\n * ```\n *\n * @example Safe with cycles\n * ```ts\n * const a: any = {};\n * a.self = a; // cycle\n * freezeState(a); // does not recurse infinitely\n * ```\n *\n * @example Already frozen objects are returned as-is\n * ```ts\n * const o = Object.freeze({ x: 1 });\n * const out = freezeState(o);\n * out === o; // true\n * ```\n *\n * @public\n */\nexport function freezeState<T>(\n obj: T,\n seen = new WeakSet<object>(),\n alias?: AliasWatch,\n): DeepReadonly<T> {\n if (obj === null || typeof obj !== \"object\") return obj as any;\n if (seen.has(obj as any)) return obj as any;\n\n // Reported before the early-exit on already-frozen values, so a payload stored twice is still\n // named the second time.\n if (alias !== undefined && obj === alias.watch) alias.onFound();\n\n if (Object.isFrozen(obj)) return obj as any;\n\n seen.add(obj as any);\n\n // Arrays: handle indices only (skip length descriptor churn)\n if (Array.isArray(obj)) {\n const arr = obj as unknown as any[];\n for (let i = 0; i < arr.length; i++) {\n arr[i] = freezeState(arr[i], seen, alias);\n }\n return Object.freeze(arr) as any;\n }\n\n // Plain objects: freeze string and symbol props (value descriptors only)\n for (const key of Object.getOwnPropertyNames(obj)) {\n const desc = Object.getOwnPropertyDescriptor(obj, key);\n if (!desc || !(\"value\" in desc)) continue; // skip getters/setters\n (obj as any)[key] = freezeState((obj as any)[key], seen, alias);\n }\n for (const sym of Object.getOwnPropertySymbols(obj)) {\n const desc = Object.getOwnPropertyDescriptor(obj, sym);\n if (!desc || !(\"value\" in desc)) continue;\n (obj as any)[sym as any] = freezeState((obj as any)[sym as any], seen, alias);\n }\n\n return Object.freeze(obj) as any;\n}\n\n/**\n * Watches the freeze walk for one specific reference.\n *\n * @remarks\n * Exists to turn a dev-only heisenbug into a named warning. Because the freeze is deep and\n * in place, anything a reducer stores **by reference** is frozen too — the event payload, a\n * module-level default, a cached response. Mutating that object afterwards then throws, only in\n * development, from a stack that has nothing to do with the store, and the same code works in\n * production because the freeze is compiled out.\n *\n * Freezing it is not the mistake: an object reachable from state genuinely must not be mutated,\n * or state changes behind the store's back. Keeping the reference is. The walk already visits\n * every node, so recognising one of them costs an identity comparison and lets the store say so\n * at the moment it happens.\n *\n * @public\n */\nexport interface AliasWatch {\n /** The reference to look for while freezing. */\n readonly watch: object;\n /** Called if `watch` is reachable from the value being frozen. */\n readonly onFound: () => void;\n}","/**\n * @module @yoltra/core\n */\n\n/**\n * Brand identifying a {@link Rejection}.\n *\n * @remarks\n * `Symbol.for` rather than `Symbol()`, so the brand survives two copies of this package meeting\n * at runtime — a duplicated dependency, a bundle that inlined a second copy, a consumer that\n * pinned an older minor. With a unique symbol the check would silently answer `false` across that boundary and a\n * refusal would read as ordinary state, which is the failure this whole feature exists to end.\n *\n * @internal\n */\nconst REJECTED = Symbol.for(\"yoltra.rejected\");\n\n/**\n * A reducer's refusal to apply a write, carrying the reason.\n *\n * @remarks\n * Distinct from a reducer returning its state unchanged, which is indistinguishable from \"the\n * event did not concern me\". A `Rejection` says *this write was considered and declined*, and it\n * says why — which is what a contended store needs and what a lost update otherwise costs.\n *\n * @public\n */\nexport interface Rejection {\n readonly [REJECTED]: true;\n /** Why the write was refused. Surfaced to the caller and to `onRejected`. */\n readonly reason: string;\n}\n\n/**\n * Builds a {@link Rejection} for a reducer to return instead of state.\n *\n * @param reason - Why the write is refused; surfaced verbatim to the caller.\n *\n * @remarks\n * Rejecting is a whole-event act: no slice commits, no change notifications fire, and the\n * caller's `emit` resolves reporting the refusal. A reducer that merely has nothing to do should\n * return its state, not this.\n *\n * @example Compare-and-swap on a contended slice\n * ```ts\n * reducer: (state, event) =>\n * event.payload.expectedVersion === state.version\n * ? { ...state, ...event.payload.patch, version: state.version + 1 }\n * : Rejected(`stale write: expected v${event.payload.expectedVersion}, have v${state.version}`)\n * ```\n *\n * @public\n */\nexport function Rejected(reason: string): Rejection {\n return { [REJECTED]: true, reason };\n}\n\n/**\n * Whether a reducer returned a {@link Rejection} rather than state.\n *\n * @public\n */\nexport function isRejected(value: unknown): value is Rejection {\n return (\n typeof value === \"object\" &&\n value !== null &&\n (value as { [REJECTED]?: unknown })[REJECTED] === true\n );\n}\n","/**\n * @module @yoltra/core\n */\n\nimport type { EventMapBase, EventUnion } from \"../types\";\n\n/**\n * Which reply events end a {@link StoreInstance.call | call}, and therefore what it resolves to.\n *\n * @remarks\n * Given as `[channel]` or `[channel, type]` or `[channel, [type, type]]`. The named types are\n * **terminal**: the first one to arrive settles the call. Every other correlated event on that\n * channel is progress.\n *\n * Naming a channel alone makes every event on it terminal, which suits a responder with a single\n * kind of answer. Naming types is what lets a responder stream: `[\"rpc\", [\"answer\", \"error\"]]`\n * ends on either, and anything else — `progress`, `partial`, `log` — flows to the consumer.\n *\n * @public\n */\nexport type ReplySpec<EM extends EventMapBase> =\n | readonly [channel: keyof EM & string]\n | readonly [channel: keyof EM & string, type: string]\n | readonly [channel: keyof EM & string, types: readonly string[]];\n\n/**\n * Options for {@link StoreInstance.call}.\n *\n * @public\n */\nexport interface CallOptions<EM extends EventMapBase> {\n /** Which reply events end the call. See {@link ReplySpec}. */\n readonly reply: ReplySpec<EM>;\n\n /**\n * How long the call may sit **idle** before it gives up, in milliseconds.\n *\n * @remarks\n * Idle, not total: every correlated event resets it, progress included. A job that streams for\n * two minutes must not fail a thirty-second call, and a total deadline would make the timeout a\n * function of how much work the responder had to do rather than whether it is still alive.\n *\n * For a genuine deadline — \"this must be finished by then, however lively\" — use\n * {@link CallOptions.signal} with an `AbortSignal.timeout()`.\n *\n * @default 30000\n */\n readonly timeoutMs?: number;\n\n /**\n * Aborts the call. The returned promise rejects and the iterator ends.\n *\n * @remarks\n * Unlike `timeoutMs` this is absolute, so it is the right tool for a request deadline, a\n * user-cancelled action, or a component unmounting.\n */\n readonly signal?: AbortSignal;\n\n /**\n * How many progress events may buffer before the producer is made to wait.\n *\n * @remarks\n * Only meaningful once the caller is iterating. See {@link StoreInstance.call} for what\n * backpressure means here and when it engages.\n *\n * @default 16\n */\n readonly highWaterMark?: number;\n\n /**\n * Correlate on this id instead of on causality.\n *\n * @remarks\n * Causal matching — a reply is correlated because the store stamped it as *caused by* the\n * request — is free and cannot be forged, but only holds in one process. A reply arriving from\n * another node, a worker, or any transport carries no causal link, so for those the responder\n * echoes an id and both sides agree on it here.\n *\n * When set, the id is sent as `meta.correlationId` and a reply matches if it echoes the same\n * value **or** is causally descended. Causality still wins where it applies, so a local\n * responder needs no changes to be compatible with a remote one.\n */\n readonly correlationId?: string;\n}\n\n/**\n * The result of {@link StoreInstance.call}: awaitable for the terminal reply, async-iterable for\n * progress.\n *\n * @typeParam TReply - The terminal reply event.\n * @typeParam TProgress - Non-terminal correlated events.\n *\n * @remarks\n * One object serving both shapes, rather than two functions, because the caller's intent is not\n * known at the call site — the same request may be awaited in one place and streamed in another,\n * and the responder should not have to care which.\n *\n * ```ts\n * // Await the answer, ignore the running commentary.\n * const done = await store.call(\"rpc\", \"ask\", { q }, { reply: [\"rpc\", \"answer\"] });\n *\n * // Or consume the commentary, then take the answer.\n * const call = store.call(\"rpc\", \"ask\", { q }, { reply: [\"rpc\", \"answer\"] });\n * for await (const step of call) render(step.payload);\n * const answer = await call;\n * ```\n *\n * Awaiting the same call twice is safe and yields the same reply; the terminal event is retained.\n *\n * @public\n */\nexport interface CallHandle<TReply, TProgress> extends Promise<TReply>, AsyncIterable<TProgress> {\n /**\n * Progress events discarded because nothing was iterating.\n *\n * @remarks\n * Zero unless the call was awaited without being iterated *and* the responder streamed more\n * than `highWaterMark` events. Non-zero is not an error — it is the honest count of what a\n * caller chose not to read, and is worth logging rather than guessing at.\n */\n readonly dropped: number;\n\n /** Stops listening and settles the call. Safe to call more than once. */\n cancel(reason?: string): void;\n}\n\n/**\n * Raised when a call goes {@link CallOptions.timeoutMs} without a correlated event.\n *\n * @public\n */\nexport class CallTimeoutError extends Error {\n readonly channel: string;\n readonly type: string;\n readonly idleMs: number;\n\n constructor(channel: string, type: string, idleMs: number) {\n super(\n `[yoltra] call to \"${channel}/${type}\" saw no correlated reply for ${idleMs}ms. ` +\n `The timeout is idle rather than total, so this means the responder went quiet, not ` +\n `that it was slow. Check that something handles \"${channel}/${type}\" and that its reply ` +\n `is emitted through the \\`emit\\` it was handed — a reply emitted from an unrelated ` +\n `context carries no causal link, and needs an explicit correlationId instead.`,\n );\n this.name = \"CallTimeoutError\";\n this.channel = channel;\n this.type = type;\n this.idleMs = idleMs;\n }\n}\n\n/**\n * Raised when a call is cancelled, or its {@link CallOptions.signal} aborts.\n *\n * @public\n */\nexport class CallAbortedError extends Error {\n constructor(reason: string) {\n super(`[yoltra] call aborted: ${reason}`);\n this.name = \"CallAbortedError\";\n }\n}\n\n/**\n * Normalises a {@link ReplySpec} into a channel and a terminal-type test.\n *\n * @internal\n */\nexport function parseReply<EM extends EventMapBase>(\n reply: ReplySpec<EM>,\n): { channel: string; isTerminal: (type: string) => boolean } {\n const [channel, types] = reply as readonly [string, (string | readonly string[])?];\n\n // A channel on its own means every reply on it ends the call — the shape a responder with one\n // kind of answer takes, and the one where naming the type would be noise.\n if (types === undefined) return { channel, isTerminal: () => true };\n\n if (typeof types === \"string\") return { channel, isTerminal: (t) => t === types };\n\n const set = new Set(types);\n return { channel, isTerminal: (t) => set.has(t) };\n}\n\n/**\n * Whether `event` is a reply to the request identified by `requestId` / `correlationId`.\n *\n * @remarks\n * Causality first: the store stamps `parentId` on anything emitted while handling an event, so a\n * responder that answers through the `emit` it was given is correlated without doing anything.\n * The explicit id is the fallback for replies that crossed a boundary causality cannot.\n *\n * @internal\n */\nexport function isReplyTo<EM extends EventMapBase>(\n event: EventUnion<EM>,\n requestId: string,\n correlationId: string | undefined,\n): boolean {\n if (event.parentId === requestId) return true;\n if (correlationId === undefined) return false;\n return (event.meta as { correlationId?: unknown } | undefined)?.correlationId === correlationId;\n}\n","/**\n * @module @yoltra/core\n */\n\n/**\n * A bounded hand-off queue between one producer and one consumer, where **the producer waits**.\n *\n * @remarks\n * This is what makes {@link StoreInstance.call}'s backpressure real rather than decorative. A\n * plain buffer accepts everything and grows; this one hands the producer a promise that does not\n * resolve until the consumer has taken an item. Because the store awaits effects, and `emit`\n * resolves only once its effects have finished, a producer writing\n *\n * ```ts\n * await emit(\"rpc\", \"progress\", chunk);\n * ```\n *\n * genuinely blocks until the consumer catches up — end to end, through machinery that already\n * existed, with nothing polling and nothing dropped.\n *\n * **Backpressure only engages once the consumer has begun iterating.** Before that, items buffer\n * up to `highWaterMark` and further ones are counted and discarded. That asymmetry is deliberate:\n * a caller that only awaits the terminal reply never pulls, so blocking the producer would\n * deadlock the very call it is feeding — the producer would be waiting to deliver progress\n * nobody will read, and would therefore never emit the terminal event that ends the wait.\n *\n * @internal\n */\nexport class CallQueue<T> {\n private readonly buffer: T[] = [];\n\n /** Consumers parked in `take`, oldest first. */\n private readonly takers: Array<(value: IteratorResult<T>) => void> = [];\n\n /** Producers parked in `put`, each with the item they are waiting to hand over. */\n private readonly putters: Array<{ item: T; release: () => void }> = [];\n\n private consuming = false;\n\n /** No more items will be accepted, but what is already here is still owed to the consumer. */\n private ended = false;\n\n /** Abandoned: nothing further is owed to anybody. */\n private closed = false;\n\n /** Items discarded because nobody was iterating and the buffer was full. */\n private dropped = 0;\n\n constructor(private readonly highWaterMark: number) {}\n\n /** How many items were discarded for want of a consumer. */\n get droppedCount(): number {\n return this.dropped;\n }\n\n /**\n * Marks that a consumer has started pulling. From here on, a full buffer parks the producer\n * rather than dropping.\n */\n beginConsuming(): void {\n this.consuming = true;\n }\n\n /**\n * Offers an item. The returned promise settles when the item has been taken — or immediately,\n * if it fit in the buffer or was dropped.\n */\n put(item: T): Promise<void> {\n if (this.closed || this.ended) return Promise.resolve();\n\n // A parked consumer takes it directly; no buffering, no waiting either way.\n const taker = this.takers.shift();\n if (taker !== undefined) {\n taker({ value: item, done: false });\n return Promise.resolve();\n }\n\n if (this.buffer.length < this.highWaterMark) {\n this.buffer.push(item);\n return Promise.resolve();\n }\n\n if (!this.consuming) {\n // Nobody is reading and nobody has said they will. Dropping is the only option that does\n // not deadlock the producer — see the note on this class.\n this.dropped++;\n return Promise.resolve();\n }\n\n return new Promise<void>((release) => {\n this.putters.push({ item, release });\n });\n }\n\n /** Takes the next item, waiting if none is available. Resolves `done` once closed and drained. */\n take(): Promise<IteratorResult<T>> {\n this.consuming = true;\n\n const buffered = this.buffer.shift();\n if (buffered !== undefined) {\n // A parked producer can now hand its item to the space just freed.\n const putter = this.putters.shift();\n if (putter !== undefined) {\n this.buffer.push(putter.item);\n putter.release();\n }\n return Promise.resolve({ value: buffered, done: false });\n }\n\n // Nothing buffered, but a producer is parked: take directly from it.\n const putter = this.putters.shift();\n if (putter !== undefined) {\n putter.release();\n return Promise.resolve({ value: putter.item, done: false });\n }\n\n // Nothing left to hand over. `ended` counts here as well as `closed`: the terminal reply has\n // arrived and the buffer is drained, so the stream is genuinely over.\n if (this.closed || this.ended) return Promise.resolve({ value: undefined, done: true });\n\n return new Promise<IteratorResult<T>>((taker) => {\n this.takers.push(taker);\n });\n }\n\n /**\n * Stops accepting items, but keeps owing the consumer everything already queued.\n *\n * @remarks\n * What the terminal reply does. Closing outright at that moment would throw away progress the\n * responder had already handed over and the consumer had not yet read — which is exactly what\n * happened before this existed: a six-step job delivered five steps, because the sixth was in\n * the buffer when `done` arrived and the buffer was cleared. The terminal event says \"no more\n * is coming\", not \"forget what you were given\".\n */\n end(): void {\n if (this.ended || this.closed) return;\n this.ended = true;\n\n // Anything a producer is still parked with was sent before the terminal, so it is owed.\n let putter = this.putters.shift();\n while (putter !== undefined) {\n this.buffer.push(putter.item);\n putter.release();\n putter = this.putters.shift();\n }\n\n // Hand the buffer to anyone already waiting, then tell the rest we are done.\n let taker = this.takers.shift();\n while (taker !== undefined) {\n const next = this.buffer.shift();\n taker(\n next !== undefined\n ? { value: next, done: false }\n : { value: undefined, done: true },\n );\n taker = this.takers.shift();\n }\n }\n\n /**\n * Closes the queue: waiting consumers are told `done`, and **every parked producer is\n * released**.\n *\n * @remarks\n * Releasing producers is not tidying up. A producer parked on `put` is a pending `await emit`\n * somewhere; leaving it parked when the call has already settled would hang the responder for\n * good — turning a timed-out call into a wedged process, which is worse than the problem\n * backpressure was added to solve.\n */\n close(): void {\n if (this.closed) return;\n this.closed = true;\n this.buffer.length = 0;\n\n let taker = this.takers.shift();\n while (taker !== undefined) {\n taker({ value: undefined, done: true });\n taker = this.takers.shift();\n }\n\n let putter = this.putters.shift();\n while (putter !== undefined) {\n putter.release();\n putter = this.putters.shift();\n }\n }\n}\n","/**\n * The orchestration behind `store.call()`.\n *\n * @remarks\n * Moved out of `Store.ts` unchanged, and it lands beside the types and the queue it already\n * used. The seam is three members wide, which is what made this one extractable: the body mints\n * an id, registers a collector effect, and emits the request. It reaches nothing else.\n *\n * `registerEffect` and `emit` arrive as bound references, since `Store` binds both in its\n * constructor. `Store.call` keeps its signature and its explicit return type.\n *\n * @module\n */\n\nimport type {\n DeepReadonly,\n EffectSpec,\n EmitOptions,\n EmitResult,\n EventMapBase,\n EventUnion,\n} from \"../types\";\nimport {\n CallAbortedError,\n CallTimeoutError,\n type CallHandle,\n type CallOptions,\n parseReply,\n isReplyTo,\n} from \"./call\";\nimport { CallQueue } from \"./callQueue\";\n\n/** Idle time a {@link performCall} tolerates before giving up. */\nconst DEFAULT_CALL_TIMEOUT_MS = 30_000;\n\n/** Progress events a call buffers before pacing the producer. */\nconst DEFAULT_CALL_WATERMARK = 16;\n\n/**\n * What `performCall` needs from the store.\n *\n * @remarks\n * Three members, named rather than structural over the whole class, because three is few enough\n * that naming them documents the coupling instead of hiding it.\n */\nexport interface CallDeps<St, EM extends EventMapBase> {\n readonly idFactory: () => string;\n readonly registerEffect: (spec: EffectSpec<DeepReadonly<St>, EM>) => () => void;\n readonly emit: <C extends keyof EM & string, T extends keyof EM[C] & string>(\n channel: C,\n type: T,\n payload: EM[C][T],\n opts?: EmitOptions,\n ) => Promise<EmitResult>;\n}\n\nexport function performCall<\n St,\n EM extends EventMapBase,\n C extends keyof EM & string,\n T extends keyof EM[C] & string,\n>(\n deps: CallDeps<St, EM>,\n channel: C,\n type: T,\n payload: EM[C][T],\n opts: CallOptions<EM>,\n): CallHandle<EventUnion<EM>, EventUnion<EM>> {\n const { channel: replyChannel, isTerminal } = parseReply<EM>(opts.reply);\n const idleMs = opts.timeoutMs ?? DEFAULT_CALL_TIMEOUT_MS;\n const queue = new CallQueue<EventUnion<EM>>(opts.highWaterMark ?? DEFAULT_CALL_WATERMARK);\n\n // Minted here rather than left to `emit`, because the correlation has to be known before the\n // request goes out — a reply can arrive during the emit itself, synchronously.\n const requestId = deps.idFactory();\n\n let settle!: (event: EventUnion<EM>) => void;\n let fail!: (error: Error) => void;\n let settled = false;\n const terminal = new Promise<EventUnion<EM>>((resolve, reject) => {\n settle = resolve;\n fail = reject;\n });\n // Attached immediately so a rejection that nobody has awaited yet is not reported as\n // unhandled; the caller's own await still sees it.\n terminal.catch(() => undefined);\n\n let timer: ReturnType<typeof setTimeout> | null = null;\n let unregister: (() => void) | null = null;\n\n /**\n * Settles the call once. `graceful` distinguishes a terminal reply — after which the\n * consumer is still owed whatever progress it has not read — from an abort, after which\n * nothing is owed to anyone.\n */\n const finish = (fn: () => void, graceful = false): void => {\n if (settled) return;\n settled = true;\n if (timer !== null) clearTimeout(timer);\n timer = null;\n unregister?.();\n unregister = null;\n if (graceful) queue.end();\n else queue.close();\n opts.signal?.removeEventListener(\"abort\", onAbort);\n fn();\n };\n\n function onAbort(): void {\n finish(() => fail(new CallAbortedError(String(opts.signal?.reason ?? \"signal aborted\"))));\n }\n\n const arm = (): void => {\n if (timer !== null) clearTimeout(timer);\n // Idle: every correlated event pushes the deadline out, so a streaming responder is not\n // punished for having a lot to say.\n timer = setTimeout(() => {\n finish(() => fail(new CallTimeoutError(channel, type, idleMs)));\n }, idleMs);\n (timer as { unref?: () => void }).unref?.();\n };\n\n unregister = deps.registerEffect({\n // A pattern effect on the reply channel: which types are terminal is known, which are\n // progress is not, so the filter cannot be a key list.\n when: { channel: replyChannel as keyof EM & string },\n effect: async (event) => {\n if (settled) return;\n if (!isReplyTo<EM>(event, requestId, opts.correlationId)) return;\n\n arm();\n\n if (isTerminal(String(event.type))) {\n finish(() => settle(event), true);\n return;\n }\n\n // The await is the backpressure. This runs inside the store's effect phase, so the\n // responder's own `await emit(...)` does not resolve until it returns.\n await queue.put(event);\n },\n });\n\n if (opts.signal !== undefined) {\n if (opts.signal.aborted) onAbort();\n else opts.signal.addEventListener(\"abort\", onAbort, { once: true });\n }\n\n arm();\n\n void deps.emit(channel, type, payload, {\n id: requestId,\n ...(opts.correlationId !== undefined\n ? { meta: { correlationId: opts.correlationId } }\n : {}),\n });\n\n const handle = {\n then: (onOk?: never, onErr?: never) => terminal.then(onOk, onErr),\n catch: (onErr?: never) => terminal.catch(onErr),\n finally: (onDone?: () => void) => terminal.finally(onDone),\n get dropped() {\n return queue.droppedCount;\n },\n cancel: (reason = \"cancelled\") => {\n finish(() => fail(new CallAbortedError(reason)));\n },\n [Symbol.asyncIterator]: (): AsyncIterator<EventUnion<EM>> => {\n queue.beginConsuming();\n return {\n next: () => queue.take(),\n // Called by `for await` on `break`, `return` or a throw. Without it, abandoning the\n // loop would leave the effect registered and the producer parked for good.\n return: async () => {\n queue.close();\n return { value: undefined, done: true };\n },\n };\n },\n } as CallHandle<EventUnion<EM>, EventUnion<EM>>;\n\n return handle;\n}\n","/**\n * Reading and expanding dotted state paths.\n *\n * @remarks\n * Moved out of `Store.ts` unchanged. Neither function touched an instance field.\n *\n * `Store` still exposes both as members, and deliberately so. `Store.buildAncestorPaths` is\n * public API that appears in the committed reference, and `getAtPath` is replaced on the\n * instance by a test that counts the walks a change description costs, so the internal callers\n * have to keep reaching it through `this`.\n *\n * @module\n */\n\n/**\n * Reads a dotted path from an object (supports numeric array indices via string keys).\n *\n * @param obj - Root object (slice or value).\n * @param path - Dotted path; leading dot is ignored.\n * @returns The value at the path, or `undefined`.\n *\n * @internal\n */\nexport function getAtPath(obj: any, path: string): any {\n if (!path) return obj;\n\n // Normalize any accidental leading dots\n const clean = path[0] === \".\" ? path.slice(1) : path;\n const parts = clean.split(\".\");\n\n let cur = obj;\n for (const seg of parts) {\n if (cur == null) return undefined;\n cur = cur[seg as any];\n }\n return cur;\n}\n\n/**\n * Builds ancestor paths for a dotted path.\n *\n * For `\"a.b.c\"`, returns `[\"a\", \"a.b\", \"a.b.c\"]`. Leading dots are trimmed.\n *\n * @param path - Dotted path string.\n * @returns Array of ancestor paths.\n *\n * @example\n * ```ts\n * buildAncestorPaths('x.y.z'); // ['x','x.y','x.y.z']\n * ```\n *\n * @public\n */\nexport function buildAncestorPaths(path: string): string[] {\n if (!path) return [];\n\n const clean = path[0] === \".\" ? path.slice(1) : path;\n const parts = clean.split(\".\");\n const out: string[] = [];\n\n for (let i = 0; i < parts.length; i++) {\n out.push(parts.slice(0, i + 1).join(\".\"));\n }\n\n return out;\n}\n","/**\n * Event targeting: deciding whether an event matches a `When` matcher, and reading the parts of\n * a middleware declaration.\n *\n * @remarks\n * Moved out of `Store.ts` unchanged. These four functions never touched an instance field, so\n * they were already free functions wearing method clothing, and the class kept them only because\n * that is where they were written.\n *\n * @module\n */\n\nimport type {\n EventKey,\n EventMapBase,\n EventUnion,\n MiddlewareFunction,\n MiddlewareInput,\n When,\n} from \"../types\";\n\n/**\n * Checks if an event matches a `When` matcher.\n *\n * @param when - The When matcher (or undefined for \"all events\").\n * @param event - The event to check.\n * @returns `true` if the event matches, `false` otherwise.\n *\n * @remarks\n * - `undefined` or missing `when` matches ALL events.\n * - `{ any: true }` matches ALL events.\n * - `{ keys: [...] }` matches if event's `[channel, type]` is in the array.\n * - `{ channel: 'x' }` matches if event's channel equals 'x'.\n * - `{ channels: ['x', 'y'] }` matches if event's channel is in the array.\n *\n * @internal\n */\nexport function matchesWhen<EM extends EventMapBase>(\n when: When<EM> | undefined,\n event: EventUnion<EM>,\n): boolean {\n // No targeting = match all events\n if (!when) return true;\n\n // Match all events\n if (\"any\" in when && when.any === true) {\n return true;\n }\n\n // Match specific event keys\n if (\"keys\" in when) {\n return when.keys.some(\n ([channel, type]) => event.channel === channel && event.type === type,\n );\n }\n\n // Match single channel (all types within that channel)\n if (\"channel\" in when) {\n return event.channel === when.channel;\n }\n\n // Match multiple channels\n if (\"channels\" in when) {\n return when.channels.includes(event.channel as keyof EM & string);\n }\n\n return false;\n}\n\n/**\n * Extracts the middleware function from a MiddlewareInput.\n * Handles both raw functions (legacy) and MiddlewareSpec objects.\n *\n * @param input - MiddlewareInput (function or spec).\n * @returns The middleware function.\n *\n * @internal\n */\nexport function getMiddlewareFunction<St, EM extends EventMapBase>(\n input: MiddlewareInput<St, EM>,\n): MiddlewareFunction<St, EM> {\n if (typeof input === \"function\") {\n return input;\n }\n return input.middleware;\n}\n\n/**\n * Gets the `when` matcher from a MiddlewareInput.\n *\n * @param input - MiddlewareInput (function or spec).\n * @returns The `when` matcher, or `undefined` for raw functions (match all).\n *\n * @internal\n */\nexport function getMiddlewareWhen<St, EM extends EventMapBase>(\n input: MiddlewareInput<St, EM>,\n): When<EM> | undefined {\n if (typeof input === \"function\") {\n // Raw functions match all events\n return undefined;\n }\n return input.when;\n}\n\n/**\n * Normalizes event targeting from `when` to an array of EventKeys.\n *\n * @param spec - Object with an optional `when` matcher.\n * @returns Array of `[channel, type]` pairs.\n *\n * @internal\n */\nexport function normalizeEventKeys<EM extends EventMapBase>(spec: {\n when?: When<EM>;\n events?: ReadonlyArray<EventKey<EM>>;\n}): ReadonlyArray<EventKey<EM>> {\n\n if (spec.when) {\n const when = spec.when;\n\n // Only `keys` can reach this point: both callers intercept pattern-based matchers\n // (`any`, `channel`, `channels`) before normalizing, because those register against the\n // emit loop rather than against per-key handler maps.\n if (\"keys\" in when) {\n return when.keys;\n }\n }\n\n // No targeting specified\n return [];\n}\n","/**\n * @module @yoltra/core\n */\n\nimport { Reducer } from \"../reducer/Reducer\";\nimport { detectChangedProps } from \"../utils/detectChangedProps\";\nimport { EventBus } from \"../eventBus/EventBus\";\nimport { LooseEventBus } from \"../eventBus/LooseEventBus\";\nimport type {\n Event,\n EventMapBase,\n EventKey,\n EventUnion,\n Change,\n DeepReadonly,\n EffectFunction,\n EffectSpec,\n EventConsumerMeta,\n EventMeta,\n MiddlewareFunction,\n MiddlewareInput,\n MiddlewareSpec,\n ReducersMapAny,\n ReducerSpec,\n StateFromReducers,\n StoreInstance,\n StoreSpec,\n Unsubscribe,\n EMFromReducersStrict,\n Emit,\n EmitOptions,\n EmitResult,\n ConnectOptions,\n InstrumentationObserver,\n CascadeInfo,\n InstrumentedEvent,\n EventPhase,\n EventSubscriptionHandler,\n NarrowedEventHandler,\n When,\n} from \"../types\";\nimport { freezeState } from \"../utils/immutability\";\nimport { isRejected } from \"./rejection\";\nimport type { CallHandle, CallOptions } from \"./call\";\nimport { performCall } from \"./performCall\";\nimport type { Rejection } from \"./rejection\";\nimport type { AliasWatch } from \"../utils/immutability\";\nimport {\n buildAncestorPaths as ancestorPaths,\n getAtPath as readAtPath,\n} from \"./paths\";\nimport {\n getMiddlewareFunction,\n getMiddlewareWhen,\n matchesWhen,\n normalizeEventKeys,\n} from \"./matching\";\n\n/**\n * Deep-freezes a value **in development only**, returning it untouched in\n * production.\n *\n * @remarks\n * Deep-freezing is a dev-time guard against accidental state mutation; in\n * production it is pure overhead. Because {@link freezeState} freezes in place\n * and early-exits on already-frozen nodes, freezing a structurally-shared value\n * touches only the **newly-created** nodes — O(change), not O(state size). This\n * is why the write path does **not** deep-clone before freezing.\n *\n * @internal\n */\n/**\n * Copies a slice's initial state so the store owns it, naming the slice if it cannot.\n *\n * @remarks\n * `structuredClone` refuses functions and drops class prototypes, and its `DataCloneError`\n * says only that something was uncloneable — not which slice, and not which key. For a store\n * built from several slices at once that leaves the developer bisecting their own\n * configuration. The message here names the slice and points at the usual cause.\n *\n * @internal\n */\nfunction cloneInitialState<T>(sliceName: unknown, state: T): T {\n try {\n return structuredClone(state);\n } catch (err) {\n throw new Error(\n `[yoltra] Initial state for slice \"${String(sliceName)}\" could not be copied: ` +\n `${err instanceof Error ? err.message : String(err)}. State must be structured-cloneable ` +\n `— functions, class instances and DOM nodes are not. Keep behaviour out of state and ` +\n `store plain data.`,\n );\n }\n}\n\nfunction freezeInDev<T>(value: T, alias?: AliasWatch): DeepReadonly<T> {\n return process.env.NODE_ENV === \"production\"\n ? (value as unknown as DeepReadonly<T>)\n : freezeState(value, new WeakSet<object>(), alias);\n}\n\n/**\n * Default window (ms) for identity-based dedup via {@link EmitOptions.dedupKey}\n * when content-based dedup (`dedupWindowMs`) is disabled. Large enough to absorb\n * a synchronous re-fire (e.g. React Strict Mode's mount → unmount → mount),\n * small enough not to swallow genuine user repeats.\n */\nconst DEFAULT_DEDUP_KEY_WINDOW_MS = 100;\n\n/**\n * Causal depth at which the store stops extending an event chain.\n *\n * @remarks\n * Chosen to be uncontroversial rather than tight. An event caused by an event caused by an event\n * is ordinary application wiring; sixty-four deep is a cycle. The cost of being wrong in the\n * generous direction is a cascade that runs a few more hops before it is named; the cost of being\n * wrong in the strict direction is refusing correct code, which would teach people to raise the\n * limit reflexively and defeat it.\n */\nconst DEFAULT_MAX_REDUCE_DEPTH = 64;\n\n/**\n * How many ancestor ids {@link CascadeInfo.chain} carries.\n *\n * @remarks\n * A cascade is long by definition. The diagnostic value is in the cycle at the end — which\n * handler emitted back into which — not in the several thousand identical hops that preceded it,\n * and retaining all of them would make the guard against runaway memory itself retain\n * unboundedly.\n */\nconst CASCADE_CHAIN_LIMIT = 16;\n\n/**\n * One slice's pending write: computed, frozen, and not yet visible to anybody.\n *\n * @remarks\n * `prev` is retained because change notifications report old and new, and by the time they are\n * built the slice has already been replaced in `this.state` — the whole point of staging.\n *\n * @internal\n */\nconst NOT_COMMITTED: EmitResult = Object.freeze({ committed: false, written: false });\nconst COMMITTED_UNWRITTEN: EmitResult = Object.freeze({ committed: true, written: false });\nconst WRITTEN: EmitResult = Object.freeze({ committed: true, written: true });\n\ninterface StagedSlice {\n readonly name: string;\n readonly prev: unknown;\n readonly frozen: unknown;\n readonly leafPaths: string[];\n}\n\n/**\n * High-resolution monotonic clock in milliseconds for instrumentation timing;\n * falls back to `Date.now()` where `performance` is unavailable.\n */\nconst now = (): number =>\n typeof performance !== \"undefined\" && typeof performance.now === \"function\"\n ? performance.now()\n : Date.now();\n\nexport class Store<EM extends EventMapBase, R extends string, S extends Record<R, any>>\n implements StoreInstance<R, S, EM> {\n /**\n * Store name (used by DevTools & diagnostics).\n *\n * @public\n */\n name: string;\n\n /**\n * Registered middleware pipeline (run **before** reducers).\n * Stores either raw functions (legacy) or MiddlewareSpec objects.\n * Return `false` from the middleware function to stop propagation.\n *\n * @internal\n */\n private readonly middleware: MiddlewareInput<DeepReadonly<S>, EM>[];\n\n /**\n * Installed slice reducers keyed by slice name.\n *\n * @internal\n */\n private readonly reducers: Record<R, Reducer<S[R], EM>>;\n\n /**\n * Current immutable snapshot of the store state.\n * This reference changes whenever any slice changes (shallow immutability).\n *\n * @internal\n */\n private state: DeepReadonly<S>;\n\n /**\n * Bus for reducer wiring (emit by `(channel, type)`).\n *\n * @internal\n */\n private readonly reducerBus: EventBus<EM>;\n\n /**\n * Bus for **granular** connector events (emit by **dotted path** inside a slice).\n *\n * @internal\n */\n private readonly connectorBus: LooseEventBus<R, string, Change>;\n\n /**\n * Coarse-grained listeners (called once per committed event, only if state changed).\n *\n * @internal\n */\n private readonly listeners: Set<() => void> = new Set();\n\n /**\n * Registered effect handlers keyed by `\"channel::type\"` for O(1) lookup.\n * Used for effects with explicit `keys` targeting.\n *\n * @internal\n */\n private readonly effects = new Map<string, Set<EffectFunction<DeepReadonly<S>, EM>>>();\n\n /**\n * Pattern-based effects that need runtime matching.\n * Used for effects with `when: { any }`, `{ channel }`, or `{ channels }`.\n * Stores tuples of [effect function, when matcher].\n *\n * @internal\n */\n private readonly patternEffects = new Set<{\n effect: EffectFunction<DeepReadonly<S>, EM>;\n when: When<EM>;\n }>();\n\n /**\n * Committed event subscribers keyed by `\"channel::type\"` for O(1) lookup.\n * Notified after reducers, before effects, for events that passed middleware.\n *\n * @internal\n */\n private readonly committedEventSubscribers = new Map<\n string,\n Set<EventSubscriptionHandler<DeepReadonly<S>, EM>>\n >();\n\n /**\n * Uncommitted event subscribers keyed by `\"channel::type\"` for O(1) lookup.\n * Notified when middleware rejects an event.\n *\n * @internal\n */\n private readonly uncommittedEventSubscribers = new Map<\n string,\n Set<EventSubscriptionHandler<DeepReadonly<S>, EM>>\n >();\n\n /**\n * All-events subscribers keyed by `\"channel::type\"` for O(1) lookup.\n * Notified for both committed and uncommitted events with phase parameter.\n *\n * @internal\n */\n /**\n * Subscribers to events that actually changed state, notified after the commit.\n *\n * @remarks\n * Separate from `committedEventSubscribers` rather than a filter over it, because the two\n * answer different questions and one of them is load bearing: `committed` means \"not vetoed\"\n * and fires for every event a store accepts, including every event in a store with no\n * reducers. Narrowing it would have silently stopped toasts and analytics firing.\n *\n * @internal\n */\n private readonly writtenEventSubscribers = new Map<\n string,\n Set<EventSubscriptionHandler<DeepReadonly<S>, EM>>\n >();\n\n private readonly allEventSubscribers = new Map<\n string,\n Set<EventSubscriptionHandler<DeepReadonly<S>, EM>>\n >();\n\n /**\n * Track reducerBus unsubs per slice for HMR/register/unregister.\n *\n * @internal\n */\n private readonly sliceUnsubs = new Map<string, Array<() => void>>();\n\n /**\n * Pattern-based reducers that need runtime matching.\n * Used for reducers with `when: { any }`, `{ channel }`, or `{ channels }`.\n * Maps slice name to the `when` matcher.\n *\n * @internal\n */\n private readonly patternReducers = new Map<R, When<EM>>();\n\n /**\n * Whether `__replayEvents()` is allowed.\n * Set from `spec.devtools.allowReplay`.\n *\n * @internal\n */\n private readonly replayEnabled: boolean;\n\n /**\n * Produces the `id` for each emitted event. Defaults to `crypto.randomUUID()`; overridable\n * via {@link StoreSpec.idFactory} for runtimes lacking it or for deterministic tests.\n *\n * @internal\n */\n private readonly idFactory: () => string;\n\n /**\n * Optional hook invoked when an effect throws/rejects. See\n * {@link StoreSpec.onEffectError}. `await emit()` never rejects on effect\n * failure — this is how callers observe effect errors.\n */\n private readonly onEffectError?: (error: unknown, event: EventUnion<EM>) => void;\n\n /**\n * Optional hook invoked when a reducer throws. See {@link StoreSpec.onReducerError}. The\n * failing slice is isolated rather than the event being rolled back, so this is the only\n * signal that a reducer misbehaved.\n */\n private readonly onReducerError?: (\n error: unknown,\n event: EventUnion<EM>,\n slice: string,\n ) => void;\n\n /**\n * `slice:channel:type` combinations already warned about for payload aliasing.\n *\n * @remarks\n * Development-only diagnostics have to stay quiet enough to be read. One warning names the\n * pattern; repeating it once per event would bury it.\n */\n private readonly warnedPayloadAliases = new Set<string>();\n\n /**\n * Pending events awaiting the **synchronous** reduce phase (middleware +\n * reducers + subscribers + coarse listeners). Drained by {@link drainReduce}.\n *\n * @internal\n */\n private readonly reduceQueue: Array<{\n channel: string;\n type: string;\n payload: any;\n id: string;\n meta?: EventMeta;\n resolve: (result: EmitResult) => void;\n parentId?: string;\n depth?: number;\n /** Ancestor ids, for {@link CascadeInfo.chain}. Never surfaced on the event itself. */\n chain?: readonly string[];\n }> = [];\n\n /**\n * Re-entrancy guard for the synchronous reduce phase.\n *\n * @internal\n */\n private isReducing = false;\n\n /**\n * The event currently being reduced, or `null` outside the drain.\n *\n * @remarks\n * This is what makes causality exact rather than best-effort. The drain is synchronous — no\n * `await` can interleave — so any `emit` that arrives while it is set is, without ambiguity, a\n * consequence of this event. That catches the case a scoped `emit` closure cannot: a\n * middleware or subscriber that captured the store and calls `store.emit` directly instead of\n * using the injected one. Attribution should not depend on which reference a consumer reached\n * for.\n *\n * @internal\n */\n private currentEvent: { id: string; depth: number; chain: readonly string[] } | null = null;\n\n /**\n * Events processed by the drain currently in progress. Compared against\n * `maxTransitionsPerDrain`, which is off unless configured.\n *\n * @internal\n */\n private transitionsThisDrain = 0;\n\n /**\n * Ceilings that stop a cascade from becoming a hung process. See {@link StoreSpec.maxReduceDepth}.\n *\n * @internal\n */\n private readonly maxReduceDepth: number;\n private readonly maxTransitionsPerDrain: number;\n private readonly onCascade?: (info: CascadeInfo<EM>) => void;\n private readonly onRejected?: (\n rejection: Rejection,\n event: EventUnion<EM>,\n slice: string,\n ) => void;\n\n /**\n * Registered instrumentation observers (DevTools seam). See {@link instrument}.\n *\n * @internal\n */\n private readonly instrumentObservers = new Set<InstrumentationObserver<EM>>();\n\n /**\n * Scratch array collecting slice-prefixed changed leaf paths during an\n * instrumented reduce. Set by {@link drainReduce} while observers are active;\n * appended to by {@link commitStaged}. `null` when not instrumenting.\n *\n * @internal\n */\n private changedPathSink: string[] | null = null;\n\n /**\n * Where keyed reducers put their pending writes during a reduce, and the refusal one of them\n * returned.\n *\n * @remarks\n * Keyed reducers are invoked through `reducerBus`, which delivers to handlers and has no way\n * to hand a value back — the same reason `changedPathSink` exists. `null` outside a reduce.\n *\n * @internal\n */\n private stagingSink: StagedSlice[] | null = null;\n private stagedRejection: Rejection | null = null;\n private stagedRejectedBy = \"\";\n\n /**\n * Count of effect tasks currently in flight; surfaced as queue depth by\n * {@link __devtoolsIntrospect}.\n *\n * @internal\n */\n private inFlightEffects = 0;\n\n /**\n * Tracks processed events by fingerprint with timestamps for TTL-based deduplication.\n *\n * **Deduplication Behavior:**\n * - Events are fingerprinted using `channel::type::JSON(payload)`\n * - If an identical fingerprint is seen within the dedup window, it's skipped\n * - The window is 50ms in development, 100ms in production\n *\n * **Limitations:**\n * - Non-serializable payloads (functions, symbols, circular refs) get unique\n * fingerprints and won't be deduplicated\n * - Legitimate rapid-fire identical events may be incorrectly deduplicated\n * - The cache is bounded to 1000 entries with lazy pruning\n *\n * @internal\n */\n private readonly processedEvents = new Map<string, number>();\n\n /**\n * Lifetime count of events suppressed by the deduplication cache.\n * Exposed via {@link __devtoolsIntrospect} so the DevTools agent can\n * surface it in the STORE_METRICS response without further core changes.\n *\n * @internal\n */\n private dedupCount = 0;\n\n /**\n * Store-owned metadata for registered effects, keyed by the effect function.\n * Kept **off** the caller's function object: mutating a user-owned function\n * (the old `fn.__quoMeta`) bled metadata across stores that share a handler\n * and left it attached after unregister. Cleared on {@link dispose}.\n *\n * @internal\n */\n private effectMeta = new WeakMap<object, EventConsumerMeta<\"effect\">>();\n\n /**\n * Configuration for event deduplication.\n * @internal\n */\n private readonly dedupConfig: {\n /** Time window in ms for considering events as duplicates */\n windowMs: number;\n /** Maximum cache size to prevent unbounded growth */\n maxCacheSize: number;\n };\n\n /**\n * Timer for periodic cleanup of processed events.\n *\n * @internal\n */\n private eventCleanupTimer: ReturnType<typeof setInterval> | null = null;\n\n /**\n * Creates a store from a {@link StoreSpec}.\n *\n * @param spec - Store configuration (name, reducers, middleware, optional effects).\n *\n * @public\n */\n constructor(spec: StoreSpec<R, S, EM>) {\n this.name = spec.name ?? \"yoltra Store\";\n this.reducerBus = new EventBus<EM>();\n this.connectorBus = new LooseEventBus();\n this.middleware = [...(spec.middleware ?? [])];\n this.reducers = {} as Record<R, Reducer<S[R], EM>>;\n this.state = {} as any;\n this.replayEnabled = spec.devtools?.allowReplay ?? false;\n this.idFactory = spec.idFactory ?? (() => crypto.randomUUID());\n this.onEffectError = spec.onEffectError;\n this.onReducerError = spec.onReducerError;\n\n // Depth is bounded whether or not anybody asked. The queue drains synchronously, so an\n // unbounded cascade is a frozen tab or a pinned core with no error to point at — a failure\n // mode a library should not require configuration to avoid.\n //\n // Width stays opt-in, because wide and deep mean different things: a fan-out (one event whose\n // subscriber emits five hundred siblings) is legitimate and wide, while a cascade is narrow\n // and deep. Depth separates them; a count cannot. See StoreSpec.maxTransitionsPerDrain.\n this.maxReduceDepth = spec.maxReduceDepth ?? DEFAULT_MAX_REDUCE_DEPTH;\n this.maxTransitionsPerDrain = spec.maxTransitionsPerDrain ?? Infinity;\n this.onCascade = spec.onCascade;\n this.onRejected = spec.onRejected;\n\n // Deduplication is OPT-IN. Content-based dedup is OFF by default because it\n // can silently drop legitimate rapid-fire identical events; enable it with\n // `dedupWindowMs > 0`, or use per-emit `dedupKey` for identity-based dedup.\n this.dedupConfig = {\n windowMs: spec.dedupWindowMs ?? 0,\n maxCacheSize: 1000,\n };\n\n /**\n * Reducer wiring\n */\n Object.entries(spec.reducer).forEach(([name, rSpec]) => {\n this.mountSlice(name as R, rSpec as ReducerSpec<S[R], EM>, { preserveState: false });\n });\n\n /**\n * Effects from spec (optional)\n */\n if (spec.effects?.length) {\n for (const effSpec of spec.effects) {\n this.registerEffect(effSpec);\n }\n }\n\n // Event dedup cleanup runs on a lazily-started interval: it begins the first\n // time an entry is cached (content dedup OR identity `dedupKey`) and stops\n // when the cache empties (see ensureCleanupTimer / pruneProcessedEvents).\n // When no dedup is used the cache stays empty, so no timer is ever started\n // and the store never keeps the event loop alive unnecessarily.\n\n /**\n * Method bindings\n */\n this.dispose = this.dispose.bind(this);\n this.notifyEffects = this.notifyEffects.bind(this);\n\n // private API\n this.__applyExternalState = this.__applyExternalState.bind(this);\n this.__replayEvents = this.__replayEvents.bind(this);\n this.__devtoolsIntrospect = this.__devtoolsIntrospect.bind(this);\n this.mountSlice = this.mountSlice.bind(this);\n this.unmountSlice = this.unmountSlice.bind(this);\n this.getAtPath = this.getAtPath.bind(this);\n\n // public API\n this.emit = this.emit.bind(this);\n this.subscribe = this.subscribe.bind(this);\n this.connect = this.connect.bind(this);\n this.onEffect = this.onEffect.bind(this);\n this.onEvent = this.onEvent.bind(this);\n this.getState = this.getState.bind(this);\n this.registerEffect = this.registerEffect.bind(this);\n this.registerMiddleware = this.registerMiddleware.bind(this);\n this.registerReducer = this.registerReducer.bind(this);\n this.replaceMiddleware = this.replaceMiddleware.bind(this);\n this.replaceEffects = this.replaceEffects.bind(this);\n this.replaceReducers = this.replaceReducers.bind(this);\n this.hotReplace = this.hotReplace.bind(this);\n }\n\n /**\n * Cleanup resources (timers, etc.) when disposing the store.\n * Call this if you're dynamically creating/destroying stores.\n *\n * @example\n * ```ts\n * const store = createStore({ ... });\n * // later\n * store.dispose();\n * ```\n *\n * @public\n */\n public dispose(): void {\n if (this.eventCleanupTimer) {\n clearInterval(this.eventCleanupTimer);\n this.eventCleanupTimer = null;\n }\n\n this.processedEvents.clear();\n this.effects.clear();\n this.patternEffects.clear();\n this.effectMeta = new WeakMap();\n\n // The once-per-slice-and-event latch for the payload-aliasing warning. Left populated, a\n // disposed-and-recreated store — per-route stores, HMR, a test suite building one per case —\n // inherits the suppression and stays quiet about aliasing in code that has never been warned\n // about. The latch exists to stop a hot path becoming a log, not to silence the next store.\n this.warnedPayloadAliases.clear();\n\n // Release every subscription and observer. Without this, the closures they\n // hold (React fibers, DevTools sockets, effect handlers) pin the store and\n // leak on per-route / SSR / test / HMR stores that create and dispose stores.\n this.listeners.clear();\n this.committedEventSubscribers.clear();\n this.uncommittedEventSubscribers.clear();\n this.writtenEventSubscribers.clear();\n this.allEventSubscribers.clear();\n this.instrumentObservers.clear();\n this.connectorBus.clear();\n this.reducerBus.clear();\n this.patternReducers.clear();\n this.sliceUnsubs.clear();\n this.changedPathSink = null;\n }\n\n /**\n * Generates a fingerprint for an event for deduplication purposes.\n * Falls back gracefully for non-serializable payloads.\n *\n * @param channel - Event channel.\n * @param type - Event type.\n * @param payload - Event payload.\n * @returns A string fingerprint for the event.\n *\n * @internal\n */\n private fingerprint(channel: string, type: string, payload: unknown): string {\n const base = `${channel}::${type}`;\n\n try {\n // Fast path for primitives\n if (payload === null || payload === undefined) {\n return `${base}::null`;\n }\n if (typeof payload !== \"object\") {\n return `${base}::${String(payload)}`;\n }\n\n // Attempt JSON serialization (handles most cases)\n const json = JSON.stringify(payload);\n return `${base}::${json}`;\n } catch {\n // Non-serializable payload - use timestamp to avoid false positives\n // This means non-serializable payloads won't be deduplicated\n return `${base}::${Date.now()}::${Math.random()}`;\n }\n }\n\n /**\n * Checks if an event should be deduplicated.\n * Returns true if this is a duplicate that should be skipped.\n *\n * @param fp - Event fingerprint.\n * @returns `true` if duplicate (should skip), `false` otherwise.\n *\n * @internal\n */\n private shouldDedupe(fp: string, windowMs: number): boolean {\n const now = Date.now();\n const existing = this.processedEvents.get(fp);\n\n if (existing !== undefined) {\n // Check if within dedup window\n if (now - existing < windowMs) {\n this.dedupCount++;\n return true; // Duplicate, skip\n }\n }\n\n // Record this event and make sure the periodic prune is running (it may not\n // be — e.g. identity `dedupKey` dedup at windowMs 0 never started it at\n // construction). The timer stops itself once the cache drains.\n this.processedEvents.set(fp, now);\n this.ensureCleanupTimer();\n\n // Lazy cleanup if cache is getting large\n if (this.processedEvents.size > this.dedupConfig.maxCacheSize) {\n this.pruneProcessedEvents(now);\n }\n\n return false; // Not a duplicate\n }\n\n /**\n * Starts the periodic prune interval if it isn't already running. Called when\n * the first entry is cached so the timer's lifetime tracks actual dedup use\n * (content window or identity `dedupKey`), independent of `dedupWindowMs`.\n *\n * @internal\n */\n private ensureCleanupTimer(): void {\n if (this.eventCleanupTimer !== null) return;\n this.eventCleanupTimer = setInterval(() => {\n this.pruneProcessedEvents(Date.now());\n }, 5000);\n // Never let the cleanup interval by itself keep a Node process alive.\n (this.eventCleanupTimer as { unref?: () => void }).unref?.();\n }\n\n /**\n * Removes expired entries from the processed events cache.\n *\n * @param now - Current timestamp.\n *\n * @internal\n */\n private pruneProcessedEvents(now: number): void {\n // Keep 2x the largest window in play (content window or the keyed-dedup\n // default) so entries aren't evicted before their dedup window elapses.\n const effectiveWindow = Math.max(this.dedupConfig.windowMs, DEFAULT_DEDUP_KEY_WINDOW_MS);\n const cutoff = now - effectiveWindow * 2;\n\n for (const [key, timestamp] of this.processedEvents) {\n if (timestamp < cutoff) {\n this.processedEvents.delete(key);\n }\n }\n\n // Once the cache has drained, stop the interval so an idle store doesn't\n // hold a repeating timer. It restarts on the next cached event.\n if (this.processedEvents.size === 0 && this.eventCleanupTimer !== null) {\n clearInterval(this.eventCleanupTimer);\n this.eventCleanupTimer = null;\n }\n }\n\n /**\n * Reports a breached ceiling and refuses the emit.\n *\n * @remarks\n * Console *and* hook, matching how reducer and effect errors are reported: a cascade is a\n * wiring bug, and the console line is what a developer who has not registered a hook will\n * actually see. Without one, refusing the emit would look exactly like the event never having\n * been emitted at all — which is the invisibility this whole guard exists to end.\n *\n * @internal\n */\n private reportCascade(\n limit: \"maxReduceDepth\" | \"maxTransitionsPerDrain\",\n limitValue: number,\n event: EventUnion<EM>,\n depth: number,\n chain: readonly string[],\n ): void {\n console.error(\n `[yoltra] Cascade stopped: \"${event.channel}/${event.type}\" would exceed ${limit} ` +\n `(${limitValue}). This event was refused and the chain ends here. A chain this long is ` +\n `almost always two consumers emitting into each other — check what reacts to ` +\n `\"${event.channel}/${event.type}\" and what that emits in turn.` +\n (chain.length > 0 ? ` Recent causal chain: ${chain.join(\" → \")} → (refused).` : \"\"),\n );\n\n try {\n this.onCascade?.({ limit, limitValue, event, depth, chain });\n } catch (err) {\n // A throwing diagnostic must not become the failure it was reporting.\n console.error(\"onCascade handler error:\", err);\n }\n }\n\n /**\n * Invokes all registered **effects** for a given event.\n * Handles both key-based effects (O(1) lookup) and pattern-based effects (runtime matching).\n * Errors are caught and logged.\n *\n * @param event - The event that was reduced.\n * @internal\n */\n private async notifyEffects(event: EventUnion<EM>) {\n // Effects resume in their own task, after the drain that produced this event has ended, so\n // `currentEvent` is null by the time they run and cannot speak for them. This closure is how\n // an effect's emits stay attached to the event that triggered them — which is what bounds a\n // cascade that crosses drains rather than staying inside one.\n const emit = this.scopedEmit(event);\n\n // 1. Call key-based effects (O(1) lookup)\n const key = `${String(event.channel)}::${String(event.type)}`;\n const effectSet = this.effects.get(key);\n\n if (effectSet && effectSet.size > 0) {\n for (const h of [...effectSet]) {\n try {\n await h(event, this.getState, emit);\n } catch (e) {\n console.error(\"Effect error:\", e);\n this.onEffectError?.(e, event);\n }\n }\n }\n\n // 2. Call pattern-based effects (runtime matching)\n for (const { effect, when } of this.patternEffects) {\n if (matchesWhen(when, event)) {\n try {\n await effect(event, this.getState, emit);\n } catch (e) {\n console.error(\"Effect error:\", e);\n this.onEffectError?.(e, event);\n }\n }\n }\n }\n\n /**\n * An `emit` that attributes whatever it sends to `cause`.\n *\n * @remarks\n * Built per event rather than per effect: every effect reacting to one event shares a cause,\n * and one closure is cheaper than one per handler on a path that runs for every committed\n * event.\n *\n * @internal\n */\n private scopedEmit(cause: EventUnion<EM>): Emit<EM> {\n const parent = {\n id: cause.id,\n depth: cause.depth ?? 0,\n chain: [...(this.currentEvent?.chain ?? []), cause.id].slice(-CASCADE_CHAIN_LIMIT),\n };\n return ((channel, type, payload, opts) =>\n this.emitCaused(parent, channel, type, payload, opts)) as Emit<EM>;\n }\n\n /**\n * Notifies event subscribers for a specific phase.\n *\n * Calls both phase-specific subscribers and 'all' subscribers.\n * Errors are caught and logged, allowing other subscribers to continue.\n *\n * @param event - The event to notify about.\n * @param phase - The phase ('committed' or 'uncommitted').\n * @internal\n */\n private notifyEventSubscribers(\n event: EventUnion<EM>,\n phase: \"committed\" | \"uncommitted\" | \"written\",\n ): void {\n const key = `${String(event.channel)}::${String(event.type)}`;\n\n // Notify phase-specific subscribers\n const phaseMap =\n phase === \"committed\"\n ? this.committedEventSubscribers\n : phase === \"written\"\n ? this.writtenEventSubscribers\n : this.uncommittedEventSubscribers;\n const phaseSet = phaseMap.get(key);\n\n if (phaseSet?.size) {\n for (const handler of [...phaseSet]) this.invokeEventSubscriber(handler, event, phase);\n }\n\n // Notify 'all' subscribers.\n //\n // Deliberately not reached for `written`. An event that writes is also committed, so folding\n // it in would hand every existing 'all' subscriber a second notification for the same event\n // and quietly double their counts — a silent change to code that never asked for the new\n // phase. `all` means committed-or-uncommitted, as it always has.\n if (phase === \"written\") return;\n const allSet = this.allEventSubscribers.get(key);\n if (allSet?.size) {\n for (const handler of [...allSet]) this.invokeEventSubscriber(handler, event, phase);\n }\n }\n\n /**\n * Invokes a single event-subscription handler **fire-and-forget**: synchronous\n * throws and async rejections are logged but never block the emit pipeline.\n * Event subscribers are notifications, not part of the committed reduce result.\n *\n * @internal\n */\n private invokeEventSubscriber(\n handler: EventSubscriptionHandler<DeepReadonly<S>, EM>,\n event: EventUnion<EM>,\n phase: \"committed\" | \"uncommitted\" | \"written\",\n ): void {\n try {\n const result = handler(event, this.getState, this.emit, phase) as unknown;\n if (result && typeof (result as Promise<unknown>).then === \"function\") {\n (result as Promise<unknown>).catch((e) => console.error(\"Event subscription error:\", e));\n }\n } catch (e) {\n console.error(\"Event subscription error:\", e);\n }\n }\n\n /**\n * Applies a reduced event to a slice and emits **precise** connector events.\n *\n * For each changed **leaf path** (via {@link detectChangedProps}), emits that leaf and\n * all of its **ancestors** once (e.g., `\"data\"`, `\"data.123\"`, `\"data.123.title\"`).\n *\n * A slice whose state **is** a single value — a primitive, a `Map`/`Set`, a `Date` — has no\n * leaf below its root, and `detectChangedProps` reports its change as the empty path `\"\"`.\n * That path is emitted as-is, so `connect({ reducer, property: \"\" })` (and any `**` pattern)\n * hears it. It has no ancestors to walk.\n *\n * **State Immutability**: When a slice changes, a new state object is created via\n * shallow spread: `{ ...this.state, [sliceName]: newSlice }`. This ensures that\n * `this.state` reference changes, enabling efficient change detection via `===`.\n *\n * @param rName - Slice name being updated.\n * @param event - Reduced event with typed payload.\n * @returns `true` if the slice actually changed, `false` otherwise.\n *\n * @internal\n */\n /**\n * Reduces one slice and contains any error it raises.\n *\n * @returns `true` when the slice changed.\n *\n * @remarks\n * The single funnel both dispatch paths go through, which is the point. Keyed reducers run\n * through `reducerBus`, whose handler loop caught and logged; pattern reducers were called\n * straight from the drain, so their errors escaped to the caller instead. The same bug in the\n * same reducer therefore produced two different outcomes depending on how the slice happened\n * to be targeted — a keyed reducer's throw let the event commit and its effects run, while a\n * pattern reducer's throw aborted the commit and notified nobody, not even the uncommitted\n * subscribers a veto would have reached.\n *\n * The semantics are the same either way: **the failing slice is isolated.** Its state is\n * unchanged, every other slice still reduces, and the event still commits if anything else\n * changed.\n *\n * That is deliberately *not* what a {@link Rejected} refusal does, which discards the whole\n * event. A crash and a refusal are different acts: a reducer that throws has a bug and should\n * not be able to veto its neighbours' work, while a reducer that refuses has made a decision\n * and must be able to.\n *\n * This once argued that rolling back was untenable, because subscribers were notified as each\n * slice committed and a later revert would have told them about a value that no longer\n * existed. Staging removed that obstacle — nothing is notified until every slice is written —\n * which is what made refusal possible at all.\n *\n * @internal\n */\n private stageSliceGuarded<C extends keyof EM & string, T extends keyof EM[C] & string>(\n rName: R,\n event: Event<EM, C, T>,\n staged: StagedSlice[],\n ): Rejection | null {\n try {\n return this.stageSlice(rName, event, staged);\n } catch (err) {\n // Reported through a hook as well as the console: a reducer throwing is a bug in\n // application code, and until now the only trace of it was a console line in one case and\n // an exception surfacing somewhere unrelated in the other.\n console.error(`Reducer error in slice \"${rName as string}\":`, err);\n this.onReducerError?.(err, event as EventUnion<EM>, rName as string);\n return null;\n }\n }\n\n /**\n * Runs one slice's reducer and records what it *would* write. Writes nothing.\n *\n * @returns The reducer's {@link Rejection} if it refused, otherwise `null`.\n *\n * @remarks\n * The staging half of the write path. Nothing here touches `this.state` or notifies anybody,\n * which is what lets the event be refused after every reducer has had its say — a decision\n * that has to see the whole diff cannot be made one slice at a time.\n *\n * Freezing happens here rather than at commit because it is where the new value is built, and\n * the freeze is a no-op on anything already frozen; a staged slice that never commits is\n * discarded frozen, which costs nothing and keeps the committed path free of a second walk.\n *\n * @internal\n */\n private stageSlice<C extends keyof EM & string, T extends keyof EM[C] & string>(\n rName: R,\n event: Event<EM, C, T>,\n staged: StagedSlice[],\n ): Rejection | null {\n // @ts-expect-error R indexing on DeepReadonly<S> is valid at runtime\n const prev = this.state[rName] as S[R];\n const next = this.reducers[rName].reduce(prev, event as any);\n\n // A refusal, not a value. Checked before the identity comparison below, because a rejection\n // object is never the previous state and would otherwise be staged as one.\n if (isRejected(next)) return next;\n\n // if reducer returned same ref, definitely no change\n if (prev === next) return null;\n\n // Compute precise leaf paths that changed (relative to slice root).\n //\n // Not filtered for truthiness. `\"\"` is how `detectChangedProps` reports a change at the\n // slice ROOT — a slice that *is* one value: a primitive, a `Map`/`Set`, a `Date`, or an\n // object replaced by something of a different shape. Discarding it as falsy made the\n // length check below read \"nothing changed\", so the write path returned before assigning\n // `this.state`: the reducer ran, its result was thrown away, and nothing said so. A store\n // holding `state: 0` could never leave `0`.\n const leafPaths = detectChangedProps(prev, next);\n\n // if nothing actually changed at the leaves, treat as a no-op\n if (leafPaths.length === 0) return null;\n\n // No deep clone: the reducer already returned a fresh `next` (purity contract), so\n // structural sharing is preserved and freezeInDev only touches new nodes.\n // In development the freeze walk also watches for the event payload appearing in the new\n // state by reference. That is the aliasing that makes a deep in-place freeze surprising:\n // the caller still holds the object, mutating it later throws from an unrelated stack, and\n // the same code works in production because the freeze is compiled out. Warned once per\n // slice and event so a hot path does not become a log.\n const payload = (event as { payload?: unknown }).payload;\n const alias: AliasWatch | undefined =\n process.env.NODE_ENV !== \"production\" && payload !== null && typeof payload === \"object\"\n ? {\n watch: payload,\n onFound: () => {\n const key = `${rName as string}:${event.channel}:${event.type}`;\n if (this.warnedPayloadAliases.has(key)) return;\n this.warnedPayloadAliases.add(key);\n console.warn(\n `[yoltra] Slice \"${rName as string}\" stored the payload of ` +\n `\"${event.channel}/${event.type}\" by reference. It is now frozen along with ` +\n `the rest of the state, so the emitter mutating it later will throw in ` +\n `development and silently corrupt state in production. Copy the payload in ` +\n `the reducer instead.`,\n );\n },\n }\n : undefined;\n\n staged.push({\n name: rName as string,\n prev,\n frozen: freezeInDev(next, alias),\n leafPaths,\n });\n\n return null;\n }\n\n /**\n * Writes every staged slice, then tells the world — in that order.\n *\n * @remarks\n * The commit half. Assigning all slices under a single new root before any notification goes\n * out is what closes the window this used to leave open: notifications fired per slice as each\n * committed, so a subscriber to slice A that read `getState()` could observe slice B of the\n * *same event* not yet applied. In React that window is real, because the atomic hooks use a\n * change as a bare signal and then re-read the whole store.\n *\n * It is also what makes refusal possible at all. The previous code documented rollback as\n * untenable precisely because \"an event that reverted afterwards would have already told\n * components about a value that no longer exists\" — true when notification and commit were the\n * same step, and no longer true now that they are not.\n *\n * @returns `true` if anything was written.\n *\n * @internal\n */\n private commitStaged(staged: StagedSlice[], event: EventUnion<EM>): boolean {\n if (staged.length === 0) return false;\n\n // One new root for the whole event, not one per slice.\n const nextState = { ...(this.state as object) } as Record<string, unknown>;\n for (const slice of staged) nextState[slice.name] = slice.frozen;\n this.state = nextState as DeepReadonly<S>;\n\n // Record slice-prefixed changed leaf paths for any active instrumentation\n // (lets DevTools agents build precise patches without re-diffing state).\n if (this.changedPathSink) {\n for (const slice of staged) {\n for (const p of slice.leafPaths) {\n this.changedPathSink.push(p ? `${slice.name}.${p}` : slice.name);\n }\n }\n }\n\n // Every notification happens after every write, so any handler reading `getState()` sees the\n // event applied in full.\n for (const slice of staged) {\n // emit deep + ancestor paths once each\n const toEmit = new Set<string>();\n for (const p of slice.leafPaths) {\n // The slice root has no ancestors to walk — `buildAncestorPaths(\"\")` is `[]` by contract,\n // which is what callers holding a real path rely on — so it is added directly. Without\n // this a slice that is entirely one value changes and tells nobody, which is the\n // subscription half of the same bug the missing filter caused in the commit half.\n if (p === \"\") {\n toEmit.add(\"\");\n continue;\n }\n for (const a of Store.buildAncestorPaths(p)) toEmit.add(a);\n }\n\n for (const prop of toEmit) {\n // Built only if a handler matched. Reading the old and new value walks the state tree\n // twice per path, and a slice nobody subscribes to used to pay that for every path it\n // changed — describing the change in detail to an audience of nobody.\n this.connectorBus.emitWith(slice.name as R, prop, () => ({\n oldValue: this.getAtPath(slice.prev, prop),\n newValue: this.getAtPath(slice.frozen, prop),\n path: prop,\n // Provenance, built inside the same lazy factory as the values: a subscriber that\n // needs to know why a value moved no longer has to mirror the cause into state and\n // keep it there twice.\n eventId: event.id,\n channel: event.channel as string,\n type: event.type as string,\n }));\n }\n }\n\n return true;\n }\n\n /**\n * Returns a structured introspection snapshot for DevTools UIs.\n *\n * @remarks\n * Reads the internal middleware, effects, reducers, and subscriber\n * registries and returns a plain-object summary matching the\n * `STORE_SUBSCRIPTIONS` protocol message shape.\n *\n * @public\n */\n public __devtoolsIntrospect() {\n // Reducers\n const reducers = (Object.keys(this.reducers) as Array<R>).map((name) => {\n const when = this.patternReducers.get(name);\n return { name: name as string, when };\n });\n\n // Effects (keyed) — metadata looked up from the store-owned effectMeta map\n const effects: Array<{ channel: string; type: string; name?: string; description?: string }> = [];\n for (const [key, set] of this.effects) {\n if (set.size === 0) continue;\n const [channel, type] = key.split(\"::\");\n for (const fn of set) {\n const meta = this.effectMeta.get(fn);\n effects.push({ channel, type, name: meta?.name, description: meta?.description });\n }\n }\n // Effects (pattern-based) — entry is { effect, when }; metadata in effectMeta\n for (const entry of this.patternEffects) {\n const meta = this.effectMeta.get(entry.effect);\n effects.push({\n channel: \"*\",\n type: \"*\",\n name: meta?.name,\n description: meta?.description,\n });\n }\n\n // Middleware\n const middleware: Array<{ name?: string; description?: string; when?: unknown }> = [];\n for (const mwInput of this.middleware) {\n if (typeof mwInput === \"function\") {\n middleware.push({ name: mwInput.name || undefined });\n } else {\n middleware.push({\n name: (mwInput as any).meta?.name,\n description: (mwInput as any).meta?.description,\n when: (mwInput as any).when,\n });\n }\n }\n\n // Atomic (connect) subscriptions — enumerate from the connectorBus\n const atomic: Array<{ reducer: string; property: string }> = [];\n for (const entry of this.connectorBus.__introspect()) {\n for (let i = 0; i < entry.count; i++) {\n atomic.push({ reducer: entry.channel, property: entry.type });\n }\n }\n\n // Event subscriptions\n const event: Array<{ channel: string; type: string; phase: string }> = [];\n for (const [key, set] of this.committedEventSubscribers) {\n if (set.size === 0) continue;\n const [channel, type] = key.split(\"::\");\n for (let i = 0; i < set.size; i++) {\n event.push({ channel, type, phase: \"committed\" });\n }\n }\n for (const [key, set] of this.uncommittedEventSubscribers) {\n if (set.size === 0) continue;\n const [channel, type] = key.split(\"::\");\n for (let i = 0; i < set.size; i++) {\n event.push({ channel, type, phase: \"uncommitted\" });\n }\n }\n for (const [key, set] of this.allEventSubscribers) {\n if (set.size === 0) continue;\n const [channel, type] = key.split(\"::\");\n for (let i = 0; i < set.size; i++) {\n event.push({ channel, type, phase: \"all\" });\n }\n }\n\n // Coarse subscribers count\n const coarse = this.listeners.size;\n\n return {\n reducers,\n effects,\n middleware,\n atomic,\n event,\n coarse,\n dedupHits: this.dedupCount,\n queueDepth: this.reduceQueue.length + this.inFlightEffects,\n };\n }\n\n /**\n * Applies an externally provided **whole-state** (e.g., DevTools time travel) and emits\n * fine-grained path changes for each slice.\n *\n * **State Immutability**: If any slices change, a new state object is created via\n * shallow spread. This ensures consistent immutability with {@link commitStaged}.\n *\n * **Missing slices**: the snapshot should contain every slice. A slice absent\n * from `nextPlain` is **retained at its current value** (not blanked to\n * `undefined`, which would make `getState().<slice>` throw on next access).\n *\n * @param nextPlain - Plain JS object to become the new state.\n *\n * @internal\n */\n public __applyExternalState(nextPlain: any) {\n // Gate on the same runtime flag as __replayEvents: time-travel replaces the\n // whole state tree, so it must stay off unless the app opted in via\n // createStore({ devtools: { allowReplay: true } }). Enforced here at the\n // seam so a devtools agent (or a client driving it) cannot bypass it.\n if (!this.replayEnabled) {\n // Throws, like `__replayEvents`. Both replace state wholesale on behalf of a devtools\n // client; one refusing loudly while the other returned quietly meant a disabled seam\n // looked like a working one that had simply found nothing to do.\n throw new Error(\n \"[yoltra] External state apply (time-travel) is disabled. Enable it with createStore({ devtools: { allowReplay: true } })\",\n );\n }\n\n const prev = this.state as any;\n const next = nextPlain;\n\n const newState = { ...this.state } as any;\n let anyChanged = false;\n\n (Object.keys(this.reducers) as Array<R>).forEach((rName) => {\n const prevSlice = prev?.[rName];\n const nextSlice = next?.[rName];\n\n // A snapshot missing this slice must not blank it out — retain the current\n // slice (storing `undefined` would make getState().<slice>.x throw later).\n if (nextSlice === undefined) {\n if (process.env.NODE_ENV !== \"production\") {\n console.warn(\n `[yoltra] External state is missing slice \"${String(\n rName,\n )}\"; retaining its current value. Time-travel snapshots should contain all slices.`,\n );\n }\n return;\n }\n\n // if reference equal, nothing to emit\n if (prevSlice === nextSlice) return;\n\n // freeze the incoming slice before storing (dev-only; no deep clone — the\n // external snapshot is freshly deserialized and owned by the store)\n const frozenNextSlice = freezeInDev(nextSlice) as DeepReadonly<S[typeof rName]>;\n newState[rName] = frozenNextSlice;\n anyChanged = true;\n\n // Full dotted leaf paths relative to the slice. Unfiltered, for the reason given in\n // `stageSlice`: `\"\"` is a genuine root-level change, not an absent one. Time travel\n // onto a primitive slice committed the state here but emitted nothing, so a component\n // subscribed through `connect` kept rendering the value it had before the jump.\n const leafPaths = detectChangedProps(prevSlice, nextSlice);\n if (leafPaths.length === 0) return;\n\n // emit every leaf AND its ancestors once\n const toEmit = new Set<string>();\n for (const p of leafPaths) {\n if (p === \"\") {\n toEmit.add(\"\");\n continue;\n }\n for (const a of Store.buildAncestorPaths(p)) toEmit.add(a);\n }\n\n for (const path of toEmit) {\n const oldValue = this.getAtPath(prevSlice, path);\n const newValue = this.getAtPath(frozenNextSlice, path);\n this.connectorBus.emit(rName, path as any, { oldValue, newValue, path });\n }\n });\n\n // commit new state if any slices changed\n if (anyChanged) {\n this.state = newState as DeepReadonly<S>;\n }\n\n // coerse subscribers after all fine-grained emits (only if changed)\n if (anyChanged) {\n this.listeners.forEach((l) => l());\n }\n }\n\n /**\n * Replays a sequence of events from a snapshot through reducers and event\n * subscribers ONLY. Skips dedup, middleware, and effects.\n *\n * This method is gated by the `devtools.allowReplay` runtime config.\n * If replay is not enabled, this method throws.\n *\n * @param snapshot - The state snapshot to restore before replaying.\n * @param events - Array of events to replay (in order).\n *\n * @internal\n */\n public __replayEvents(\n snapshot: any,\n events: Array<{ channel: string; type: string; payload: any; id: string; meta?: EventMeta }>,\n ): void {\n if (!this.replayEnabled) {\n throw new Error(\n \"[yoltra] Event replay is disabled. Enable it with createStore({ devtools: { allowReplay: true } })\",\n );\n }\n\n // 1. Apply snapshot (restores base state)\n this.__applyExternalState(snapshot);\n\n // 2. Replay each event through reducers + event subscribers only\n for (const evt of events) {\n const event = evt as EventUnion<EM>;\n\n // Staged and committed exactly as a live event is, so a replay reproduces the same state\n // by the same path — including a reducer that refuses, which must refuse identically or\n // the replayed history is not the history.\n const staged: StagedSlice[] = [];\n this.stagingSink = staged;\n let rejection: Rejection | null = null;\n\n try {\n // Run key-based reducers via reducerBus. The event travels alongside the payload so\n // keyed reducers observe the replayed event's real id, exactly like pattern reducers.\n this.reducerBus.emit(event.channel as any, event.type as any, event.payload, event as any);\n rejection = this.stagedRejection;\n\n // Run pattern-based reducers. Guarded like the live path: one bad event in a replayed log\n // should cost that event, not abandon the replay halfway through with the store left at\n // whatever state it happened to reach.\n for (const [sliceName, when] of this.patternReducers) {\n if (rejection !== null) break;\n if (matchesWhen(when, event)) {\n const refused = this.stageSliceGuarded(sliceName, event as any, staged);\n if (refused !== null) rejection = refused;\n }\n }\n } finally {\n this.stagingSink = null;\n this.stagedRejection = null;\n this.stagedRejectedBy = \"\";\n }\n\n const anySliceChanged = rejection === null && this.commitStaged(staged, event);\n\n // Notify committed event subscribers (sync, fire-and-forget)\n this.notifyEventSubscribers(event, \"committed\");\n\n // Notify coarse subscribers if state changed\n if (anySliceChanged) {\n this.notifyEventSubscribers(event, \"written\");\n this.listeners.forEach((l) => l());\n }\n\n // NOTE: No middleware, no effects, no dedup, no DevTools logging\n }\n }\n\n /**\n * Emits a typed event `(channel, type, payload)`.\n * Events are queued and processed **sequentially** (FIFO).\n *\n * **Pipeline per event:** the *reduce phase* (steps 1-4) runs **synchronously**,\n * so `getState()` reflects the change as soon as `emit()` returns; the *effect\n * phase* (step 5) runs afterwards, asynchronously.\n * 1. **Deduplication** (opt-in) - Skip when content-dedup is enabled (`dedupWindowMs > 0`) or a matching `dedupKey` recurs; off by default\n * 2. **Middleware** (sync) - Pre-reducer hooks; may cancel by returning `false`\n * 3. **Reducers** (sync) - every matching slice is *staged*; nothing is written yet, so a refusal from the last reducer still stops the first one's write\n * 4. **Commit + subscribers** (sync) - all staged slices are assigned under one new root, then event subscribers (`committed`, then `written` when state actually changed), then coarse listeners\n * 5. **Effects** (async) - side-effects keyed by `(channel, type)`; the returned promise resolves once they complete\n *\n * **Change Detection**: Uses reference equality (`===`) on `this.state` to determine\n * if any slice changed. Works because the commit builds a new state reference via\n * shallow spread when any slice changes.\n *\n * @typeParam C - Channel key in `EM`.\n * @typeParam T - Type key within channel `C`.\n * @param channel - Channel name.\n * @param type - Event type name.\n * @param payload - Payload typed as `EM[C][T]`.\n * @param opts - Optional per-emit options (e.g. `dedupKey` for identity-based dedup).\n * @returns A promise that resolves once this event's effects have finished.\n * State is already updated synchronously before `emit()` returns.\n *\n * @example Basic usage\n * ```ts\n * await store.emit('ui', 'increment', 1);\n * ```\n *\n * @example With middleware cancellation\n * ```ts\n * store.registerMiddleware((state, event) => {\n * if (event.type === 'dangerous') return false; // cancel\n * return true; // allow\n * });\n *\n * await store.emit('ui', 'dangerous', null); // cancelled, no state change\n * ```\n *\n * @public\n */\n public async emit<C extends keyof EM & string, T extends keyof EM[C] & string>(\n channel: C,\n type: T,\n payload: EM[C][T],\n opts?: EmitOptions,\n ): Promise<EmitResult> {\n return this.emitCaused(null, channel, type, payload, opts);\n }\n\n /**\n * The real emit, with an explicitly supplied cause.\n *\n * @remarks\n * Exists so the parent can be passed without a pseudo-private field on the public\n * {@link EmitOptions}. Two callers supply one: the public {@link emit} passes `null` and lets\n * `currentEvent` speak for the synchronous case, and the scoped `emit` handed to effects passes\n * the event that triggered them — effects resume after the drain has ended, so nothing else\n * could still know what caused them.\n *\n * @internal\n */\n private async emitCaused<C extends keyof EM & string, T extends keyof EM[C] & string>(\n scopedParent: { id: string; depth: number; chain: readonly string[] } | null,\n channel: C,\n type: T,\n payload: EM[C][T],\n opts?: EmitOptions,\n ): Promise<EmitResult> {\n // Deduplication is OPT-IN (see EmitOptions / StoreSpec.dedupWindowMs).\n // Content-based dedup runs only when `dedupWindowMs > 0`; identity-based\n // dedup runs when an explicit `dedupKey` is supplied. By default neither is\n // active, so legitimate rapid-fire identical events are never silently dropped.\n const dedupKey = opts?.dedupKey;\n const contentWindow = this.dedupConfig.windowMs;\n // `skipDedup` wins over both the per-emit key and the store-level window: callers that\n // already guarantee distinctness must not have events silently coalesced by payload.\n if (opts?.skipDedup !== true && (contentWindow > 0 || dedupKey !== undefined)) {\n const windowMs =\n dedupKey !== undefined && contentWindow <= 0 ? DEFAULT_DEDUP_KEY_WINDOW_MS : contentWindow;\n const fp =\n dedupKey !== undefined\n ? `${channel}::${type}::#${dedupKey}`\n : this.fingerprint(channel as string, type as string, payload);\n if (this.shouldDedupe(fp, windowMs)) {\n // A suppressed duplicate never reaches middleware or a reducer, so it is neither\n // committed nor written — the same answer a vetoed event gives, which is correct: in\n // both cases the caller's event had no effect.\n return NOT_COMMITTED;\n }\n }\n\n // Assign a unique id and a completion deferred, resolved after this event's\n // effects run. Reducers run synchronously (see drainReduce), so state is\n // already updated before emit() returns; the returned promise tracks the\n // async effect phase for `await emit(...)`.\n const id = opts?.id ?? this.idFactory();\n\n // Causality. `currentEvent` is set only inside the synchronous drain, so if it is set this\n // emit is a consequence of that event — no matter whether the caller used the injected\n // `emit` or reached for `store.emit` directly. Outside the drain, an explicitly scoped\n // parent (given to effects, which resume after the drain has ended) supplies it instead.\n const parent = this.currentEvent ?? scopedParent;\n const depth = parent === null ? 0 : parent.depth + 1;\n\n if (parent !== null && depth > this.maxReduceDepth) {\n // Refused, not thrown: the throw would land in whichever frame happened to be emitting.\n // Guarded on `parent` as well as depth — a root is depth 0 and can only breach a ceiling\n // set below zero, and refusing the caller's own emit is never the right answer.\n this.reportCascade(\n \"maxReduceDepth\",\n this.maxReduceDepth,\n {\n channel,\n type,\n payload,\n id,\n ...(opts?.meta !== undefined ? { meta: opts.meta } : {}),\n parentId: parent.id,\n depth,\n } as EventUnion<EM>,\n depth,\n parent.chain,\n );\n return NOT_COMMITTED;\n }\n\n let resolve!: (result: EmitResult) => void;\n const done = new Promise<EmitResult>((r) => {\n resolve = r;\n });\n\n this.reduceQueue.push({\n channel: channel as string,\n type: type as string,\n payload,\n id,\n meta: opts?.meta,\n resolve,\n // Only carried for caused events, so a root event's object stays byte-identical to one\n // built before causality existed — the same rule `meta` follows.\n ...(parent !== null ? { parentId: parent.id, depth, chain: parent.chain } : {}),\n });\n\n // Synchronous reduce phase (drains re-entrant emits too), then async effects.\n this.drainReduce();\n\n return done;\n }\n\n /**\n * Drains the reduce queue **synchronously**. For each event it runs middleware,\n * reducers, event subscribers, and coarse listeners in the same tick, so\n * `getState()` reflects the change the moment {@link emit} returns. Re-entrant\n * emits (from middleware or subscribers) are appended and drained in the same\n * pass — preserving FIFO order without interleaving reducers. Each committed\n * event's effects then run in an independent task (see {@link runEventEffects}).\n *\n * @internal\n */\n private drainReduce(): void {\n if (this.isReducing) return;\n this.isReducing = true;\n this.transitionsThisDrain = 0;\n try {\n while (this.reduceQueue.length > 0) {\n const next = this.reduceQueue.shift()!;\n const { channel, type, payload, id, meta, resolve, parentId, depth, chain } = next;\n\n // Conditional spread, not `meta` unconditionally: when no metadata was supplied the\n // event object stays byte-identical to one built before `meta` existed, so\n // Object.keys / JSON.stringify / toStrictEqual behaviour is unchanged. `parentId` and\n // `depth` follow the same rule, and are absent on a root event.\n const event = {\n channel,\n type,\n payload,\n id,\n ...(meta !== undefined ? { meta } : {}),\n ...(parentId !== undefined ? { parentId, depth } : {}),\n } as EventUnion<EM>;\n\n // Width ceiling, checked as the event is dequeued rather than as it is emitted: a burst\n // is only excessive relative to the pass draining it, and at emit time there is no pass\n // yet. Off unless configured — see StoreSpec.maxTransitionsPerDrain.\n //\n // The root is never refused. It is the caller's own emit, not part of any burst, and a\n // ceiling that rejected it would turn \"this store's cascades are bounded\" into \"this\n // store randomly drops the event you just sent\". Only what the drain caused can be\n // excessive, which is also why `depth` and `chain` are known to be set here.\n if (parentId !== undefined && ++this.transitionsThisDrain > this.maxTransitionsPerDrain) {\n this.reportCascade(\n \"maxTransitionsPerDrain\",\n this.maxTransitionsPerDrain,\n event,\n depth as number,\n chain as readonly string[],\n );\n // Resolve rather than abandon: a caller awaiting this emit would otherwise hang, which\n // is the failure the ceiling exists to prevent, arriving by another door.\n resolve(NOT_COMMITTED);\n continue;\n }\n\n // Anything emitted from here until the end of this iteration is caused by this event.\n // The drain is synchronous, so this is exact rather than a heuristic — and it holds even\n // when a consumer calls `store.emit` directly instead of the injected `emit`.\n this.currentEvent = {\n id,\n depth: depth ?? 0,\n chain: [...(chain ?? []), id].slice(-CASCADE_CHAIN_LIMIT),\n };\n\n // Instrumentation: capture prev state, collect changed paths, and time\n // the synchronous reduce — all skipped entirely when no observers.\n const instrumenting = this.instrumentObservers.size > 0;\n const prevState = instrumenting ? this.state : undefined;\n const sink: string[] | undefined = instrumenting ? [] : undefined;\n if (sink !== undefined) this.changedPathSink = sink;\n const t0 = instrumenting ? now() : 0;\n\n let result: EmitResult = NOT_COMMITTED;\n try {\n result = this.applyEventSync(event);\n } catch (err) {\n console.error(\"Emit reduce error:\", err);\n } finally {\n if (instrumenting) this.changedPathSink = null;\n // Cleared before effects are scheduled. Effects resume in a later task, when this\n // event is no longer what the drain is processing; they carry their cause explicitly\n // through the scoped emit instead.\n this.currentEvent = null;\n }\n\n if (instrumenting) {\n this.emitInstrumentation(\n event,\n result,\n sink ?? [],\n prevState as DeepReadonly<S>,\n now() - t0,\n );\n }\n\n // Run this event's effects as an independent task and resolve its\n // completion deferred when they finish. Independent per-event tasks\n // (rather than one shared serialized loop) let an effect `await` a\n // re-entrant emit without deadlocking.\n void this.runEventEffects(event, result, resolve);\n }\n } finally {\n this.isReducing = false;\n }\n }\n\n /**\n * Runs the **synchronous** part of the pipeline for a single event: middleware\n * (may veto), key- and pattern-based reducers, committed/uncommitted event\n * subscribers (fire-and-forget), and coarse listeners.\n *\n * @returns `true` if the event was committed (passed middleware), `false` if a\n * middleware vetoed it.\n *\n * @internal\n */\n private applyEventSync(event: EventUnion<EM>): EmitResult {\n // Middleware (synchronous). Return false to veto; async work belongs in effects.\n for (const mwInput of this.middleware) {\n const when = getMiddlewareWhen(mwInput);\n if (!matchesWhen(when, event)) continue;\n const mw = getMiddlewareFunction(mwInput);\n let ok: boolean;\n try {\n ok = mw(this.state, event, this.emit);\n if (\n process.env.NODE_ENV !== \"production\" &&\n typeof (ok as unknown as { then?: unknown })?.then === \"function\"\n ) {\n // A Promise is truthy, so an async middleware silently allows everything: the event\n // commits while the middleware is still deciding, and the veto it was written to\n // perform can never fire. Caught here because the symptom — a rule that simply does\n // not apply — looks nothing like its cause.\n console.error(\n `[yoltra] Middleware for \"${event.channel}/${event.type}\" returned a Promise. ` +\n `Middleware is synchronous: a Promise is truthy, so this event was allowed ` +\n `without waiting and a \"return false\" inside it can never veto. Do the check ` +\n `synchronously, and put anything that must await in an effect.`,\n );\n }\n } catch (err) {\n console.error(\"Middleware error:\", err);\n ok = false;\n }\n if (!ok) {\n // Rejected by middleware — notify uncommitted subscribers, do not commit.\n this.notifyEventSubscribers(event, \"uncommitted\");\n return NOT_COMMITTED;\n }\n }\n\n // Reduce every matching slice into a staging list. Nothing is written yet, so a refusal\n // arriving from the last reducer can still stop the first one's write.\n const staged: StagedSlice[] = [];\n this.stagingSink = staged;\n let rejection: Rejection | null = null;\n let rejectedBy = \"\";\n\n try {\n // Pass the event itself, not just the payload: keyed reducers are wired through\n // `reducerBus` in `mountSlice` and would otherwise have to invent an id.\n this.reducerBus.emit(\n event.channel as any,\n event.type as any,\n event.payload as any,\n event as any,\n );\n rejection = this.stagedRejection;\n rejectedBy = this.stagedRejectedBy;\n\n for (const [sliceName, when] of this.patternReducers) {\n if (rejection !== null) break;\n if (matchesWhen(when, event)) {\n const refused = this.stageSliceGuarded(sliceName, event as any, staged);\n if (refused !== null) {\n rejection = refused;\n rejectedBy = sliceName as string;\n }\n }\n }\n } finally {\n this.stagingSink = null;\n this.stagedRejection = null;\n this.stagedRejectedBy = \"\";\n }\n\n // A refusal discards every staged slice, not just the refusing one. Authorising a write to\n // one slice while a sibling records it as accepted is not authorisation — and a caller told\n // \"rejected\" must not find half of its event applied.\n if (rejection !== null) {\n this.onRejected?.(rejection, event, rejectedBy);\n this.notifyEventSubscribers(event, \"committed\");\n return { committed: true, written: false, rejected: rejection };\n }\n\n const written = this.commitStaged(staged, event);\n\n // Committed subscribers fire whether or not anything was written — `committed` means \"not\n // vetoed\", which is what a notification or analytics bus depends on. `written` is the\n // stricter fact, and fires after the commit so a handler reading getState() sees it.\n this.notifyEventSubscribers(event, \"committed\");\n if (written) {\n this.notifyEventSubscribers(event, \"written\");\n this.listeners.forEach((l) => l());\n }\n return written ? WRITTEN : COMMITTED_UNWRITTEN;\n }\n\n /**\n * Runs a single committed event's effects as an **independent async task**,\n * then resolves that event's completion deferred so `await emit(...)` settles\n * once its effects finish. Per-event tasks (rather than one shared serialized\n * loop) let an effect `await` a re-entrant emit without deadlocking.\n *\n * @internal\n */\n private async runEventEffects(\n event: EventUnion<EM>,\n result: EmitResult,\n resolve: (result: EmitResult) => void,\n ): Promise<void> {\n this.inFlightEffects++;\n try {\n if (result.committed) await this.notifyEffects(event);\n } catch (err) {\n console.error(\"Effect error:\", err);\n } finally {\n this.inFlightEffects--;\n resolve(result);\n }\n }\n\n /**\n * Registers an instrumentation observer. See {@link StoreInstance.instrument}.\n *\n * @public\n */\n public instrument(observer: InstrumentationObserver<EM>): Unsubscribe {\n this.instrumentObservers.add(observer);\n return () => {\n this.instrumentObservers.delete(observer);\n };\n }\n\n /**\n * Builds an {@link InstrumentedEvent} from the reduce result and notifies\n * observers. `changedPaths` are the exact slice-prefixed leaf paths recorded\n * by {@link commitStaged} during this reduce, so DevTools patches need no\n * re-diff.\n *\n * @internal\n */\n private emitInstrumentation(\n event: EventUnion<EM>,\n result: EmitResult,\n changedPaths: string[],\n prevState: DeepReadonly<S>,\n reduceTimeMs: number,\n ): void {\n const prevValues: Record<string, unknown> = {};\n const nextValues: Record<string, unknown> = {};\n for (const path of changedPaths) {\n prevValues[path] = this.getAtPath(prevState, path);\n nextValues[path] = this.getAtPath(this.state, path);\n }\n const info: InstrumentedEvent<EM> = {\n event: {\n id: event.id,\n channel: event.channel as string,\n type: event.type as string,\n payload: event.payload,\n // Conditional, so an event without metadata produces an observer payload\n // byte-identical to the pre-`meta` shape.\n ...(event.meta !== undefined ? { meta: event.meta } : {}),\n },\n committed: result.committed,\n changedPaths,\n prevValues,\n nextValues,\n reduceTimeMs,\n // Present only when a reducer refused, so an observer can tell a refusal from a veto —\n // identical in state, entirely different in cause.\n ...(result.rejected !== undefined ? { rejected: result.rejected } : {}),\n };\n for (const observer of [...this.instrumentObservers]) {\n try {\n observer(info);\n } catch (e) {\n console.error(\"Instrumentation observer error:\", e);\n }\n }\n }\n\n /**\n * Connects a **fine-grained** listener to a dotted path under a slice.\n *\n * @param spec - `{ reducer, property }` where `property` is a dotted path (e.g., `\"items.0.title\"`).\n * Supports wildcards: `*` (one segment) and `**` (zero or more segments).\n * @param h - Handler receiving a {@link Change} with `{ oldValue, newValue, path }`.\n * @returns Unsubscribe function.\n *\n * @example Exact path\n * ```ts\n * const off = store.connect(\n * { reducer: 'todos', property: 'items.0.title' },\n * (chg) => console.log('title changed:', chg.newValue)\n * );\n * off();\n * ```\n *\n * @example Wildcard pattern\n * ```ts\n * // Listen to any item title change\n * const off = store.connect(\n * { reducer: 'todos', property: 'items.*.title' },\n * (chg) => console.log('some title changed')\n * );\n * ```\n *\n * @public\n */\n public connect(\n spec: { reducer: R; property: string },\n h: (chg: Change) => void,\n options?: ConnectOptions,\n ): () => void {\n const off = this.connectorBus.on(spec.reducer, spec.property, h);\n\n if (options?.immediate === true) {\n // @ts-expect-error R indexing on DeepReadonly<S> is valid at runtime\n const slice = this.state[spec.reducer] as unknown;\n // A pattern matches a set of paths, and a set has no single current value — so the slice\n // root is delivered instead, at the path a whole-slice subscription would use.\n // Same test the bus uses to tell a pattern from an exact path.\n const path = spec.property.includes(\"*\") ? \"\" : spec.property;\n\n // No `eventId`, `channel` or `type`: nothing caused this, and inventing a cause would be\n // a lie a subscriber could act on. `oldValue` is undefined for the same reason — there is\n // no previous value, only a first one.\n h({ oldValue: undefined, newValue: this.getAtPath(slice, path), path });\n }\n\n return off;\n }\n\n /**\n * Subscribe to events by channel and type.\n *\n * Event subscriptions are intended for the View layer (e.g., React components)\n * to react to events without affecting the event flow. They are fire-and-forget\n * and cannot cancel event propagation.\n *\n * **Phases:**\n * - `'committed'` (default): Events that passed middleware and reached reducers.\n * Notified after reducers, before effects.\n * - `'uncommitted'`: Events rejected by middleware. Notified immediately after rejection.\n * - `'all'`: Both committed and uncommitted events. Handler receives the phase parameter\n * to distinguish between the two.\n *\n * @typeParam C - Channel key within `EM`.\n * @typeParam T - Event type key within channel `C`.\n * @param channel - Channel to subscribe to.\n * @param type - Event type to subscribe to.\n * @param handler - Handler function `(event, getState, emit, phase)`.\n * @param phase - Event phase to subscribe to (default: `'committed'`).\n * @returns Unsubscribe function.\n *\n * @example Committed events (default)\n * ```ts\n * const off = store.onEvent('ui', 'save', (event, getState, emit, phase) => {\n * console.log('Save committed:', event.payload);\n * });\n * off();\n * ```\n *\n * @example Uncommitted (rejected) events\n * ```ts\n * store.onEvent('ui', 'delete', (event, getState, emit, phase) => {\n * console.log('Delete was rejected by middleware');\n * }, 'uncommitted');\n * ```\n *\n * @example All events\n * ```ts\n * store.onEvent('ui', 'action', (event, getState, emit, phase) => {\n * console.log('Action:', phase); // 'committed' or 'uncommitted'\n * }, 'all');\n * ```\n *\n * @public\n */\n public onEvent<C extends keyof EM & string, T extends keyof EM[C] & string>(\n channel: C,\n type: T,\n handler: NarrowedEventHandler<DeepReadonly<S>, EM, C, T>,\n phase: EventPhase = \"committed\",\n ): Unsubscribe {\n const key = `${channel}::${String(type)}`;\n\n const targetMap =\n phase === \"committed\"\n ? this.committedEventSubscribers\n : phase === \"uncommitted\"\n ? this.uncommittedEventSubscribers\n : phase === \"written\"\n ? this.writtenEventSubscribers\n : this.allEventSubscribers;\n\n if (!targetMap.has(key)) {\n targetMap.set(key, new Set());\n }\n // Store handler with type cast since internal storage uses the broad type\n targetMap.get(key)!.add(handler as EventSubscriptionHandler<DeepReadonly<S>, EM>);\n\n return () => {\n const set = targetMap.get(key);\n if (set) {\n set.delete(handler as EventSubscriptionHandler<DeepReadonly<S>, EM>);\n if (set.size === 0) targetMap.delete(key);\n }\n };\n }\n\n /**\n * Subscribes to **coarse-grained** commits (called once per successful event, only if state changed).\n *\n * **Use Case**: React's `useSyncExternalStore` or similar external store integrations.\n *\n * @param fn - Listener invoked after reducers/effects have run and state has changed.\n * @returns Unsubscribe function.\n *\n * @example\n * ```ts\n * const off = store.subscribe(() => console.log('state committed'));\n * // Later:\n * off();\n * ```\n *\n * @public\n */\n public subscribe(fn: () => void): () => void {\n this.listeners.add(fn);\n return () => this.listeners.delete(fn);\n }\n\n /**\n * Returns the current immutable state snapshot.\n *\n * @returns Deep-readonly state object.\n *\n * @example\n * ```ts\n * const state = store.getState();\n * console.log(state.counter.value);\n * ```\n *\n * @public\n */\n public getState(): DeepReadonly<S> {\n return this.state;\n }\n\n /**\n * Registers a middleware (runs **before** reducers).\n *\n * @param mw - Middleware `(state, event, emit) => boolean`. Return `false` to cancel event\n * propagation.\n * @returns Unsubscribe function that removes this middleware.\n *\n * @remarks\n * **Synchronous, and that is the contract.** The reduce phase completes before `emit()`\n * returns, so the commit decision has to be available in the same tick. An `async` middleware\n * returns a Promise, every Promise is truthy, and the veto would therefore never fire — the\n * event would commit while the middleware was still deciding. The type rejects it; this note\n * exists because the examples here used to teach it. Do authorization and validation here, and\n * anything that needs to await in an effect.\n *\n * @example Logging middleware\n * ```ts\n * const off = store.registerMiddleware((state, event) => {\n * console.log('Event:', event.channel, event.type, event.payload);\n * return true; // allow\n * });\n * off();\n * ```\n *\n * @example Cancellation middleware\n * ```ts\n * store.registerMiddleware((state, event) => {\n * if (event.type === 'forbidden') return false; // cancel\n * return true;\n * });\n * ```\n *\n * @public\n */\n public registerMiddleware(mw: MiddlewareInput<DeepReadonly<S>, EM>): Unsubscribe {\n this.middleware.push(mw as any);\n return () => {\n const i = this.middleware.indexOf(mw as any);\n if (i !== -1) this.middleware.splice(i, 1);\n };\n }\n\n /**\n * Dynamically **adds** a named slice reducer at runtime.\n *\n * @param name - New slice name (must not already exist).\n * @param spec - Reducer spec (state, when, reducer).\n * @returns Disposer function that **removes** the slice (and its state).\n *\n * @example\n * ```ts\n * const dispose = store.registerReducer('filters', {\n * state: { q: '' },\n * events: [['ui', 'setQuery']],\n * reducer(s, evt) {\n * return evt.type === 'setQuery' ? { q: evt.payload } : s;\n * }\n * });\n * // Later:\n * dispose();\n * ```\n *\n * @public\n */\n public registerReducer(name: string, spec: ReducerSpec<any, EM>): () => void {\n // `hasOwnProperty`, not `in`: the registry is a plain object, so `in` also answers true for\n // everything on `Object.prototype`. A slice legitimately named `toString`, `constructor` or\n // `valueOf` was refused as already existing — with a message naming a reducer that does not\n // exist, which is the least useful place to send someone.\n if (Object.prototype.hasOwnProperty.call(this.reducers, name)) {\n throw new Error(`Reducer ${name} already exists`);\n }\n\n this.mountSlice(name as R, spec as ReducerSpec<S[R], EM>, {\n preserveState: false,\n });\n\n this.listeners.forEach((l) => l()); // broadcast new slice\n\n return () => {\n // disposer\n this.unmountSlice(name as R, { deleteState: true });\n this.listeners.forEach((l) => l());\n };\n }\n\n /**\n * Registers an **effect** (stateless async event consumer) that runs after reducers.\n *\n * Effects are **keyed** by `(channel, type)` for O(1) lookup (no scanning all effects).\n *\n * @param spec - Effect specification with `when` targeting and `effect` (handler).\n * @returns Unsubscribe function.\n *\n * @example Logging effect\n * ```ts\n * const off = store.registerEffect({\n * events: [['ui', 'increment']],\n * effect: async (evt, getState, emit) => {\n * console.log('increment', evt.payload, getState().counter.value);\n * }\n * });\n * off();\n * ```\n *\n * @example Multi-event effect\n * ```ts\n * store.registerEffect({\n * events: [['ui', 'increment'], ['ui', 'decrement']],\n * effect: async (evt, getState, emit) => {\n * // Runs for both increment and decrement\n * await saveToServer(getState());\n * }\n * });\n * ```\n *\n * @public\n */\n /**\n * Sends a request and waits for the reply, correlating the two automatically.\n *\n * @typeParam C - Request channel.\n * @typeParam T - Request type within `C`.\n * @param channel - Channel to send on.\n * @param type - Event type to send.\n * @param payload - The **request** payload. This is what you are sending; what comes back is\n * described by {@link CallOptions.reply}, not by this.\n * @param opts - Which replies end the call, and how long to wait. See {@link CallOptions}.\n * @returns A {@link CallHandle}: `await` it for the terminal reply, or `for await` it for\n * progress events as they arrive.\n *\n * @remarks\n * Every consumer of an event bus eventually writes request/reply by hand — mint an id,\n * subscribe, match, time out, unsubscribe — and every one of them writes the same eighty lines\n * with the same two bugs: the subscription outlives the call, and a responder that forgets to\n * echo the id produces a timeout with nothing to point at. This is that, once.\n *\n * **Correlation is causal.** The store stamps `parentId` on anything emitted while an event is\n * being handled, so a responder that replies through the `emit` it was handed is already\n * correlated. There is no id to mint, echo, or forget:\n *\n * ```ts\n * store.registerEffect({\n * when: { keys: [[\"rpc\", \"ask\"]] },\n * effect: async (event, _get, emit) => {\n * await emit(\"rpc\", \"answer\", await lookup(event.payload.q));\n * },\n * });\n * ```\n *\n * **The reply carries its own discriminant.** A call resolves to the *event*, not the payload,\n * because a caller often cannot know which kind of reply it will get:\n *\n * ```ts\n * const res = await store.call(\"rpc\", \"ask\", { q }, { reply: [\"rpc\", [\"answer\", \"error\"]] });\n * switch (res.type) {\n * case \"answer\": return res.payload;\n * case \"error\": throw new Error(res.payload.reason);\n * }\n * ```\n *\n * **Progress streams, with backpressure.** Any correlated event that is not terminal is\n * progress, and iterating the call consumes it. The producer genuinely waits: `emit` resolves\n * only once its effects have run, and the collector is an effect that does not return until the\n * consumer has taken the item. A responder writing `await emit(\"rpc\", \"progress\", chunk)` is\n * therefore paced by the reader, with nothing buffering without bound.\n *\n * ```ts\n * const call = store.call(\"job\", \"start\", { id }, {\n * reply: [\"job\", \"done\"],\n * highWaterMark: 4,\n * });\n * for await (const step of call) await render(step.payload); // producer waits on this\n * const { payload } = await call;\n * ```\n *\n * Backpressure engages **once you begin iterating**. A call that is only awaited never pulls,\n * so blocking its producer would deadlock the call itself — progress nobody reads would stop\n * the terminal event from ever being sent. Un-iterated progress therefore buffers to\n * `highWaterMark` and is then counted on {@link CallHandle.dropped} rather than blocking.\n *\n * **This is a local primitive.**\n *\n * @example Timeout is idle, not total\n * ```ts\n * // Survives a job that streams for minutes; fails a responder that goes quiet for 5s.\n * await store.call(\"job\", \"start\", { id }, { reply: [\"job\", \"done\"], timeoutMs: 5_000 });\n * ```\n *\n * @example Cancelling\n * ```ts\n * const call = store.call(\"rpc\", \"ask\", { q }, { reply: [\"rpc\", \"answer\"] });\n * useEffect(() => () => call.cancel(\"unmounted\"), [call]);\n * ```\n *\n * @public\n */\n public call<C extends keyof EM & string, T extends keyof EM[C] & string>(\n channel: C,\n type: T,\n payload: EM[C][T],\n opts: CallOptions<EM>,\n ): CallHandle<EventUnion<EM>, EventUnion<EM>> {\n return performCall<S, EM, C, T>(\n { idFactory: this.idFactory, registerEffect: this.registerEffect, emit: this.emit },\n channel,\n type,\n payload,\n opts,\n );\n }\n\n public registerEffect(spec: EffectSpec<DeepReadonly<S>, EM>): () => void {\n const { effect, meta, when } = spec;\n const unsubs: Array<() => void> = [];\n\n // Record metadata in a store-owned map keyed by the effect function, rather\n // than mutating the caller's function (which would bleed across stores).\n if (meta) {\n this.effectMeta.set(effect, meta);\n }\n\n // Check if this is a pattern-based effect (any, channel, channels)\n // or a key-based effect (keys, or no targeting = all events)\n const isPatternBased =\n when &&\n ((\"any\" in when && when.any === true) ||\n \"channel\" in when ||\n \"channels\" in when);\n\n if (isPatternBased) {\n // Store as pattern-based effect for runtime matching\n const entry = { effect, when: when! };\n this.patternEffects.add(entry);\n\n return () => {\n this.patternEffects.delete(entry);\n };\n }\n\n // Key-based effect: normalize to event keys\n const eventKeys = normalizeEventKeys(spec);\n\n // If no keys (no targeting at all), this effect matches ALL events\n // We treat it as a pattern-based effect with `any: true`\n if (eventKeys.length === 0 && !when) {\n const entry = { effect, when: { any: true } as When<EM> };\n this.patternEffects.add(entry);\n\n return () => {\n this.patternEffects.delete(entry);\n };\n }\n\n // Register for specific event keys\n for (const [channel, type] of eventKeys) {\n const key = `${String(channel)}::${String(type)}`;\n if (!this.effects.has(key)) {\n this.effects.set(key, new Set());\n }\n this.effects.get(key)!.add(effect);\n\n // Create disposer\n unsubs.push(() => {\n const set = this.effects.get(key);\n if (set) {\n set.delete(effect);\n if (set.size === 0) this.effects.delete(key);\n }\n });\n }\n\n return () => {\n for (const u of unsubs) u();\n };\n }\n\n\n\n /**\n * Convenience helper to register an **effect** filtered by a single `(channel, type)` pair.\n *\n * @typeParam C - Channel key within `EM`.\n * @typeParam T - Event type key within channel `C`.\n * @param channel - Channel to filter.\n * @param type - Event type to filter.\n * @param handler - Effect handler `(payload, getState, emit, event)`.\n * @returns Unsubscribe/teardown function.\n *\n * @example\n * ```ts\n * const off = store.onEffect('ui', 'increment', async (n, get, emit) => {\n * if (n > 10) await emit('ui', 'increment', -10);\n * });\n * // later\n * off();\n * ```\n *\n * @public\n */\n public onEffect<\n C extends keyof EM & string,\n T extends keyof EM[C] & string\n >(\n channel: C,\n type: T,\n handler: (\n payload: EM[C][T],\n getState: () => DeepReadonly<S>,\n emit: Emit<EM>,\n event: Event<EM, C, T>,\n ) => void | Promise<void>,\n ): () => void {\n const effect: EffectFunction<DeepReadonly<S>, EM> = async (evt, getState, emit) => {\n if (evt.channel !== channel || evt.type !== type) return;\n\n const typed = evt as Event<EM, C, T>;\n return handler(typed.payload, getState, emit, typed);\n };\n\n return this.registerEffect({\n when: { keys: [[channel, type] as EventKey<EM>] },\n effect,\n });\n }\n\n /**\n * Replaces the **entire** middleware pipeline (HMR-friendly).\n *\n * @param next - New middleware array.\n *\n * @example Hot module replacement\n * ```ts\n * if (import.meta.hot) {\n * import.meta.hot.accept('./middleware', (newModule) => {\n * store.replaceMiddleware(newModule.middleware);\n * });\n * }\n * ```\n *\n * @public\n */\n public replaceMiddleware(next: MiddlewareInput<DeepReadonly<S>, EM>[]): void {\n // Accepts either form. Taking only the bare function meant a hot reload silently discarded\n // the `when` targeting and `meta` of every spec-form middleware, so after an HMR pass a\n // middleware scoped to one channel began running on all of them.\n (this.middleware as any).length = 0;\n for (const mw of next) this.middleware.push(mw as any);\n }\n\n /**\n * Replaces all registered **effects** (HMR-friendly).\n *\n * @param next - New effects array (as EffectSpecs).\n *\n * @example Hot module replacement\n * ```ts\n * if (import.meta.hot) {\n * import.meta.hot.accept('./effects', (newModule) => {\n * store.replaceEffects(newModule.effects);\n * });\n * }\n * ```\n *\n * @public\n */\n public replaceEffects(next: Array<EffectSpec<DeepReadonly<S>, EM>>): void {\n this.effects.clear();\n this.patternEffects.clear();\n for (const spec of next) {\n this.registerEffect(spec);\n }\n }\n\n /**\n * Replaces the entire **reducer set** (HMR-friendly).\n *\n * @param next - Map of slice specs keyed by slice name.\n * @param opts - `{ preserveState?: boolean }` (default `true`).\n *\n * @example Hot module replacement\n * ```ts\n * if (import.meta.hot) {\n * import.meta.hot.accept('./reducers', (newModule) => {\n * store.replaceReducers(newModule.reducers, { preserveState: true });\n * });\n * }\n * ```\n *\n * @public\n */\n public replaceReducers(\n next: Record<R, ReducerSpec<S[R], EM>>,\n opts: { preserveState?: boolean } = {},\n ): void {\n const preserveState = opts.preserveState !== false; // default true\n\n const currentKeys = new Set(Object.keys(this.reducers as any));\n const nextEntries = Object.entries(next);\n const nextKeys = new Set(nextEntries.map(([k]) => k));\n\n // Remove slices that no longer exist\n for (const k of currentKeys) {\n if (!nextKeys.has(k)) this.unmountSlice(k as R, { deleteState: true });\n }\n\n // Add or update slices\n for (const [k, rSpec] of nextEntries) {\n if (currentKeys.has(k)) {\n // Update reducer impl + event wiring; preserve current state\n this.unmountSlice(k as R, { deleteState: false });\n this.mountSlice(k as R, rSpec as any, { preserveState });\n } else {\n // New slice\n this.mountSlice(k as R, rSpec as any, { preserveState: false });\n }\n }\n\n }\n\n /**\n * Convenience API to replace **any subset** of store parts (HMR patterns).\n *\n * @param partial - Partial replacement set.\n *\n * @example Replace everything\n * ```ts\n * store.hotReplace({\n * reducer: newReducers,\n * middleware: newMiddleware,\n * effects: newEffects,\n * preserveState: true\n * });\n * ```\n *\n * @public\n */\n public hotReplace(partial: {\n reducer?: Record<R, ReducerSpec<S[R], EM>>;\n middleware?: MiddlewareInput<DeepReadonly<S>, EM>[];\n effects?: Array<EffectSpec<DeepReadonly<S>, EM>>;\n preserveState?: boolean;\n }): void {\n if (partial.middleware) this.replaceMiddleware(partial.middleware);\n if (partial.effects) this.replaceEffects(partial.effects);\n if (partial.reducer)\n this.replaceReducers(partial.reducer, { preserveState: partial.preserveState });\n }\n\n /**\n * Mounts a slice: installs reducer, initializes state (unless preserved),\n * and wires `(channel, type)` listeners on the reducer bus.\n *\n * @param name - Slice name.\n * @param rSpec - Reducer spec (state, when, reducer).\n * @param opts - `{ preserveState: boolean }` whether to keep existing state.\n *\n * @internal\n */\n private mountSlice(\n name: R,\n rSpec: ReducerSpec<S[R], EM>,\n opts: { preserveState: boolean },\n ): void {\n const rName = name as unknown as string;\n const { reducer, state, when } = rSpec;\n\n // Install reducer instance (FIXED: only pass reducer function)\n this.reducers[name] = new Reducer(reducer);\n\n // Initialize state unless preserving an existing value\n if (!opts.preserveState || (this.state as any)[rName] === undefined) {\n // A NEW root, not a write into the existing one. Mounting a slice is a state change, and\n // anything keyed on root identity — `useSelector` bailing out on `Object.is`, a memo, a\n // devtools snapshot differ — could not see it when the root object stayed the same.\n // Clone the caller's initial state so the store owns an independent copy; freeze is\n // dev-only.\n this.state = {\n ...(this.state as object),\n [rName]: freezeInDev(cloneInitialState(rName, state)),\n } as DeepReadonly<S>;\n }\n\n // Check if this is a pattern-based reducer (any, channel, channels)\n const isPatternBased =\n when &&\n ((\"any\" in when && when.any === true) ||\n \"channel\" in when ||\n \"channels\" in when);\n\n if (isPatternBased) {\n // Store as pattern-based reducer for runtime matching\n this.patternReducers.set(name, when);\n // No unsubs needed for pattern reducers - they're called from emit loop\n this.sliceUnsubs.set(rName, []);\n return;\n }\n\n // Normalize event keys from `when: { keys }`\n const eventKeys = normalizeEventKeys(rSpec);\n\n // If no targeting at all, treat as \"all events\" (pattern-based)\n if (eventKeys.length === 0 && !when) {\n this.patternReducers.set(name, { any: true });\n this.sliceUnsubs.set(rName, []);\n return;\n }\n\n // Wire reducerBus listeners and save disposers for HMR\n const unsubs: Array<() => void> = [];\n for (const [ch, tp] of eventKeys) {\n const u = this.reducerBus.on(ch, tp, (payload, sourceEvent) => {\n // Prefer the source event so keyed reducers see the same `id` (and `meta`) as\n // pattern reducers, effects, event subscribers and instrumentation. The fallback\n // only applies when something emits on `reducerBus` without an event.\n const event = (sourceEvent ?? {\n channel: ch,\n type: tp,\n payload,\n id: this.idFactory(),\n }) as Event<EM, typeof ch, typeof tp>;\n // Staged, not committed. `reducerBus` delivers to handlers and has no return channel,\n // so a refusal is recorded on the store for `applyEventSync` to read — the same reason\n // `changedPathSink` exists. The sink is null outside a reduce, which is the only path\n // that can reach here.\n if (this.stagingSink === null) return;\n const refused = this.stageSliceGuarded(name, event as any, this.stagingSink);\n if (refused !== null && this.stagedRejection === null) {\n this.stagedRejection = refused;\n this.stagedRejectedBy = name as string;\n }\n });\n\n unsubs.push(u);\n }\n\n this.sliceUnsubs.set(rName, unsubs);\n }\n\n /**\n * Unmounts a slice: disposes reducer-bus listeners, removes reducer,\n * and optionally deletes the slice state.\n *\n * @param name - Slice name.\n * @param opts - `{ deleteState: boolean }`.\n *\n * @internal\n */\n private unmountSlice(name: R, opts: { deleteState: boolean }): void {\n const rName = name as unknown as string;\n\n // Remove from pattern reducers if present\n this.patternReducers.delete(name);\n\n // Dispose reducerBus listeners\n const unsubs = this.sliceUnsubs.get(rName);\n if (unsubs) {\n for (const u of unsubs)\n try {\n u();\n } catch (e) {\n console.error(`[Store error]: ${e}`);\n }\n\n this.sliceUnsubs.delete(rName);\n }\n\n // Remove reducer instance\n delete this.reducers[name];\n\n // Optionally drop state\n if (opts.deleteState) {\n const { [rName]: _removed, ...rest } = this.state as Record<string, unknown>;\n this.state = rest as DeepReadonly<S>;\n }\n }\n\n /**\n * Reads a dotted path from an object (supports numeric array indices via string keys).\n *\n * @param obj - Root object (slice or value).\n * @param path - Dotted path; leading dot is ignored.\n * @returns The value at the path, or `undefined`.\n *\n * @remarks\n * A member rather than a bare import: a test replaces this on the instance to count how many\n * walks describing a change costs, which only works while the callers go through `this`.\n *\n * @internal\n */\n private getAtPath(obj: any, path: string): any {\n return readAtPath(obj, path);\n }\n\n /**\n * Builds ancestor paths for a dotted path.\n *\n * For `\"a.b.c\"`, returns `[\"a\", \"a.b\", \"a.b.c\"]`. Leading dots are trimmed.\n *\n * @param path - Dotted path string.\n * @returns Array of ancestor paths.\n *\n * @example\n * ```ts\n * Store.buildAncestorPaths('x.y.z'); // ['x','x.y','x.y.z']\n * ```\n *\n * @public\n */\n static buildAncestorPaths(path: string): string[] {\n return ancestorPaths(path);\n }\n}\n\n/**\n * Creates a store with explicit State and EventMap types.\n *\n * Use this overload for:\n * - **Event-only stores** (no reducers, just middleware/effects)\n * - When TypeScript inference from reducers isn't sufficient\n * - When you want to define the EventMap independently of reducers\n *\n * @typeParam S - State record type (can be empty `{}` for event-only stores).\n * @typeParam EM - Event map type defining all `channel → type → payload` combinations.\n * @param cfg - Configuration with `name`, optional `reducer`, optional `middleware`, optional `effects`.\n * @returns A typed {@link StoreInstance}.\n *\n * @example Event-only store\n * ```ts\n * type AppEM = {\n * notifications: { show: { message: string }; hide: void };\n * };\n *\n * const store = createStore<{}, AppEM>({\n * name: 'NotificationBus',\n * effects: [{\n * when: { channel: 'notifications' },\n * effect: (evt) => {\n * if (evt.type === 'show') showToast(evt.payload.message);\n * },\n * }],\n * });\n * ```\n *\n * @example Explicit generics with reducers\n * ```ts\n * const store = createStore<AppState, AppEM>({\n * name: 'App',\n * reducer: { counter: counterSpec },\n * middleware: [loggingMiddleware],\n * });\n * ```\n *\n * @public\n */\nexport function createStore<\n S extends Record<string, any>,\n EM extends EventMapBase,\n>(cfg: {\n name: string;\n reducer?: { [K in keyof S]?: ReducerSpec<S[K], EM> };\n middleware?: MiddlewareInput<DeepReadonly<S>, EM>[];\n effects?: Array<EffectSpec<DeepReadonly<S>, EM>>;\n dedupWindowMs?: number;\n idFactory?: () => string;\n devtools?: { allowReplay?: boolean };\n onEffectError?: (error: unknown, event: EventUnion<EM>) => void;\n onReducerError?: (error: unknown, event: EventUnion<EM>, slice: string) => void;\n maxReduceDepth?: number;\n maxTransitionsPerDrain?: number;\n onCascade?: (info: CascadeInfo<EM>) => void;\n onRejected?: (rejection: Rejection, event: EventUnion<EM>, slice: string) => void;\n}): StoreInstance<keyof S & string, S, EM>;\n\n/**\n * Creates a store with types inferred from the reducers map.\n *\n * This is the primary overload for most use cases where reducers define\n * both the state shape and the event map.\n *\n * @typeParam RM - Reducers map object with each slice's `ReducerSpec`.\n * @param cfg - Configuration with `name`, `reducer`, optional `middleware`, optional `effects`.\n * @returns A typed {@link StoreInstance}.\n *\n * @example\n * ```ts\n * const store = createStore({\n * name: 'App',\n * reducer: {\n * counter: {\n * state: { value: 0 },\n * when: { keys: eventKeys<MyEM>()([['ui', 'increment']]) },\n * reducer: (s, evt) => evt.type === 'increment' ? { value: s.value + evt.payload } : s\n * }\n * },\n * middleware: [],\n * effects: []\n * });\n * ```\n *\n * @public\n */\nexport function createStore<RM extends ReducersMapAny>(cfg: {\n name: string;\n reducer: RM;\n middleware?: MiddlewareInput<\n DeepReadonly<StateFromReducers<RM>>,\n EMFromReducersStrict<RM>\n >[];\n effects?: Array<EffectSpec<DeepReadonly<StateFromReducers<RM>>, EMFromReducersStrict<RM>>>;\n dedupWindowMs?: number;\n idFactory?: () => string;\n devtools?: { allowReplay?: boolean };\n onEffectError?: (error: unknown, event: EventUnion<EMFromReducersStrict<RM>>) => void;\n onReducerError?: (\n error: unknown,\n event: EventUnion<EMFromReducersStrict<RM>>,\n slice: string,\n ) => void;\n maxReduceDepth?: number;\n maxTransitionsPerDrain?: number;\n onCascade?: (info: CascadeInfo<EMFromReducersStrict<RM>>) => void;\n onRejected?: (\n rejection: Rejection,\n event: EventUnion<EMFromReducersStrict<RM>>,\n slice: string,\n ) => void;\n}): StoreInstance<keyof RM & string, StateFromReducers<RM>, EMFromReducersStrict<RM>>;\n\nexport function createStore(cfg: any) {\n type RM = typeof cfg.reducer;\n type S = StateFromReducers<RM>;\n type EM = EMFromReducersStrict<RM>;\n type RN = keyof RM & string;\n\n // Spread, then override the three fields that need a default. Copying the option list by hand\n // meant every option added to `StoreSpec` had to be added here too, and forgetting was silent:\n // the option type-checked at the call site, reached `createStore`, and was dropped on the\n // floor. `maxReduceDepth` was lost exactly that way. The Store constructor reads named fields,\n // so anything extra in `cfg` is ignored rather than harmful.\n return new Store<EM, RN, S>({\n ...cfg,\n reducer: (cfg.reducer ?? {}) as unknown as Record<RN, ReducerSpec<S[RN], EM>>,\n middleware: (cfg.middleware ?? []) as any,\n effects: (cfg.effects ?? []) as any,\n });\n}\n\n/**\n * Utility to define **typed** `(channel, events[])` definitions for reducer specs.\n *\n * @typeParam EM - Event map for the store.\n * @param _ - Internal marker parameter (usually `events` array placeholder). Not used at runtime.\n * @returns A helper that, given a `channel` and a readonly `events` array, returns typed event keys.\n *\n * @example\n * ```ts\n * // In a ReducerSpec:\n * const events = typedEvents<EM>([])('ui', ['increment', 'decrement'] as const);\n * // events: ReadonlyArray<EventKey<EM>>\n * ```\n *\n * @public\n */\nexport const typedEvents = <EM extends EventMapBase>(_: string[][]) =>\n <C extends keyof EM & string, Evt extends readonly (keyof EM[C] & string)[]>(\n channel: C,\n events: Evt,\n ): ReadonlyArray<EventKey<EM>> => events.map((e) => [channel, e] as const);","/**\n * @module @yoltra/core\n */\n\nimport type { Rejection } from \"./store/rejection\";\nimport type { CallHandle, CallOptions } from \"./store/call\";\n\n/**\n * A minimal \"record of record\" constraint for EventMaps.\n *\n * @example\n * ```ts\n * type EM = {\n * ui: { toggle: boolean; setTheme: string };\n * data: { loaded: { items: string[] } };\n * };\n * ```\n *\n * @public\n */\nexport type EventMapBase = {\n [C in string]: { [T in string]: unknown };\n};\n\n/**\n * Canonical routing concept: a readonly tuple `[channel, type]` that uniquely identifies an event.\n *\n * @typeParam EM - Event map.\n *\n * @remarks\n * - Used consistently across ReducerSpec, EffectSpec, and React hooks.\n * - Literal key lists narrow channel/type/payload in reducers and effects.\n * - Non-literal usage degrades safely to unions.\n *\n * @example\n * ```ts\n * type EM = {\n * ui: { increment: number; decrement: number };\n * data: { loaded: string[] };\n * };\n *\n * type K = EventKey<EM>;\n * // K = ['ui', 'increment'] | ['ui', 'decrement'] | ['data', 'loaded']\n *\n * const key: EventKey<EM> = ['ui', 'increment'];\n * ```\n *\n * @public\n */\nexport type EventKey<EM extends EventMapBase> = {\n [C in keyof EM & string]: [C, keyof EM[C] & string];\n}[keyof EM & string];\n\n/**\n * Opaque, optional envelope metadata carried alongside an {@link Event}.\n *\n * @remarks\n * The store never reads, validates or acts on this — it only carries it end to end, so\n * reducers, middleware, effects, event subscribers and instrumentation all observe the same\n * value. It is deliberately untyped at this level: consumers namespace their own keys (for\n * example a tracing integration keeping provenance under `meta.trace`) rather than\n * extending core with domain concepts.\n *\n * It is **not** part of the deduplication fingerprint, which is computed from\n * `(channel, type, payload)` only. Two events differing solely in `meta` still dedupe.\n *\n * @example\n * ```ts\n * await store.emit('orders', 'created', payload, {\n * meta: { trace: { origin: 'checkout-service', hop: 1 } },\n * });\n * ```\n *\n * @public\n */\nexport type EventMeta = Readonly<Record<string, unknown>>;\n\n/**\n * A single event object: `{ channel, type, payload, id }`, plus optional `meta`.\n *\n * @typeParam EM - Event map.\n * @typeParam C - Channel key.\n * @typeParam T - Type key within channel `C`.\n * @typeParam P - Payload type (defaults to `EM[C][T]`).\n *\n * @remarks\n * - The `id` field is automatically added by the store to enable deduplication, unless the\n * emitter supplies one via {@link EmitOptions.id}.\n * - Used for preventing duplicate event processing (e.g., React Strict Mode).\n * - `meta` is present only when {@link EmitOptions.meta} was supplied. See {@link EventMeta}.\n *\n * @example\n * ```ts\n * type EM = { ui: { toggle: boolean } };\n * type Evt = Event<EM, 'ui', 'toggle'>;\n * // { channel: 'ui'; type: 'toggle'; payload: boolean; id: string; meta?: EventMeta }\n * ```\n *\n * @public\n */\nexport interface Event<\n EM extends EventMapBase = EventMapBase,\n C extends keyof EM & string = keyof EM & string,\n T extends keyof EM[C] & string = keyof EM[C] & string,\n P = EM[C][T],\n> {\n channel: C;\n type: T;\n payload: P;\n /** Unique identifier for deduplication and devtools tracking (automatically added by store) */\n id: string;\n /**\n * Optional caller-supplied metadata, carried through the pipeline untouched.\n * Absent entirely unless {@link EmitOptions.meta} was supplied. See {@link EventMeta}.\n */\n readonly meta?: EventMeta;\n /**\n * The `id` of the event whose handling caused this one, when there was one.\n *\n * @remarks\n * Absent on a **root** event — one emitted by application code rather than by a middleware,\n * subscriber or effect reacting to another event. Together with {@link Event.depth} this makes\n * a cascade legible after the fact: without it, a runaway chain is a pile of unrelated events\n * with no way to tell which caused which.\n */\n readonly parentId?: string;\n /**\n * How many events deep in a causal chain this one is. A root event is depth `0`; an event\n * emitted while handling it is `1`, and so on.\n *\n * @remarks\n * Absent on a root event rather than present as `0`, so an event emitted by application code\n * stays byte-identical to one built before causality tracking existed — the same treatment\n * {@link Event.meta} gets, and for the same reason: `Object.keys` and `toStrictEqual` are load\n * bearing in consumer tests.\n *\n * This is the value {@link StoreSpec.maxReduceDepth} bounds.\n */\n readonly depth?: number;\n}\n\n/**\n * Generic \"old → new\" wrapper for fine-grained change notifications.\n * Carries the dotted `path` that changed.\n *\n * @typeParam V - Value type at the changed path.\n *\n * @example\n * ```ts\n * const change: Change<string> = {\n * oldValue: 'foo',\n * newValue: 'bar',\n * path: 'user.name'\n * };\n * ```\n *\n * @public\n */\nexport interface Change<V = any> {\n oldValue: V;\n newValue: V;\n /** Dotted path for fine-grained listeners; e.g., \"data.items.0.title\" */\n path?: string;\n /**\n * The `id` of the event that caused this change.\n *\n * @remarks\n * A change used to be anonymous, so a subscriber that needed to know *why* a value moved had\n * to mirror the cause into state and store it twice. Absent when the change did not come from\n * an event — a DevTools time-travel snapshot, for instance — which is itself the signal that\n * no event caused it.\n */\n eventId?: string;\n /** Channel of the causing event. Absent for the same reason as {@link Change.eventId}. */\n channel?: string;\n /** Type of the causing event. Absent for the same reason as {@link Change.eventId}. */\n type?: string;\n}\n\n/**\n * Emit function narrowed to the developer's EventMap.\n * Returns a Promise that resolves when the event has been fully processed.\n *\n * @typeParam EM - Event map.\n *\n * @example\n * ```ts\n * type EM = { ui: { increment: number } };\n * const emit: Emit<EM> = async (channel, type, payload) => { /* ... *\\/ };\n * await emit('ui', 'increment', 1);\n * ```\n *\n * @public\n */\n/**\n * What an `emit` resolves to once its effects have run.\n *\n * @remarks\n * `emit` used to resolve to `void`, so a caller could not tell \"the reducer applied my write\"\n * from \"the reducer looked at my write and returned the state unchanged\". On a single-writer\n * store that distinction is academic; on a contended one it is a lost update the API could not\n * report.\n *\n * Deliberately does **not** carry the changed paths. Building that list costs a string\n * concatenation per changed path on every emit, and almost no caller reads it — the same reason\n * change notifications are built lazily. Instrumentation already provides them to the observers\n * that do want them.\n *\n * @public\n */\nexport interface EmitResult {\n /**\n * The event was not vetoed by middleware.\n *\n * @remarks\n * Unchanged in meaning, and deliberately not narrowed to \"state changed\" — an event-only store\n * commits every event and writes nothing, by construction.\n */\n readonly committed: boolean;\n /** A reducer actually changed state. */\n readonly written: boolean;\n /** Present when a reducer refused the write. See {@link Rejection}. */\n readonly rejected?: Rejection;\n}\n\n/**\n * Options for {@link StoreInstance.connect}.\n *\n * @public\n */\nexport interface ConnectOptions {\n /**\n * Deliver the current value once, immediately, before any change arrives.\n *\n * @remarks\n * A subscription otherwise starts at \"from now on\", so a subscriber's first render has to read\n * the path separately — the same path, spelled twice, which is one place for them to drift.\n *\n * The synthetic change has `oldValue: undefined` and no `eventId`, `channel` or `type`: no\n * event caused it, and claiming one would be a lie a subscriber could act on.\n *\n * For a wildcard pattern the \"current value\" of a match set is not a thing, so the slice root\n * is delivered with `path: \"\"`. React's hooks do not need this at all — `useSyncExternalStore`\n * already reads a snapshot on mount — so it is aimed at imperative subscribers.\n */\n readonly immediate?: boolean;\n}\n\n/**\n * Per-emit options.\n *\n * @public\n */\nexport interface EmitOptions {\n /**\n * Opt this specific emit into **identity-based** deduplication: if another\n * event with the same `(channel, type, dedupKey)` was emitted within the dedup\n * window, this one is skipped. Unlike content-based dedup\n * ({@link StoreSpec.dedupWindowMs}), it never coalesces two *distinct* logical\n * emits that merely share a payload — only re-fires of the *same* keyed emit\n * (e.g. a React Strict Mode double-invoke). Works even when `dedupWindowMs`\n * is 0, using a short default window.\n */\n dedupKey?: string;\n\n /**\n * Use this exact id for the event instead of generating one.\n *\n * @remarks\n * Intended for **idempotent re-emission**: a caller replaying an event from elsewhere (another\n * store, a durable log) can preserve the original id so the same logical event keeps\n * one identity everywhere, which makes it traceable across systems and in DevTools.\n *\n * The store does **not** enforce uniqueness — supplying a duplicate id does not dedupe the\n * event. Deduplication is a separate, opt-in concern; see {@link EmitOptions.dedupKey}.\n */\n id?: string;\n\n /**\n * Metadata to attach to this event, carried through the pipeline untouched and visible to\n * reducers, middleware, effects, subscribers and instrumentation. See {@link EventMeta}.\n *\n * @remarks\n * Omitting this leaves `event.meta` genuinely absent rather than `undefined`, so event\n * objects are byte-identical to those produced before this option existed.\n */\n meta?: EventMeta;\n\n /**\n * Bypass deduplication for this emit entirely, even when the store was created with\n * {@link StoreSpec.dedupWindowMs} greater than 0.\n *\n * @remarks\n * Content-based dedup fingerprints `(channel, type, payload)`, so a store with a dedup\n * window silently collapses genuinely distinct events that happen to share a payload —\n * repeated ticks with an empty payload, or the same event legitimately arriving twice from\n * two different sources. Set this when the caller already guarantees distinctness by other\n * means and needs every emit to land.\n *\n * Takes precedence over both {@link EmitOptions.dedupKey} and the store-level window.\n */\n skipDedup?: boolean;\n}\n\nexport type Emit<EM extends EventMapBase> = <\n C extends keyof EM & string,\n T extends keyof EM[C] & string,\n>(\n channel: C,\n type: T,\n payload: EM[C][T],\n opts?: EmitOptions,\n) => Promise<EmitResult>;\n\n/**\n * Basic unsubscribe handle.\n *\n * @public\n */\nexport type Unsubscribe = () => void;\n\n/**\n * A single observed event delivered to an {@link InstrumentationObserver}.\n *\n * @typeParam EM - Event map.\n *\n * @public\n */\nexport interface InstrumentedEvent<EM extends EventMapBase = EventMapBase> {\n /**\n * The processed event, including its `id` and any {@link EventMeta} the emitter attached.\n * `meta` is absent unless it was supplied.\n */\n event: { id: string; channel: string; type: string; payload: unknown; meta?: EventMeta };\n /** `true` if the event passed middleware and ran reducers; `false` if vetoed. */\n committed: boolean;\n /**\n * Dotted **leaf** paths that changed, prefixed with the slice name (e.g.\n * `\"todos.items.0.title\"`). Empty when nothing changed. These are the exact\n * paths the store computed while reducing — no re-diff required.\n */\n changedPaths: string[];\n /** Old value at each changed path, keyed by path. */\n prevValues: Record<string, unknown>;\n /** New value at each changed path, keyed by path. */\n nextValues: Record<string, unknown>;\n /** Wall-clock milliseconds spent in the synchronous reduce phase for this event. */\n reduceTimeMs: number;\n /**\n * Present when a reducer refused the write, carrying its reason.\n *\n * @remarks\n * Distinct from `committed: false`, which means middleware vetoed the event before any reducer\n * saw it. This is a reducer having considered the write and declined it — the two look\n * identical in state and are entirely different in cause.\n */\n rejected?: Rejection;\n}\n\n/**\n * Observer for {@link StoreInstance.instrument}. Called once per emitted event\n * (committed or vetoed), after the synchronous reduce phase.\n *\n * @typeParam EM - Event map.\n *\n * @public\n */\nexport type InstrumentationObserver<EM extends EventMapBase = EventMapBase> = (\n info: InstrumentedEvent<EM>,\n) => void;\n\n/**\n * Store spec - what you feed into the constructor / factory.\n *\n * @typeParam R - Reducer name union (string literal union).\n * @typeParam S - State record keyed by `R`.\n * @typeParam EM - Event map.\n *\n * @example\n * ```ts\n * type S = { counter: { value: number } };\n * type EM = { ui: { increment: number } };\n *\n * const spec: StoreSpec<'counter', S, EM> = {\n * name: 'App',\n * reducer: {\n * counter: {\n * state: { value: 0 },\n * events: [['ui', 'increment']],\n * reducer(s, evt) {\n * if (evt.type === 'increment') return { value: s.value + evt.payload };\n * return s;\n * }\n * }\n * }\n * };\n * ```\n *\n * @public\n */\n/**\n * Middleware input: accepts either a function (legacy) or a spec object (recommended).\n *\n * @typeParam S - Store state (readonly).\n * @typeParam EM - Event map.\n *\n * @example Function form (legacy)\n * ```ts\n * const mw: MiddlewareInput<AppState, AppEM> = (state, event, emit) => {\n * console.log(event.type);\n * return true;\n * };\n * ```\n *\n * @example Spec form (recommended)\n * ```ts\n * const mw: MiddlewareInput<AppState, AppEM> = {\n * when: { channel: 'admin' },\n * middleware: (state, event, emit) => state.auth.isAdmin,\n * meta: { type: 'middleware', name: 'authGuard' },\n * };\n * ```\n *\n * @public\n */\nexport type MiddlewareInput<S = any, EM extends EventMapBase = EventMapBase> =\n | MiddlewareFunction<S, EM>\n | MiddlewareSpec<S, EM>;\n\n/**\n * Store configuration object passed to the {@link Store} constructor or {@link createStore}.\n *\n * @typeParam R - Reducer name union (string literal union).\n * @typeParam S - State record keyed by `R`.\n * @typeParam EM - Event map.\n *\n * @example\n * ```ts\n * type S = { counter: { value: number } };\n * type EM = { ui: { increment: number } };\n *\n * const spec: StoreSpec<'counter', S, EM> = {\n * name: 'App',\n * reducer: {\n * counter: {\n * state: { value: 0 },\n * when: { keys: eventKeys<EM>()([['ui', 'increment']]) },\n * reducer(s, evt) {\n * if (evt.type === 'increment') return { value: s.value + evt.payload };\n * return s;\n * }\n * }\n * }\n * };\n * ```\n *\n * @public\n */\nexport type StoreSpec<R extends string, S extends Record<R, any>, EM extends EventMapBase> = {\n /**\n * Store name (used by DevTools to identify the instance).\n */\n name: string;\n\n /**\n * Map of slice name → reducer spec.\n * Each entry declares initial state, the reducer function, and the event targeting.\n */\n reducer: Record<R, ReducerSpec<S[R], EM>>;\n\n /**\n * Middleware chain executed before reducers/effects.\n * Accepts either functions (legacy) or MiddlewareSpec objects (recommended).\n * If any middleware returns false (or resolves to false), the event will not propagate.\n */\n middleware?: MiddlewareInput<DeepReadonly<S>, EM>[];\n\n /**\n * Optional side-effect handlers registered at construction time.\n * Runs after reducers for every propagated event.\n */\n effects?: Array<EffectSpec<DeepReadonly<S>, EM>>;\n\n /**\n * Time window in milliseconds for **content-based** event deduplication.\n * When greater than 0, events with identical fingerprints\n * (channel + type + serialized payload) within this window are treated as\n * duplicates and skipped.\n *\n * **Off by default.** Content-based dedup can silently drop legitimate\n * rapid-fire identical events (double-clicks, repeated `+1`, sliders emitting\n * the same value), so it is opt-in. To safely coalesce a *specific* re-fired\n * emit (e.g. React Strict Mode), prefer the per-emit {@link EmitOptions.dedupKey}.\n *\n * @default 0 (disabled)\n */\n dedupWindowMs?: number;\n\n /**\n * Generates the `id` for each emitted event. Defaults to `crypto.randomUUID()`.\n *\n * @remarks\n * Two reasons to override it. First, portability: `crypto.randomUUID` requires a **secure\n * context** in browsers and is absent on some runtimes (React Native / Hermes), where the\n * default would throw on every emit. Second, determinism: injecting a counter makes event\n * ids stable across runs, which is what allows byte-exact assertions in tests.\n *\n * The factory must return a string. Uniqueness is the caller's responsibility.\n *\n * @default () => crypto.randomUUID()\n *\n * @example\n * ```ts\n * let n = 0;\n * const store = createStore({ name: 'Test', reducer, idFactory: () => `evt-${++n}` });\n * ```\n */\n idFactory?: () => string;\n\n /**\n * DevTools configuration options.\n *\n * @remarks\n * These options control runtime DevTools capabilities such as event replay.\n */\n devtools?: {\n /**\n * Enable event replay via `__replayEvents()`.\n * When `false` (default), calling `__replayEvents()` throws.\n *\n * @default false\n */\n allowReplay?: boolean;\n };\n\n /**\n * Called when an effect throws or its returned promise rejects.\n *\n * @remarks\n * `await emit(...)` **never rejects** on effect failure: the reduce phase has\n * already committed synchronously, and effects run as independent per-event\n * tasks. Effect errors are logged to the console and delivered here (when\n * provided), so this is the single place to observe and route them — e.g.\n * report to a service or emit a failure event. Other effects still run.\n *\n * @param error - The thrown value or rejection reason.\n * @param event - The event whose effect failed.\n */\n onEffectError?: (error: unknown, event: EventUnion<EM>) => void;\n\n /**\n * Invoked when a reducer throws.\n *\n * @remarks\n * A reducer is meant to be pure and total, so a throw is a bug in application code — and it\n * used to be almost invisible. Keyed reducers ran through a bus that logged and moved on,\n * letting the event commit and its effects run; pattern reducers threw straight out of the\n * drain, aborting the commit and notifying nobody. Both paths now isolate the failing slice\n * and report here.\n *\n * The failing slice keeps its previous state; every other slice still reduces, and the event\n * still commits if anything else changed. `emit()` never rejects because of a reducer error,\n * so this hook is how a caller observes one.\n *\n * @param error - The thrown value.\n * @param event - The event being reduced when it threw.\n * @param slice - Name of the slice whose reducer threw.\n */\n onReducerError?: (error: unknown, event: EventUnion<EM>, slice: string) => void;\n\n /**\n * Maximum causal depth of an event chain before the store refuses to extend it.\n *\n * @remarks\n * An event emitted while handling another is one deeper than its cause. Two reducers wired to\n * each other, or an effect that emits the event its own reducer answers, climb this without\n * bound — and the reduce queue drains synchronously, so in a browser that is a frozen tab with\n * no error and no stack, and on a server a pinned core.\n *\n * **On by default**, because the whole point is that the failure mode does not require\n * configuration to avoid. The default is far past any legitimate chain: an event caused by an\n * event caused by an event is normal, sixty-four deep is a bug. Raise it if an application\n * genuinely nests deeper, or set `Infinity` to opt out entirely and own the consequences.\n *\n * Breaching does not throw — see {@link StoreSpec.onCascade}.\n *\n * @default 64\n */\n maxReduceDepth?: number;\n\n /**\n * Maximum number of events one synchronous drain will process before refusing more.\n *\n * @remarks\n * A drain processes one root event plus every event emitted *while it runs* — so this counts a\n * single causal burst, not application traffic. A plain loop is unaffected: `emit` drains to\n * completion before it returns, so `for (const row of rows) store.emit(…)` is a thousand drains\n * of one event each, never one drain of a thousand.\n *\n * **Off by default** because a wide burst is not by itself a bug. One `sync` event whose\n * subscriber fans out to five hundred `upsert`s is a legitimate shape, and a default low enough\n * to catch a runaway would refuse it. Depth is what separates a cascade from a fan-out — a\n * fan-out is wide and shallow, a cascade is narrow and deep — which is why\n * {@link StoreSpec.maxReduceDepth} carries the default and this does not.\n *\n * Set it when a store's bursts are known to be bounded and an unexpectedly wide one is itself\n * the symptom worth catching.\n *\n * @default undefined (no limit)\n */\n maxTransitionsPerDrain?: number;\n\n /**\n * Called when a ceiling is breached, instead of throwing.\n *\n * @remarks\n * The offending emit is refused and the chain stops there; everything already committed\n * stands. It does not throw, because the throw would surface in whichever frame happened to be\n * emitting — a subscriber, an effect, a middleware — which is the same species of\n * hard-to-attribute failure the ceiling exists to prevent. A cascade is a wiring bug, and this\n * is where the wiring gets named.\n *\n * @param info - Which ceiling, the event that would have extended the chain, and its causal\n * chain of ids, newest last.\n */\n onCascade?: (info: CascadeInfo<EM>) => void;\n\n /**\n * Called when a reducer refuses a write by returning {@link Rejected}.\n *\n * @remarks\n * The caller learns of its own refusal from the `emit` result; this is for everyone else —\n * logging, metrics, alerting on a rate of rejected writes. Shaped as a callback rather than a\n * subscription for the same reason {@link StoreSpec.onReducerError} is: it is a rare global\n * signal, not something several independent parties register and unregister for.\n *\n * A refusal is a normal outcome, not an error. It means a reducer considered the write and\n * declined it — a stale compare-and-swap, an unmet precondition — and the event is rejected\n * whole, so no slice writes.\n *\n * @param rejection - The refusal and its reason.\n * @param event - The event that was refused.\n * @param slice - Name of the slice whose reducer refused.\n */\n onRejected?: (rejection: Rejection, event: EventUnion<EM>, slice: string) => void;\n};\n\n/**\n * What {@link StoreSpec.onCascade} receives when a ceiling is breached.\n *\n * @typeParam EM - Event map.\n *\n * @public\n */\nexport interface CascadeInfo<EM extends EventMapBase = EventMapBase> {\n /** Which ceiling was hit. */\n readonly limit: \"maxReduceDepth\" | \"maxTransitionsPerDrain\";\n /** The configured value that was exceeded. */\n readonly limitValue: number;\n /** The event that was refused — the one that would have extended the chain. */\n readonly event: EventUnion<EM>;\n /** Causal depth the refused event would have had. */\n readonly depth: number;\n /**\n * Ids from the root of the chain to the refused event's parent, newest last.\n *\n * @remarks\n * Bounded to the most recent entries: a cascade is long by definition, and the useful part is\n * the cycle at the end rather than the thousand identical hops before it.\n */\n readonly chain: readonly string[];\n}\n\n/**\n * Public Store surface.\n *\n * @typeParam R - Reducer name union.\n * @typeParam S - State record (already readonly at the call site).\n * @typeParam EM - Event map.\n *\n * @remarks\n * The concrete Store implements this as `StoreInstance<R, DeepReadonly<S>, EM>`.\n *\n * @public\n */\nexport interface StoreInstance<\n R extends string = string,\n S extends Record<R, any> = Record<string, any>,\n EM extends EventMapBase = EventMapBase,\n> {\n /**\n * Store name (used by DevTools to identify the instance).\n */\n name: string;\n\n /**\n * Read the full state (already readonly).\n */\n getState(): DeepReadonly<S>;\n\n /**\n * Emit a typed event `(channel, type, payload)`.\n * Returns a promise that resolves when the event has been processed.\n */\n emit: Emit<EM>;\n\n /**\n * Coarse subscription: runs after any state change (once per committed event).\n */\n subscribe(listener: () => void): Unsubscribe;\n\n /**\n * Fine-grained subscription: listen to a specific `reducer.property` path.\n * Accepts a dotted path string (e.g., \"data.123.title\").\n * Fires when that path (or its ancestors) actually changes.\n *\n * @param spec - `{ reducer, property }` where `property` is a single dotted path string.\n * @param handler - Handler receiving a {@link Change} with `{ oldValue, newValue, path }`.\n */\n connect(\n spec: { reducer: R; property: string },\n handler: (change: Change) => void,\n options?: ConnectOptions,\n ): Unsubscribe;\n\n /**\n * Sends a request and waits for the reply, correlating the two automatically.\n *\n * @remarks\n * Awaitable for the terminal reply, async-iterable for progress. See the implementation on\n * {@link Store.call} for the full contract: correlation, backpressure, timeouts, and why it\n * is a local primitive.\n */\n call<C extends keyof EM & string, T extends keyof EM[C] & string>(\n channel: C,\n type: T,\n payload: EM[C][T],\n opts: CallOptions<EM>,\n ): CallHandle<EventUnion<EM>, EventUnion<EM>>;\n\n /**\n * Convenience helper to register an **effect** filtered by a single `(channel, type)` pair.\n *\n * @typeParam C - Channel key within `EM`.\n * @typeParam T - Event type key within channel `C`.\n * @param channel - Channel to filter.\n * @param type - Event type to filter.\n * @param handler - Effect handler `(payload, getState, emit, event)`.\n * \n * @returns Unsubscribe/teardown function.\n */\n onEffect<\n C extends keyof EM & string,\n T extends keyof EM[C] & string\n >(\n channel: C,\n type: T,\n handler: (\n payload: EM[C][T],\n getState: () => DeepReadonly<S>,\n emit: Emit<EM>,\n event: Event<EM, C, T>,\n ) => void | Promise<void>,\n ): Unsubscribe;\n\n /**\n * Register a post-reducer effect (sees final state). Returns an unsubscribe.\n */\n registerEffect(spec: EffectSpec<DeepReadonly<S>, EM>): Unsubscribe;\n\n /**\n * Dynamically add middleware, in either the function or the spec form.\n */\n registerMiddleware(mw: MiddlewareInput<DeepReadonly<S>, EM>): Unsubscribe;\n\n /**\n * Dynamically add/remove a namespaced reducer slice at runtime.\n */\n registerReducer(name: string, spec: ReducerSpec<any, EM>): Unsubscribe;\n\n /**\n * Cleanup resources (timers, etc.) when disposing the store.\n * Call this if you're dynamically creating/destroying stores.\n */\n dispose(): void;\n\n /**\n * Subscribe to events by channel and type.\n *\n * Event subscriptions are intended for the View layer (e.g., React components)\n * to react to events without affecting the event flow. They are fire-and-forget\n * and cannot cancel event propagation.\n *\n * **Phases:**\n * - `'committed'` (default): Events that passed middleware and reached reducers\n * - `'uncommitted'`: Events rejected by middleware\n * - `'all'`: Both committed and uncommitted events (handler receives phase parameter)\n *\n * @typeParam C - Channel key within `EM`.\n * @typeParam T - Event type key within channel `C`.\n * @param channel - Channel to subscribe to.\n * @param type - Event type to subscribe to.\n * @param handler - Handler function `(event, getState, emit, phase)`.\n * @param phase - Event phase to subscribe to (default: `'committed'`).\n * @returns Unsubscribe function.\n *\n * @example Committed events (default)\n * ```ts\n * const off = store.onEvent('ui', 'save', (event, getState, emit, phase) => {\n * console.log('Save committed:', event.payload);\n * });\n * ```\n *\n * @example Uncommitted (rejected) events\n * ```ts\n * store.onEvent('ui', 'delete', (event, getState, emit, phase) => {\n * console.log('Delete was rejected by middleware');\n * }, 'uncommitted');\n * ```\n *\n * @example All events\n * ```ts\n * store.onEvent('ui', 'action', (event, getState, emit, phase) => {\n * console.log('Action:', phase); // 'committed' or 'uncommitted'\n * }, 'all');\n * ```\n */\n onEvent<C extends keyof EM & string, T extends keyof EM[C] & string>(\n channel: C,\n type: T,\n handler: NarrowedEventHandler<DeepReadonly<S>, EM, C, T>,\n phase?: EventPhase,\n ): Unsubscribe;\n\n /**\n * Replaces the entire middleware pipeline (HMR-friendly).\n *\n * @param next - New middleware array.\n */\n replaceMiddleware(next: MiddlewareFunction<DeepReadonly<S>, EM>[]): void;\n\n /**\n * Replaces all registered effects (HMR-friendly).\n *\n * @param next - New effects array (as EffectSpecs).\n */\n replaceEffects(next: Array<EffectSpec<DeepReadonly<S>, EM>>): void;\n\n /**\n * Replaces the entire reducer set (HMR-friendly).\n *\n * @param next - Map of slice specs keyed by slice name.\n * @param opts - `{ preserveState?: boolean }` (default `true`).\n */\n replaceReducers(\n next: Record<R, ReducerSpec<S[R], EM>>,\n opts?: { preserveState?: boolean },\n ): void;\n\n /**\n * Convenience API to replace any subset of store parts (HMR patterns).\n *\n * @param partial - Partial replacement set.\n */\n hotReplace(partial: {\n reducer?: Record<R, ReducerSpec<S[R], EM>>;\n middleware?: MiddlewareInput<DeepReadonly<S>, EM>[];\n effects?: Array<EffectSpec<DeepReadonly<S>, EM>>;\n preserveState?: boolean;\n }): void;\n\n /**\n * Replays a sequence of events from a snapshot through reducers and event\n * subscribers ONLY. Skips dedup, middleware, and effects.\n *\n * Gated by `createStore({ devtools: { allowReplay: true } })`.\n * Throws if replay is not enabled.\n *\n * @param snapshot - The state snapshot to restore before replaying.\n * @param events - Array of events to replay (in order).\n *\n * @internal\n */\n __replayEvents(\n snapshot: any,\n events: Array<{ channel: string; type: string; payload: any; id: string; meta?: EventMeta }>,\n ): void;\n\n /**\n * Returns a structured introspection snapshot for DevTools UIs.\n *\n * @returns Reducers, effects, middleware, event subscriptions, coarse\n * subscriber count, dedup hit count, and current queue depth.\n *\n * @internal\n */\n __devtoolsIntrospect(): {\n reducers: Array<{ name: string; when?: unknown }>;\n effects: Array<{ channel: string; type: string; name?: string; description?: string }>;\n middleware: Array<{ name?: string; description?: string; when?: unknown }>;\n atomic: Array<{ reducer: string; property: string }>;\n event: Array<{ channel: string; type: string; phase: string }>;\n coarse: number;\n dedupHits: number;\n queueDepth: number;\n };\n\n /**\n * Registers an instrumentation observer, called once per emitted event\n * (committed or vetoed) after the synchronous reduce phase, with the exact\n * changed paths, their old/new values, and reduce timing. This is the typed\n * seam DevTools agents consume — no `as any` bridging required.\n *\n * @param observer - Receives an {@link InstrumentedEvent} per emit.\n * @returns Unsubscribe function.\n */\n instrument(observer: InstrumentationObserver<EM>): Unsubscribe;\n\n /**\n * Applies an externally-provided whole-state snapshot (DevTools time-travel),\n * emitting fine-grained path changes and notifying coarse subscribers.\n *\n * @param next - Plain state object to apply.\n *\n * @internal\n */\n __applyExternalState(next: unknown): void;\n}\n\n\n/**\n * One reducer's definition blob (stateful event consumer).\n *\n * @typeParam S - State managed by this reducer.\n * @typeParam EM - Event map.\n *\n * @remarks\n * Use `when` for event targeting (preferred). The `events` property is\n * kept for backward compatibility but `when` is recommended for new code.\n *\n * @example\n * Using `when` (recommended)\n * ```ts\n * const counterSpec: ReducerSpec<{ value: number }, MyEM> = {\n * state: { value: 0 },\n * when: { keys: eventKeys<MyEM>()([['ui', 'increment'], ['ui', 'decrement']]) },\n * reducer(s, evt) {\n * if (evt.type === 'increment') return { value: s.value + evt.payload };\n * if (evt.type === 'decrement') return { value: s.value - evt.payload };\n * return s;\n * },\n * meta: { type: 'reducer', name: 'counter' },\n * };\n * ```\n *\n * @public\n */\nexport interface ReducerSpec<S = any, EM extends EventMapBase = EventMapBase> {\n /**\n * Initial state for this reducer.\n */\n state: S;\n\n /**\n * Event targeting using the unified `When` matcher.\n */\n when?: When<EM>;\n\n /**\n * Pure reducer function: `(state, event) => nextState`.\n */\n reducer: ReducerFunction<S, EM>;\n\n /**\n * Optional metadata for debugging tools and DevTools integration.\n */\n meta?: EventConsumerMeta<\"reducer\">;\n}\n\n/**\n * Pure reducer function (stateful event consumer).\n *\n * @typeParam S - State type.\n * @typeParam EM - Event map.\n *\n * @public\n */\nexport type ReducerFunction<S = any, EM extends EventMapBase = EventMapBase> = (\n state: S,\n event: EventUnion<EM>,\n) => S | Rejection;\n\n/**\n * Effect specification (stateless async event consumer).\n *\n * @typeParam S - Store state type (readonly).\n * @typeParam EM - Event map.\n *\n * @remarks\n * - Effects run after reducers see the event.\n * - Effects are async-safe and do not own state.\n * - Effects are keyed by event for O(1) lookup (no scanning).\n * - Use `when` for event targeting (preferred over `events`).\n *\n * @example\n * Using `when` (recommended)\n * ```ts\n * const logEffect: EffectSpec<AppState, MyEM> = {\n * when: { keys: eventKeys<MyEM>()([['ui', 'increment']]) },\n * effect: async (evt, getState, emit) => {\n * console.log('increment', evt.payload, getState().counter.value);\n * },\n * meta: { type: 'effect', name: 'logEffect', description: 'Logs increment events' },\n * };\n * ```\n *\n * @example Match all events in a channel\n * ```ts\n * const notificationEffect: EffectSpec<AppState, MyEM> = {\n * when: { channel: 'notifications' },\n * effect: (evt, getState, emit) => {\n * if (evt.type === 'show') showToast(evt.payload.message);\n * },\n * };\n * ```\n *\n * @public\n */\nexport interface EffectSpec<S = any, EM extends EventMapBase = EventMapBase> {\n /**\n * Event targeting using the unified `When` matcher.\n */\n when?: When<EM>;\n\n /**\n * Async effect handler: `(event, getState, emit) => void | Promise<void>`.\n */\n effect: EffectFunction<S, EM>;\n\n /**\n * Optional metadata for debugging tools and DevTools integration.\n */\n meta?: EventConsumerMeta<\"effect\">;\n}\n\n/**\n * Every legal `{ channel, type, payload, id }` as a *distinct* object type.\n *\n * @typeParam EM - Event map.\n *\n * @public\n */\nexport type EventUnion<EM extends EventMapBase> = {\n [C in keyof EM & string]: {\n [T in keyof EM[C] & string]: Event<EM, C, T>;\n }[keyof EM[C] & string];\n}[keyof EM & string];\n\n/**\n * Middleware function: log, guard, or veto an event **synchronously**.\n * Return `true` to continue, `false` to swallow / cancel propagation.\n *\n * @remarks\n * Middleware runs in the synchronous reduce phase (so `getState()` is correct\n * immediately after `emit()`), and therefore must be synchronous. Perform async\n * work in effects instead.\n *\n * @typeParam S - Store state (readonly).\n * @typeParam EM - Event map.\n *\n * @public\n */\nexport type MiddlewareFunction<S = any, EM extends EventMapBase = EventMapBase> = (\n state: S,\n event: EventUnion<EM>,\n emit: Emit<EM>,\n) => boolean;\n\n/**\n * Middleware specification with optional event targeting and metadata.\n *\n * @typeParam S - Store state (readonly).\n * @typeParam EM - Event map.\n *\n * @remarks\n * - If `when` is omitted, middleware receives ALL events.\n * - Use `when` to filter which events the middleware processes.\n * - Middleware runs BEFORE reducers and can cancel event propagation.\n *\n * @example Global logging middleware (all events)\n * ```ts\n * const loggingMiddleware: MiddlewareSpec<AppState, AppEM> = {\n * middleware: (state, event, emit) => {\n * console.log('Event:', event.channel, event.type);\n * return true; // allow propagation\n * },\n * meta: { type: 'middleware', name: 'logger' },\n * };\n * ```\n *\n * @example Filtered middleware (specific events)\n * ```ts\n * const authMiddleware: MiddlewareSpec<AppState, AppEM> = {\n * when: { channel: 'admin' },\n * middleware: (state, event, emit) => {\n * if (!state.auth.isAdmin) return false; // cancel\n * return true;\n * },\n * meta: { type: 'middleware', name: 'authGuard', description: 'Guards admin events' },\n * };\n * ```\n *\n * @public\n */\nexport interface MiddlewareSpec<S = any, EM extends EventMapBase = EventMapBase> {\n /**\n * Event targeting (optional). If omitted, middleware receives ALL events.\n */\n when?: When<EM>;\n\n /**\n * Middleware function: `(state, event, emit) => boolean` (synchronous).\n * Return `false` to cancel event propagation.\n */\n middleware: MiddlewareFunction<S, EM>;\n\n /**\n * Optional metadata for debugging tools and DevTools integration.\n */\n meta?: EventConsumerMeta<\"middleware\">;\n}\n\n/**\n * Effect handler: runs AFTER reducers, sees the final state.\n *\n * @typeParam S - Store state (readonly).\n * @typeParam EM - Event map.\n *\n * @public\n */\nexport type EffectFunction<S = any, EM extends EventMapBase = EventMapBase> = (\n event: EventUnion<EM>,\n getState: () => S,\n emit: Emit<EM>,\n) => void | Promise<void>;\n\n/**\n * Helper: extract state shape from a reducers map.\n *\n * @internal\n */\nexport type ReducersMapAny = Record<string, ReducerSpec<any, any>>;\n\n/**\n * Helper: derive state type from a reducers map.\n *\n * @internal\n */\nexport type StateFromReducers<R> = {\n [K in keyof R]: R[K] extends ReducerSpec<infer S, any> ? S : never;\n};\n\n/**\n * Helper: turn a union into an intersection.\n *\n * @internal\n */\nexport type UnionToIntersection<U> = (U extends unknown ? (k: U) => void : never) extends (\n k: infer I,\n) => void\n ? I\n : never;\n\n/**\n * Helper: the event map of a single reducer spec.\n *\n * @internal\n */\nexport type EMOfSpec<Spec> = Spec extends ReducerSpec<any, infer EM> ? EM : never;\n\n/**\n * Helper: derive the combined event map from a reducers map (strict).\n * Used by the createStore inference overload.\n *\n * Each slice contributes its own event map; those maps are **merged** (channels,\n * and each channel's `type → payload` entries, combined across slices) rather\n * than collapsed to a single slice's map. `EMOfSpec` distributes over the union\n * of specs to yield the union of per-slice event maps, and `UnionToIntersection`\n * merges them — so a store whose slices declare divergent event maps still types\n * `emit` against the union of every slice's channels/types.\n *\n * @internal\n */\nexport type EMFromReducersStrict<RM extends ReducersMapAny> = UnionToIntersection<\n EMOfSpec<RM[keyof RM]>\n> extends infer Merged\n ? Merged extends EventMapBase\n ? Merged\n : EventMapBase\n : EventMapBase;\n\n// ============================================\n// Event Targeting (When Matcher)\n// ============================================\n\n/**\n * Matcher for event targeting across reducers, effects, middleware, and subscriptions.\n *\n * Supports four targeting modes:\n * - `{ any: true }` — match all events\n * - `{ keys: [...] }` — match specific `[channel, type]` pairs (correlated)\n * - `{ channel: 'x' }` — match all events in a channel\n * - `{ channels: ['x', 'y'] }` — match all events in multiple channels\n *\n * @typeParam EM - Event map.\n *\n * @example Match all events\n * ```ts\n * const mw: MiddlewareSpec<S, EM> = {\n * when: { any: true },\n * middleware: (state, event, emit) => true,\n * };\n * ```\n *\n * @example Match specific event keys\n * ```ts\n * const reducer: ReducerSpec<S, EM> = {\n * state: { value: 0 },\n * when: { keys: eventKeys<EM>()([['ui', 'increment'], ['ui', 'decrement']]) },\n * reducer: (s, e) => { ... },\n * };\n * ```\n *\n * @example Match entire channel\n * ```ts\n * const effect: EffectSpec<S, EM> = {\n * when: { channel: 'notifications' },\n * effect: (e, getState, emit) => { ... },\n * };\n * ```\n *\n * @public\n */\nexport type When<EM extends EventMapBase> =\n | { any: true }\n | { keys: ReadonlyArray<EventKey<EM>> }\n | { channel: keyof EM & string }\n | { channels: ReadonlyArray<keyof EM & string> };\n\n/**\n * Helper to create type-safe EventKey arrays without requiring `as const`.\n * Preserves literal tuple types for proper type correlation in handlers.\n *\n * @typeParam EM - Event map.\n *\n * @example\n * ```ts\n * type AppEM = {\n * ui: { increment: number; decrement: number };\n * data: { loaded: string[] };\n * };\n *\n * // Without helper (requires `as const`):\n * const keys = [['ui', 'increment'], ['ui', 'decrement']] as const;\n *\n * // With helper (no `as const` needed):\n * const keys = eventKeys<AppEM>()([\n * ['ui', 'increment'],\n * ['ui', 'decrement'],\n * ]);\n * // Type: readonly [['ui', 'increment'], ['ui', 'decrement']]\n * ```\n *\n * @public\n */\nexport const eventKeys =\n <EM extends EventMapBase>() =>\n <const K extends ReadonlyArray<EventKey<EM>>>(keys: K): K =>\n keys;\n\n/**\n * Extracts the event union from a `When` matcher.\n * Used internally to narrow handler `event` parameter types based on the matcher.\n *\n * @typeParam EM - Event map.\n * @typeParam W - When matcher type.\n *\n * @internal\n */\nexport type EventFromWhen<EM extends EventMapBase, W extends When<EM>> = W extends { any: true }\n ? EventUnion<EM>\n : W extends { keys: ReadonlyArray<infer K> }\n ? K extends readonly [infer C, infer T]\n ? C extends keyof EM & string\n ? T extends keyof EM[C] & string\n ? Event<EM, C, T>\n : never\n : never\n : never\n : W extends { channel: infer C }\n ? C extends keyof EM & string\n ? { [T in keyof EM[C] & string]: Event<EM, C, T> }[keyof EM[C] & string]\n : never\n : W extends { channels: ReadonlyArray<infer C> }\n ? C extends keyof EM & string\n ? { [T in keyof EM[C] & string]: Event<EM, C, T> }[keyof EM[C] & string]\n : never\n : never;\n\n// ============================================\n// Path Value Resolution\n// ============================================\n\n/**\n * Resolves the value type at a dotted path `P` inside object/array `T`.\n * Supports numeric segments for array indexing (e.g., `\"items.0.title\"`).\n *\n * @typeParam T - Root type to index into.\n * @typeParam P - Dotted path string.\n *\n * @example\n * ```ts\n * type S = { todos: Array<{ title: string; done: boolean }> };\n * type T1 = PathValue<S['todos'], '0.title'>; // string\n * type T2 = PathValue<S, 'todos.0'>; // { title: string; done: boolean }\n * type T3 = PathValue<S, 'todos'>; // Array<{ title: string; done: boolean }>\n * ```\n *\n * @remarks\n * The empty path resolves to `T` itself, matching what the code has always done: both the\n * store's internal path reader and the React one return the object unchanged for `\"\"`. The type\n * used to say `never`, so a subscription to a root-value slice was typed as nothing at all.\n *\n * @public\n */\nexport type PathValue<T, P extends string> = P extends \"\"\n ? T\n : P extends `${infer K}.${infer Rest}`\n ? K extends keyof T\n ? PathValue<T[K], Rest>\n : K extends `${number}`\n ? T extends readonly (infer E)[]\n ? PathValue<E, Rest>\n : never\n : never\n : P extends keyof T\n ? T[P]\n : P extends `${number}`\n ? T extends readonly (infer E)[]\n ? E\n : never\n : never;\n\n// ============================================\n// Metadata for Debugging Tools\n// ============================================\n\n/**\n * Type discriminator for event consumers.\n *\n * @public\n */\nexport type EventConsumerType = \"reducer\" | \"middleware\" | \"effect\";\n\n/**\n * Metadata for event consumers (reducers, effects, middleware).\n * Useful for debugging tools, DevTools integration, and introspection.\n *\n * @typeParam T - Consumer type discriminator.\n *\n * @example\n * ```ts\n * const counterReducer: ReducerSpec<CounterState, AppEM> = {\n * state: { value: 0 },\n * when: { keys: eventKeys<AppEM>()([['ui', 'increment']]) },\n * reducer: (s, e) => ({ value: s.value + e.payload }),\n * meta: {\n * type: 'reducer',\n * name: 'counterReducer',\n * description: 'Handles counter increment/decrement events',\n * },\n * };\n * ```\n *\n * @public\n */\nexport interface EventConsumerMeta<T extends EventConsumerType = EventConsumerType> {\n /** Consumer type discriminator */\n type: T;\n\n /** Unique identifier for this consumer */\n name: string;\n\n /** Brief one-liner description of what this consumer does */\n description?: string;\n}\n\n/**\n * Alias for DeepReadonly.\n *\n * @public\n */\nexport type DeepRO<T> = DeepReadonly<T>;\n\n/**\n * Primitive types (terminal leaves in deep traversal).\n *\n * @public\n */\nexport type Primitive =\n | string\n | number\n | boolean\n | bigint\n | symbol\n | null\n | undefined\n | Date\n | RegExp;\n\n/**\n * A value with **no addressable interior**: its changes are reported at the slice root rather\n * than at a path beneath it.\n *\n * @remarks\n * The distinction the path types were missing. `Map` and `Set` keep their contents outside own\n * enumerable keys, so walking them with `keyof` yields the names of their *methods* — which is\n * how `\"byId.get\"` and `\"byId.size\"` came to be offered as subscribable paths, and why a slice\n * holding a plain number autocompleted `\"toFixed\"`. Neither ever notified anything, because\n * `detectChangedProps` reports such a value at its own path and never descends into it.\n *\n * This is the type-level counterpart of that runtime rule: what the diff reports at the root,\n * the types address at the root, with the empty path.\n *\n * @public\n */\nexport type RootValue = Primitive | ReadonlyMap<unknown, unknown> | ReadonlySet<unknown>;\n\n/**\n * Compute dotted paths of T, including nested objects and arrays.\n *\n * @typeParam T - Type to compute paths for.\n *\n * @public\n */\nexport type Path<T> = T extends RootValue\n ? never\n : T extends readonly (infer U)[]\n ? `${number}` | (Path<U> extends never ? never : `${number}.${Path<U>}`)\n : {\n [K in keyof T & string]: T[K] extends Primitive\n ? K\n : K | (Path<T[K]> extends never ? never : `${K}.${Path<T[K]>}`);\n }[keyof T & string];\n\n/**\n * Allow wildcard patterns like \"*\" and \"**\" anywhere in the string.\n *\n * @typeParam T - Base string type.\n *\n * @public\n */\nexport type WithGlob<T extends string> = T | `${string}*${string}`;\n\n/**\n * Dotted keys of a slice: top-level keys or any nested path.\n *\n * @typeParam Slice - Slice state type.\n *\n * @remarks\n * A slice that **is** one value — a primitive, a `Map`, a `Set`, a `Date` — has no key to\n * address, and its only subscribable path is the empty one. Saying so is what makes\n * `{ reducer, property: \"\" }` type-check where it can actually fire, instead of falling through\n * to the untyped `property: string` overload and returning `unknown`.\n *\n * The conditional distributes over unions, which is why a nullable object slice gets both:\n * `Dotted<{ a: number } | null>` is `\"\" | \"a\"`. That is exactly right — such a slice really does\n * change at its root when it becomes `null`, and at `\"a\"` otherwise.\n *\n * @public\n */\nexport type Dotted<Slice> = Slice extends RootValue\n ? \"\"\n : (keyof Slice & string) | Path<Slice>;\n\n/**\n * Deep readonly type: recursively makes all properties readonly.\n *\n * @remarks\n * The built-in object types are handled before the general mapped-object case, because\n * mapping over one destroys it. `{ readonly [K in keyof Map<K, V>]: ... }` produces an object\n * carrying the *names* of a Map's methods with their signatures rewritten, so reading a Map\n * out of state and calling `.get()` on it was a type error even though the value at runtime\n * is an ordinary Map. The same applied to `Set`, `Date`, `RegExp` and any function stored in\n * state.\n *\n * Collections become their `Readonly*` counterparts, which is the same treatment arrays\n * already had. Functions are returned untouched: a function's properties are not state, and\n * mapping over them makes it uncallable.\n *\n * @typeParam T - Type to make readonly.\n *\n * @public\n */\nexport type DeepReadonly<T> = T extends (...args: never[]) => unknown\n ? T\n : T extends (infer A)[]\n ? ReadonlyArray<DeepReadonly<A>>\n : T extends ReadonlyMap<infer K, infer V>\n ? ReadonlyMap<DeepReadonly<K>, DeepReadonly<V>>\n : T extends ReadonlySet<infer V>\n ? ReadonlySet<DeepReadonly<V>>\n : T extends Date | RegExp | Promise<unknown> | Error\n ? T\n : T extends object\n ? { readonly [K in keyof T]: DeepReadonly<T[K]> }\n : T;\n\n/**\n * Phase of event subscription notification.\n *\n * - `'committed'`: Events that passed middleware and reached reducers (default)\n * - `'uncommitted'`: Events rejected by middleware\n * - `'written'`: Events that actually changed state\n * - `'all'`: Both committed and uncommitted events\n *\n * @remarks\n * `'committed'` means **not vetoed**, and always has. It fires for an event that passed\n * middleware whether or not any reducer wrote anything — including every event in a store with\n * no reducers at all, which is the shape a notification or analytics bus takes. Toasts,\n * animations and tracking depend on that, so it is not narrowed.\n *\n * `'written'` is the stricter fact, added rather than substituted: state changed. It fires\n * **after** the commit, so a subscriber reading `getState()` from it sees the new value — which\n * is what people tend to assume `'committed'` does.\n *\n * `'all'` deliberately stays `committed | uncommitted`. Folding `'written'` into it would hand\n * every existing `'all'` subscriber a second notification per written event and quietly double\n * their counts.\n *\n * @public\n */\nexport type EventPhase = \"committed\" | \"uncommitted\" | \"written\" | \"all\";\n\n/**\n * The phases a handler is actually *told about*.\n *\n * @remarks\n * `'all'` is a subscription selector, not an outcome — nothing is ever delivered \"in the all\n * phase\". Naming the difference keeps the two from being conflated in a handler signature, which\n * is where they were previously spelled out by hand and drifted: adding `'written'` to\n * {@link EventPhase} left three copies in `@yoltra/react` still claiming a handler could only\n * ever see two phases, and the build failed on the mismatch.\n *\n * @public\n */\nexport type NotifiedPhase = Exclude<EventPhase, \"all\">;\n\n/**\n * Handler function for event subscriptions (receives full event union).\n *\n * Event subscriptions are intended for the View layer (e.g., React components)\n * to react to events without affecting the event flow. They are fire-and-forget\n * and cannot cancel event propagation.\n *\n * @typeParam S - Store state type (readonly).\n * @typeParam EM - Event map.\n *\n * @param event - The event that was emitted\n * @param getState - Function to get current state\n * @param emit - Function to emit new events\n * @param phase - The phase ('committed' or 'uncommitted') indicating how the event was processed\n *\n * @example\n * ```ts\n * const handler: EventSubscriptionHandler<AppState, AppEM> = (event, getState, emit, phase) => {\n * if (phase === 'committed') {\n * console.log('Event committed:', event.type);\n * } else {\n * console.log('Event rejected:', event.type);\n * }\n * };\n * ```\n *\n * @public\n */\nexport type EventSubscriptionHandler<S = any, EM extends EventMapBase = EventMapBase> = (\n event: EventUnion<EM>,\n getState: () => S,\n emit: Emit<EM>,\n phase: NotifiedPhase,\n) => void | Promise<void>;\n\n/**\n * Narrowed event subscription handler for specific `(channel, type)` pairs.\n * Provides better type inference when subscribing to a single event type.\n *\n * @typeParam S - Store state type (readonly).\n * @typeParam EM - Event map.\n * @typeParam C - Channel key within `EM`.\n * @typeParam T - Event type key within channel `C`.\n *\n * @example\n * ```ts\n * const handler: NarrowedEventHandler<AppState, AppEM, 'ui', 'increment'> = (\n * event, // Event<AppEM, 'ui', 'increment'> - narrowed!\n * getState,\n * emit,\n * phase,\n * ) => {\n * // event.payload is typed as number (from EM['ui']['increment'])\n * console.log('Increment by:', event.payload);\n * };\n * ```\n *\n * @public\n */\nexport type NarrowedEventHandler<\n S,\n EM extends EventMapBase,\n C extends keyof EM & string,\n T extends keyof EM[C] & string,\n> = (\n event: Event<EM, C, T>,\n getState: () => S,\n emit: Emit<EM>,\n phase: NotifiedPhase,\n) => void | Promise<void>;","/**\n * Normalised collections, so a list stops paying O(N) for an O(1) change.\n *\n * @remarks\n * Path notification is positional for arrays. `detectChangedProps` walks indices and reports\n * `items.0.title`, which names a *slot*, not a thing. So `unshift`, `splice(0, 1)` and `sort`\n * move nearly every element into a different slot, and the diff correctly reports that nearly\n * every leaf changed. Inserting one row at the front of a thousand wakes a thousand\n * subscribers.\n *\n * The remedy is the state shape, not a quieter diff. A key-stable array diff would need an\n * identity key the diff has no business knowing, and even then the *paths* would still be\n * positional — `items.0.title` names position zero, and so does the RFC-6902 pointer the\n * devtools agents build from it.\n *\n * Normalising to `{ ids, entities }` makes `entities.abc.title` stable across insert, remove\n * and reorder.\n *\n * **What this does not do:** `ids` is still an array, so a reorder still reports `ids.0`,\n * `ids.1` and so on. That cost is confined rather than removed. A list container subscribes to\n * `ids` and reorders its children; rows subscribe to `entities.<id>.<field>` and stay asleep.\n * The promise is cost proportional to what actually changed.\n *\n * @module @yoltra/core\n */\n\n/** What an entity may be keyed by. */\nexport type EntityId = string | number;\n\n/**\n * A normalised collection.\n *\n * @typeParam T - The entity.\n * @typeParam Id - Its key type.\n *\n * @public\n */\nexport interface EntityState<T, Id extends EntityId = string> {\n /** Order. Reordering touches this and nothing under `entities`. */\n readonly ids: readonly Id[];\n /** Identity-keyed, so a path to one entity survives every change to the others. */\n readonly entities: Readonly<Record<Id, T>>;\n}\n\n/** A change to apply to one entity. */\nexport interface EntityUpdate<T, Id extends EntityId> {\n readonly id: Id;\n readonly changes: Partial<T>;\n}\n\n/** How an adapter identifies and orders its entities. */\nexport interface EntityAdapterOptions<T, Id extends EntityId> {\n /** Defaults to reading `id`. */\n readonly selectId?: (entity: T) => Id;\n /**\n * Keeps `ids` sorted.\n *\n * @remarks\n * Omit it and `ids` holds insertion order, which is cheaper: with a comparer, any change\n * that could affect position re-sorts. The sorted array is only adopted when it actually\n * differs, so a sort that changes nothing reports nothing.\n */\n readonly sortComparer?: (a: T, b: T) => number;\n}\n\n/**\n * Reducer helpers, selectors, and the subscription paths that make the shape worth having.\n *\n * @public\n */\nexport interface EntityAdapter<T, Id extends EntityId = string> {\n getInitialState(): EntityState<T, Id>;\n getInitialState<Extra extends object>(extra: Extra): EntityState<T, Id> & Extra;\n\n /** Adds an entity. Existing ids are left alone — this is not an upsert. */\n addOne<S extends EntityState<T, Id>>(state: S, entity: T): S;\n addMany<S extends EntityState<T, Id>>(state: S, entities: readonly T[]): S;\n /** Adds or replaces one entity wholesale. */\n setOne<S extends EntityState<T, Id>>(state: S, entity: T): S;\n setMany<S extends EntityState<T, Id>>(state: S, entities: readonly T[]): S;\n /** Replaces the whole collection. */\n setAll<S extends EntityState<T, Id>>(state: S, entities: readonly T[]): S;\n /** Merges `changes` into one entity. Unknown ids are ignored. */\n updateOne<S extends EntityState<T, Id>>(state: S, update: EntityUpdate<T, Id>): S;\n updateMany<S extends EntityState<T, Id>>(state: S, updates: readonly EntityUpdate<T, Id>[]): S;\n /** Adds, or merges into an existing entity. */\n upsertOne<S extends EntityState<T, Id>>(state: S, entity: T): S;\n upsertMany<S extends EntityState<T, Id>>(state: S, entities: readonly T[]): S;\n removeOne<S extends EntityState<T, Id>>(state: S, id: Id): S;\n removeMany<S extends EntityState<T, Id>>(state: S, ids: readonly Id[]): S;\n removeAll<S extends EntityState<T, Id>>(state: S): S;\n\n selectIds(state: EntityState<T, Id>): readonly Id[];\n selectEntities(state: EntityState<T, Id>): Readonly<Record<Id, T>>;\n selectAll(state: EntityState<T, Id>): readonly T[];\n selectById(state: EntityState<T, Id>, id: Id): T | undefined;\n selectTotal(state: EntityState<T, Id>): number;\n\n /** Path to the order array. Subscribe here for a list that reorders. */\n readonly idsPath: string;\n /** Path to one entity, or to a field of it. */\n pathTo(id: Id, field?: string): string;\n /** Wildcard across every entity's `field`, for the loose subscription registry. */\n anyField(field: string): string;\n}\n\n/** @internal */\nconst warnedDottedIds = new Set<string>();\n\n/** @internal */\nfunction warnDottedId(id: EntityId): void {\n const key = String(id);\n if (warnedDottedIds.has(key)) return;\n warnedDottedIds.add(key);\n console.warn(\n `[yoltra] Entity id \"${key}\" contains a dot. Paths are dotted, so a subscription to ` +\n `\"entities.${key}\" is indistinguishable from one to a nested object of the same name. ` +\n `Use ids without dots.`,\n );\n}\n\n/**\n * Returns `next` only when it differs from `current`, element by element.\n *\n * @remarks\n * Reusing the existing array when the order did not change is what keeps `ids` out of the\n * changed-path list. Without it, every update to a sorted collection would report the order\n * as changed and wake the list container for nothing.\n *\n * @internal\n */\nfunction sameOrder<Id extends EntityId>(\n current: readonly Id[],\n next: readonly Id[],\n): readonly Id[] {\n if (current.length !== next.length) return next;\n for (let i = 0; i < current.length; i++) {\n if (current[i] !== next[i]) return next;\n }\n return current;\n}\n\n/**\n * Builds an adapter for one entity type.\n *\n * @example\n * ```ts\n * const todos = createEntityAdapter<Todo>();\n *\n * const spec: ReducerSpec<EntityState<Todo>, EM> = {\n * state: todos.getInitialState(),\n * when: { keys: eventKeys<EM>()([['todos', 'toggled']]) },\n * reducer: (state, event) =>\n * todos.updateOne(state, { id: event.payload.id, changes: { done: event.payload.done } }),\n * };\n *\n * // and in a component\n * useAtomicProp({ reducer: 'todos', property: todos.pathTo(id, 'title') });\n * ```\n *\n * @public\n */\nexport function createEntityAdapter<T, Id extends EntityId = string>(\n options: EntityAdapterOptions<T, Id> = {},\n): EntityAdapter<T, Id> {\n const selectId = options.selectId ?? ((entity: T) => (entity as { id: Id }).id);\n const { sortComparer } = options;\n\n const order = <S extends EntityState<T, Id>>(state: S, ids: readonly Id[]): readonly Id[] => {\n if (sortComparer === undefined) return ids;\n const sorted = [...ids].sort((a, b) => {\n const left = state.entities[a];\n const right = state.entities[b];\n if (left === undefined || right === undefined) return 0;\n return sortComparer(left, right);\n });\n return sameOrder(ids, sorted);\n };\n\n const write = <S extends EntityState<T, Id>>(\n state: S,\n entities: Record<Id, T>,\n ids: readonly Id[],\n ): S => {\n const next = { ...state, entities, ids } as S;\n return { ...next, ids: order(next, ids) };\n };\n\n const put = <S extends EntityState<T, Id>>(\n state: S,\n incoming: readonly T[],\n mode: \"add\" | \"set\" | \"upsert\",\n ): S => {\n let entities: Record<Id, T> | null = null;\n let ids: Id[] | null = null;\n\n for (const entity of incoming) {\n const id = selectId(entity);\n if (process.env.NODE_ENV !== \"production\" && String(id).includes(\".\")) warnDottedId(id);\n\n const existing = (entities ?? state.entities)[id];\n if (existing !== undefined && mode === \"add\") continue;\n\n const value =\n existing !== undefined && mode === \"upsert\" ? { ...existing, ...entity } : entity;\n\n entities ??= { ...state.entities };\n entities[id] = value;\n if (existing === undefined) {\n ids ??= [...state.ids];\n ids.push(id);\n }\n }\n\n if (entities === null) return state;\n return write(state, entities, ids ?? state.ids);\n };\n\n const merge = <S extends EntityState<T, Id>>(\n state: S,\n updates: readonly EntityUpdate<T, Id>[],\n ): S => {\n let entities: Record<Id, T> | null = null;\n\n for (const { id, changes } of updates) {\n const existing = (entities ?? state.entities)[id];\n if (existing === undefined) continue;\n entities ??= { ...state.entities };\n // Only the touched entity gets a new reference. Cloning the rest would report every\n // entity as changed, which is the defect this whole module exists to remove.\n entities[id] = { ...existing, ...changes };\n }\n\n if (entities === null) return state;\n return write(state, entities, state.ids);\n };\n\n const drop = <S extends EntityState<T, Id>>(state: S, ids: readonly Id[]): S => {\n const doomed = new Set<Id>(ids.filter((id) => state.entities[id] !== undefined));\n if (doomed.size === 0) return state;\n\n const entities = { ...state.entities };\n for (const id of doomed) delete entities[id];\n return write(\n state,\n entities,\n state.ids.filter((id) => !doomed.has(id)),\n );\n };\n\n return {\n getInitialState<Extra extends object>(extra?: Extra) {\n const base: EntityState<T, Id> = { ids: [], entities: {} as Record<Id, T> };\n return (extra === undefined ? base : { ...base, ...extra }) as EntityState<T, Id> & Extra;\n },\n\n addOne: (state, entity) => put(state, [entity], \"add\"),\n addMany: (state, entities) => put(state, entities, \"add\"),\n setOne: (state, entity) => put(state, [entity], \"set\"),\n setMany: (state, entities) => put(state, entities, \"set\"),\n setAll: (state, entities) => {\n const next = {} as Record<Id, T>;\n const ids: Id[] = [];\n for (const entity of entities) {\n const id = selectId(entity);\n if (next[id] === undefined) ids.push(id);\n next[id] = entity;\n }\n return write(state, next, ids);\n },\n updateOne: (state, update) => merge(state, [update]),\n updateMany: (state, updates) => merge(state, updates),\n upsertOne: (state, entity) => put(state, [entity], \"upsert\"),\n upsertMany: (state, entities) => put(state, entities, \"upsert\"),\n removeOne: (state, id) => drop(state, [id]),\n removeMany: (state, ids) => drop(state, ids),\n removeAll: (state) => (state.ids.length === 0 ? state : write(state, {} as Record<Id, T>, [])),\n\n selectIds: (state) => state.ids,\n selectEntities: (state) => state.entities,\n selectAll: (state) => state.ids.map((id) => state.entities[id]!),\n selectById: (state, id) => state.entities[id],\n selectTotal: (state) => state.ids.length,\n\n idsPath: \"ids\",\n pathTo: (id, field) => (field === undefined ? `entities.${id}` : `entities.${id}.${field}`),\n anyField: (field) => `entities.*.${field}`,\n };\n}\n","/**\n * Lossless encoding of store state for the wire.\n *\n * @remarks\n * The wire is JSON, and `JSON.stringify` is not a safe way to put arbitrary state on it. It does\n * not fail on the values it cannot represent — it quietly destroys them. A `Map` becomes `{}`, a\n * `Set` becomes `{}`, a `Date` becomes a string, `undefined` disappears from objects entirely,\n * and a `BigInt` or a cycle throws from inside a handler nobody awaits.\n *\n * Silent destruction is the dangerous half. The panel showed `{}` where a `Map` lived, which is\n * merely wrong; but time-travel then sent that `{}` back and applied it to the running store,\n * replacing a live `Map` with an empty object in the user's own application. A debugging tool\n * corrupting the program it is inspecting is the worst failure available to it.\n *\n * Values are therefore tagged rather than coerced. Anything JSON can carry travels unchanged;\n * anything it cannot is wrapped in a marker object that {@link decodeState} reverses exactly.\n *\n * @module\n */\n\n/** Marker key identifying an encoded value. Chosen to be improbable in application state. */\nconst TAG = \"$yoltra\" as const;\n\n/** What an encoded non-JSON value looks like on the wire. */\ntype Tagged =\n | { readonly [TAG]: \"map\"; readonly entries: Array<[unknown, unknown]> }\n | { readonly [TAG]: \"set\"; readonly values: unknown[] }\n | { readonly [TAG]: \"date\"; readonly iso: string }\n | { readonly [TAG]: \"bigint\"; readonly value: string }\n | { readonly [TAG]: \"undefined\" }\n | { readonly [TAG]: \"nan\" }\n | { readonly [TAG]: \"infinity\"; readonly sign: 1 | -1 }\n | { readonly [TAG]: \"regexp\"; readonly source: string; readonly flags: string }\n | { readonly [TAG]: \"error\"; readonly name: string; readonly message: string }\n | { readonly [TAG]: \"ref\"; readonly path: string }\n | { readonly [TAG]: \"unsupported\"; readonly kind: string }\n | { readonly [TAG]: \"escaped\"; readonly value: Record<string, unknown> };\n\n/** Options for {@link encodeState}. */\nexport interface EncodeOptions {\n /**\n * Redacts a value before it leaves the process.\n *\n * @remarks\n * State frequently holds tokens, session material and personal data, and devtools traffic\n * crosses a socket to another process. Return the replacement value, or the value itself to\n * keep it. Applied before encoding, so a redacted value is encoded like any other.\n */\n readonly sanitize?: (path: string, value: unknown) => unknown;\n /**\n * Maximum number of nodes to encode. Beyond it, subtrees are replaced by a truncation marker.\n *\n * @remarks\n * A snapshot larger than the hub's frame cap is rejected outright, which reads to the user as\n * a panel that hangs. Truncating visibly is a better failure: the panel renders, and says\n * where it stopped. Defaults to 100000.\n */\n readonly maxNodes?: number;\n}\n\n/** Reports what an encode had to compromise. Empty when nothing was lost. */\nexport interface EncodeReport {\n /** Node budget was exhausted and some subtrees were replaced by markers. */\n readonly truncated: boolean;\n /** Values no JSON representation exists for, by path — functions, symbols, DOM nodes. */\n readonly unsupported: readonly string[];\n}\n\n/** Result of {@link encodeState}. */\nexport interface EncodeResult {\n readonly value: unknown;\n readonly report: EncodeReport;\n}\n\n/**\n * Encodes a value into something `JSON.stringify` can carry losslessly.\n *\n * @param input - Any value, including one holding `Map`, `Set`, `Date`, `BigInt` or cycles.\n * @param options - Redaction and size limits.\n * @returns The encoded value plus a report of anything that could not be represented.\n *\n * @example\n * ```ts\n * const { value } = encodeState({ index: new Map([['a', 1]]) });\n * JSON.stringify(value); // safe, and decodeState restores the Map\n * ```\n *\n * @public\n */\nexport function encodeState(input: unknown, options: EncodeOptions = {}): EncodeResult {\n const maxNodes = options.maxNodes ?? 100_000;\n const sanitize = options.sanitize;\n const unsupported: string[] = [];\n\n // Identity → JSON Pointer of the first place it was seen. A cycle then encodes as a reference\n // to that path rather than recursing forever, and repeated references stay repeated rather\n // than being silently expanded into copies.\n const seen = new Map<object, string>();\n let nodes = 0;\n let truncated = false;\n\n function walk(value: unknown, path: string): unknown {\n if (sanitize !== undefined) value = sanitize(path, value);\n\n nodes += 1;\n if (nodes > maxNodes) {\n truncated = true;\n return { [TAG]: \"unsupported\", kind: \"truncated\" } satisfies Tagged;\n }\n\n switch (typeof value) {\n case \"undefined\":\n return { [TAG]: \"undefined\" } satisfies Tagged;\n case \"bigint\":\n return { [TAG]: \"bigint\", value: value.toString() } satisfies Tagged;\n case \"number\":\n if (Number.isNaN(value)) return { [TAG]: \"nan\" } satisfies Tagged;\n if (value === Infinity) return { [TAG]: \"infinity\", sign: 1 } satisfies Tagged;\n if (value === -Infinity) return { [TAG]: \"infinity\", sign: -1 } satisfies Tagged;\n return value;\n case \"function\":\n case \"symbol\":\n unsupported.push(path);\n return { [TAG]: \"unsupported\", kind: typeof value } satisfies Tagged;\n case \"string\":\n case \"boolean\":\n return value;\n default:\n break;\n }\n\n if (value === null) return null;\n\n const asObject = value as object;\n const previous = seen.get(asObject);\n if (previous !== undefined) return { [TAG]: \"ref\", path: previous } satisfies Tagged;\n seen.set(asObject, path);\n\n if (value instanceof Date) {\n return { [TAG]: \"date\", iso: value.toISOString() } satisfies Tagged;\n }\n if (value instanceof RegExp) {\n return { [TAG]: \"regexp\", source: value.source, flags: value.flags } satisfies Tagged;\n }\n if (value instanceof Error) {\n return { [TAG]: \"error\", name: value.name, message: value.message } satisfies Tagged;\n }\n if (value instanceof Map) {\n const entries: Array<[unknown, unknown]> = [];\n let i = 0;\n for (const [k, v] of value) {\n entries.push([walk(k, `${path}/@k${i}`), walk(v, `${path}/${i}`)]);\n i += 1;\n }\n return { [TAG]: \"map\", entries } satisfies Tagged;\n }\n if (value instanceof Set) {\n const values: unknown[] = [];\n let i = 0;\n for (const v of value) {\n values.push(walk(v, `${path}/${i}`));\n i += 1;\n }\n return { [TAG]: \"set\", values } satisfies Tagged;\n }\n if (Array.isArray(value)) {\n return value.map((item, index) => walk(item, `${path}/${index}`));\n }\n\n const out: Record<string, unknown> = {};\n for (const [key, item] of Object.entries(value as Record<string, unknown>)) {\n out[key] = walk(item, `${path}/${escapePointer(key)}`);\n }\n // An application object that happens to carry the marker key would decode as a tagged value\n // and come back as something else entirely. Wrap it so the decoder knows it is ordinary.\n if (TAG in out) return { [TAG]: \"escaped\", value: out } satisfies Tagged;\n return out;\n }\n\n const value = walk(input, \"\");\n return { value, report: { truncated, unsupported } };\n}\n\n/**\n * Reverses {@link encodeState}.\n *\n * @param input - A value produced by `encodeState` (typically after a JSON round trip).\n * @returns The original structure, with `Map`, `Set`, `Date` and friends restored.\n *\n * @remarks\n * Unsupported markers decode to `undefined`: a function cannot be reconstructed, and inventing a\n * placeholder would be worse than an absent value. Cycles are restored by resolving references\n * after the tree is built, so a decoded structure is cyclic exactly where the original was.\n *\n * @public\n */\nexport function decodeState(input: unknown): unknown {\n // Built during the walk so a reference can resolve to a node that may not exist yet.\n const byPath = new Map<string, unknown>();\n const pending: Array<{ target: unknown; key: string | number; path: string }> = [];\n\n function walk(value: unknown, path: string): unknown {\n if (value === null || typeof value !== \"object\") return value;\n\n if (Array.isArray(value)) {\n const arr: unknown[] = [];\n byPath.set(path, arr);\n value.forEach((item, index) => {\n if (isRef(item)) {\n // Left undefined for now; the second pass fills it once every node exists.\n pending.push({ target: arr, key: index, path: item.path });\n arr[index] = undefined;\n return;\n }\n arr[index] = walk(item, `${path}/${index}`);\n });\n return arr;\n }\n\n const tag = (value as Record<string, unknown>)[TAG];\n if (typeof tag === \"string\") {\n const tagged = value as unknown as Tagged;\n switch (tagged[TAG]) {\n case \"undefined\":\n return undefined;\n case \"nan\":\n return Number.NaN;\n case \"infinity\":\n return tagged.sign === 1 ? Infinity : -Infinity;\n case \"bigint\":\n return BigInt(tagged.value);\n case \"date\":\n return new Date(tagged.iso);\n case \"regexp\":\n return new RegExp(tagged.source, tagged.flags);\n case \"error\": {\n const error = new Error(tagged.message);\n error.name = tagged.name;\n return error;\n }\n case \"unsupported\":\n // Nothing faithful to return. `undefined` says \"not representable\" without pretending.\n return undefined;\n case \"ref\":\n // Resolved by the caller once the whole tree exists.\n return undefined;\n case \"map\": {\n const map = new Map<unknown, unknown>();\n byPath.set(path, map);\n tagged.entries.forEach(([k, v], index) => {\n map.set(walk(k, `${path}/@k${index}`), walk(v, `${path}/${index}`));\n });\n return map;\n }\n case \"set\": {\n const set = new Set<unknown>();\n byPath.set(path, set);\n tagged.values.forEach((v, index) => set.add(walk(v, `${path}/${index}`)));\n return set;\n }\n case \"escaped\":\n return walkPlain(tagged.value, path);\n default:\n return undefined;\n }\n }\n\n return walkPlain(value as Record<string, unknown>, path);\n }\n\n function walkPlain(value: Record<string, unknown>, path: string): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n byPath.set(path, out);\n for (const [key, item] of Object.entries(value)) {\n const childPath = `${path}/${escapePointer(key)}`;\n if (isRef(item)) {\n pending.push({ target: out, key, path: item.path });\n out[key] = undefined;\n continue;\n }\n out[key] = walk(item, childPath);\n }\n return out;\n }\n\n const root = walk(input, \"\");\n byPath.set(\"\", root);\n\n // Second pass: every reference now has a node to point at.\n for (const { target, key, path } of pending) {\n (target as Record<string | number, unknown>)[key] = byPath.get(path);\n }\n\n return root;\n}\n\n/** @internal */\nfunction isRef(value: unknown): value is { [TAG]: \"ref\"; path: string } {\n return (\n value !== null &&\n typeof value === \"object\" &&\n (value as Record<string, unknown>)[TAG] === \"ref\" &&\n typeof (value as Record<string, unknown>).path === \"string\"\n );\n}\n\n/**\n * Escapes a key for use in a JSON Pointer segment (RFC 6901).\n *\n * @internal\n */\nfunction escapePointer(key: string): string {\n return key.replace(/~/g, \"~0\").replace(/\\//g, \"~1\");\n}\n\n/** Outcome of {@link encodeStateBounded}. */\nexport interface BoundedEncodeResult {\n /** The encoded value, small enough to send. */\n readonly value: unknown;\n /** `true` when the state did not fit and parts were replaced by markers. */\n readonly truncated: boolean;\n /** Explains what was dropped, for display beside a partial tree. */\n readonly note?: string;\n}\n\n/**\n * Encodes a value, shrinking it until its serialized form fits within `maxBytes`.\n *\n * @param input - Any value.\n * @param maxBytes - Byte budget for the serialized form.\n * @param options - Passed through to {@link encodeState}.\n *\n * @returns The encoded value and whether anything had to be dropped.\n *\n * @remarks\n * A frame larger than the hub's cap is not merely slow — it is rejected, and the connection with\n * it, so the client reconnects, asks again, is refused again, and the panel sits waiting through\n * a loop with nothing on screen to explain it. The size therefore has to be bounded before the\n * frame is sent rather than discovered afterwards.\n *\n * Node count is a poor proxy for bytes: a hundred nodes holding base64 blobs outweigh a hundred\n * thousand holding integers. So this measures the encoded output and, when it is too large,\n * scales the node budget by how far over it went and measures again. Scaling by the overshoot\n * rather than halving matters: from a default of a hundred thousand nodes, repeated halving\n * needs a dozen rounds to reach the hundreds, so a state that could have been shown in part\n * would have been abandoned instead.\n *\n * Truncation is reported rather than performed silently. A partial tree presented as the state is\n * worse than no tree at all: a debugger that quietly lies about state is not a debugger.\n *\n * @public\n */\nexport function encodeStateBounded(\n input: unknown,\n maxBytes: number,\n options: EncodeOptions = {},\n): BoundedEncodeResult {\n let nodeBudget = options.maxNodes ?? 100_000;\n\n for (let attempt = 0; attempt < 8; attempt += 1) {\n const { value, report } = encodeState(input, { ...options, maxNodes: nodeBudget });\n // `JSON.stringify` can still refuse a value the encoder passed through untouched, so a\n // failure here is measured as \"does not fit\" rather than thrown at the caller.\n let size: number;\n try {\n size = JSON.stringify(value)?.length ?? 0;\n } catch {\n size = Number.POSITIVE_INFINITY;\n }\n\n if (size <= maxBytes) {\n return report.truncated\n ? {\n value,\n truncated: true,\n note: `State was too large to send in full; parts beyond ${nodeBudget} nodes are omitted.`,\n }\n : { value, truncated: false };\n }\n\n // Aim at 80% of the budget so the next attempt has room for the tagging overhead that\n // shrinking cannot remove, and always make progress even when the estimate is optimistic.\n const scaled = Math.floor((nodeBudget * maxBytes * 0.8) / size);\n nodeBudget = Math.max(1, Math.min(scaled, nodeBudget - 1));\n if (nodeBudget <= 1 && attempt > 0) {\n // Already at the floor and still too large: the remaining bytes are one enormous value,\n // not many small ones, and no node budget will cut it down.\n break;\n }\n }\n\n // Nothing fit, even at the smallest budget. Say so instead of sending a frame that will be\n // refused and leaving the panel to retry against a wall.\n return {\n value: { [TAG]: \"unsupported\", kind: \"truncated\" } satisfies Tagged,\n truncated: true,\n note: `State exceeds the ${maxBytes}-byte transport limit and could not be reduced to fit.`,\n };\n}\n","/**\n * Saving state, and starting from saved state.\n *\n * @remarks\n * The two halves happen on opposite sides of the store's existence, which is why this is two\n * functions rather than one. {@link hydrate} produces *initial slice state*, so the store is\n * born hydrated; {@link persist} subscribes to a store that already exists.\n *\n * Restoring after construction is the obvious alternative and the wrong one. It means applying\n * a whole-state snapshot to a live store, which emits a change across every path: a visible\n * flash on boot, a burst of instrumentation entries describing changes nobody made, and\n * effects observing a transition that never happened.\n *\n * @module @yoltra/core\n */\n\nimport { decodeState, encodeState } from \"../serialize/codec\";\n\n/** Where persisted state lives. Bring your own; core imports no platform global. */\nexport interface PersistenceAdapter {\n read(key: string): string | null | Promise<string | null>;\n write(key: string, value: string): void | Promise<void>;\n remove(key: string): void | Promise<void>;\n}\n\n/** Where a failure happened, so a handler can tell a bad write from a bad payload. */\nexport type PersistencePhase = \"read\" | \"write\" | \"decode\" | \"migrate\";\n\n/** Shared configuration. */\nexport interface PersistOptions {\n /** Storage key. */\n readonly key: string;\n readonly adapter: PersistenceAdapter;\n /**\n * Schema version of what is written.\n *\n * @remarks\n * Compared on read. A mismatch is handed to {@link PersistOptions.migrate}, and without one\n * the stored value is discarded rather than trusted — reducers change, and a snapshot\n * written against an older shape is not merely stale, it may not be valid state at all.\n */\n readonly version: number;\n /** Slices to persist. Every slice by default. */\n readonly slices?: readonly string[];\n /** Coalescing window for writes, in milliseconds. Defaults to 250. */\n readonly throttleMs?: number;\n /**\n * Upgrades a payload written by an older version.\n *\n * @returns The slices to restore, or `null` to start fresh.\n */\n readonly migrate?: (persisted: unknown, from: number) => Record<string, unknown> | null;\n /**\n * Called on any failure.\n *\n * @remarks\n * Persistence never throws into the application it is persisting. A store that will not\n * start because storage holds stale JSON is worse than one that starts fresh, and a full\n * disk should not take down a page.\n */\n readonly onError?: (error: unknown, phase: PersistencePhase) => void;\n}\n\n/** What {@link hydrate} recovered. */\nexport interface Hydration {\n /** Slice states to start from. Empty when there was nothing usable to restore. */\n readonly slices: Readonly<Record<string, unknown>>;\n /** `true` when a payload was found, decoded and accepted. */\n readonly restored: boolean;\n}\n\n/** What is written to storage. */\ninterface Envelope {\n readonly version: number;\n readonly slices: Record<string, unknown>;\n}\n\n/** @internal */\nfunction report(options: PersistOptions, error: unknown, phase: PersistencePhase): void {\n options.onError?.(error, phase);\n}\n\n/**\n * Reads persisted state, ready to seed a store.\n *\n * @remarks\n * Every read-side failure — missing, unparseable, wrong version with no migration, a\n * migration that declines — resolves to \"nothing to restore\" and reports through\n * {@link PersistOptions.onError}. Nothing throws.\n *\n * @example\n * ```ts\n * const hydration = await hydrate({ key: 'app', adapter, version: 3 });\n * const store = createStore({\n * name: 'App',\n * reducer: withHydration({ todos: todosSpec }, hydration),\n * });\n * ```\n *\n * @public\n */\nexport async function hydrate(\n options: PersistOptions & { readonly source?: string },\n): Promise<Hydration> {\n const empty: Hydration = { slices: {}, restored: false };\n\n let raw: string | null | undefined;\n try {\n raw = options.source ?? (await options.adapter.read(options.key));\n } catch (error) {\n report(options, error, \"read\");\n return empty;\n }\n if (raw === null || raw === undefined || raw === \"\") return empty;\n\n let envelope: Envelope;\n try {\n envelope = decodeState(JSON.parse(raw)) as Envelope;\n } catch (error) {\n report(options, error, \"decode\");\n return empty;\n }\n\n if (envelope === null || typeof envelope !== \"object\" || typeof envelope.version !== \"number\") {\n report(options, new Error(\"persisted payload is not a recognisable envelope\"), \"decode\");\n return empty;\n }\n\n if (envelope.version !== options.version) {\n if (options.migrate === undefined) {\n report(\n options,\n new Error(\n `persisted state is version ${envelope.version}, this build expects ${options.version}, and no migrate was supplied`,\n ),\n \"migrate\",\n );\n return empty;\n }\n try {\n const migrated = options.migrate(envelope.slices, envelope.version);\n if (migrated === null) return empty;\n return { slices: migrated, restored: true };\n } catch (error) {\n report(options, error, \"migrate\");\n return empty;\n }\n }\n\n return { slices: envelope.slices ?? {}, restored: true };\n}\n\n/**\n * Replaces each reducer's initial state with what was restored for it.\n *\n * @remarks\n * Slices absent from the payload keep their declared defaults, so adding a reducer does not\n * invalidate everything written before it existed.\n *\n * @public\n */\nexport function withHydration<R extends Record<string, { state: unknown }>>(\n reducers: R,\n hydration: Hydration,\n): R {\n if (!hydration.restored) return reducers;\n\n const next = {} as Record<string, { state: unknown }>;\n for (const [name, spec] of Object.entries(reducers)) {\n const restored = hydration.slices[name];\n next[name] = restored === undefined ? spec : { ...spec, state: restored };\n }\n return next as R;\n}\n\n/** The store surface persistence needs, which is two methods wide. */\nexport interface PersistableStore {\n getState(): unknown;\n instrument(observer: (info: { changedPaths?: readonly string[] }) => void): () => void;\n}\n\n/** Serializes the slices being persisted. */\nfunction encodeEnvelope(state: unknown, options: Pick<PersistOptions, \"version\" | \"slices\">): string {\n const all = (state ?? {}) as Record<string, unknown>;\n const slices: Record<string, unknown> =\n options.slices === undefined\n ? all\n : Object.fromEntries(options.slices.filter((s) => s in all).map((s) => [s, all[s]]));\n\n return JSON.stringify(encodeState({ version: options.version, slices }).value);\n}\n\n/**\n * Writes state as it changes.\n *\n * @returns A function that stops persisting and flushes anything pending.\n *\n * @remarks\n * Driven by `instrument` rather than the coarse subscription, so a change confined to a slice\n * that is not persisted costs nothing at all. Writes are coalesced on the trailing edge.\n *\n * @public\n */\nexport function persist(store: PersistableStore, options: PersistOptions): () => void {\n const throttleMs = options.throttleMs ?? 250;\n const watched = options.slices;\n let timer: ReturnType<typeof setTimeout> | null = null;\n let pending = false;\n\n const flush = (): void => {\n if (!pending) return;\n pending = false;\n try {\n const written = options.adapter.write(options.key, encodeEnvelope(store.getState(), options));\n if (written instanceof Promise) {\n void written.catch((error: unknown) => report(options, error, \"write\"));\n }\n } catch (error) {\n // Storage being full, or unavailable in private mode, must not surface to the caller.\n report(options, error, \"write\");\n }\n };\n\n const schedule = (): void => {\n pending = true;\n if (throttleMs <= 0) {\n flush();\n return;\n }\n if (timer !== null) return;\n timer = setTimeout(() => {\n timer = null;\n flush();\n }, throttleMs);\n // Never hold a process open for a pending write.\n (timer as unknown as { unref?: () => void }).unref?.();\n };\n\n const stop = store.instrument((info) => {\n if (watched === undefined) {\n schedule();\n return;\n }\n // A changed path is `slice.rest`; only a watched slice is worth a write.\n const touched = (info.changedPaths ?? []).some((path) =>\n watched.some((slice) => path === slice || path.startsWith(`${slice}.`)),\n );\n if (touched) schedule();\n });\n\n return () => {\n stop();\n if (timer !== null) {\n clearTimeout(timer);\n timer = null;\n }\n flush();\n };\n}\n\n/**\n * Serializes a store for handoff, for example from a server render to the client.\n *\n * @public\n */\nexport function dehydrate(\n store: Pick<PersistableStore, \"getState\">,\n options: Pick<PersistOptions, \"version\" | \"slices\">,\n): string {\n return encodeEnvelope(store.getState(), options);\n}\n","/**\n * Storage adapters for the environments core can reach without importing them.\n *\n * @remarks\n * Each is built by a factory that takes the storage object rather than reaching for a global,\n * so this module stays isomorphic: nothing here breaks a Worker, a server render or a test.\n *\n * @module @yoltra/core\n */\n\nimport type { PersistenceAdapter } from \"./persist\";\n\n/** The slice of the Web Storage API used here. */\nexport interface WebStorageLike {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n removeItem(key: string): void;\n}\n\n/**\n * Wraps a Web Storage object.\n *\n * @remarks\n * Pass `localStorage` or `sessionStorage` explicitly. Reading the global here would make this\n * module unusable anywhere one does not exist, which includes a server render — exactly where\n * hydration payloads are produced.\n *\n * @example\n * ```ts\n * const adapter = createWebStorageAdapter(localStorage);\n * ```\n *\n * @public\n */\nexport function createWebStorageAdapter(storage: WebStorageLike): PersistenceAdapter {\n return {\n read: (key) => storage.getItem(key),\n write: (key, value) => storage.setItem(key, value),\n remove: (key) => storage.removeItem(key),\n };\n}\n\n/**\n * Keeps state in memory.\n *\n * @remarks\n * For tests, and for a server render that wants the persistence path exercised without a\n * store behind it. It forgets on restart, which is the whole of what it claims.\n *\n * @public\n */\nexport function createMemoryAdapter(initial?: Record<string, string>): PersistenceAdapter {\n const store = new Map<string, string>(Object.entries(initial ?? {}));\n return {\n read: (key) => store.get(key) ?? null,\n write: (key, value) => {\n store.set(key, value);\n },\n remove: (key) => {\n store.delete(key);\n },\n };\n}\n"],"names":["EventBus","channel","type","handler","byType","set","payload","event","h","err","LooseEventBus","typeStr","pattern","pmap","key","map","normalizedType","cMap","list","i","pMap","exactList","patternLists","called","deliver","arr","exc","make","s","p","index","segments","entry","head","bucket","at","e","patternMap","subject","lists","test","entries","handlers","pSegs","sSegs","j","star","matchIdx","result","Reducer","reduce","state","warnedDottedKeys","warnDottedKey","path","full","detectChangedProps","oldState","newState","ancestors","out","walk","oldObj","newObj","active","onPath","isArrOld","isArrNew","a","b","overlap","oldKeys","newKeys","sameKeys","hasOld","nextPath","freezeState","obj","seen","alias","desc","sym","REJECTED","Rejected","reason","isRejected","value","CallTimeoutError","idleMs","CallAbortedError","parseReply","reply","types","t","isReplyTo","requestId","correlationId","CallQueue","highWaterMark","item","taker","release","buffered","putter","next","DEFAULT_CALL_TIMEOUT_MS","DEFAULT_CALL_WATERMARK","performCall","deps","opts","replyChannel","isTerminal","queue","settle","fail","settled","terminal","resolve","reject","timer","unregister","finish","fn","graceful","onAbort","arm","onOk","onErr","onDone","getAtPath","parts","cur","seg","buildAncestorPaths","matchesWhen","when","getMiddlewareFunction","input","getMiddlewareWhen","normalizeEventKeys","spec","cloneInitialState","sliceName","freezeInDev","DEFAULT_DEDUP_KEY_WINDOW_MS","DEFAULT_MAX_REDUCE_DEPTH","CASCADE_CHAIN_LIMIT","NOT_COMMITTED","COMMITTED_UNWRITTEN","WRITTEN","now","Store","name","rSpec","effSpec","base","json","fp","windowMs","existing","effectiveWindow","cutoff","timestamp","limit","limitValue","depth","chain","emit","effectSet","effect","cause","parent","phase","phaseSet","allSet","rName","staged","prev","leafPaths","nextState","slice","toEmit","prop","reducers","effects","meta","middleware","mwInput","atomic","coarse","nextPlain","anyChanged","prevSlice","nextSlice","frozenNextSlice","oldValue","newValue","l","snapshot","events","evt","rejection","refused","anySliceChanged","scopedParent","dedupKey","contentWindow","id","done","r","parentId","instrumenting","prevState","sink","t0","mw","ok","rejectedBy","written","observer","changedPaths","reduceTimeMs","prevValues","nextValues","info","options","off","targetMap","unsubs","eventKeys","u","getState","typed","preserveState","currentKeys","nextEntries","nextKeys","k","partial","reducer","ch","tp","sourceEvent","_removed","rest","readAtPath","ancestorPaths","createStore","cfg","typedEvents","_","keys","warnedDottedIds","warnDottedId","sameOrder","current","createEntityAdapter","selectId","entity","sortComparer","order","ids","sorted","left","right","write","entities","put","incoming","mode","merge","updates","changes","drop","doomed","extra","update","field","TAG","encodeState","maxNodes","sanitize","unsupported","nodes","truncated","asObject","previous","v","values","escapePointer","decodeState","byPath","pending","isRef","tagged","error","walkPlain","childPath","root","target","encodeStateBounded","maxBytes","nodeBudget","attempt","report","size","scaled","hydrate","empty","raw","envelope","migrated","withHydration","hydration","restored","encodeEnvelope","all","slices","persist","store","throttleMs","watched","flush","schedule","stop","dehydrate","createWebStorageAdapter","storage","createMemoryAdapter","initial"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"yoltra.mjs","sources":["../src/eventBus/EventBus.ts","../src/eventBus/LooseEventBus.ts","../src/reducer/Reducer.ts","../src/utils/detectChangedProps.ts","../src/utils/immutability.ts","../src/store/rejection.ts","../src/store/call.ts","../src/store/callQueue.ts","../src/store/performCall.ts","../src/store/paths.ts","../src/serialize/codec.ts","../src/store/fingerprint.ts","../src/store/matching.ts","../src/store/Store.ts","../src/types.ts","../src/entity/entityAdapter.ts","../src/persistence/persist.ts","../src/persistence/adapters.ts"],"sourcesContent":["/**\n * @module @yoltra/core\n */\n\nimport type { Event, EventMapBase } from \"../types\";\n\n/**\n * Minimal, synchronous pub/sub event bus keyed by **channel** and **type**.\n *\n * @typeParam EM - Event map shape:\n * ```ts\n * type EventMapBase = Record<string, Record<string, unknown>>;\n * // Example:\n * type EM = {\n * ui: { toggle: boolean };\n * data: { loaded: { items: string[] } };\n * };\n * ```\n *\n * @remarks\n * - Handlers are stored per `(channel, type)` and invoked **synchronously** in subscription order.\n * - Exceptions thrown by a handler are **caught and logged**, and do **not** stop other handlers.\n * - Intended for in-memory, single-process usage (no cross-tab/process broadcasting).\n *\n * @example\n * ```ts\n * type EM = {\n * ui: { toggle: boolean };\n * data: { loaded: { items: string[] } };\n * };\n *\n * const bus = new EventBus<EM>();\n *\n * // Subscribe\n * const off = bus.on('ui', 'toggle', (on) => {\n * console.log('UI toggled:', on);\n * });\n *\n * // Emit\n * bus.emit('ui', 'toggle', true); // logs: \"UI toggled: true\"\n *\n * // Unsubscribe\n * off();\n * ```\n *\n * @public\n */\nexport class EventBus<EM extends EventMapBase> {\n /**\n * Internal registry: `channel → type → Set<handler>`.\n * @internal\n */\n private handlers: Map<string, Map<string, Set<(payload: any, event?: any) => void>>> = new Map();\n\n /**\n * Subscribes a handler to an exact `(channel, type)`.\n *\n * @typeParam C - Channel key (must be a string key of `EM`).\n * @typeParam T - Type key within channel `C` (must be a string key of `EM[C]`).\n * @param channel - Channel name to subscribe to.\n * @param type - Event type within the channel.\n * @param handler - Function invoked with the payload type `EM[C][T]`. It optionally\n * receives the **source event** as a second argument when the emitter supplies one, so\n * subscribers can read the true `id` (and any `meta`) instead of reconstructing an event\n * from the payload alone. Handlers that declare only `payload` remain valid.\n * @returns An **unsubscribe** function that removes this handler.\n *\n * @example\n * ```ts\n * const off = bus.on('data', 'loaded', ({ items }) => {\n * console.log('Loaded', items.length, 'items');\n * });\n *\n * // Later, stop listening:\n * off();\n * ```\n *\n * @example Reading the source event\n * ```ts\n * bus.on('data', 'loaded', (payload, event) => {\n * console.log('event id:', event?.id);\n * });\n * ```\n *\n * @public\n */\n public on<C extends keyof EM & string, T extends keyof EM[C] & string>(\n channel: C,\n type: T,\n handler: (payload: EM[C][T], event?: Event<EM, C, T>) => void,\n ): () => void {\n let byType = this.handlers.get(channel);\n if (!byType) {\n byType = new Map();\n this.handlers.set(channel, byType);\n }\n\n let set = byType.get(type);\n if (!set) {\n set = new Set();\n byType.set(type, set);\n }\n\n set.add(handler as any);\n\n return () => this.off(channel, type, handler);\n }\n\n /**\n * Removes a specific handler previously added with {@link EventBus.on | `on`}.\n *\n * @typeParam C - Channel key (string key of `EM`).\n * @typeParam T - Type key within channel `C` (string key of `EM[C]`).\n * @param channel - Channel name of the subscription to remove.\n * @param type - Event type of the subscription to remove.\n * @param handler - The same handler reference that was passed to `on`.\n *\n * @example\n * ```ts\n * const h = (n: number) => console.log('inc', n);\n * bus.on('math', 'inc', h);\n *\n * // Explicitly remove this handler:\n * bus.off('math', 'inc', h);\n * ```\n *\n * @public\n */\n public off<C extends keyof EM & string, T extends keyof EM[C] & string>(\n channel: C,\n type: T,\n handler: (payload: EM[C][T], event?: Event<EM, C, T>) => void,\n ): void {\n const byType = this.handlers.get(channel);\n if (!byType) return;\n\n const set = byType.get(type);\n if (!set) return;\n\n set.delete(handler as any);\n\n if (set.size === 0) byType.delete(type);\n if (byType.size === 0) this.handlers.delete(channel);\n }\n\n /**\n * Emits an event to all subscribers of the exact `(channel, type)`.\n *\n * Handlers are invoked **synchronously**. Any exception thrown by a handler is\n * caught and logged, and other handlers still run.\n *\n * @typeParam C - Channel key (string key of `EM`).\n * @typeParam T - Type key within channel `C` (string key of `EM[C]`).\n * @param channel - Channel name to emit on.\n * @param type - Event type to emit.\n * @param payload - Payload matching `EM[C][T]`.\n * @param event - Optional **source event**, forwarded to handlers as a second argument.\n * Supply it whenever the caller already holds the real event so subscribers observe its\n * true `id` rather than reconstructing one; omitting it keeps the original behaviour.\n *\n * @example\n * ```ts\n * bus.emit('ui', 'toggle', false);\n * ```\n *\n * @public\n */\n public emit<C extends keyof EM & string, T extends keyof EM[C] & string>(\n channel: C,\n type: T,\n payload: EM[C][T],\n event?: Event<EM, C, T>,\n ): void {\n const byType = this.handlers.get(channel);\n if (!byType) return;\n\n const set = byType.get(type);\n if (!set || set.size === 0) return;\n\n for (const h of [...set]) {\n try {\n (h as any)(payload, event);\n } catch (err) {\n console.error(\"EventBus handler error:\", err);\n }\n }\n }\n\n /**\n * Clears **all** listeners across all channels/types.\n *\n * Useful for tests or during HMR teardown to avoid duplicate handlers.\n *\n * @example\n * ```ts\n * // In a test teardown:\n * afterEach(() => bus.clear());\n * ```\n *\n * @public\n */\n public clear(): void {\n this.handlers.clear();\n }\n}","/**\n * @module @yoltra/core\n */\n\n/**\n * Flexible, synchronous pub/sub bus that supports **exact** and **pattern** event subscriptions.\n *\n * @typeParam C - Channel name type (defaults to `string`).\n * @typeParam T - Event type name type (defaults to `string`). Types are treated as **dot-separated paths** (e.g. `\"a.b.c\"`).\n * @typeParam P - Payload type for all events (defaults to `any`).\n *\n * @remarks\n * - **Exact handlers** subscribe to a specific `(channel, type)` pair. Type keys are **normalized** by stripping a single leading dot (`\".foo\"` → `\"foo\"`).\n * - **Pattern handlers** subscribe using wildcards over dot-separated segments:\n * - `*` matches **one** segment.\n * - `**` matches **zero or more** segments (greedy).\n * - On {@link LooseEventBus.emit | `emit`}, exact handlers fire first, then any matching pattern handlers.\n * - Handlers are **de-duplicated**: if the same function is both exact and pattern-registered, it is called **once**.\n * - Handler invocation is **synchronous**. Exceptions are caught and logged; remaining handlers still run.\n *\n * @example\n * ```ts\n * type C = 'ui' | 'data';\n * type T = string;\n * type P = unknown;\n *\n * const bus = new LooseEventBus<C, T, P>();\n *\n * // Exact\n * const offA = bus.on('ui', 'panel.open', () => console.log('panel opened'));\n *\n * // Patterns\n * const offB = bus.on('ui', 'panel.*', () => console.log('any single sub-event under panel'));\n * const offC = bus.on('ui', 'panel.**', () => console.log('any depth under panel'));\n *\n * bus.emit('ui', 'panel.open', null);\n * // => exact fires, then 'panel.*', then 'panel.**'\n *\n * offA(); offB(); offC(); // unsubscribe\n * ```\n *\n * @public\n */\n/**\n * One registered pattern, kept pre-split.\n * @internal\n */\ninterface PatternEntry {\n readonly pattern: string;\n readonly segments: readonly string[];\n}\n\n/**\n * The patterns on one channel, arranged by what a subject's first segment can match.\n * @internal\n */\ninterface PatternIndex {\n /** Keyed by a literal first segment. */\n readonly byHead: Map<string, PatternEntry[]>;\n /** Patterns beginning with `*` or `**`, which every subject has to test. */\n readonly anyHead: PatternEntry[];\n}\n\nexport class LooseEventBus<C extends string = string, T extends string = string, P = any> {\n /**\n * Exact handlers: `channel → type → [handlers]`.\n * @internal\n */\n private handlers = new Map<C, Map<T, Array<(p: P) => void>>>();\n\n /**\n * Pattern handlers with `*` and `**`: `channel → pattern(string) → [handlers]`.\n * @internal\n */\n private patternHandlers = new Map<C, Map<string, Array<(p: P) => void>>>();\n\n /**\n * Patterns bucketed by their first segment, so an emit tests only what could match.\n *\n * @remarks\n * Delivery used to walk every pattern registered on the channel and run the full segment\n * matcher against each. That is linear in the number of patterns rather than in the number\n * that match, and it re-split both the pattern and the subject on every test — for a thousand\n * patterns, two thousand string splits to deliver one event.\n *\n * A subject's first segment can only be matched by a pattern whose first segment is that same\n * literal, or is `*` or `**`. Bucketing on that turns the common shape — distinct event\n * families like `panel.*` and `order.**` — from a scan of everything into a map lookup plus\n * the handful that begin with a wildcard.\n *\n * It buys nothing for a channel where every pattern starts with `**`, since all of those must\n * still be tested. That is the honest worst case, and it is unchanged rather than worsened.\n */\n private patternIndex = new Map<C, PatternIndex>();\n\n /**\n * Subscribes a handler to either an **exact** type or a **pattern**.\n *\n * @param channel - Channel to subscribe on.\n * @param type - Exact event type (e.g. `\"a.b\"`) or pattern (contains `*`/`**`).\n * @param handler - Function invoked with the emitted payload.\n * @returns An **unsubscribe** function that removes this handler.\n *\n * @remarks\n * - Exact subscriptions are stored under a **normalized** key (leading `.` removed).\n * - Pattern subscriptions are stored **as provided**; matching normalizes the subject.\n *\n * @example Exact subscription\n * ```ts\n * const off = bus.on('data', 'items.loaded', ({ count }) => {\n * console.log('Loaded', count);\n * });\n * // Later\n * off();\n * ```\n *\n * @example Pattern subscription\n * ```ts\n * // Match any single sub-event: 'panel.open', 'panel.close', etc.\n * const offStar = bus.on('ui', 'panel.*', () => {});\n *\n * // Match any depth: 'panel.open', 'panel.items.add', 'panel', etc.\n * const offGlob = bus.on('ui', 'panel.**', () => {});\n * ```\n *\n * @public\n */\n on(channel: C, type: T, handler: (payload: P) => void): () => void {\n const typeStr = String(type);\n if (!this.isPattern(typeStr)) {\n // Exact subscription with normalized key (strip leading dot)\n const key = this.normalizeTypeKey(typeStr) as T;\n\n if (!this.handlers.has(channel)) this.handlers.set(channel, new Map());\n const map = this.handlers.get(channel)!;\n\n if (!map.has(key)) map.set(key, []);\n map.get(key)!.push(handler);\n\n // capture normalized key for off()\n return () => this.offExactNormalized(channel, key, handler);\n } else {\n // Pattern subscription (stored as provided; matcher handles normalization)\n const pattern = typeStr;\n\n if (!this.patternHandlers.has(channel)) this.patternHandlers.set(channel, new Map());\n const pmap = this.patternHandlers.get(channel)!;\n\n if (!pmap.has(pattern)) {\n pmap.set(pattern, []);\n // Split once here rather than on every emit, and file it under the segment that decides\n // whether it is even a candidate.\n this.indexPattern(channel, pattern);\n }\n pmap.get(pattern)!.push(handler);\n\n return () => this.offPattern(channel, pattern, handler);\n }\n }\n\n /**\n * Unsubscribes an **exact** handler. The `type` key is normalized internally,\n * so callers can pass `\"foo\"` or `\".foo\"` interchangeably.\n *\n * @param channel - Channel name.\n * @param type - Exact event type key to remove (normalization applied).\n * @param handler - The same handler reference previously passed to {@link LooseEventBus.on | `on`}.\n *\n * @example\n * ```ts\n * const h = () => {};\n * bus.on('ui', 'panel.open', h);\n * // Remove it (with or without leading dot)\n * bus.off('ui', '.panel.open', h);\n * ```\n *\n * @public\n */\n off(channel: C, type: T, handler: (payload: P) => void): void {\n const key = this.normalizeTypeKey(String(type)) as T;\n this.offExactNormalized(channel, key, handler);\n }\n\n /**\n * Internal exact unsubscription using an already **normalized** type key.\n *\n * @param channel - Channel name.\n * @param normalizedType - Event type key with leading dot removed.\n * @param handler - Handler to remove.\n * @internal\n */\n private offExactNormalized(\n channel: C,\n normalizedType: T,\n handler: (payload: P) => void,\n ): void {\n const cMap = this.handlers.get(channel);\n if (!cMap) return;\n const list = cMap.get(normalizedType);\n if (!list) return;\n\n const i = list.indexOf(handler);\n if (i !== -1) list.splice(i, 1);\n\n // cleanup empties\n if (list.length === 0) cMap.delete(normalizedType);\n if (cMap.size === 0) this.handlers.delete(channel);\n }\n\n /**\n * Internal removal for a **pattern** subscription. No-ops if missing.\n *\n * @param channel - Channel name.\n * @param pattern - Pattern string as originally subscribed.\n * @param handler - Handler to remove.\n * @internal\n */\n private offPattern(channel: C, pattern: string, handler: (payload: P) => void): void {\n const pMap = this.patternHandlers.get(channel);\n if (!pMap) return;\n\n const list = pMap.get(pattern);\n if (!list) return;\n\n const i = list.indexOf(handler);\n if (i !== -1) list.splice(i, 1);\n\n // cleanup empties\n if (list.length === 0) {\n pMap.delete(pattern);\n this.unindexPattern(channel, pattern);\n }\n if (pMap.size === 0) {\n this.patternHandlers.delete(channel);\n this.patternIndex.delete(channel);\n }\n }\n\n /**\n * Emits an event to all exact subscribers first, then to **matching pattern** subscribers.\n * Duplicate handler references are called **once** (de-duped).\n *\n * @param channel - Channel to emit on.\n * @param type - Event type (subject). A leading dot is ignored for matching.\n * @param payload - Payload delivered to handlers.\n *\n * @example\n * ```ts\n * // Suppose:\n * // - on('ui', 'panel.open', h)\n * // - on('ui', 'panel.*', h) // same handler ref!\n * // - on('ui', 'panel.**', other)\n * bus.emit('ui', 'panel.open', { id: 1 });\n * // => 'h' runs once (de-duped), then 'other'\n * ```\n *\n * @public\n */\n emit(channel: C, type: T, payload: P): void {\n const typeStr = String(type);\n const normalizedType = this.normalizeTypeKey(typeStr) as T;\n\n // Exact delivery (normalized)\n const exactList = this.handlers.get(channel)?.get(normalizedType) ?? [];\n\n // Pattern delivery (normalize subject before matching)\n const patternLists = this.matchingPatternHandlers(channel, typeStr);\n\n const called = new Set<(p: P) => void>();\n const deliver = (arr: Array<(p: P) => void>) => {\n for (const h of [...arr]) {\n if (called.has(h)) continue;\n\n called.add(h);\n\n try {\n h(payload);\n } catch (exc) {\n console.error(exc);\n continue;\n }\n }\n };\n\n deliver(exactList);\n for (const list of patternLists) deliver(list);\n }\n\n /**\n * Emits a payload that is only built if somebody is listening.\n *\n * @param channel - Channel to emit on.\n * @param type - Concrete event type.\n * @param make - Builds the payload. Called at most once, and only when a handler matched.\n *\n * @remarks\n * Same matching as {@link LooseEventBus.emit}; the difference is *when* the payload exists.\n * The store's change notification carries the old and new value at a path, and reading those\n * means walking the state tree twice per path. Doing that eagerly meant a slice nobody had\n * subscribed to paid the full cost of describing changes to an audience of nobody — the\n * matching work was already being done to discover there were no handlers.\n *\n * @public\n */\n emitWith(channel: C, type: T, make: () => P): void {\n const typeStr = String(type);\n const normalizedType = this.normalizeTypeKey(typeStr) as T;\n\n const exactList = this.handlers.get(channel)?.get(normalizedType) ?? [];\n\n const patternLists = this.matchingPatternHandlers(channel, typeStr);\n\n if (exactList.length === 0 && patternLists.length === 0) return;\n\n // Exactly one construction, shared by every handler — the same guarantee `emit` gives.\n const payload = make();\n\n const called = new Set<(p: P) => void>();\n const deliver = (arr: Array<(p: P) => void>) => {\n for (const h of [...arr]) {\n if (called.has(h)) continue;\n called.add(h);\n try {\n h(payload);\n } catch (exc) {\n console.error(exc);\n continue;\n }\n }\n };\n\n deliver(exactList);\n for (const list of patternLists) deliver(list);\n }\n\n /**\n * Determines if a string is a **pattern** (contains `*`).\n * @param s - Event type or pattern string.\n * @returns `true` if it contains at least one `*`, else `false`.\n * @internal\n */\n private isPattern(s: string): boolean {\n return s.includes(\"*\");\n }\n\n /**\n * Normalizes event type keys for exact matching by stripping a **single** leading dot.\n *\n * @param s - Event type key.\n * @returns Normalized key without a leading dot.\n * @example\n * ```ts\n * normalizeTypeKey('.a.b') // 'a.b'\n * normalizeTypeKey('a.b') // 'a.b'\n * ```\n * @internal\n */\n private normalizeTypeKey(s: string): string {\n return s.replace(/^\\./, \"\");\n }\n\n /**\n * Splits a path into dot-separated segments after normalization and removes empties.\n * @param p - Event type or pattern string.\n * @internal\n */\n private splitPath(p: string): string[] {\n return this.normalizeTypeKey(p).split(\".\").filter(Boolean);\n }\n\n /**\n * Files a pattern under the first segment that could select it.\n * @internal\n */\n private indexPattern(channel: C, pattern: string): void {\n let index = this.patternIndex.get(channel);\n if (index === undefined) {\n index = { byHead: new Map(), anyHead: [] };\n this.patternIndex.set(channel, index);\n }\n const segments = this.splitPath(pattern);\n const entry: PatternEntry = { pattern, segments };\n const head = segments[0];\n // A pattern with no segments at all, or one starting with a wildcard, cannot be narrowed by\n // the subject's first segment — so it goes in the list every emit walks.\n if (head === undefined || head === \"*\" || head === \"**\") {\n index.anyHead.push(entry);\n return;\n }\n const bucket = index.byHead.get(head);\n if (bucket === undefined) index.byHead.set(head, [entry]);\n else bucket.push(entry);\n }\n\n /**\n * Removes a pattern from the index. Paired with {@link LooseEventBus.offPattern}.\n * @internal\n */\n private unindexPattern(channel: C, pattern: string): void {\n const index = this.patternIndex.get(channel);\n if (index === undefined) return;\n const head = this.splitPath(pattern)[0];\n const bucket =\n head === undefined || head === \"*\" || head === \"**\"\n ? index.anyHead\n : index.byHead.get(head);\n if (bucket === undefined) return;\n const at = bucket.findIndex((e) => e.pattern === pattern);\n if (at !== -1) bucket.splice(at, 1);\n if (bucket.length === 0 && bucket !== index.anyHead && head !== undefined) {\n index.byHead.delete(head);\n }\n }\n\n /**\n * The handler lists of every pattern matching this subject.\n *\n * @remarks\n * Shared by `emit` and `emitWith` so the two cannot drift on what \"matching\" means — which\n * they could, being two copies of the same walk before.\n *\n * The subject is split once here rather than once per pattern tested.\n *\n * @internal\n */\n private matchingPatternHandlers(channel: C, typeStr: string): Array<Array<(p: P) => void>> {\n const patternMap = this.patternHandlers.get(channel);\n const index = this.patternIndex.get(channel);\n if (patternMap === undefined || patternMap.size === 0 || index === undefined) return [];\n\n const subject = this.splitPath(typeStr);\n const lists: Array<Array<(p: P) => void>> = [];\n\n const test = (entries: readonly PatternEntry[]): void => {\n for (const entry of entries) {\n if (!this.matchSegments(entry.segments, subject)) continue;\n const handlers = patternMap.get(entry.pattern);\n if (handlers !== undefined) lists.push(handlers);\n }\n };\n\n const head = subject[0];\n if (head !== undefined) {\n const bucket = index.byHead.get(head);\n if (bucket !== undefined) test(bucket);\n }\n test(index.anyHead);\n\n return lists;\n }\n\n /**\n * Pattern matcher over dot-separated segments, which arrive already split.\n *\n * Rules:\n * - **literal**: exact match.\n * - `*` : matches exactly **one** segment.\n * - `**` : matches **zero or more** remaining segments (including empty).\n *\n * @remarks\n * Takes segments rather than strings so delivery can split each pattern once at registration\n * and the subject once per emit, instead of both once per test. Re-splitting per test was most\n * of what made wildcard delivery expensive: a thousand patterns meant two thousand string\n * splits to deliver one event.\n *\n * @param pSegs - Pattern segments (may include `*`/`**`).\n * @param sSegs - Subject segments to test.\n * @returns `true` if the pattern matches; otherwise `false`.\n *\n * @example\n * ```ts\n * matchSegments(['a', '*'], ['a', 'b']) // true\n * matchSegments(['a', '*'], ['a', 'b', 'c']) // false\n * matchSegments(['a', '**'], ['a']) // true\n * matchSegments(['**', 'end'], ['x', 'y', 'end']) // true\n * ```\n *\n * @internal\n */\n private matchSegments(pSegs: readonly string[], sSegs: readonly string[]): boolean {\n\n // Iterative segment glob with backtracking — no per-suffix recursion or\n // string re-joining. `*` matches exactly one segment; `**` matches zero or\n // more. Standard wildcard algorithm (`*`≈`?`, `**`≈`*`).\n let i = 0; // pattern index\n let j = 0; // subject index\n let star = -1; // pSegs index of the most recent '**' seen\n let matchIdx = 0; // sSegs index captured when that '**' was seen\n\n while (j < sSegs.length) {\n if (i < pSegs.length && (pSegs[i] === \"*\" || pSegs[i] === sSegs[j])) {\n i++;\n j++;\n } else if (i < pSegs.length && pSegs[i] === \"**\") {\n // '**' initially absorbs zero segments; remember it for backtracking.\n star = i;\n matchIdx = j;\n i++;\n } else if (star !== -1) {\n // Backtrack: let the last '**' absorb one more subject segment.\n i = star + 1;\n j = ++matchIdx;\n } else {\n return false;\n }\n }\n\n // Any leftover pattern tokens must all be '**' (each matching zero segments).\n while (i < pSegs.length && pSegs[i] === \"**\") i++;\n return i === pSegs.length;\n }\n\n /**\n * Removes **all** listeners (exact and pattern). Useful for tests/HMR teardown.\n *\n * @example\n * ```ts\n * afterEach(() => bus.clear());\n * ```\n *\n * @public\n */\n clear(): void {\n this.handlers.clear();\n this.patternHandlers.clear();\n // The index is derived state; leaving it behind would re-register a pattern twice on the\n // next `on()` and hold every cleared pattern string alive for the life of the bus.\n this.patternIndex.clear();\n }\n\n /**\n * Returns a snapshot of all registered subscriptions for DevTools introspection.\n *\n * @returns An array of `{ channel, type, count }` entries for each distinct\n * (channel, type/pattern) pair with at least one handler.\n *\n * @internal\n */\n __introspect(): Array<{ channel: string; type: string; count: number }> {\n const result: Array<{ channel: string; type: string; count: number }> = [];\n for (const [channel, map] of this.handlers) {\n for (const [type, list] of map) {\n if (list.length > 0) {\n result.push({ channel: channel as string, type: type as string, count: list.length });\n }\n }\n }\n for (const [channel, map] of this.patternHandlers) {\n for (const [pattern, list] of map) {\n if (list.length > 0) {\n result.push({ channel: channel as string, type: pattern, count: list.length });\n }\n }\n }\n return result;\n }\n}","/**\n * @module @yoltra/core\n */\n\nimport type { EventMapBase, EventUnion, ReducerFunction } from \"../types\";\nimport type { Rejection } from \"../store/rejection\";\n\n/**\n * Thin wrapper around a pure reducer function (stateful event consumer):\n * given a state `S` and an event (from {@link EventUnion | `EventUnion<EM>`}),\n * returns the next state `S`.\n *\n * @typeParam S - State shape handled by this reducer.\n * @typeParam EM - Event map describing the valid event keys and payload types.\n *\n * @remarks\n * - The reducer function is expected to be **pure** and **side-effect free**.\n * - Use this class when you want to pass a reducer around as a value, or to\n * unify the reducer interface across the core API.\n *\n * @example Basic counter\n * ```ts\n * type State = { count: number };\n * type EM = { math: { add: number; set: number } };\n *\n * const rf: ReducerFunction<State, EM> = (s, evt) => {\n * if (evt.channel === 'math' && evt.type === 'add') {\n * return { count: s.count + evt.payload };\n * }\n * if (evt.channel === 'math' && evt.type === 'set') {\n * return { count: evt.payload };\n * }\n * return s;\n * };\n *\n * const r = new Reducer<State, EM>(rf);\n *\n * const s0 = { count: 0 };\n * const s1 = r.reduce(s0, {\n * channel: 'math',\n * type: 'add',\n * payload: 2,\n * id: crypto.randomUUID()\n * } as EventUnion<EM>);\n * // s1.count === 2\n * ```\n *\n * @public\n */\nexport class Reducer<S, EM extends EventMapBase = EventMapBase> {\n /**\n * The underlying pure reducer function.\n * @internal\n */\n private readonly _reduce: ReducerFunction<S, EM>;\n\n /**\n * Creates a new {@link Reducer} from a pure reducer function.\n *\n * @param reduce - A function `(state, event) => nextState` that implements your update logic.\n *\n * @example\n * ```ts\n * const reducer = new Reducer<MyState, MyEM>((state, event) => {\n * // implement your transitions here\n * return state;\n * });\n * ```\n *\n * @public\n */\n constructor(reduce: ReducerFunction<S, EM>) {\n this._reduce = reduce;\n }\n\n /**\n * Applies the reducer to produce the next state.\n *\n * @param state - Current state.\n * @param event - An event drawn from {@link EventUnion | `EventUnion<EM>`}.\n * @returns The next state, or a {@link Rejection} if the reducer refused the write.\n *\n * @example\n * ```ts\n * const next = reducer.reduce(curr, someEvent as EventUnion<MyEM>);\n * ```\n *\n * @public\n */\n reduce(state: S, event: EventUnion<EM>): S | Rejection {\n return this._reduce(state, event);\n }\n}","/**\n * @module @yoltra/core\n */\n\n/**\n * Keys already warned about, so a hot path does not turn into a log.\n *\n * @internal\n */\nconst warnedDottedKeys = new Set<string>();\n\n/** @internal */\nfunction warnDottedKey(path: string, key: string): void {\n const full = path ? `${path}.${key}` : key;\n if (warnedDottedKeys.has(full)) return;\n warnedDottedKeys.add(full);\n console.warn(\n `[yoltra] State key \"${key}\"${path ? ` under \"${path}\"` : \"\"} contains a dot. Paths are ` +\n `dotted, so this key is indistinguishable from nested objects of the same name: a ` +\n `subscription to \"${full}\" may match the wrong value, and DevTools patches for it will ` +\n `address the wrong node. Rename the key, or nest it.`,\n );\n}\n\n\n/**\n * Computes the list of **dotted leaf paths** that changed between two values.\n *\n * The algorithm performs a deep structural comparison with special handling for:\n * - **Primitives / null** → treated as leafs (change = current `path`; two `NaN`s are equal)\n * - **Date** → compares `getTime()`\n * - **RegExp** → compares `source` and `flags`\n * - **Arrays** → if lengths differ, the whole array path is marked changed; otherwise compares\n * element-by-element producing paths like `\"items.0.title\"`\n * - **Objects** → compares by the **union of keys**, recursing into shared keys and marking\n * added/removed keys as changed at their **full path**\n *\n * Cycles are handled by tracking the `(old, new)` pairs currently on the **recursion path**\n * (added on entry, removed on unwind). A pair is skipped only when it is a genuine ancestor of\n * itself (a real cycle) — a pair that merely appears again at a *sibling* path (legitimate\n * aliasing, e.g. the same object referenced from two keys) is still diffed, so real changes at\n * the second site are never dropped.\n *\n * @param oldState - Previous value to diff.\n * @param newState - Next value to diff.\n * @param path - Current dotted path (callers pass `\"\"` for root; recursion appends segments).\n * @param ancestors - (Advanced) Pairs on the current recursion path, for cycle detection. You\n * generally never pass this.\n * @returns An array of **dotted leaf paths** that changed. Paths use `\".\"` as a separator and\n * indices for arrays (e.g., `\"todos.0.title\"`). If nothing changed, returns `[]`.\n *\n * @example Basic object leaf\n * ```ts\n * detectChangedProps(\n * { user: { name: 'Ada', age: 37 } },\n * { user: { name: 'Grace', age: 37 } }\n * );\n * // => ['user.name']\n * ```\n *\n * @example Array element change\n * ```ts\n * detectChangedProps(\n * { items: [{ title: 'A' }, { title: 'B' }] },\n * { items: [{ title: 'A+' }, { title: 'B' }] }\n * );\n * // => ['items.0.title']\n * ```\n *\n * @example Array length change (marks the array path)\n * ```ts\n * detectChangedProps({ nums: [1,2] }, { nums: [1,2,3] });\n * // => ['nums']\n * ```\n *\n * @example Dates & RegExps\n * ```ts\n * detectChangedProps(new Date(0), new Date(0), 'createdAt'); // => []\n * detectChangedProps(new Date(0), new Date(1), 'createdAt'); // => ['createdAt']\n * detectChangedProps(/a/i, /a/i, 'pattern'); // => []\n * detectChangedProps(/a/i, /a/g, 'pattern'); // => ['pattern']\n * ```\n *\n * @remarks\n * - If `oldState === newState` (same reference), returns `[]` immediately.\n * - A change at the **root** — the values themselves differ and neither is a walkable object,\n * as for a primitive, a `Map`/`Set`, or two `Date`s — is reported at the `path` given, which\n * is `\"\"` for the default root call. `[\"\"]` therefore means *\"the whole value changed\"*, and\n * is emphatically **not** the same as `[]`. Callers must not filter it out for falsiness:\n * doing so is indistinguishable from \"nothing changed\", which is how a store slice holding a\n * primitive once silently refused every update it was given.\n * - For objects, only **own enumerable** keys are compared (via `Object.keys`).\n * - Returned paths are **leaf paths** where a primitive/terminal difference was detected; for arrays,\n * a length change is treated as a leaf change at the array path.\n *\n * @public\n */\nexport function detectChangedProps(\n oldState: any,\n newState: any,\n path = \"\",\n ancestors: Map<object, Set<object>> = new Map(),\n): string[] {\n const out: string[] = [];\n walk(oldState, newState, path, ancestors, out);\n return out;\n}\n\n/**\n * The recursion, writing into one array rather than returning a new one per node.\n *\n * @remarks\n * Every node used to allocate its own `string[]` and every parent spread its children's back in.\n * On a thousand-entity normalised map that is roughly four thousand short-lived arrays per diff,\n * for a result that is usually a single path — the allocation dwarfed the comparison it existed\n * to report.\n *\n * @internal\n */\nfunction walk(\n oldState: any,\n newState: any,\n path: string,\n ancestors: Map<object, Set<object>>,\n out: string[],\n): void {\n if (oldState === newState) return;\n\n if (\n typeof oldState !== \"object\" ||\n typeof newState !== \"object\" ||\n oldState === null ||\n newState === null\n ) {\n // Two NaNs are never `===` but represent no change — don't report a spurious diff.\n if (typeof oldState === \"number\" && Number.isNaN(oldState) && Number.isNaN(newState as number)) {\n return;\n }\n out.push(path);\n return;\n }\n\n if (oldState instanceof Date && newState instanceof Date) {\n if (oldState.getTime() !== newState.getTime()) out.push(path);\n return;\n }\n\n if (oldState instanceof RegExp && newState instanceof RegExp) {\n if (oldState.source !== newState.source || newState.flags !== oldState.flags) out.push(path);\n return;\n }\n\n // `Map` and `Set` keep their contents outside own enumerable keys, so the key-walk below sees\n // two empty objects and reports no change at all. The store treats \"no changed paths\" as a\n // no-op and skips the commit entirely, so a reducer returning a new Map produced no state\n // update, no subscriber notification and no error — the update simply vanished.\n //\n // Reported at this path rather than diffed internally: the references differ, which under the\n // immutability contract means the value changed. Reactivity for such a value is therefore\n // reference-level, not per-entry.\n if (oldState instanceof Map || newState instanceof Map) {\n out.push(path);\n return;\n }\n if (oldState instanceof Set || newState instanceof Set) {\n out.push(path);\n return;\n }\n\n const oldObj = oldState as object;\n const newObj = newState as object;\n\n // Cycle guard: skip a pair only when it is currently an ANCESTOR on this\n // recursion path (a genuine cycle). A pair seen earlier at a sibling path is\n // legitimate aliasing and must still be diffed.\n const active = ancestors.get(oldObj);\n if (active?.has(newObj)) return;\n const onPath = active ?? new Set<object>();\n onPath.add(newObj);\n if (!active) ancestors.set(oldObj, onPath);\n\n try {\n const isArrOld = Array.isArray(oldState);\n const isArrNew = Array.isArray(newState);\n if (isArrOld !== isArrNew) {\n out.push(path);\n return;\n }\n\n if (isArrOld) {\n const a = oldState;\n const b = newState as any[];\n\n // A length change reports the array path — the array's own identity changed, so a\n // subscriber watching `items` must hear about it — and then keeps going. Returning early\n // here used to be the whole story, which meant an `unshift` or `splice` notified `items`\n // and nothing beneath it: a component subscribed to the exact path `items.0.title`, the\n // very example the documentation leads with, kept rendering the previous row's title.\n // Guarded rather than filtered afterwards: at the root there is no path to report, and an\n // empty string in the output would read downstream as \"the whole slice\".\n if (a.length !== b.length && path) out.push(path);\n\n // Overlapping indices are compared as usual. With positional paths a shift genuinely\n // changes the value at nearly every index, so this is honest rather than noisy — the\n // remedy for that cost is identity-keyed state, not a diff that stays quiet.\n // The identity check happens *before* the path is built. `walk` would short-circuit on it\n // a line later anyway, but only after this frame had already concatenated a string for a\n // child that turns out to be unchanged — which for the overwhelmingly common shape of an\n // update (one element of many) is one allocation per element that nobody reads.\n const overlap = Math.min(a.length, b.length);\n for (let i = 0; i < overlap; i++) {\n if (a[i] === b[i]) continue;\n walk(a[i], b[i], path ? `${path}.${i}` : `${i}`, ancestors, out);\n }\n\n // Indices present in only one of the two: the element as a whole appeared or vanished,\n // which is the same treatment an added or removed object key gets below.\n for (let i = overlap; i < Math.max(a.length, b.length); i++) {\n out.push(path ? `${path}.${i}` : `${i}`);\n }\n\n return;\n }\n\n const oldKeys = Object.keys(oldState);\n const newKeys = Object.keys(newState);\n\n // Two distinct references with nothing enumerable to compare: any class instance holding its\n // state in private fields or behind accessors lands here. Assume changed rather than equal —\n // the alternative is the silent no-op that `Map` and `Set` used to produce, and a false\n // \"changed\" costs a render while a false \"unchanged\" costs correctness.\n if (oldKeys.length === 0 && newKeys.length === 0) {\n out.push(path);\n return;\n }\n\n // Whether both sides carry exactly the same keys, which is the overwhelmingly common case:\n // an update changes values, not shape. Equal counts plus one-way containment is enough to\n // conclude it — a key of `newState` missing from `oldState` would have to be balanced by a\n // key of `oldState` missing from `newState`, and the counts forbid that.\n //\n // Worth establishing because the alternative is materialising the union, and that union used\n // to be built unconditionally: two key arrays and a `Set` per object, at every level of the\n // tree. On a thousand-entity normalised map — the exact shape `createEntityAdapter` steers\n // people toward — that allocation was most of the diff's cost.\n let sameKeys = oldKeys.length === newKeys.length;\n if (sameKeys) {\n for (let i = 0; i < newKeys.length; i++) {\n if (!Object.prototype.hasOwnProperty.call(oldState, newKeys[i]!)) {\n sameKeys = false;\n break;\n }\n }\n }\n\n if (sameKeys) {\n for (const key of newKeys) {\n // Skip before building a path. `walk` would short-circuit on this identity a line later\n // anyway, but only after this frame had already concatenated a string for a child that\n // turns out to be unchanged — one allocation per key that nobody reads, which for the\n // common shape of an update (one field of many) is nearly all of them.\n if (oldState[key] === newState[key]) continue;\n // A key containing a dot cannot survive the join: `{ \"a.b\": 1 }` and `{ a: { b: 1 } }`\n // both produce \"a.b\", so a subscription and a devtools patch pointing at one silently\n // address the other. Nothing downstream can recover the difference from the string, which\n // is why this is said here, where the key is still intact.\n if (process.env.NODE_ENV !== \"production\" && key.includes(\".\")) warnDottedKey(path, key);\n walk(oldState[key], newState[key], path ? `${path}.${key}` : key, ancestors, out);\n }\n return;\n }\n\n // The shapes differ, so both sides have to be visited — but still without materialising a\n // union. Two passes over the key lists find additions and removals directly; building a\n // `Set` of every key on both sides to iterate once costs more than walking each list.\n for (const key of newKeys) {\n const hasOld = Object.prototype.hasOwnProperty.call(oldState, key);\n // Only compare values once presence is established: with differing shapes, `oldState[key]`\n // and `newState[key]` both read `undefined` for a key genuinely absent from one side, and\n // that is a change rather than a match.\n if (hasOld && oldState[key] === newState[key]) continue;\n if (process.env.NODE_ENV !== \"production\" && key.includes(\".\")) warnDottedKey(path, key);\n const nextPath = path ? `${path}.${key}` : key;\n if (!hasOld) {\n out.push(nextPath);\n continue;\n }\n walk(oldState[key], newState[key], nextPath, ancestors, out);\n }\n\n for (const key of oldKeys) {\n if (Object.prototype.hasOwnProperty.call(newState, key)) continue;\n if (process.env.NODE_ENV !== \"production\" && key.includes(\".\")) warnDottedKey(path, key);\n out.push(path ? `${path}.${key}` : key);\n }\n } finally {\n // Unwind: leave the current recursion path so sibling branches can revisit\n // this pair (legitimate aliasing) without being suppressed as a cycle.\n onPath.delete(newObj);\n if (onPath.size === 0) ancestors.delete(oldObj);\n }\n}\n","/**\n * @module @yoltra/core\n */\n\nimport type { DeepReadonly } from \"../types\";\n\n/**\n * Deep-freezes a value **in place** and returns it as {@link DeepReadonly | `DeepReadonly<T>`}.\n *\n * @typeParam T - The input value type to freeze.\n * @param obj - Any value; objects and arrays are frozen recursively.\n * @param seen - (Advanced) A `WeakSet` used to track visited objects for cycle/alias safety.\n * @returns The **same** reference as `obj`, but frozen and typed as `DeepReadonly<T>`.\n *\n * @remarks\n * - **In-place**: this function mutates the input by freezing it and its children, then returns it.\n * - **Early exits**:\n * - Primitives and `null` are returned as-is.\n * - Already-frozen objects (`Object.isFrozen(obj)`) are returned as-is.\n * - Previously seen objects (by identity) are returned as-is to avoid infinite recursion on cycles.\n * - **Arrays**: freezes each element, then `Object.freeze(array)`. Length/property descriptors are not rewritten.\n * - **Objects**: iterates **own** string and symbol keys. Only **data properties** are recursed (getters/setters are skipped).\n * - **Strict mode**: Mutating a frozen object throws; in non-strict mode it is a no-op (per JS semantics).\n *\n * @example Basic usage\n * ```ts\n * const state = { user: { name: 'Ada' }, items: [1, { id: 1 }] };\n * const frozen = freezeState(state);\n *\n * Object.isFrozen(frozen); // true\n * Object.isFrozen(frozen.user); // true\n * Object.isFrozen(frozen.items); // true\n * Object.isFrozen(frozen.items[1]); // true\n * ```\n *\n * @example Safe with cycles\n * ```ts\n * const a: any = {};\n * a.self = a; // cycle\n * freezeState(a); // does not recurse infinitely\n * ```\n *\n * @example Already frozen objects are returned as-is\n * ```ts\n * const o = Object.freeze({ x: 1 });\n * const out = freezeState(o);\n * out === o; // true\n * ```\n *\n * @public\n */\nexport function freezeState<T>(\n obj: T,\n seen = new WeakSet<object>(),\n alias?: AliasWatch,\n): DeepReadonly<T> {\n if (obj === null || typeof obj !== \"object\") return obj as any;\n if (seen.has(obj as any)) return obj as any;\n\n // Reported before the early-exit on already-frozen values, so a payload stored twice is still\n // named the second time.\n if (alias !== undefined && obj === alias.watch) alias.onFound();\n\n if (Object.isFrozen(obj)) return obj as any;\n\n seen.add(obj as any);\n\n // Binary views are returned untouched. `Object.freeze` on a TypedArray or DataView that\n // has elements is a `TypeError` by language rule - indexed properties on a view cannot be\n // made non-configurable - so walking one here threw at store construction and made it\n // impossible to keep bytes in slice state at all. There is nothing to deep-freeze in any\n // case: the contents are numbers, not a reachable object graph. Immutability for a view is\n // therefore reference-level, the same treatment `Map` and `Set` already get.\n if (ArrayBuffer.isView(obj)) return obj as any;\n\n // Arrays: handle indices only (skip length descriptor churn)\n if (Array.isArray(obj)) {\n const arr = obj as unknown as any[];\n for (let i = 0; i < arr.length; i++) {\n arr[i] = freezeState(arr[i], seen, alias);\n }\n return Object.freeze(arr) as any;\n }\n\n // Plain objects: freeze string and symbol props (value descriptors only)\n for (const key of Object.getOwnPropertyNames(obj)) {\n const desc = Object.getOwnPropertyDescriptor(obj, key);\n if (!desc || !(\"value\" in desc)) continue; // skip getters/setters\n (obj as any)[key] = freezeState((obj as any)[key], seen, alias);\n }\n for (const sym of Object.getOwnPropertySymbols(obj)) {\n const desc = Object.getOwnPropertyDescriptor(obj, sym);\n if (!desc || !(\"value\" in desc)) continue;\n (obj as any)[sym as any] = freezeState((obj as any)[sym as any], seen, alias);\n }\n\n return Object.freeze(obj) as any;\n}\n\n/**\n * Watches the freeze walk for one specific reference.\n *\n * @remarks\n * Exists to turn a dev-only heisenbug into a named warning. Because the freeze is deep and\n * in place, anything a reducer stores **by reference** is frozen too — the event payload, a\n * module-level default, a cached response. Mutating that object afterwards then throws, only in\n * development, from a stack that has nothing to do with the store, and the same code works in\n * production because the freeze is compiled out.\n *\n * Freezing it is not the mistake: an object reachable from state genuinely must not be mutated,\n * or state changes behind the store's back. Keeping the reference is. The walk already visits\n * every node, so recognising one of them costs an identity comparison and lets the store say so\n * at the moment it happens.\n *\n * @public\n */\nexport interface AliasWatch {\n /** The reference to look for while freezing. */\n readonly watch: object;\n /** Called if `watch` is reachable from the value being frozen. */\n readonly onFound: () => void;\n}","/**\n * @module @yoltra/core\n */\n\n/**\n * Brand identifying a {@link Rejection}.\n *\n * @remarks\n * `Symbol.for` rather than `Symbol()`, so the brand survives two copies of this package meeting\n * at runtime — a duplicated dependency, a bundle that inlined a second copy, a consumer that\n * pinned an older minor. With a unique symbol the check would silently answer `false` across that boundary and a\n * refusal would read as ordinary state, which is the failure this whole feature exists to end.\n *\n * @internal\n */\nconst REJECTED = Symbol.for(\"yoltra.rejected\");\n\n/**\n * A reducer's refusal to apply a write, carrying the reason.\n *\n * @remarks\n * Distinct from a reducer returning its state unchanged, which is indistinguishable from \"the\n * event did not concern me\". A `Rejection` says *this write was considered and declined*, and it\n * says why — which is what a contended store needs and what a lost update otherwise costs.\n *\n * @public\n */\nexport interface Rejection {\n readonly [REJECTED]: true;\n /** Why the write was refused. Surfaced to the caller and to `onRejected`. */\n readonly reason: string;\n}\n\n/**\n * Builds a {@link Rejection} for a reducer to return instead of state.\n *\n * @param reason - Why the write is refused; surfaced verbatim to the caller.\n *\n * @remarks\n * Rejecting is a whole-event act: no slice commits, no change notifications fire, and the\n * caller's `emit` resolves reporting the refusal. A reducer that merely has nothing to do should\n * return its state, not this.\n *\n * @example Compare-and-swap on a contended slice\n * ```ts\n * reducer: (state, event) =>\n * event.payload.expectedVersion === state.version\n * ? { ...state, ...event.payload.patch, version: state.version + 1 }\n * : Rejected(`stale write: expected v${event.payload.expectedVersion}, have v${state.version}`)\n * ```\n *\n * @public\n */\nexport function Rejected(reason: string): Rejection {\n return { [REJECTED]: true, reason };\n}\n\n/**\n * Whether a reducer returned a {@link Rejection} rather than state.\n *\n * @public\n */\nexport function isRejected(value: unknown): value is Rejection {\n return (\n typeof value === \"object\" &&\n value !== null &&\n (value as { [REJECTED]?: unknown })[REJECTED] === true\n );\n}\n","/**\n * @module @yoltra/core\n */\n\nimport type { EventMapBase, EventUnion } from \"../types\";\n\n/**\n * Which reply events end a {@link StoreInstance.call | call}, and therefore what it resolves to.\n *\n * @remarks\n * Given as `[channel]` or `[channel, type]` or `[channel, [type, type]]`. The named types are\n * **terminal**: the first one to arrive settles the call. Every other correlated event on that\n * channel is progress.\n *\n * Naming a channel alone makes every event on it terminal, which suits a responder with a single\n * kind of answer. Naming types is what lets a responder stream: `[\"rpc\", [\"answer\", \"error\"]]`\n * ends on either, and anything else — `progress`, `partial`, `log` — flows to the consumer.\n *\n * @public\n */\nexport type ReplySpec<EM extends EventMapBase> =\n | readonly [channel: keyof EM & string]\n | readonly [channel: keyof EM & string, type: string]\n | readonly [channel: keyof EM & string, types: readonly string[]];\n\n/**\n * Options for {@link StoreInstance.call}.\n *\n * @public\n */\nexport interface CallOptions<EM extends EventMapBase> {\n /** Which reply events end the call. See {@link ReplySpec}. */\n readonly reply: ReplySpec<EM>;\n\n /**\n * How long the call may sit **idle** before it gives up, in milliseconds.\n *\n * @remarks\n * Idle, not total: every correlated event resets it, progress included. A job that streams for\n * two minutes must not fail a thirty-second call, and a total deadline would make the timeout a\n * function of how much work the responder had to do rather than whether it is still alive.\n *\n * For a genuine deadline — \"this must be finished by then, however lively\" — use\n * {@link CallOptions.signal} with an `AbortSignal.timeout()`.\n *\n * @default 30000\n */\n readonly timeoutMs?: number;\n\n /**\n * Aborts the call. The returned promise rejects and the iterator ends.\n *\n * @remarks\n * Unlike `timeoutMs` this is absolute, so it is the right tool for a request deadline, a\n * user-cancelled action, or a component unmounting.\n */\n readonly signal?: AbortSignal;\n\n /**\n * How many progress events may buffer before the producer is made to wait.\n *\n * @remarks\n * Only meaningful once the caller is iterating. See {@link StoreInstance.call} for what\n * backpressure means here and when it engages.\n *\n * @default 16\n */\n readonly highWaterMark?: number;\n\n /**\n * Correlate on this id instead of on causality.\n *\n * @remarks\n * Causal matching — a reply is correlated because the store stamped it as *caused by* the\n * request — is free and cannot be forged, but only holds in one process. A reply arriving from\n * another node, a worker, or any transport carries no causal link, so for those the responder\n * echoes an id and both sides agree on it here.\n *\n * When set, the id is sent as `meta.correlationId` and a reply matches if it echoes the same\n * value **or** is causally descended. Causality still wins where it applies, so a local\n * responder needs no changes to be compatible with a remote one.\n */\n readonly correlationId?: string;\n}\n\n/**\n * The result of {@link StoreInstance.call}: awaitable for the terminal reply, async-iterable for\n * progress.\n *\n * @typeParam TReply - The terminal reply event.\n * @typeParam TProgress - Non-terminal correlated events.\n *\n * @remarks\n * One object serving both shapes, rather than two functions, because the caller's intent is not\n * known at the call site — the same request may be awaited in one place and streamed in another,\n * and the responder should not have to care which.\n *\n * ```ts\n * // Await the answer, ignore the running commentary.\n * const done = await store.call(\"rpc\", \"ask\", { q }, { reply: [\"rpc\", \"answer\"] });\n *\n * // Or consume the commentary, then take the answer.\n * const call = store.call(\"rpc\", \"ask\", { q }, { reply: [\"rpc\", \"answer\"] });\n * for await (const step of call) render(step.payload);\n * const answer = await call;\n * ```\n *\n * Awaiting the same call twice is safe and yields the same reply; the terminal event is retained.\n *\n * @public\n */\nexport interface CallHandle<TReply, TProgress> extends Promise<TReply>, AsyncIterable<TProgress> {\n /**\n * Progress events discarded because nothing was iterating.\n *\n * @remarks\n * Zero unless the call was awaited without being iterated *and* the responder streamed more\n * than `highWaterMark` events. Non-zero is not an error — it is the honest count of what a\n * caller chose not to read, and is worth logging rather than guessing at.\n */\n readonly dropped: number;\n\n /** Stops listening and settles the call. Safe to call more than once. */\n cancel(reason?: string): void;\n}\n\n/**\n * Raised when a call goes {@link CallOptions.timeoutMs} without a correlated event.\n *\n * @public\n */\nexport class CallTimeoutError extends Error {\n readonly channel: string;\n readonly type: string;\n readonly idleMs: number;\n\n constructor(channel: string, type: string, idleMs: number) {\n super(\n `[yoltra] call to \"${channel}/${type}\" saw no correlated reply for ${idleMs}ms. ` +\n `The timeout is idle rather than total, so this means the responder went quiet, not ` +\n `that it was slow. Check that something handles \"${channel}/${type}\" and that its reply ` +\n `is emitted through the \\`emit\\` it was handed — a reply emitted from an unrelated ` +\n `context carries no causal link, and needs an explicit correlationId instead.`,\n );\n this.name = \"CallTimeoutError\";\n this.channel = channel;\n this.type = type;\n this.idleMs = idleMs;\n }\n}\n\n/**\n * Raised when a call is cancelled, or its {@link CallOptions.signal} aborts.\n *\n * @public\n */\nexport class CallAbortedError extends Error {\n constructor(reason: string) {\n super(`[yoltra] call aborted: ${reason}`);\n this.name = \"CallAbortedError\";\n }\n}\n\n/**\n * Normalises a {@link ReplySpec} into a channel and a terminal-type test.\n *\n * @internal\n */\nexport function parseReply<EM extends EventMapBase>(\n reply: ReplySpec<EM>,\n): { channel: string; isTerminal: (type: string) => boolean } {\n const [channel, types] = reply as readonly [string, (string | readonly string[])?];\n\n // A channel on its own means every reply on it ends the call — the shape a responder with one\n // kind of answer takes, and the one where naming the type would be noise.\n if (types === undefined) return { channel, isTerminal: () => true };\n\n if (typeof types === \"string\") return { channel, isTerminal: (t) => t === types };\n\n const set = new Set(types);\n return { channel, isTerminal: (t) => set.has(t) };\n}\n\n/**\n * Whether `event` is a reply to the request identified by `requestId` / `correlationId`.\n *\n * @remarks\n * Causality first: the store stamps `parentId` on anything emitted while handling an event, so a\n * responder that answers through the `emit` it was given is correlated without doing anything.\n * The explicit id is the fallback for replies that crossed a boundary causality cannot.\n *\n * @internal\n */\nexport function isReplyTo<EM extends EventMapBase>(\n event: EventUnion<EM>,\n requestId: string,\n correlationId: string | undefined,\n): boolean {\n if (event.parentId === requestId) return true;\n if (correlationId === undefined) return false;\n return (event.meta as { correlationId?: unknown } | undefined)?.correlationId === correlationId;\n}\n","/**\n * @module @yoltra/core\n */\n\n/**\n * A bounded hand-off queue between one producer and one consumer, where **the producer waits**.\n *\n * @remarks\n * This is what makes {@link StoreInstance.call}'s backpressure real rather than decorative. A\n * plain buffer accepts everything and grows; this one hands the producer a promise that does not\n * resolve until the consumer has taken an item. Because the store awaits effects, and `emit`\n * resolves only once its effects have finished, a producer writing\n *\n * ```ts\n * await emit(\"rpc\", \"progress\", chunk);\n * ```\n *\n * genuinely blocks until the consumer catches up — end to end, through machinery that already\n * existed, with nothing polling and nothing dropped.\n *\n * **Backpressure only engages once the consumer has begun iterating.** Before that, items buffer\n * up to `highWaterMark` and further ones are counted and discarded. That asymmetry is deliberate:\n * a caller that only awaits the terminal reply never pulls, so blocking the producer would\n * deadlock the very call it is feeding — the producer would be waiting to deliver progress\n * nobody will read, and would therefore never emit the terminal event that ends the wait.\n *\n * @internal\n */\nexport class CallQueue<T> {\n private readonly buffer: T[] = [];\n\n /** Consumers parked in `take`, oldest first. */\n private readonly takers: Array<(value: IteratorResult<T>) => void> = [];\n\n /** Producers parked in `put`, each with the item they are waiting to hand over. */\n private readonly putters: Array<{ item: T; release: () => void }> = [];\n\n private consuming = false;\n\n /** No more items will be accepted, but what is already here is still owed to the consumer. */\n private ended = false;\n\n /** Abandoned: nothing further is owed to anybody. */\n private closed = false;\n\n /** Items discarded because nobody was iterating and the buffer was full. */\n private dropped = 0;\n\n constructor(private readonly highWaterMark: number) {}\n\n /** How many items were discarded for want of a consumer. */\n get droppedCount(): number {\n return this.dropped;\n }\n\n /**\n * Marks that a consumer has started pulling. From here on, a full buffer parks the producer\n * rather than dropping.\n */\n beginConsuming(): void {\n this.consuming = true;\n }\n\n /**\n * Offers an item. The returned promise settles when the item has been taken — or immediately,\n * if it fit in the buffer or was dropped.\n */\n put(item: T): Promise<void> {\n if (this.closed || this.ended) return Promise.resolve();\n\n // A parked consumer takes it directly; no buffering, no waiting either way.\n const taker = this.takers.shift();\n if (taker !== undefined) {\n taker({ value: item, done: false });\n return Promise.resolve();\n }\n\n if (this.buffer.length < this.highWaterMark) {\n this.buffer.push(item);\n return Promise.resolve();\n }\n\n if (!this.consuming) {\n // Nobody is reading and nobody has said they will. Dropping is the only option that does\n // not deadlock the producer — see the note on this class.\n this.dropped++;\n return Promise.resolve();\n }\n\n return new Promise<void>((release) => {\n this.putters.push({ item, release });\n });\n }\n\n /** Takes the next item, waiting if none is available. Resolves `done` once closed and drained. */\n take(): Promise<IteratorResult<T>> {\n this.consuming = true;\n\n const buffered = this.buffer.shift();\n if (buffered !== undefined) {\n // A parked producer can now hand its item to the space just freed.\n const putter = this.putters.shift();\n if (putter !== undefined) {\n this.buffer.push(putter.item);\n putter.release();\n }\n return Promise.resolve({ value: buffered, done: false });\n }\n\n // Nothing buffered, but a producer is parked: take directly from it.\n const putter = this.putters.shift();\n if (putter !== undefined) {\n putter.release();\n return Promise.resolve({ value: putter.item, done: false });\n }\n\n // Nothing left to hand over. `ended` counts here as well as `closed`: the terminal reply has\n // arrived and the buffer is drained, so the stream is genuinely over.\n if (this.closed || this.ended) return Promise.resolve({ value: undefined, done: true });\n\n return new Promise<IteratorResult<T>>((taker) => {\n this.takers.push(taker);\n });\n }\n\n /**\n * Stops accepting items, but keeps owing the consumer everything already queued.\n *\n * @remarks\n * What the terminal reply does. Closing outright at that moment would throw away progress the\n * responder had already handed over and the consumer had not yet read — which is exactly what\n * happened before this existed: a six-step job delivered five steps, because the sixth was in\n * the buffer when `done` arrived and the buffer was cleared. The terminal event says \"no more\n * is coming\", not \"forget what you were given\".\n */\n end(): void {\n if (this.ended || this.closed) return;\n this.ended = true;\n\n // Anything a producer is still parked with was sent before the terminal, so it is owed.\n let putter = this.putters.shift();\n while (putter !== undefined) {\n this.buffer.push(putter.item);\n putter.release();\n putter = this.putters.shift();\n }\n\n // Hand the buffer to anyone already waiting, then tell the rest we are done.\n let taker = this.takers.shift();\n while (taker !== undefined) {\n const next = this.buffer.shift();\n taker(\n next !== undefined\n ? { value: next, done: false }\n : { value: undefined, done: true },\n );\n taker = this.takers.shift();\n }\n }\n\n /**\n * Closes the queue: waiting consumers are told `done`, and **every parked producer is\n * released**.\n *\n * @remarks\n * Releasing producers is not tidying up. A producer parked on `put` is a pending `await emit`\n * somewhere; leaving it parked when the call has already settled would hang the responder for\n * good — turning a timed-out call into a wedged process, which is worse than the problem\n * backpressure was added to solve.\n */\n close(): void {\n if (this.closed) return;\n this.closed = true;\n this.buffer.length = 0;\n\n let taker = this.takers.shift();\n while (taker !== undefined) {\n taker({ value: undefined, done: true });\n taker = this.takers.shift();\n }\n\n let putter = this.putters.shift();\n while (putter !== undefined) {\n putter.release();\n putter = this.putters.shift();\n }\n }\n}\n","/**\n * The orchestration behind `store.call()`.\n *\n * @remarks\n * Moved out of `Store.ts` unchanged, and it lands beside the types and the queue it already\n * used. The seam is three members wide, which is what made this one extractable: the body mints\n * an id, registers a collector effect, and emits the request. It reaches nothing else.\n *\n * `registerEffect` and `emit` arrive as bound references, since `Store` binds both in its\n * constructor. `Store.call` keeps its signature and its explicit return type.\n *\n * @module\n */\n\nimport type {\n DeepReadonly,\n EffectSpec,\n EmitOptions,\n EmitResult,\n EventMapBase,\n EventUnion,\n} from \"../types\";\nimport {\n CallAbortedError,\n CallTimeoutError,\n type CallHandle,\n type CallOptions,\n parseReply,\n isReplyTo,\n} from \"./call\";\nimport { CallQueue } from \"./callQueue\";\n\n/** Idle time a {@link performCall} tolerates before giving up. */\nconst DEFAULT_CALL_TIMEOUT_MS = 30_000;\n\n/** Progress events a call buffers before pacing the producer. */\nconst DEFAULT_CALL_WATERMARK = 16;\n\n/**\n * What `performCall` needs from the store.\n *\n * @remarks\n * Three members, named rather than structural over the whole class, because three is few enough\n * that naming them documents the coupling instead of hiding it.\n */\nexport interface CallDeps<St, EM extends EventMapBase> {\n readonly idFactory: () => string;\n readonly registerEffect: (spec: EffectSpec<DeepReadonly<St>, EM>) => () => void;\n readonly emit: <C extends keyof EM & string, T extends keyof EM[C] & string>(\n channel: C,\n type: T,\n payload: EM[C][T],\n opts?: EmitOptions,\n ) => Promise<EmitResult>;\n}\n\nexport function performCall<\n St,\n EM extends EventMapBase,\n C extends keyof EM & string,\n T extends keyof EM[C] & string,\n>(\n deps: CallDeps<St, EM>,\n channel: C,\n type: T,\n payload: EM[C][T],\n opts: CallOptions<EM>,\n): CallHandle<EventUnion<EM>, EventUnion<EM>> {\n const { channel: replyChannel, isTerminal } = parseReply<EM>(opts.reply);\n const idleMs = opts.timeoutMs ?? DEFAULT_CALL_TIMEOUT_MS;\n const queue = new CallQueue<EventUnion<EM>>(opts.highWaterMark ?? DEFAULT_CALL_WATERMARK);\n\n // Minted here rather than left to `emit`, because the correlation has to be known before the\n // request goes out — a reply can arrive during the emit itself, synchronously.\n const requestId = deps.idFactory();\n\n let settle!: (event: EventUnion<EM>) => void;\n let fail!: (error: Error) => void;\n let settled = false;\n const terminal = new Promise<EventUnion<EM>>((resolve, reject) => {\n settle = resolve;\n fail = reject;\n });\n // Attached immediately so a rejection that nobody has awaited yet is not reported as\n // unhandled; the caller's own await still sees it.\n terminal.catch(() => undefined);\n\n let timer: ReturnType<typeof setTimeout> | null = null;\n let unregister: (() => void) | null = null;\n\n /**\n * Settles the call once. `graceful` distinguishes a terminal reply — after which the\n * consumer is still owed whatever progress it has not read — from an abort, after which\n * nothing is owed to anyone.\n */\n const finish = (fn: () => void, graceful = false): void => {\n if (settled) return;\n settled = true;\n if (timer !== null) clearTimeout(timer);\n timer = null;\n unregister?.();\n unregister = null;\n if (graceful) queue.end();\n else queue.close();\n opts.signal?.removeEventListener(\"abort\", onAbort);\n fn();\n };\n\n function onAbort(): void {\n finish(() => fail(new CallAbortedError(String(opts.signal?.reason ?? \"signal aborted\"))));\n }\n\n const arm = (): void => {\n if (timer !== null) clearTimeout(timer);\n // Idle: every correlated event pushes the deadline out, so a streaming responder is not\n // punished for having a lot to say.\n timer = setTimeout(() => {\n finish(() => fail(new CallTimeoutError(channel, type, idleMs)));\n }, idleMs);\n (timer as { unref?: () => void }).unref?.();\n };\n\n unregister = deps.registerEffect({\n // A pattern effect on the reply channel: which types are terminal is known, which are\n // progress is not, so the filter cannot be a key list.\n when: { channel: replyChannel as keyof EM & string },\n effect: async (event) => {\n if (settled) return;\n if (!isReplyTo<EM>(event, requestId, opts.correlationId)) return;\n\n arm();\n\n if (isTerminal(String(event.type))) {\n finish(() => settle(event), true);\n return;\n }\n\n // The await is the backpressure. This runs inside the store's effect phase, so the\n // responder's own `await emit(...)` does not resolve until it returns.\n await queue.put(event);\n },\n });\n\n if (opts.signal !== undefined) {\n if (opts.signal.aborted) onAbort();\n else opts.signal.addEventListener(\"abort\", onAbort, { once: true });\n }\n\n arm();\n\n void deps.emit(channel, type, payload, {\n id: requestId,\n ...(opts.correlationId !== undefined\n ? { meta: { correlationId: opts.correlationId } }\n : {}),\n });\n\n const handle = {\n then: (onOk?: never, onErr?: never) => terminal.then(onOk, onErr),\n catch: (onErr?: never) => terminal.catch(onErr),\n finally: (onDone?: () => void) => terminal.finally(onDone),\n get dropped() {\n return queue.droppedCount;\n },\n cancel: (reason = \"cancelled\") => {\n finish(() => fail(new CallAbortedError(reason)));\n },\n [Symbol.asyncIterator]: (): AsyncIterator<EventUnion<EM>> => {\n queue.beginConsuming();\n return {\n next: () => queue.take(),\n // Called by `for await` on `break`, `return` or a throw. Without it, abandoning the\n // loop would leave the effect registered and the producer parked for good.\n return: async () => {\n queue.close();\n return { value: undefined, done: true };\n },\n };\n },\n } as CallHandle<EventUnion<EM>, EventUnion<EM>>;\n\n return handle;\n}\n","/**\n * Reading and expanding dotted state paths.\n *\n * @remarks\n * Moved out of `Store.ts` unchanged. Neither function touched an instance field.\n *\n * `Store` still exposes both as members, and deliberately so. `Store.buildAncestorPaths` is\n * public API that appears in the committed reference, and `getAtPath` is replaced on the\n * instance by a test that counts the walks a change description costs, so the internal callers\n * have to keep reaching it through `this`.\n *\n * @module\n */\n\n/**\n * Reads a dotted path from an object (supports numeric array indices via string keys).\n *\n * @param obj - Root object (slice or value).\n * @param path - Dotted path; leading dot is ignored.\n * @returns The value at the path, or `undefined`.\n *\n * @internal\n */\nexport function getAtPath(obj: any, path: string): any {\n if (!path) return obj;\n\n // Normalize any accidental leading dots\n const clean = path[0] === \".\" ? path.slice(1) : path;\n const parts = clean.split(\".\");\n\n let cur = obj;\n for (const seg of parts) {\n if (cur == null) return undefined;\n cur = cur[seg as any];\n }\n return cur;\n}\n\n/**\n * Builds ancestor paths for a dotted path.\n *\n * For `\"a.b.c\"`, returns `[\"a\", \"a.b\", \"a.b.c\"]`. Leading dots are trimmed.\n *\n * @param path - Dotted path string.\n * @returns Array of ancestor paths.\n *\n * @example\n * ```ts\n * buildAncestorPaths('x.y.z'); // ['x','x.y','x.y.z']\n * ```\n *\n * @public\n */\nexport function buildAncestorPaths(path: string): string[] {\n if (!path) return [];\n\n const clean = path[0] === \".\" ? path.slice(1) : path;\n const parts = clean.split(\".\");\n const out: string[] = [];\n\n for (let i = 0; i < parts.length; i++) {\n out.push(parts.slice(0, i + 1).join(\".\"));\n }\n\n return out;\n}\n","/**\n * Lossless encoding of store state for the wire.\n *\n * @remarks\n * The wire is JSON, and `JSON.stringify` is not a safe way to put arbitrary state on it. It does\n * not fail on the values it cannot represent — it quietly destroys them. A `Map` becomes `{}`, a\n * `Set` becomes `{}`, a `Date` becomes a string, `undefined` disappears from objects entirely,\n * and a `BigInt` or a cycle throws from inside a handler nobody awaits.\n *\n * Silent destruction is the dangerous half. The panel showed `{}` where a `Map` lived, which is\n * merely wrong; but time-travel then sent that `{}` back and applied it to the running store,\n * replacing a live `Map` with an empty object in the user's own application. A debugging tool\n * corrupting the program it is inspecting is the worst failure available to it.\n *\n * Values are therefore tagged rather than coerced. Anything JSON can carry travels unchanged;\n * anything it cannot is wrapped in a marker object that {@link decodeState} reverses exactly.\n *\n * @module\n */\n\n/** Marker key identifying an encoded value. Chosen to be improbable in application state. */\nconst TAG = \"$yoltra\" as const;\n\n/** What an encoded non-JSON value looks like on the wire. */\ntype Tagged =\n | { readonly [TAG]: \"map\"; readonly entries: Array<[unknown, unknown]> }\n | { readonly [TAG]: \"set\"; readonly values: unknown[] }\n | { readonly [TAG]: \"date\"; readonly iso: string }\n | { readonly [TAG]: \"bigint\"; readonly value: string }\n | { readonly [TAG]: \"undefined\" }\n | { readonly [TAG]: \"nan\" }\n | { readonly [TAG]: \"infinity\"; readonly sign: 1 | -1 }\n | { readonly [TAG]: \"regexp\"; readonly source: string; readonly flags: string }\n | { readonly [TAG]: \"error\"; readonly name: string; readonly message: string }\n | { readonly [TAG]: \"ref\"; readonly path: string }\n | { readonly [TAG]: \"binary\"; readonly kind: BinaryKind; readonly b64: string }\n | {\n readonly [TAG]: \"unsupported\";\n readonly kind: string;\n /**\n * The value's own enumerable properties, when it had any worth keeping.\n *\n * A class instance used to encode as a plain object carrying its own props - lossy,\n * but often good enough for persistence. Replacing that with a bare marker would make\n * a data-loss *fix* more destructive than the bug, so the props ride along and the\n * path is still reported in {@link EncodeReport.unsupported}. Lossy and loud, without\n * being newly lossy.\n */\n readonly value?: Record<string, unknown>;\n }\n | { readonly [TAG]: \"escaped\"; readonly value: Record<string, unknown> };\n\n/**\n * The binary views the codec round-trips faithfully.\n *\n * @remarks\n * One tag with a discriminant rather than eleven tags. The constructor name is carried so\n * {@link decodeState} can restore the right view type rather than handing back bytes.\n */\ntype BinaryKind =\n | \"ArrayBuffer\"\n | \"DataView\"\n | \"Int8Array\"\n | \"Uint8Array\"\n | \"Uint8ClampedArray\"\n | \"Int16Array\"\n | \"Uint16Array\"\n | \"Int32Array\"\n | \"Uint32Array\"\n | \"Float32Array\"\n | \"Float64Array\"\n | \"BigInt64Array\"\n | \"BigUint64Array\";\n\n/**\n * Decode targets, as a frozen allow-list.\n *\n * @remarks\n * **Never `globalThis[kind]`.** A snapshot arrives off a devtools socket or out of\n * `localStorage`, so `kind` is attacker-influenced input; indexing the global object with it\n * is an injection vector. An unrecognised kind decodes to `undefined`, exactly like every\n * other unrecognised tag.\n *\n * The prototype is `null`, and lookups go through `Object.hasOwn`. A frozen **object\n * literal** is not enough: `Object.freeze` stops writes, not inherited reads, so\n * `kind: \"constructor\"` resolved to `Object.prototype.constructor` and\n * `new Object(buffer)` handed the buffer straight back. Same hole as `globalThis[kind]`,\n * reached by a different road.\n */\nconst BINARY_CONSTRUCTORS = Object.freeze(\n Object.assign(Object.create(null) as object, {\n Int8Array,\n Uint8Array,\n Uint8ClampedArray,\n Int16Array,\n Uint16Array,\n Int32Array,\n Uint32Array,\n Float32Array,\n Float64Array,\n BigInt64Array,\n BigUint64Array,\n }),\n) as Readonly<Record<string, { new (buffer: ArrayBufferLike): ArrayBufferView } | undefined>>;\n\n/**\n * The supported kind a view should round-trip as, or `undefined` if there is none.\n *\n * @remarks\n * Resolved by `instanceof`, not by `constructor.name`. Node's `Buffer` is a `Uint8Array`\n * subclass and is everywhere, and its name is not in the allow-list, so a name lookup tagged\n * it `kind: \"Buffer\"`, reported nothing, and the decoder returned `undefined` for it - a\n * silent total loss of the value, through `persist` as much as through time travel. The same\n * applied to `Float16Array` and to any user subclass.\n *\n * A subclass therefore comes back as its base. That is lossy, and the caller is told: the\n * path is added to {@link EncodeReport.unsupported} whenever the resolved kind is not the\n * constructor's own name.\n *\n * @internal\n */\nfunction resolveBinaryKind(view: ArrayBufferView): BinaryKind | undefined {\n const own = view.constructor?.name;\n if (own !== undefined && Object.prototype.hasOwnProperty.call(BINARY_CONSTRUCTORS, own)) {\n return own as BinaryKind;\n }\n if (view instanceof DataView) return \"DataView\";\n for (const name of Object.keys(BINARY_CONSTRUCTORS)) {\n const Ctor = BINARY_CONSTRUCTORS[name] as unknown as\n | (abstract new (...args: never[]) => ArrayBufferView)\n | undefined;\n if (Ctor !== undefined && view instanceof Ctor) return name as BinaryKind;\n }\n return undefined;\n}\n\n/**\n * Bytes to base64.\n *\n * @remarks\n * Base64 rather than a number array for two reasons that both bite at scale: it costs about\n * 1.37 JSON characters per byte against roughly 3.5 for `255,`, which decides whether a\n * snapshot fits {@link encodeStateBounded}'s cap; and it is **one** node where an array of\n * 100 000 bytes is 100 000 nodes and would exhaust the budget on its own.\n *\n * Chunked because `String.fromCharCode.apply` throws `RangeError` somewhere above 64K\n * arguments, which is not a size a state tree has any trouble reaching.\n *\n * @internal\n */\nfunction bytesToBase64(bytes: Uint8Array): string {\n const maybeBuffer = (globalThis as { Buffer?: { from(b: Uint8Array): { toString(e: string): string } } })\n .Buffer;\n if (maybeBuffer !== undefined) return maybeBuffer.from(bytes).toString(\"base64\");\n\n const CHUNK = 0x2000;\n let binary = \"\";\n for (let i = 0; i < bytes.length; i += CHUNK) {\n binary += String.fromCharCode(...bytes.subarray(i, i + CHUNK));\n }\n return btoa(binary);\n}\n\n/** @internal */\nfunction base64ToBytes(b64: string): Uint8Array {\n const maybeBuffer = (\n globalThis as { Buffer?: { from(s: string, e: string): Uint8Array } }\n ).Buffer;\n if (maybeBuffer !== undefined) {\n const buf = maybeBuffer.from(b64, \"base64\");\n // Copy out of Node's pooled allocation: a Buffer is a view onto a shared slab, so\n // handing its `.buffer` to a typed array would expose unrelated memory.\n return new Uint8Array(buf.subarray(0, buf.length));\n }\n const binary = atob(b64);\n const out = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i += 1) out[i] = binary.charCodeAt(i);\n return out;\n}\n\n/** Options for {@link encodeState}. */\nexport interface EncodeOptions {\n /**\n * Redacts a value before it leaves the process.\n *\n * @remarks\n * State frequently holds tokens, session material and personal data, and devtools traffic\n * crosses a socket to another process. Return the replacement value, or the value itself to\n * keep it. Applied before encoding, so a redacted value is encoded like any other.\n */\n readonly sanitize?: (path: string, value: unknown) => unknown;\n /**\n * Maximum number of nodes to encode. Beyond it, subtrees are replaced by a truncation marker.\n *\n * @remarks\n * A snapshot larger than the hub's frame cap is rejected outright, which reads to the user as\n * a panel that hangs. Truncating visibly is a better failure: the panel renders, and says\n * where it stopped. Defaults to 100000.\n */\n readonly maxNodes?: number;\n}\n\n/** Reports what an encode had to compromise. Empty when nothing was lost. */\nexport interface EncodeReport {\n /** Node budget was exhausted and some subtrees were replaced by markers. */\n readonly truncated: boolean;\n /** Values no JSON representation exists for, by path — functions, symbols, DOM nodes. */\n readonly unsupported: readonly string[];\n}\n\n/** Result of {@link encodeState}. */\nexport interface EncodeResult {\n readonly value: unknown;\n readonly report: EncodeReport;\n}\n\n/**\n * Encodes a value into something `JSON.stringify` can carry losslessly.\n *\n * @param input - Any value, including one holding `Map`, `Set`, `Date`, `BigInt` or cycles.\n * @param options - Redaction and size limits.\n * @returns The encoded value plus a report of anything that could not be represented.\n *\n * @example\n * ```ts\n * const { value } = encodeState({ index: new Map([['a', 1]]) });\n * JSON.stringify(value); // safe, and decodeState restores the Map\n * ```\n *\n * @public\n */\nexport function encodeState(input: unknown, options: EncodeOptions = {}): EncodeResult {\n const maxNodes = options.maxNodes ?? 100_000;\n const sanitize = options.sanitize;\n const unsupported: string[] = [];\n\n // Identity → JSON Pointer of the first place it was seen. A cycle then encodes as a reference\n // to that path rather than recursing forever, and repeated references stay repeated rather\n // than being silently expanded into copies.\n const seen = new Map<object, string>();\n let nodes = 0;\n let truncated = false;\n\n function walk(value: unknown, path: string): unknown {\n if (sanitize !== undefined) value = sanitize(path, value);\n\n nodes += 1;\n if (nodes > maxNodes) {\n truncated = true;\n return { [TAG]: \"unsupported\", kind: \"truncated\" } satisfies Tagged;\n }\n\n switch (typeof value) {\n case \"undefined\":\n return { [TAG]: \"undefined\" } satisfies Tagged;\n case \"bigint\":\n return { [TAG]: \"bigint\", value: value.toString() } satisfies Tagged;\n case \"number\":\n if (Number.isNaN(value)) return { [TAG]: \"nan\" } satisfies Tagged;\n if (value === Infinity) return { [TAG]: \"infinity\", sign: 1 } satisfies Tagged;\n if (value === -Infinity) return { [TAG]: \"infinity\", sign: -1 } satisfies Tagged;\n return value;\n case \"function\":\n case \"symbol\":\n unsupported.push(path);\n return { [TAG]: \"unsupported\", kind: typeof value } satisfies Tagged;\n case \"string\":\n case \"boolean\":\n return value;\n default:\n break;\n }\n\n if (value === null) return null;\n\n const asObject = value as object;\n const previous = seen.get(asObject);\n if (previous !== undefined) return { [TAG]: \"ref\", path: previous } satisfies Tagged;\n seen.set(asObject, path);\n\n if (value instanceof Date) {\n return { [TAG]: \"date\", iso: value.toISOString() } satisfies Tagged;\n }\n if (value instanceof RegExp) {\n return { [TAG]: \"regexp\", source: value.source, flags: value.flags } satisfies Tagged;\n }\n if (value instanceof Error) {\n return { [TAG]: \"error\", name: value.name, message: value.message } satisfies Tagged;\n }\n if (value instanceof Map) {\n const entries: Array<[unknown, unknown]> = [];\n let i = 0;\n for (const [k, v] of value) {\n entries.push([walk(k, `${path}/@k${i}`), walk(v, `${path}/${i}`)]);\n i += 1;\n }\n return { [TAG]: \"map\", entries } satisfies Tagged;\n }\n if (value instanceof Set) {\n const values: unknown[] = [];\n let i = 0;\n for (const v of value) {\n values.push(walk(v, `${path}/${i}`));\n i += 1;\n }\n return { [TAG]: \"set\", values } satisfies Tagged;\n }\n if (Array.isArray(value)) {\n return value.map((item, index) => walk(item, `${path}/${index}`));\n }\n\n if (value instanceof ArrayBuffer) {\n // Charged by size, and charged *before* encoding, so `encodeStateBounded`'s shrink\n // loop stops an oversized buffer on the next attempt rather than base64-encoding it\n // again first. Left at one node, a state dominated by a single large buffer would\n // burn every attempt reducing a budget that was never the reason it overflowed.\n nodes += Math.ceil(value.byteLength / 64);\n if (nodes > maxNodes) {\n truncated = true;\n return { [TAG]: \"unsupported\", kind: \"truncated\" } satisfies Tagged;\n }\n return {\n [TAG]: \"binary\",\n kind: \"ArrayBuffer\",\n b64: bytesToBase64(new Uint8Array(value)),\n } satisfies Tagged;\n }\n if (ArrayBuffer.isView(value)) {\n const view = value as ArrayBufferView;\n // Charged *before* encoding, not after. Charging afterwards meant a 10 MB buffer was\n // fully base64-encoded on every one of the shrink loop's attempts before the budget\n // it had just blown was noticed.\n nodes += Math.ceil(view.byteLength / 64);\n\n const kind = resolveBinaryKind(view);\n if (kind === undefined) {\n // An exotic view with no supported base. Reported, and its bytes kept, rather than\n // tagged with a kind the decoder will reject.\n unsupported.push(path);\n return {\n [TAG]: \"unsupported\",\n kind: view.constructor?.name ?? \"ArrayBufferView\",\n } satisfies Tagged;\n }\n\n // Only the view's own window, not the whole backing buffer. A decoded view therefore\n // does not share a buffer with its former siblings - a real fidelity loss, and much\n // cheaper than carrying the buffer plus every offset.\n const bytes = new Uint8Array(view.buffer, view.byteOffset, view.byteLength);\n const out: Tagged = { [TAG]: \"binary\", kind, b64: bytesToBase64(bytes) };\n // A subclass round-trips as its base, which keeps the bytes but loses the subclass.\n // Reported, because `Buffer` coming back a `Uint8Array` changes what `.toString()`\n // and `.equals()` do, and silence about that is what this module exists to prevent.\n if (view.constructor?.name !== kind) unsupported.push(path);\n return out;\n }\n\n // Everything past here is walked with `Object.entries`, which is only faithful for a\n // plain object. Without this guard a class instance silently lost its prototype, and\n // nothing anywhere said so.\n const proto = Object.getPrototypeOf(value as object) as object | null;\n const ctorName = (value as { constructor?: { name?: string } }).constructor?.name;\n // `ctorName !== \"Object\"` is not belt and braces: a cross-realm plain object - from an\n // iframe, a `vm` context, a worker boundary - has a *different* `Object.prototype` and\n // would otherwise be reported unsupported for being ordinary.\n if (proto !== null && proto !== Object.prototype && ctorName !== \"Object\") {\n unsupported.push(path);\n const own: Record<string, unknown> = {};\n for (const [key, item] of Object.entries(value as Record<string, unknown>)) {\n own[key] = walk(item, `${path}/${escapePointer(key)}`);\n }\n return {\n [TAG]: \"unsupported\",\n kind: ctorName ?? \"unknown\",\n value: own,\n } satisfies Tagged;\n }\n\n const out: Record<string, unknown> = {};\n for (const [key, item] of Object.entries(value as Record<string, unknown>)) {\n out[key] = walk(item, `${path}/${escapePointer(key)}`);\n }\n // An application object that happens to carry the marker key would decode as a tagged value\n // and come back as something else entirely. Wrap it so the decoder knows it is ordinary.\n if (TAG in out) return { [TAG]: \"escaped\", value: out } satisfies Tagged;\n return out;\n }\n\n const value = walk(input, \"\");\n return { value, report: { truncated, unsupported } };\n}\n\n/**\n * Reverses {@link encodeState}.\n *\n * @param input - A value produced by `encodeState` (typically after a JSON round trip).\n * @returns The original structure, with `Map`, `Set`, `Date` and friends restored.\n *\n * @remarks\n * Unsupported markers decode to `undefined`: a function cannot be reconstructed, and inventing a\n * placeholder would be worse than an absent value. Cycles are restored by resolving references\n * after the tree is built, so a decoded structure is cyclic exactly where the original was.\n *\n * @public\n */\nexport function decodeState(input: unknown): unknown {\n // Built during the walk so a reference can resolve to a node that may not exist yet.\n const byPath = new Map<string, unknown>();\n const pending: Array<{ target: unknown; key: string | number; path: string }> = [];\n\n function walk(value: unknown, path: string): unknown {\n if (value === null || typeof value !== \"object\") return value;\n\n if (Array.isArray(value)) {\n const arr: unknown[] = [];\n byPath.set(path, arr);\n value.forEach((item, index) => {\n if (isRef(item)) {\n // Left undefined for now; the second pass fills it once every node exists.\n pending.push({ target: arr, key: index, path: item.path });\n arr[index] = undefined;\n return;\n }\n arr[index] = walk(item, `${path}/${index}`);\n });\n return arr;\n }\n\n const tag = (value as Record<string, unknown>)[TAG];\n if (typeof tag === \"string\") {\n const tagged = value as unknown as Tagged;\n switch (tagged[TAG]) {\n case \"undefined\":\n return undefined;\n case \"nan\":\n return Number.NaN;\n case \"infinity\":\n return tagged.sign === 1 ? Infinity : -Infinity;\n case \"bigint\":\n return BigInt(tagged.value);\n case \"date\":\n return new Date(tagged.iso);\n case \"regexp\":\n return new RegExp(tagged.source, tagged.flags);\n case \"error\": {\n const error = new Error(tagged.message);\n error.name = tagged.name;\n return error;\n }\n case \"binary\": {\n const bytes = base64ToBytes(tagged.b64);\n if (tagged.kind === \"ArrayBuffer\") {\n const copy = bytes.slice();\n byPath.set(path, copy.buffer);\n return copy.buffer;\n }\n if (tagged.kind === \"DataView\") {\n const copy = bytes.slice();\n const view = new DataView(copy.buffer);\n byPath.set(path, view);\n return view;\n }\n // An own-property check as well as a null prototype: belt and braces on the one\n // lookup in this file whose key comes from the payload. `hasOwnProperty.call`\n // rather than `Object.hasOwn`, because `src` targets the oldest runtime the\n // bundle supports.\n const Ctor = Object.prototype.hasOwnProperty.call(BINARY_CONSTRUCTORS, tagged.kind)\n ? BINARY_CONSTRUCTORS[tagged.kind]\n : undefined;\n // Unknown kind: same answer as any other unrecognised tag. Never a global lookup.\n if (Ctor === undefined) return undefined;\n const restored = new Ctor(bytes.slice().buffer);\n byPath.set(path, restored);\n return restored;\n }\n case \"unsupported\":\n // An exotic that kept its own properties decodes to those properties: the same\n // lossy round-trip it had before the prototype guard existed, rather than a\n // newly destructive `undefined`. The path was reported at encode time either way.\n if (tagged.value !== undefined) return walkPlain(tagged.value, path);\n // Nothing faithful to return. `undefined` says \"not representable\" without pretending.\n return undefined;\n case \"ref\":\n // Resolved by the caller once the whole tree exists.\n return undefined;\n case \"map\": {\n const map = new Map<unknown, unknown>();\n byPath.set(path, map);\n tagged.entries.forEach(([k, v], index) => {\n map.set(walk(k, `${path}/@k${index}`), walk(v, `${path}/${index}`));\n });\n return map;\n }\n case \"set\": {\n const set = new Set<unknown>();\n byPath.set(path, set);\n tagged.values.forEach((v, index) => set.add(walk(v, `${path}/${index}`)));\n return set;\n }\n case \"escaped\":\n return walkPlain(tagged.value, path);\n default:\n return undefined;\n }\n }\n\n return walkPlain(value as Record<string, unknown>, path);\n }\n\n function walkPlain(value: Record<string, unknown>, path: string): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n byPath.set(path, out);\n for (const [key, item] of Object.entries(value)) {\n const childPath = `${path}/${escapePointer(key)}`;\n if (isRef(item)) {\n pending.push({ target: out, key, path: item.path });\n out[key] = undefined;\n continue;\n }\n out[key] = walk(item, childPath);\n }\n return out;\n }\n\n const root = walk(input, \"\");\n byPath.set(\"\", root);\n\n // Second pass: every reference now has a node to point at.\n for (const { target, key, path } of pending) {\n (target as Record<string | number, unknown>)[key] = byPath.get(path);\n }\n\n return root;\n}\n\n/** @internal */\nfunction isRef(value: unknown): value is { [TAG]: \"ref\"; path: string } {\n return (\n value !== null &&\n typeof value === \"object\" &&\n (value as Record<string, unknown>)[TAG] === \"ref\" &&\n typeof (value as Record<string, unknown>).path === \"string\"\n );\n}\n\n/**\n * Escapes a key for use in a JSON Pointer segment (RFC 6901).\n *\n * @internal\n */\nfunction escapePointer(key: string): string {\n return key.replace(/~/g, \"~0\").replace(/\\//g, \"~1\");\n}\n\n/** Outcome of {@link encodeStateBounded}. */\nexport interface BoundedEncodeResult {\n /** The encoded value, small enough to send. */\n readonly value: unknown;\n /** `true` when the state did not fit and parts were replaced by markers. */\n readonly truncated: boolean;\n /** Explains what was dropped, for display beside a partial tree. */\n readonly note?: string;\n}\n\n/**\n * Encodes a value, shrinking it until its serialized form fits within `maxBytes`.\n *\n * @param input - Any value.\n * @param maxBytes - Byte budget for the serialized form.\n * @param options - Passed through to {@link encodeState}.\n *\n * @returns The encoded value and whether anything had to be dropped.\n *\n * @remarks\n * A frame larger than the hub's cap is not merely slow — it is rejected, and the connection with\n * it, so the client reconnects, asks again, is refused again, and the panel sits waiting through\n * a loop with nothing on screen to explain it. The size therefore has to be bounded before the\n * frame is sent rather than discovered afterwards.\n *\n * Node count is a poor proxy for bytes: a hundred nodes holding base64 blobs outweigh a hundred\n * thousand holding integers. So this measures the encoded output and, when it is too large,\n * scales the node budget by how far over it went and measures again. Scaling by the overshoot\n * rather than halving matters: from a default of a hundred thousand nodes, repeated halving\n * needs a dozen rounds to reach the hundreds, so a state that could have been shown in part\n * would have been abandoned instead.\n *\n * Truncation is reported rather than performed silently. A partial tree presented as the state is\n * worse than no tree at all: a debugger that quietly lies about state is not a debugger.\n *\n * @public\n */\nexport function encodeStateBounded(\n input: unknown,\n maxBytes: number,\n options: EncodeOptions = {},\n): BoundedEncodeResult {\n let nodeBudget = options.maxNodes ?? 100_000;\n\n for (let attempt = 0; attempt < 8; attempt += 1) {\n const { value, report } = encodeState(input, { ...options, maxNodes: nodeBudget });\n // `JSON.stringify` can still refuse a value the encoder passed through untouched, so a\n // failure here is measured as \"does not fit\" rather than thrown at the caller.\n let size: number;\n try {\n size = JSON.stringify(value)?.length ?? 0;\n } catch {\n size = Number.POSITIVE_INFINITY;\n }\n\n if (size <= maxBytes) {\n return report.truncated\n ? {\n value,\n truncated: true,\n note: `State was too large to send in full; parts beyond ${nodeBudget} nodes are omitted.`,\n }\n : { value, truncated: false };\n }\n\n // Aim at 80% of the budget so the next attempt has room for the tagging overhead that\n // shrinking cannot remove, and always make progress even when the estimate is optimistic.\n const scaled = Math.floor((nodeBudget * maxBytes * 0.8) / size);\n nodeBudget = Math.max(1, Math.min(scaled, nodeBudget - 1));\n if (nodeBudget <= 1 && attempt > 0) {\n // Already at the floor and still too large: the remaining bytes are one enormous value,\n // not many small ones, and no node budget will cut it down.\n break;\n }\n }\n\n // Nothing fit, even at the smallest budget. Say so instead of sending a frame that will be\n // refused and leaving the panel to retry against a wall.\n return {\n value: { [TAG]: \"unsupported\", kind: \"truncated\" } satisfies Tagged,\n truncated: true,\n note: `State exceeds the ${maxBytes}-byte transport limit and could not be reduced to fit.`,\n };\n}\n","/**\n * Content fingerprints for event deduplication.\n *\n * @remarks\n * Extracted from `Store.ts` following the `matching.ts` / `paths.ts` precedent: nothing here\n * touches an instance field.\n *\n * The old fingerprint was `channel::type::JSON.stringify(payload)`, which produced two\n * inconsistent failures on the one path whose entire job is deciding whether two payloads are\n * the same. A `Map`, `Set` or typed array stringifies to `{}`, so **distinct payloads\n * collided and the second event was silently swallowed** - precisely the behaviour the README\n * says Yoltra refuses to do by default. A `BigInt` or a cycle threw, hit a timestamp fallback,\n * and was never deduped at all.\n *\n * `encodeState` already produces a faithful, JSON-stringifiable representation of all of\n * those, so fingerprinting through it makes content dedup mean what it says.\n *\n * @module\n */\n\nimport { encodeState } from \"../serialize/codec\";\n\n/**\n * Node budget for a fingerprint walk.\n *\n * @remarks\n * Deliberately far below the codec's 100 000 default. A fingerprint is a dedup optimisation,\n * not a snapshot, and walking an enormous payload to decide whether to skip it defeats the\n * purpose.\n *\n * @internal\n */\nconst FINGERPRINT_MAX_NODES = 10_000;\n\n/**\n * JSON with plain-object keys sorted, for a stable content fingerprint.\n *\n * @remarks\n * Insertion order is not content: `{a:1,b:2}` and `{b:2,a:1}` are the same payload and must\n * fingerprint alike, which `JSON.stringify` alone does not deliver.\n *\n * **Arrays and `Map` entries are never sorted.** Their order is semantic - `[1,2]` is not\n * `[2,1]`, and a `Map` preserves insertion order by specification. Sorting them would make\n * genuinely different payloads share a fingerprint, which is worse than the bug this module\n * exists to fix: it would silently drop real events rather than merely failing to dedup.\n *\n * Runs over the **already-encoded** value, so `Map`, `Set`, `Date` and binary have already\n * become plain JSON shapes and there is nothing exotic left to handle.\n *\n * `JSON.stringify(v, keyArray)` cannot do this: the replacer-array form applies one global\n * key list at every depth.\n *\n * @internal\n */\nexport function stableStringify(value: unknown): string {\n if (value === null || typeof value !== \"object\") return JSON.stringify(value) ?? \"null\";\n\n if (Array.isArray(value)) {\n return `[${value.map(stableStringify).join(\",\")}]`;\n }\n\n const entries = Object.entries(value as Record<string, unknown>).sort(([a], [b]) =>\n a < b ? -1 : a > b ? 1 : 0,\n );\n return `{${entries.map(([k, v]) => `${JSON.stringify(k)}:${stableStringify(v)}`).join(\",\")}}`;\n}\n\n/**\n * A content fingerprint for one event.\n *\n * @param channel - Event channel.\n * @param type - Event type.\n * @param payload - Event payload.\n * @returns A string that is equal for two events with equal content.\n *\n * @remarks\n * Primitives keep a fast path, but a typed one: `String(payload)` alone made the number `1`\n * and the string `\"1\"` the same event, as it did `true` and `\"true\"`. `null` and `undefined`\n * are likewise distinguished, having previously shared `::null`.\n *\n * When the payload exceeds the node budget the fingerprint degrades to **never dedupe**\n * rather than maybe-wrongly-dedupe. Two large payloads differing only past the cutoff would\n * otherwise collide and the second would be dropped; refusing to dedup merely costs a\n * duplicate, which is the safe direction and matches what already happened to payloads the\n * old implementation could not serialize.\n *\n * @internal\n */\nexport function fingerprint(channel: string, type: string, payload: unknown): string {\n const base = `${channel}::${type}`;\n\n if (payload === null) return `${base}::null`;\n if (payload === undefined) return `${base}::undefined`;\n if (typeof payload !== \"object\") return `${base}::${typeof payload}:${String(payload)}`;\n\n try {\n const { value, report } = encodeState(payload, { maxNodes: FINGERPRINT_MAX_NODES });\n if (report.truncated) return `${base}::${Date.now()}::${Math.random()}`;\n return `${base}::${stableStringify(value)}`;\n } catch {\n // The codec is total over the values it knows, so reaching here means something threw\n // from a getter or a `sanitize` hook. Unique fingerprint: do not dedup what we could not\n // read.\n return `${base}::${Date.now()}::${Math.random()}`;\n }\n}\n","/**\n * Event targeting: deciding whether an event matches a `When` matcher, and reading the parts of\n * a middleware declaration.\n *\n * @remarks\n * Moved out of `Store.ts` unchanged. These four functions never touched an instance field, so\n * they were already free functions wearing method clothing, and the class kept them only because\n * that is where they were written.\n *\n * @module\n */\n\nimport type {\n EventKey,\n EventMapBase,\n EventUnion,\n MiddlewareFunction,\n MiddlewareInput,\n When,\n} from \"../types\";\n\n/**\n * Checks if an event matches a `When` matcher.\n *\n * @param when - The When matcher (or undefined for \"all events\").\n * @param event - The event to check.\n * @returns `true` if the event matches, `false` otherwise.\n *\n * @remarks\n * - `undefined` or missing `when` matches ALL events.\n * - `{ any: true }` matches ALL events.\n * - `{ keys: [...] }` matches if event's `[channel, type]` is in the array.\n * - `{ channel: 'x' }` matches if event's channel equals 'x'.\n * - `{ channels: ['x', 'y'] }` matches if event's channel is in the array.\n *\n * @internal\n */\nexport function matchesWhen<EM extends EventMapBase>(\n when: When<EM> | undefined,\n event: EventUnion<EM>,\n): boolean {\n // No targeting = match all events\n if (!when) return true;\n\n // Match all events\n if (\"any\" in when && when.any === true) {\n return true;\n }\n\n // Match specific event keys\n if (\"keys\" in when) {\n return when.keys.some(\n ([channel, type]) => event.channel === channel && event.type === type,\n );\n }\n\n // Match single channel (all types within that channel)\n if (\"channel\" in when) {\n return event.channel === when.channel;\n }\n\n // Match multiple channels\n if (\"channels\" in when) {\n return when.channels.includes(event.channel as keyof EM & string);\n }\n\n return false;\n}\n\n/**\n * Extracts the middleware function from a MiddlewareInput.\n * Handles both raw functions (legacy) and MiddlewareSpec objects.\n *\n * @param input - MiddlewareInput (function or spec).\n * @returns The middleware function.\n *\n * @internal\n */\nexport function getMiddlewareFunction<St, EM extends EventMapBase>(\n input: MiddlewareInput<St, EM>,\n): MiddlewareFunction<St, EM> {\n if (typeof input === \"function\") {\n return input;\n }\n return input.middleware;\n}\n\n/**\n * Gets the `when` matcher from a MiddlewareInput.\n *\n * @param input - MiddlewareInput (function or spec).\n * @returns The `when` matcher, or `undefined` for raw functions (match all).\n *\n * @internal\n */\nexport function getMiddlewareWhen<St, EM extends EventMapBase>(\n input: MiddlewareInput<St, EM>,\n): When<EM> | undefined {\n if (typeof input === \"function\") {\n // Raw functions match all events\n return undefined;\n }\n return input.when;\n}\n\n/**\n * Normalizes event targeting from `when` to an array of EventKeys.\n *\n * @param spec - Object with an optional `when` matcher.\n * @returns Array of `[channel, type]` pairs.\n *\n * @internal\n */\nexport function normalizeEventKeys<EM extends EventMapBase>(spec: {\n when?: When<EM>;\n events?: ReadonlyArray<EventKey<EM>>;\n}): ReadonlyArray<EventKey<EM>> {\n\n if (spec.when) {\n const when = spec.when;\n\n // Only `keys` can reach this point: both callers intercept pattern-based matchers\n // (`any`, `channel`, `channels`) before normalizing, because those register against the\n // emit loop rather than against per-key handler maps.\n if (\"keys\" in when) {\n return when.keys;\n }\n }\n\n // No targeting specified\n return [];\n}\n","/**\n * @module @yoltra/core\n */\n\nimport { Reducer } from \"../reducer/Reducer\";\nimport { detectChangedProps } from \"../utils/detectChangedProps\";\nimport { EventBus } from \"../eventBus/EventBus\";\nimport { LooseEventBus } from \"../eventBus/LooseEventBus\";\nimport type {\n Event,\n EventMapBase,\n EventKey,\n EventUnion,\n Change,\n DeepReadonly,\n EffectFunction,\n EffectSpec,\n EventConsumerMeta,\n EventMeta,\n MiddlewareFunction,\n MiddlewareInput,\n MiddlewareSpec,\n ReducersMapAny,\n ReducerSpec,\n StateFromReducers,\n StoreInstance,\n StoreSpec,\n Unsubscribe,\n EMFromReducersStrict,\n Emit,\n EmitOptions,\n EmitResult,\n ConnectOptions,\n InstrumentationObserver,\n CascadeInfo,\n InstrumentedEvent,\n EventPhase,\n EventSubscriberEntry,\n Origin,\n RegistrationChange,\n RegistrationObserver,\n ReplaceScope,\n EventSubscriptionHandler,\n NotifiedPhase,\n NarrowedEventHandler,\n When,\n} from \"../types\";\nimport { freezeState } from \"../utils/immutability\";\nimport { isRejected } from \"./rejection\";\nimport type { CallHandle, CallOptions } from \"./call\";\nimport { performCall } from \"./performCall\";\nimport type { Rejection } from \"./rejection\";\nimport type { AliasWatch } from \"../utils/immutability\";\nimport {\n buildAncestorPaths as ancestorPaths,\n getAtPath as readAtPath,\n} from \"./paths\";\nimport { fingerprint as fingerprintOf } from \"./fingerprint\";\nimport {\n getMiddlewareFunction,\n getMiddlewareWhen,\n matchesWhen,\n normalizeEventKeys,\n} from \"./matching\";\n\n/**\n * Deep-freezes a value **in development only**, returning it untouched in\n * production.\n *\n * @remarks\n * Deep-freezing is a dev-time guard against accidental state mutation; in\n * production it is pure overhead. Because {@link freezeState} freezes in place\n * and early-exits on already-frozen nodes, freezing a structurally-shared value\n * touches only the **newly-created** nodes — O(change), not O(state size). This\n * is why the write path does **not** deep-clone before freezing.\n *\n * @internal\n */\n/**\n * Copies a slice's initial state so the store owns it, naming the slice if it cannot.\n *\n * @remarks\n * `structuredClone` refuses functions and drops class prototypes, and its `DataCloneError`\n * says only that something was uncloneable — not which slice, and not which key. For a store\n * built from several slices at once that leaves the developer bisecting their own\n * configuration. The message here names the slice and points at the usual cause.\n *\n * @internal\n */\nfunction cloneInitialState<T>(sliceName: unknown, state: T): T {\n try {\n return structuredClone(state);\n } catch (err) {\n throw new Error(\n `[yoltra] Initial state for slice \"${String(sliceName)}\" could not be copied: ` +\n `${err instanceof Error ? err.message : String(err)}. State must be structured-cloneable ` +\n `— functions, class instances and DOM nodes are not. Keep behaviour out of state and ` +\n `store plain data.`,\n );\n }\n}\n\nfunction freezeInDev<T>(value: T, alias?: AliasWatch): DeepReadonly<T> {\n return process.env.NODE_ENV === \"production\"\n ? (value as unknown as DeepReadonly<T>)\n : freezeState(value, new WeakSet<object>(), alias);\n}\n\n/**\n * Default window (ms) for identity-based dedup via {@link EmitOptions.dedupKey}\n * when content-based dedup (`dedupWindowMs`) is disabled. Large enough to absorb\n * a synchronous re-fire (e.g. React Strict Mode's mount → unmount → mount),\n * small enough not to swallow genuine user repeats.\n */\nconst DEFAULT_DEDUP_KEY_WINDOW_MS = 100;\n\n/**\n * Ceiling on rounds of registration notification triggered by observers registering.\n *\n * @remarks\n * Mirrors {@link DEFAULT_MAX_REDUCE_DEPTH} and exists for the same reason: a legitimate\n * reaction chain is bounded, a cycle is not.\n */\nconst MAX_REGISTRATION_CASCADE = 64;\n\n/**\n * How many disposed slice names to remember for the development-time read diagnostic.\n *\n * @remarks\n * Bounded so a long session of mount-and-dispose cycles does not accumulate forever. The\n * diagnostic is for a slice someone has just stopped using.\n */\nconst MAX_REMEMBERED_DISPOSED_SLICES = 64;\n\n/**\n * Causal depth at which the store stops extending an event chain.\n *\n * @remarks\n * Chosen to be uncontroversial rather than tight. An event caused by an event caused by an event\n * is ordinary application wiring; sixty-four deep is a cycle. The cost of being wrong in the\n * generous direction is a cascade that runs a few more hops before it is named; the cost of being\n * wrong in the strict direction is refusing correct code, which would teach people to raise the\n * limit reflexively and defeat it.\n */\nconst DEFAULT_MAX_REDUCE_DEPTH = 64;\n\n/**\n * How many ancestor ids {@link CascadeInfo.chain} carries.\n *\n * @remarks\n * A cascade is long by definition. The diagnostic value is in the cycle at the end — which\n * handler emitted back into which — not in the several thousand identical hops that preceded it,\n * and retaining all of them would make the guard against runaway memory itself retain\n * unboundedly.\n */\nconst CASCADE_CHAIN_LIMIT = 16;\n\n/**\n * One slice's pending write: computed, frozen, and not yet visible to anybody.\n *\n * @remarks\n * `prev` is retained because change notifications report old and new, and by the time they are\n * built the slice has already been replaced in `this.state` — the whole point of staging.\n *\n * @internal\n */\nconst NOT_COMMITTED: EmitResult = Object.freeze({ committed: false, written: false });\n\n/**\n * Distinct results for the three ways an event fails to commit.\n *\n * @remarks\n * These were one shared frozen object, so `committed: false` reached the caller with no way\n * to tell a guard refusing an action from a double-click being deduplicated. Those want\n * opposite responses: show the refusal, say nothing about the duplicate.\n */\nconst DEDUPED: EmitResult = Object.freeze({\n committed: false,\n written: false,\n reason: \"deduped\" as const,\n});\nconst CASCADE_REFUSED: EmitResult = Object.freeze({\n committed: false,\n written: false,\n reason: \"cascade\" as const,\n});\nconst COMMITTED_UNWRITTEN: EmitResult = Object.freeze({ committed: true, written: false });\nconst WRITTEN: EmitResult = Object.freeze({ committed: true, written: true });\n\ninterface StagedSlice {\n readonly name: string;\n readonly prev: unknown;\n readonly frozen: unknown;\n readonly leafPaths: string[];\n}\n\n/**\n * High-resolution monotonic clock in milliseconds for instrumentation timing;\n * falls back to `Date.now()` where `performance` is unavailable.\n */\nconst now = (): number =>\n typeof performance !== \"undefined\" && typeof performance.now === \"function\"\n ? performance.now()\n : Date.now();\n\nexport class Store<EM extends EventMapBase, R extends string, S extends Record<R, any>>\n implements StoreInstance<R, S, EM> {\n /**\n * Store name (used by DevTools & diagnostics).\n *\n * @public\n */\n name: string;\n\n /**\n * Registered middleware pipeline (run **before** reducers).\n * Stores either raw functions (legacy) or MiddlewareSpec objects.\n *\n * Only an explicit `false` stops propagation. Returning nothing allows the event, so\n * middleware that only logs or measures needs no `return` at all.\n *\n * @internal\n */\n private readonly middleware: Array<{\n input: MiddlewareInput<DeepReadonly<S>, EM>;\n origin: Origin;\n }>;\n\n /**\n * Installed slice reducers keyed by slice name.\n *\n * @internal\n */\n private readonly reducers: Record<R, Reducer<S[R], EM>>;\n\n /**\n * Current immutable snapshot of the store state.\n * This reference changes whenever any slice changes (shallow immutability).\n *\n * @internal\n */\n private state: DeepReadonly<S>;\n\n /**\n * Bus for reducer wiring (emit by `(channel, type)`).\n *\n * @internal\n */\n private readonly reducerBus: EventBus<EM>;\n\n /**\n * Bus for **granular** connector events (emit by **dotted path** inside a slice).\n *\n * @internal\n */\n private readonly connectorBus: LooseEventBus<R, string, Change>;\n\n /**\n * Coarse-grained listeners (called once per committed event, only if state changed).\n *\n * @internal\n */\n private readonly listeners: Set<() => void> = new Set();\n\n /**\n * Registered effect handlers keyed by `\"channel::type\"` for O(1) lookup.\n * Used for effects with explicit `keys` targeting.\n *\n * @internal\n */\n private readonly effects = new Map<\n string,\n Set<{ effect: EffectFunction<DeepReadonly<S>, EM>; origin: Origin }>\n >();\n\n /**\n * Pattern-based effects that need runtime matching.\n * Used for effects with `when: { any }`, `{ channel }`, or `{ channels }`.\n * Stores tuples of [effect function, when matcher].\n *\n * @internal\n */\n private readonly patternEffects = new Set<{\n effect: EffectFunction<DeepReadonly<S>, EM>;\n when: When<EM>;\n origin: Origin;\n }>();\n\n /**\n * Committed event subscribers keyed by `\"channel::type\"` for O(1) lookup.\n * Notified after reducers, before effects, for events that passed middleware.\n *\n * @internal\n */\n private readonly committedEventSubscribers = new Map<\n string,\n Set<EventSubscriberEntry<DeepReadonly<S>, EM>>\n >();\n\n /**\n * Uncommitted event subscribers keyed by `\"channel::type\"` for O(1) lookup.\n * Notified when middleware rejects an event.\n *\n * @internal\n */\n private readonly uncommittedEventSubscribers = new Map<\n string,\n Set<EventSubscriberEntry<DeepReadonly<S>, EM>>\n >();\n\n /**\n * All-events subscribers keyed by `\"channel::type\"` for O(1) lookup.\n * Notified for both committed and uncommitted events with phase parameter.\n *\n * @internal\n */\n /**\n * Subscribers to events that actually changed state, notified after the commit.\n *\n * @remarks\n * Separate from `committedEventSubscribers` rather than a filter over it, because the two\n * answer different questions and one of them is load bearing: `committed` means \"not vetoed\"\n * and fires for every event a store accepts, including every event in a store with no\n * reducers. Narrowing it would have silently stopped toasts and analytics firing.\n *\n * @internal\n */\n private readonly writtenEventSubscribers = new Map<\n string,\n Set<EventSubscriberEntry<DeepReadonly<S>, EM>>\n >();\n\n private readonly allEventSubscribers = new Map<\n string,\n Set<EventSubscriberEntry<DeepReadonly<S>, EM>>\n >();\n\n /**\n * True while a devtools time-travel is applying a snapshot or replaying events.\n *\n * @remarks\n * Saved and restored rather than set and cleared to `false`: `__replayEvents` calls\n * `__applyExternalState` as its first step, so clearing on the inner call's way out would\n * unset the flag for the entire event loop that follows it.\n *\n * @internal\n */\n private replaying = false;\n\n /**\n * Track reducerBus unsubs per slice for HMR/register/unregister.\n *\n * @internal\n */\n private readonly sliceUnsubs = new Map<string, Array<() => void>>();\n\n /**\n * Pattern-based reducers that need runtime matching.\n * Used for reducers with `when: { any }`, `{ channel }`, or `{ channels }`.\n * Maps slice name to the `when` matcher.\n *\n * @internal\n */\n private readonly patternReducers = new Map<R, When<EM>>();\n\n /**\n * Where each mounted slice came from. See {@link Origin}.\n *\n * @remarks\n * This is what makes `replace*` mean \"replace mine\" rather than \"replace everything\". It\n * is written by `mountSlice` and never by a caller.\n *\n * @internal\n */\n private readonly sliceOrigin = new Map<string, Origin>();\n\n /**\n * Who claims each dynamically mounted slice, for introspection only.\n *\n * @remarks\n * Surfaced in `__devtoolsIntrospect()` and named in the collision error. **Never read by\n * `replace*`.** Correctness comes from {@link Origin}, which nobody has to remember to\n * pass; if preservation depended on this string, forgetting it would silently delete a\n * library's state.\n *\n * @internal\n */\n private readonly sliceOwner = new Map<string, string>();\n\n /**\n * Slices unmounted by their owner, for a development-time diagnostic.\n *\n * @remarks\n * Decoration re-types the store, and after a disposer runs the widened type still claims\n * a slice that is gone. Reading it would hand a component `undefined` from a type that\n * promised a value, which is the silent failure this whole feature exists to remove.\n * Populated only for `dynamic` and `internal` slices: a `spec` slice removed by a\n * `replace*` was not promised by anyone's widened type.\n *\n * Bounded, because a long development session that mounts and disposes repeatedly would\n * otherwise accumulate an entry per cycle forever. The oldest is dropped: the diagnostic\n * exists for a slice someone has just stopped using, and a name disposed hundreds of\n * mounts ago is not the one being read by mistake. Maps to the owner, or `undefined`\n * when the library did not name itself.\n *\n * @internal\n */\n private readonly disposedSlices = new Map<string, string | undefined>();\n\n /** @internal */\n private readonly registrationObservers = new Set<RegistrationObserver<EM>>();\n\n /**\n * Changes accumulated inside the current public call, flushed once at its end.\n *\n * @internal\n */\n private pendingRegistrationChanges: RegistrationChange<EM>[] | null = null;\n\n /**\n * Depth of nested registration transactions.\n *\n * @remarks\n * `hotReplace` calls three `replace*` methods, and each of those registers repeatedly.\n * Only the outermost public entry point flushes, so one `hotReplace` produces one batch\n * spanning all three kinds rather than three batches of intermediate topology.\n *\n * @internal\n */\n private registrationDepth = 0;\n\n /** True while observers are being notified, so a re-entrant change is queued. @internal */\n private notifyingRegistrations = false;\n\n /** Batches produced by an observer's own registrations, drained after the current one. @internal */\n private readonly queuedRegistrationBatches: Array<readonly RegistrationChange<EM>[]> = [];\n\n /**\n * Whether `__replayEvents()` is allowed.\n * Set from `spec.devtools.allowReplay`.\n *\n * @internal\n */\n private readonly replayEnabled: boolean;\n\n /**\n * Produces the `id` for each emitted event. Defaults to `crypto.randomUUID()`; overridable\n * via {@link StoreSpec.idFactory} for runtimes lacking it or for deterministic tests.\n *\n * @internal\n */\n private readonly idFactory: () => string;\n\n /**\n * Optional hook invoked when an effect throws/rejects. See\n * {@link StoreSpec.onEffectError}. `await emit()` never rejects on effect\n * failure — this is how callers observe effect errors.\n */\n private readonly onEffectError?: (error: unknown, event: EventUnion<EM>) => void;\n\n /**\n * Optional hook invoked when a reducer throws. See {@link StoreSpec.onReducerError}. The\n * failing slice is isolated rather than the event being rolled back, so this is the only\n * signal that a reducer misbehaved.\n */\n private readonly onReducerError?: (\n error: unknown,\n event: EventUnion<EM>,\n slice: string,\n ) => void;\n\n /** @internal */\n private readonly onSubscriberError?: (\n error: unknown,\n event: EventUnion<EM>,\n phase: NotifiedPhase,\n ) => void;\n\n /**\n * `slice:channel:type` combinations already warned about for payload aliasing.\n *\n * @remarks\n * Development-only diagnostics have to stay quiet enough to be read. One warning names the\n * pattern; repeating it once per event would bury it.\n */\n private readonly warnedPayloadAliases = new Set<string>();\n\n /**\n * Pending events awaiting the **synchronous** reduce phase (middleware +\n * reducers + subscribers + coarse listeners). Drained by {@link drainReduce}.\n *\n * @internal\n */\n private readonly reduceQueue: Array<{\n channel: string;\n type: string;\n payload: any;\n id: string;\n meta?: EventMeta;\n resolve: (result: EmitResult) => void;\n parentId?: string;\n depth?: number;\n /** Ancestor ids, for {@link CascadeInfo.chain}. Never surfaced on the event itself. */\n chain?: readonly string[];\n }> = [];\n\n /**\n * Re-entrancy guard for the synchronous reduce phase.\n *\n * @internal\n */\n private isReducing = false;\n\n /**\n * The event currently being reduced, or `null` outside the drain.\n *\n * @remarks\n * This is what makes causality exact rather than best-effort. The drain is synchronous — no\n * `await` can interleave — so any `emit` that arrives while it is set is, without ambiguity, a\n * consequence of this event. That catches the case a scoped `emit` closure cannot: a\n * middleware or subscriber that captured the store and calls `store.emit` directly instead of\n * using the injected one. Attribution should not depend on which reference a consumer reached\n * for.\n *\n * @internal\n */\n private currentEvent: { id: string; depth: number; chain: readonly string[] } | null = null;\n\n /**\n * Events processed by the drain currently in progress. Compared against\n * `maxTransitionsPerDrain`, which is off unless configured.\n *\n * @internal\n */\n private transitionsThisDrain = 0;\n\n /**\n * Ceilings that stop a cascade from becoming a hung process. See {@link StoreSpec.maxReduceDepth}.\n *\n * @internal\n */\n private readonly maxReduceDepth: number;\n private readonly maxTransitionsPerDrain: number;\n private readonly onCascade?: (info: CascadeInfo<EM>) => void;\n private readonly onRejected?: (\n rejection: Rejection,\n event: EventUnion<EM>,\n slice: string,\n ) => void;\n\n /**\n * Registered instrumentation observers (DevTools seam). See {@link instrument}.\n *\n * @internal\n */\n private readonly instrumentObservers = new Set<InstrumentationObserver<EM>>();\n\n /**\n * Scratch array collecting slice-prefixed changed leaf paths during an\n * instrumented reduce. Set by {@link drainReduce} while observers are active;\n * appended to by {@link commitStaged}. `null` when not instrumenting.\n *\n * @internal\n */\n private changedPathSink: string[] | null = null;\n\n /**\n * Where keyed reducers put their pending writes during a reduce, and the refusal one of them\n * returned.\n *\n * @remarks\n * Keyed reducers are invoked through `reducerBus`, which delivers to handlers and has no way\n * to hand a value back — the same reason `changedPathSink` exists. `null` outside a reduce.\n *\n * @internal\n */\n private stagingSink: StagedSlice[] | null = null;\n private stagedRejection: Rejection | null = null;\n private stagedRejectedBy = \"\";\n\n /**\n * Count of effect tasks currently in flight; surfaced as queue depth by\n * {@link __devtoolsIntrospect}.\n *\n * @internal\n */\n private inFlightEffects = 0;\n\n /**\n * Tracks processed events by fingerprint with timestamps for TTL-based deduplication.\n *\n * **Deduplication Behavior:**\n * - Events are fingerprinted through the codec, so `Map`, `Set`, `Date`, `BigInt`, binary\n * and cyclic payloads all compare by content rather than collapsing to `{}`\n * - Plain-object keys are sorted, so key order is not content; array and `Map` order is\n * - If an identical fingerprint is seen within the dedup window, it's skipped\n * - The window is `dedupWindowMs`, which defaults to `0` (dedup off)\n *\n * **Limitations:**\n * - A payload larger than the fingerprint node budget is never deduplicated, which is the\n * safe direction: a missed dedup costs a duplicate, a false one drops a real event\n * - Legitimate rapid-fire identical events may be incorrectly deduplicated\n * - The cache is bounded to 1000 entries with lazy pruning\n *\n * @internal\n */\n private readonly processedEvents = new Map<string, number>();\n\n /**\n * Lifetime count of events suppressed by the deduplication cache.\n * Exposed via {@link __devtoolsIntrospect} so the DevTools agent can\n * surface it in the STORE_METRICS response without further core changes.\n *\n * @internal\n */\n private dedupCount = 0;\n\n /**\n * Store-owned metadata for registered effects, keyed by the effect function.\n * Kept **off** the caller's function object: mutating a user-owned function\n * (the old `fn.__quoMeta`) bled metadata across stores that share a handler\n * and left it attached after unregister. Cleared on {@link dispose}.\n *\n * @internal\n */\n private effectMeta = new WeakMap<object, EventConsumerMeta<\"effect\">>();\n\n /**\n * Configuration for event deduplication.\n * @internal\n */\n private readonly dedupConfig: {\n /** Time window in ms for considering events as duplicates */\n windowMs: number;\n /** Maximum cache size to prevent unbounded growth */\n maxCacheSize: number;\n };\n\n /**\n * Timer for periodic cleanup of processed events.\n *\n * @internal\n */\n private eventCleanupTimer: ReturnType<typeof setInterval> | null = null;\n\n /**\n * Creates a store from a {@link StoreSpec}.\n *\n * @param spec - Store configuration (name, reducers, middleware, optional effects).\n *\n * @public\n */\n constructor(spec: StoreSpec<R, S, EM>) {\n this.name = spec.name ?? \"yoltra Store\";\n this.reducerBus = new EventBus<EM>();\n this.connectorBus = new LooseEventBus();\n // Tagged `spec`, not left bare. If this tag is missing, `replaceMiddleware` silently\n // becomes a no-op: it would find nothing of `spec` provenance to remove and preserve\n // everything instead. No test notices unless one asserts that spec registrations ARE\n // still replaced, which is why that test exists.\n this.middleware = (spec.middleware ?? []).map((input) => ({\n input: input as MiddlewareInput<DeepReadonly<S>, EM>,\n origin: \"spec\" as Origin,\n }));\n this.reducers = {} as Record<R, Reducer<S[R], EM>>;\n this.state = {} as any;\n this.replayEnabled = spec.devtools?.allowReplay ?? false;\n this.idFactory = spec.idFactory ?? (() => crypto.randomUUID());\n this.onEffectError = spec.onEffectError;\n this.onReducerError = spec.onReducerError;\n this.onSubscriberError = spec.onSubscriberError;\n\n // Depth is bounded whether or not anybody asked. The queue drains synchronously, so an\n // unbounded cascade is a frozen tab or a pinned core with no error to point at — a failure\n // mode a library should not require configuration to avoid.\n //\n // Width stays opt-in, because wide and deep mean different things: a fan-out (one event whose\n // subscriber emits five hundred siblings) is legitimate and wide, while a cascade is narrow\n // and deep. Depth separates them; a count cannot. See StoreSpec.maxTransitionsPerDrain.\n this.maxReduceDepth = spec.maxReduceDepth ?? DEFAULT_MAX_REDUCE_DEPTH;\n this.maxTransitionsPerDrain = spec.maxTransitionsPerDrain ?? Infinity;\n this.onCascade = spec.onCascade;\n this.onRejected = spec.onRejected;\n\n // Deduplication is OPT-IN. Content-based dedup is OFF by default because it\n // can silently drop legitimate rapid-fire identical events; enable it with\n // `dedupWindowMs > 0`, or use per-emit `dedupKey` for identity-based dedup.\n this.dedupConfig = {\n windowMs: spec.dedupWindowMs ?? 0,\n maxCacheSize: 1000,\n };\n\n /**\n * Reducer wiring\n */\n Object.entries(spec.reducer).forEach(([name, rSpec]) => {\n this.mountSlice(name as R, rSpec as ReducerSpec<S[R], EM>, { preserveState: false });\n });\n\n /**\n * Effects from spec (optional)\n */\n if (spec.effects?.length) {\n for (const effSpec of spec.effects) {\n // `spec`, not the public `registerEffect`'s `dynamic`. Same hazard as the middleware\n // tag above: get this wrong and `replaceEffects` stops replacing anything.\n this.registerEffectWithOrigin(effSpec, \"spec\");\n }\n }\n\n // Event dedup cleanup runs on a lazily-started interval: it begins the first\n // time an entry is cached (content dedup OR identity `dedupKey`) and stops\n // when the cache empties (see ensureCleanupTimer / pruneProcessedEvents).\n // When no dedup is used the cache stays empty, so no timer is ever started\n // and the store never keeps the event loop alive unnecessarily.\n\n /**\n * Method bindings\n */\n this.dispose = this.dispose.bind(this);\n this.notifyEffects = this.notifyEffects.bind(this);\n\n // private API\n this.__applyExternalState = this.__applyExternalState.bind(this);\n this.__replayEvents = this.__replayEvents.bind(this);\n this.__devtoolsIntrospect = this.__devtoolsIntrospect.bind(this);\n this.mountSlice = this.mountSlice.bind(this);\n this.unmountSlice = this.unmountSlice.bind(this);\n this.getAtPath = this.getAtPath.bind(this);\n\n // public API\n this.emit = this.emit.bind(this);\n this.subscribe = this.subscribe.bind(this);\n this.connect = this.connect.bind(this);\n this.onEffect = this.onEffect.bind(this);\n this.onEvent = this.onEvent.bind(this);\n this.getState = this.getState.bind(this);\n this.registerEffect = this.registerEffect.bind(this);\n this.registerMiddleware = this.registerMiddleware.bind(this);\n this.registerReducer = this.registerReducer.bind(this);\n this.replaceMiddleware = this.replaceMiddleware.bind(this);\n this.replaceEffects = this.replaceEffects.bind(this);\n this.replaceReducers = this.replaceReducers.bind(this);\n this.hotReplace = this.hotReplace.bind(this);\n }\n\n /**\n * Cleanup resources (timers, etc.) when disposing the store.\n * Call this if you're dynamically creating/destroying stores.\n *\n * @example\n * ```ts\n * const store = createStore({ ... });\n * // later\n * store.dispose();\n * ```\n *\n * @public\n */\n public dispose(): void {\n if (this.eventCleanupTimer) {\n clearInterval(this.eventCleanupTimer);\n this.eventCleanupTimer = null;\n }\n\n this.processedEvents.clear();\n this.effects.clear();\n this.patternEffects.clear();\n this.effectMeta = new WeakMap();\n\n // The once-per-slice-and-event latch for the payload-aliasing warning. Left populated, a\n // disposed-and-recreated store — per-route stores, HMR, a test suite building one per case —\n // inherits the suppression and stays quiet about aliasing in code that has never been warned\n // about. The latch exists to stop a hot path becoming a log, not to silence the next store.\n this.warnedPayloadAliases.clear();\n\n // Release every subscription and observer. Without this, the closures they\n // hold (React fibers, DevTools sockets, effect handlers) pin the store and\n // leak on per-route / SSR / test / HMR stores that create and dispose stores.\n this.listeners.clear();\n this.committedEventSubscribers.clear();\n this.uncommittedEventSubscribers.clear();\n this.writtenEventSubscribers.clear();\n this.allEventSubscribers.clear();\n this.instrumentObservers.clear();\n this.connectorBus.clear();\n this.reducerBus.clear();\n this.patternReducers.clear();\n this.sliceUnsubs.clear();\n this.sliceOrigin.clear();\n this.sliceOwner.clear();\n this.disposedSlices.clear();\n // Terminal and silent. `dispose()` means the store is gone, not that its slices were\n // individually unmounted, and firing N changes would invite teardown against a store\n // already tearing down, in an order nobody controls, while these very observers are\n // being cleared. Consistent with `dispose()` not firing `listeners` either.\n this.registrationObservers.clear();\n this.pendingRegistrationChanges = null;\n this.queuedRegistrationBatches.length = 0;\n (this.middleware as unknown as unknown[]).length = 0;\n this.changedPathSink = null;\n }\n\n /**\n * Generates a fingerprint for an event for deduplication purposes.\n * Falls back gracefully for non-serializable payloads.\n *\n * @param channel - Event channel.\n * @param type - Event type.\n * @param payload - Event payload.\n * @returns A string fingerprint for the event.\n *\n * @internal\n */\n private fingerprint(channel: string, type: string, payload: unknown): string {\n return fingerprintOf(channel, type, payload);\n }\n\n /**\n * Checks if an event should be deduplicated.\n * Returns true if this is a duplicate that should be skipped.\n *\n * @param fp - Event fingerprint.\n * @returns `true` if duplicate (should skip), `false` otherwise.\n *\n * @internal\n */\n private shouldDedupe(fp: string, windowMs: number): boolean {\n const now = Date.now();\n const existing = this.processedEvents.get(fp);\n\n if (existing !== undefined) {\n // Check if within dedup window\n if (now - existing < windowMs) {\n this.dedupCount++;\n return true; // Duplicate, skip\n }\n }\n\n // Record this event and make sure the periodic prune is running (it may not\n // be — e.g. identity `dedupKey` dedup at windowMs 0 never started it at\n // construction). The timer stops itself once the cache drains.\n this.processedEvents.set(fp, now);\n this.ensureCleanupTimer();\n\n // Lazy cleanup if cache is getting large\n if (this.processedEvents.size > this.dedupConfig.maxCacheSize) {\n this.pruneProcessedEvents(now);\n }\n\n return false; // Not a duplicate\n }\n\n /**\n * Starts the periodic prune interval if it isn't already running. Called when\n * the first entry is cached so the timer's lifetime tracks actual dedup use\n * (content window or identity `dedupKey`), independent of `dedupWindowMs`.\n *\n * @internal\n */\n private ensureCleanupTimer(): void {\n if (this.eventCleanupTimer !== null) return;\n this.eventCleanupTimer = setInterval(() => {\n this.pruneProcessedEvents(Date.now());\n }, 5000);\n // Never let the cleanup interval by itself keep a Node process alive.\n (this.eventCleanupTimer as { unref?: () => void }).unref?.();\n }\n\n /**\n * Removes expired entries from the processed events cache.\n *\n * @param now - Current timestamp.\n *\n * @internal\n */\n private pruneProcessedEvents(now: number): void {\n // Keep 2x the largest window in play (content window or the keyed-dedup\n // default) so entries aren't evicted before their dedup window elapses.\n const effectiveWindow = Math.max(this.dedupConfig.windowMs, DEFAULT_DEDUP_KEY_WINDOW_MS);\n const cutoff = now - effectiveWindow * 2;\n\n for (const [key, timestamp] of this.processedEvents) {\n if (timestamp < cutoff) {\n this.processedEvents.delete(key);\n }\n }\n\n // Once the cache has drained, stop the interval so an idle store doesn't\n // hold a repeating timer. It restarts on the next cached event.\n if (this.processedEvents.size === 0 && this.eventCleanupTimer !== null) {\n clearInterval(this.eventCleanupTimer);\n this.eventCleanupTimer = null;\n }\n }\n\n /**\n * Reports a breached ceiling and refuses the emit.\n *\n * @remarks\n * Console *and* hook, matching how reducer and effect errors are reported: a cascade is a\n * wiring bug, and the console line is what a developer who has not registered a hook will\n * actually see. Without one, refusing the emit would look exactly like the event never having\n * been emitted at all — which is the invisibility this whole guard exists to end.\n *\n * @internal\n */\n private reportCascade(\n limit: \"maxReduceDepth\" | \"maxTransitionsPerDrain\",\n limitValue: number,\n event: EventUnion<EM>,\n depth: number,\n chain: readonly string[],\n ): void {\n console.error(\n `[yoltra] Cascade stopped: \"${event.channel}/${event.type}\" would exceed ${limit} ` +\n `(${limitValue}). This event was refused and the chain ends here. A chain this long is ` +\n `almost always two consumers emitting into each other — check what reacts to ` +\n `\"${event.channel}/${event.type}\" and what that emits in turn.` +\n (chain.length > 0 ? ` Recent causal chain: ${chain.join(\" → \")} → (refused).` : \"\"),\n );\n\n try {\n this.onCascade?.({ limit, limitValue, event, depth, chain });\n } catch (err) {\n // A throwing diagnostic must not become the failure it was reporting.\n console.error(\"onCascade handler error:\", err);\n }\n }\n\n /**\n * Invokes all registered **effects** for a given event.\n * Handles both key-based effects (O(1) lookup) and pattern-based effects (runtime matching).\n * Errors are caught and logged.\n *\n * @param event - The event that was reduced.\n * @internal\n */\n private async notifyEffects(event: EventUnion<EM>) {\n // Effects resume in their own task, after the drain that produced this event has ended, so\n // `currentEvent` is null by the time they run and cannot speak for them. This closure is how\n // an effect's emits stay attached to the event that triggered them — which is what bounds a\n // cascade that crosses drains rather than staying inside one.\n const emit = this.scopedEmit(event);\n\n // 1. Call key-based effects (O(1) lookup)\n const key = `${String(event.channel)}::${String(event.type)}`;\n const effectSet = this.effects.get(key);\n\n if (effectSet && effectSet.size > 0) {\n for (const h of [...effectSet]) {\n try {\n await h.effect(event, this.getState, emit);\n } catch (e) {\n console.error(\"Effect error:\", e);\n this.onEffectError?.(e, event);\n }\n }\n }\n\n // 2. Call pattern-based effects (runtime matching)\n for (const { effect, when } of this.patternEffects) {\n if (matchesWhen(when, event)) {\n try {\n await effect(event, this.getState, emit);\n } catch (e) {\n console.error(\"Effect error:\", e);\n this.onEffectError?.(e, event);\n }\n }\n }\n }\n\n /**\n * An `emit` that attributes whatever it sends to `cause`.\n *\n * @remarks\n * Built per event rather than per effect: every effect reacting to one event shares a cause,\n * and one closure is cheaper than one per handler on a path that runs for every committed\n * event.\n *\n * @internal\n */\n private scopedEmit(cause: EventUnion<EM>): Emit<EM> {\n const parent = {\n id: cause.id,\n depth: cause.depth ?? 0,\n chain: [...(this.currentEvent?.chain ?? []), cause.id].slice(-CASCADE_CHAIN_LIMIT),\n };\n return ((channel, type, payload, opts) =>\n this.emitCaused(parent, channel, type, payload, opts)) as Emit<EM>;\n }\n\n /**\n * Notifies event subscribers for a specific phase.\n *\n * Calls both phase-specific subscribers and 'all' subscribers.\n * Errors are caught and logged, allowing other subscribers to continue.\n *\n * @param event - The event to notify about.\n * @param phase - The phase ('committed' or 'uncommitted').\n * @internal\n */\n private notifyEventSubscribers(\n event: EventUnion<EM>,\n phase: \"committed\" | \"uncommitted\" | \"written\",\n ): void {\n const key = `${String(event.channel)}::${String(event.type)}`;\n\n // Notify phase-specific subscribers\n const phaseMap =\n phase === \"committed\"\n ? this.committedEventSubscribers\n : phase === \"written\"\n ? this.writtenEventSubscribers\n : this.uncommittedEventSubscribers;\n const phaseSet = phaseMap.get(key);\n\n if (phaseSet?.size) {\n for (const entry of [...phaseSet]) {\n if (this.replaying && !entry.duringReplay) continue;\n this.invokeEventSubscriber(entry.handler, event, phase);\n }\n }\n\n // Notify 'all' subscribers.\n //\n // Deliberately not reached for `written`. An event that writes is also committed, so folding\n // it in would hand every existing 'all' subscriber a second notification for the same event\n // and quietly double their counts — a silent change to code that never asked for the new\n // phase. `all` means committed-or-uncommitted, as it always has.\n if (phase === \"written\") return;\n const allSet = this.allEventSubscribers.get(key);\n if (allSet?.size) {\n for (const entry of [...allSet]) {\n if (this.replaying && !entry.duringReplay) continue;\n this.invokeEventSubscriber(entry.handler, event, phase);\n }\n }\n }\n\n /**\n * Invokes a single event-subscription handler **fire-and-forget**: synchronous\n * throws and async rejections are logged but never block the emit pipeline.\n * Event subscribers are notifications, not part of the committed reduce result.\n *\n * @internal\n */\n private invokeEventSubscriber(\n handler: EventSubscriptionHandler<DeepReadonly<S>, EM>,\n event: EventUnion<EM>,\n phase: \"committed\" | \"uncommitted\" | \"written\",\n ): void {\n const report = (e: unknown): void => {\n console.error(\"Event subscription error:\", e);\n // Reported as well as logged, so an application can route this to whatever it uses for\n // errors. Reducers, effects, rejections and cascades all had a hook; subscribers had\n // the console and nothing else.\n this.onSubscriberError?.(e, event, phase);\n };\n try {\n const result = handler(event, this.getState, this.emit, phase) as unknown;\n if (result && typeof (result as Promise<unknown>).then === \"function\") {\n (result as Promise<unknown>).catch(report);\n }\n } catch (e) {\n report(e);\n }\n }\n\n /**\n * Applies a reduced event to a slice and emits **precise** connector events.\n *\n * For each changed **leaf path** (via {@link detectChangedProps}), emits that leaf and\n * all of its **ancestors** once (e.g., `\"data\"`, `\"data.123\"`, `\"data.123.title\"`).\n *\n * A slice whose state **is** a single value — a primitive, a `Map`/`Set`, a `Date` — has no\n * leaf below its root, and `detectChangedProps` reports its change as the empty path `\"\"`.\n * That path is emitted as-is, so `connect({ reducer, property: \"\" })` (and any `**` pattern)\n * hears it. It has no ancestors to walk.\n *\n * **State Immutability**: When a slice changes, a new state object is created via\n * shallow spread: `{ ...this.state, [sliceName]: newSlice }`. This ensures that\n * `this.state` reference changes, enabling efficient change detection via `===`.\n *\n * @param rName - Slice name being updated.\n * @param event - Reduced event with typed payload.\n * @returns `true` if the slice actually changed, `false` otherwise.\n *\n * @internal\n */\n /**\n * Reduces one slice and contains any error it raises.\n *\n * @returns `true` when the slice changed.\n *\n * @remarks\n * The single funnel both dispatch paths go through, which is the point. Keyed reducers run\n * through `reducerBus`, whose handler loop caught and logged; pattern reducers were called\n * straight from the drain, so their errors escaped to the caller instead. The same bug in the\n * same reducer therefore produced two different outcomes depending on how the slice happened\n * to be targeted — a keyed reducer's throw let the event commit and its effects run, while a\n * pattern reducer's throw aborted the commit and notified nobody, not even the uncommitted\n * subscribers a veto would have reached.\n *\n * The semantics are the same either way: **the failing slice is isolated.** Its state is\n * unchanged, every other slice still reduces, and the event still commits if anything else\n * changed.\n *\n * That is deliberately *not* what a {@link Rejected} refusal does, which discards the whole\n * event. A crash and a refusal are different acts: a reducer that throws has a bug and should\n * not be able to veto its neighbours' work, while a reducer that refuses has made a decision\n * and must be able to.\n *\n * This once argued that rolling back was untenable, because subscribers were notified as each\n * slice committed and a later revert would have told them about a value that no longer\n * existed. Staging removed that obstacle — nothing is notified until every slice is written —\n * which is what made refusal possible at all.\n *\n * @internal\n */\n private stageSliceGuarded<C extends keyof EM & string, T extends keyof EM[C] & string>(\n rName: R,\n event: Event<EM, C, T>,\n staged: StagedSlice[],\n ): Rejection | null {\n try {\n return this.stageSlice(rName, event, staged);\n } catch (err) {\n // Reported through a hook as well as the console: a reducer throwing is a bug in\n // application code, and until now the only trace of it was a console line in one case and\n // an exception surfacing somewhere unrelated in the other.\n console.error(`Reducer error in slice \"${rName as string}\":`, err);\n this.onReducerError?.(err, event as EventUnion<EM>, rName as string);\n return null;\n }\n }\n\n /**\n * Runs one slice's reducer and records what it *would* write. Writes nothing.\n *\n * @returns The reducer's {@link Rejection} if it refused, otherwise `null`.\n *\n * @remarks\n * The staging half of the write path. Nothing here touches `this.state` or notifies anybody,\n * which is what lets the event be refused after every reducer has had its say — a decision\n * that has to see the whole diff cannot be made one slice at a time.\n *\n * Freezing happens here rather than at commit because it is where the new value is built, and\n * the freeze is a no-op on anything already frozen; a staged slice that never commits is\n * discarded frozen, which costs nothing and keeps the committed path free of a second walk.\n *\n * @internal\n */\n private stageSlice<C extends keyof EM & string, T extends keyof EM[C] & string>(\n rName: R,\n event: Event<EM, C, T>,\n staged: StagedSlice[],\n ): Rejection | null {\n // @ts-expect-error R indexing on DeepReadonly<S> is valid at runtime\n const prev = this.state[rName] as S[R];\n const next = this.reducers[rName].reduce(prev, event as any);\n\n // A refusal, not a value. Checked before the identity comparison below, because a rejection\n // object is never the previous state and would otherwise be staged as one.\n if (isRejected(next)) return next;\n\n // if reducer returned same ref, definitely no change\n if (prev === next) return null;\n\n // Compute precise leaf paths that changed (relative to slice root).\n //\n // Not filtered for truthiness. `\"\"` is how `detectChangedProps` reports a change at the\n // slice ROOT — a slice that *is* one value: a primitive, a `Map`/`Set`, a `Date`, or an\n // object replaced by something of a different shape. Discarding it as falsy made the\n // length check below read \"nothing changed\", so the write path returned before assigning\n // `this.state`: the reducer ran, its result was thrown away, and nothing said so. A store\n // holding `state: 0` could never leave `0`.\n const leafPaths = detectChangedProps(prev, next);\n\n // if nothing actually changed at the leaves, treat as a no-op\n if (leafPaths.length === 0) return null;\n\n // No deep clone: the reducer already returned a fresh `next` (purity contract), so\n // structural sharing is preserved and freezeInDev only touches new nodes.\n // In development the freeze walk also watches for the event payload appearing in the new\n // state by reference. That is the aliasing that makes a deep in-place freeze surprising:\n // the caller still holds the object, mutating it later throws from an unrelated stack, and\n // the same code works in production because the freeze is compiled out. Warned once per\n // slice and event so a hot path does not become a log.\n const payload = (event as { payload?: unknown }).payload;\n const alias: AliasWatch | undefined =\n process.env.NODE_ENV !== \"production\" && payload !== null && typeof payload === \"object\"\n ? {\n watch: payload,\n onFound: () => {\n const key = `${rName as string}:${event.channel}:${event.type}`;\n if (this.warnedPayloadAliases.has(key)) return;\n this.warnedPayloadAliases.add(key);\n console.warn(\n `[yoltra] Slice \"${rName as string}\" stored the payload of ` +\n `\"${event.channel}/${event.type}\" by reference. It is now frozen along with ` +\n `the rest of the state, so the emitter mutating it later will throw in ` +\n `development and silently corrupt state in production. Copy the payload in ` +\n `the reducer instead.`,\n );\n },\n }\n : undefined;\n\n staged.push({\n name: rName as string,\n prev,\n frozen: freezeInDev(next, alias),\n leafPaths,\n });\n\n return null;\n }\n\n /**\n * Writes every staged slice, then tells the world — in that order.\n *\n * @remarks\n * The commit half. Assigning all slices under a single new root before any notification goes\n * out is what closes the window this used to leave open: notifications fired per slice as each\n * committed, so a subscriber to slice A that read `getState()` could observe slice B of the\n * *same event* not yet applied. In React that window is real, because the atomic hooks use a\n * change as a bare signal and then re-read the whole store.\n *\n * It is also what makes refusal possible at all. The previous code documented rollback as\n * untenable precisely because \"an event that reverted afterwards would have already told\n * components about a value that no longer exists\" — true when notification and commit were the\n * same step, and no longer true now that they are not.\n *\n * @returns `true` if anything was written.\n *\n * @internal\n */\n private commitStaged(staged: StagedSlice[], event: EventUnion<EM>): boolean {\n if (staged.length === 0) return false;\n\n // One new root for the whole event, not one per slice.\n const nextState = { ...(this.state as object) } as Record<string, unknown>;\n for (const slice of staged) nextState[slice.name] = slice.frozen;\n this.state = nextState as DeepReadonly<S>;\n\n // Record slice-prefixed changed leaf paths for any active instrumentation\n // (lets DevTools agents build precise patches without re-diffing state).\n if (this.changedPathSink) {\n for (const slice of staged) {\n for (const p of slice.leafPaths) {\n this.changedPathSink.push(p ? `${slice.name}.${p}` : slice.name);\n }\n }\n }\n\n // Every notification happens after every write, so any handler reading `getState()` sees the\n // event applied in full.\n for (const slice of staged) {\n // emit deep + ancestor paths once each\n const toEmit = new Set<string>();\n for (const p of slice.leafPaths) {\n // The slice root has no ancestors to walk — `buildAncestorPaths(\"\")` is `[]` by contract,\n // which is what callers holding a real path rely on — so it is added directly. Without\n // this a slice that is entirely one value changes and tells nobody, which is the\n // subscription half of the same bug the missing filter caused in the commit half.\n if (p === \"\") {\n toEmit.add(\"\");\n continue;\n }\n for (const a of Store.buildAncestorPaths(p)) toEmit.add(a);\n }\n\n for (const prop of toEmit) {\n // Built only if a handler matched. Reading the old and new value walks the state tree\n // twice per path, and a slice nobody subscribes to used to pay that for every path it\n // changed — describing the change in detail to an audience of nobody.\n this.connectorBus.emitWith(slice.name as R, prop, () => ({\n oldValue: this.getAtPath(slice.prev, prop),\n newValue: this.getAtPath(slice.frozen, prop),\n path: prop,\n // Provenance, built inside the same lazy factory as the values: a subscriber that\n // needs to know why a value moved no longer has to mirror the cause into state and\n // keep it there twice.\n eventId: event.id,\n channel: event.channel as string,\n type: event.type as string,\n }));\n }\n }\n\n return true;\n }\n\n /**\n * Returns a structured introspection snapshot for DevTools UIs.\n *\n * @remarks\n * Reads the internal middleware, effects, reducers, and subscriber\n * registries and returns a plain-object summary matching the\n * `STORE_SUBSCRIPTIONS` protocol message shape.\n *\n * @public\n */\n public __devtoolsIntrospect() {\n // Reducers\n const reducers = (Object.keys(this.reducers) as Array<R>).map((name) => {\n const when = this.patternReducers.get(name);\n return {\n name: name as string,\n when,\n origin: this.sliceOrigin.get(name as string) ?? \"spec\",\n owner: this.sliceOwner.get(name as string),\n };\n });\n\n // Effects (keyed) — metadata looked up from the store-owned effectMeta map\n const effects: Array<{\n channel: string;\n type: string;\n name?: string;\n description?: string;\n origin: Origin;\n }> = [];\n for (const [key, set] of this.effects) {\n if (set.size === 0) continue;\n const [channel, type] = key.split(\"::\");\n for (const entry of set) {\n const meta = this.effectMeta.get(entry.effect);\n effects.push({\n channel,\n type,\n name: meta?.name,\n description: meta?.description,\n origin: entry.origin,\n });\n }\n }\n // Effects (pattern-based) — entry is { effect, when }; metadata in effectMeta\n for (const entry of this.patternEffects) {\n const meta = this.effectMeta.get(entry.effect);\n effects.push({\n channel: \"*\",\n type: \"*\",\n name: meta?.name,\n description: meta?.description,\n origin: entry.origin,\n });\n }\n\n // Middleware\n const middleware: Array<{\n name?: string;\n description?: string;\n when?: unknown;\n origin: Origin;\n }> = [];\n for (const { input: mwInput, origin } of this.middleware) {\n if (typeof mwInput === \"function\") {\n middleware.push({ name: mwInput.name || undefined, origin });\n } else {\n middleware.push({\n name: (mwInput as any).meta?.name,\n description: (mwInput as any).meta?.description,\n when: (mwInput as any).when,\n origin,\n });\n }\n }\n\n // Atomic (connect) subscriptions — enumerate from the connectorBus\n const atomic: Array<{ reducer: string; property: string }> = [];\n for (const entry of this.connectorBus.__introspect()) {\n for (let i = 0; i < entry.count; i++) {\n atomic.push({ reducer: entry.channel, property: entry.type });\n }\n }\n\n // Event subscriptions. `duringReplay` is reported so a panel can explain why a handler\n // stayed silent during a time-travel instead of leaving it looking broken.\n const event: Array<{\n channel: string;\n type: string;\n phase: string;\n duringReplay: boolean;\n }> = [];\n const collectSubscribers = (\n map: Map<string, Set<EventSubscriberEntry<DeepReadonly<S>, EM>>>,\n phase: string,\n ): void => {\n for (const [key, set] of map) {\n if (set.size === 0) continue;\n const [channel, type] = key.split(\"::\");\n for (const entry of set) {\n event.push({ channel, type, phase, duringReplay: entry.duringReplay });\n }\n }\n };\n collectSubscribers(this.committedEventSubscribers, \"committed\");\n collectSubscribers(this.uncommittedEventSubscribers, \"uncommitted\");\n collectSubscribers(this.writtenEventSubscribers, \"written\");\n collectSubscribers(this.allEventSubscribers, \"all\");\n\n // Coarse subscribers count\n const coarse = this.listeners.size;\n\n return {\n reducers,\n effects,\n middleware,\n atomic,\n event,\n coarse,\n dedupHits: this.dedupCount,\n queueDepth: this.reduceQueue.length + this.inFlightEffects,\n };\n }\n\n /**\n * Applies an externally provided **whole-state** (e.g., DevTools time travel) and emits\n * fine-grained path changes for each slice.\n *\n * **State Immutability**: If any slices change, a new state object is created via\n * shallow spread. This ensures consistent immutability with {@link commitStaged}.\n *\n * **Missing slices**: the snapshot should contain every slice. A slice absent\n * from `nextPlain` is **retained at its current value** (not blanked to\n * `undefined`, which would make `getState().<slice>` throw on next access).\n *\n * @param nextPlain - Plain JS object to become the new state.\n *\n * @internal\n */\n public __applyExternalState(nextPlain: any) {\n // Gate on the same runtime flag as __replayEvents: time-travel replaces the\n // whole state tree, so it must stay off unless the app opted in via\n // createStore({ devtools: { allowReplay: true } }). Enforced here at the\n // seam so a devtools agent (or a client driving it) cannot bypass it.\n if (!this.replayEnabled) {\n // Throws, like `__replayEvents`. Both replace state wholesale on behalf of a devtools\n // client; one refusing loudly while the other returned quietly meant a disabled seam\n // looked like a working one that had simply found nothing to do.\n throw new Error(\n \"[yoltra] External state apply (time-travel) is disabled. Enable it with createStore({ devtools: { allowReplay: true } })\",\n );\n }\n\n // Saved and restored, never set-and-clear-to-false. `__replayEvents` calls this as its\n // first step, so clearing on the way out here would unset the flag for the whole event\n // loop that follows and let every replayed event notify subscribers after all.\n const wasReplaying = this.replaying;\n this.replaying = true;\n try {\n return this.applyExternalStateInner(nextPlain);\n } finally {\n this.replaying = wasReplaying;\n }\n }\n\n /**\n * The body of {@link __applyExternalState}, with the replay flag already set.\n *\n * @internal\n */\n private applyExternalStateInner(nextPlain: any) {\n const prev = this.state as any;\n const next = nextPlain;\n\n const newState = { ...this.state } as any;\n let anyChanged = false;\n\n (Object.keys(this.reducers) as Array<R>).forEach((rName) => {\n const prevSlice = prev?.[rName];\n const nextSlice = next?.[rName];\n\n // A snapshot missing this slice must not blank it out — retain the current\n // slice (storing `undefined` would make getState().<slice>.x throw later).\n if (nextSlice === undefined) {\n // Only warn for slices the snapshot should have carried. A snapshot taken before a\n // decoration mounted legitimately lacks its slice, so warning would fire on every\n // step of every scrub and point at nothing actionable.\n if (\n process.env.NODE_ENV !== \"production\" &&\n (this.sliceOrigin.get(rName) ?? \"spec\") === \"spec\"\n ) {\n console.warn(\n `[yoltra] External state is missing slice \"${String(\n rName,\n )}\"; retaining its current value. Time-travel snapshots should contain all slices.`,\n );\n }\n return;\n }\n\n // if reference equal, nothing to emit\n if (prevSlice === nextSlice) return;\n\n // freeze the incoming slice before storing (dev-only; no deep clone — the\n // external snapshot is freshly deserialized and owned by the store)\n const frozenNextSlice = freezeInDev(nextSlice) as DeepReadonly<S[typeof rName]>;\n newState[rName] = frozenNextSlice;\n anyChanged = true;\n\n // Full dotted leaf paths relative to the slice. Unfiltered, for the reason given in\n // `stageSlice`: `\"\"` is a genuine root-level change, not an absent one. Time travel\n // onto a primitive slice committed the state here but emitted nothing, so a component\n // subscribed through `connect` kept rendering the value it had before the jump.\n const leafPaths = detectChangedProps(prevSlice, nextSlice);\n if (leafPaths.length === 0) return;\n\n // emit every leaf AND its ancestors once\n const toEmit = new Set<string>();\n for (const p of leafPaths) {\n if (p === \"\") {\n toEmit.add(\"\");\n continue;\n }\n for (const a of Store.buildAncestorPaths(p)) toEmit.add(a);\n }\n\n for (const path of toEmit) {\n const oldValue = this.getAtPath(prevSlice, path);\n const newValue = this.getAtPath(frozenNextSlice, path);\n this.connectorBus.emit(rName, path as any, { oldValue, newValue, path });\n }\n });\n\n // commit new state if any slices changed\n if (anyChanged) {\n this.state = newState as DeepReadonly<S>;\n }\n\n // coerse subscribers after all fine-grained emits (only if changed)\n if (anyChanged) {\n this.listeners.forEach((l) => l());\n }\n }\n\n /**\n * Replays a sequence of events from a snapshot through reducers and event\n * subscribers ONLY. Skips dedup, middleware, and effects.\n *\n * This method is gated by the `devtools.allowReplay` runtime config.\n * If replay is not enabled, this method throws.\n *\n * @param snapshot - The state snapshot to restore before replaying.\n * @param events - Array of events to replay (in order).\n *\n * @internal\n */\n public __replayEvents(\n snapshot: any,\n events: Array<{ channel: string; type: string; payload: any; id: string; meta?: EventMeta }>,\n ): void {\n if (!this.replayEnabled) {\n throw new Error(\n \"[yoltra] Event replay is disabled. Enable it with createStore({ devtools: { allowReplay: true } })\",\n );\n }\n\n // Wraps the whole body, snapshot included. Event subscribers are notified below, and\n // the point of the flag is that they are not - unless they asked to be.\n const wasReplaying = this.replaying;\n this.replaying = true;\n try {\n this.replayEventsInner(snapshot, events);\n } finally {\n // `finally`, so a reducer that throws mid-scrub does not leave the store believing it\n // is still replaying and silencing every subscriber from then on.\n this.replaying = wasReplaying;\n }\n }\n\n /**\n * The body of {@link __replayEvents}, with the replay flag already set.\n *\n * @internal\n */\n private replayEventsInner(\n snapshot: any,\n events: Array<{ channel: string; type: string; payload: any; id: string; meta?: EventMeta }>,\n ): void {\n // 1. Apply snapshot (restores base state)\n this.__applyExternalState(snapshot);\n\n // 2. Replay each event through reducers + event subscribers only\n for (const evt of events) {\n const event = evt as EventUnion<EM>;\n\n // Staged and committed exactly as a live event is, so a replay reproduces the same state\n // by the same path — including a reducer that refuses, which must refuse identically or\n // the replayed history is not the history.\n const staged: StagedSlice[] = [];\n this.stagingSink = staged;\n let rejection: Rejection | null = null;\n\n try {\n // Run key-based reducers via reducerBus. The event travels alongside the payload so\n // keyed reducers observe the replayed event's real id, exactly like pattern reducers.\n this.reducerBus.emit(event.channel as any, event.type as any, event.payload, event as any);\n rejection = this.stagedRejection;\n\n // Run pattern-based reducers. Guarded like the live path: one bad event in a replayed log\n // should cost that event, not abandon the replay halfway through with the store left at\n // whatever state it happened to reach.\n for (const [sliceName, when] of this.patternReducers) {\n if (rejection !== null) break;\n if (matchesWhen(when, event)) {\n const refused = this.stageSliceGuarded(sliceName, event as any, staged);\n if (refused !== null) rejection = refused;\n }\n }\n } finally {\n this.stagingSink = null;\n this.stagedRejection = null;\n this.stagedRejectedBy = \"\";\n }\n\n const anySliceChanged = rejection === null && this.commitStaged(staged, event);\n\n // Notify committed event subscribers (sync, fire-and-forget)\n this.notifyEventSubscribers(event, \"committed\");\n\n // Notify coarse subscribers if state changed\n if (anySliceChanged) {\n this.notifyEventSubscribers(event, \"written\");\n this.listeners.forEach((l) => l());\n }\n\n // NOTE: No middleware, no effects, no dedup, no DevTools logging, and no event\n // subscribers unless one opted in with `{ duringReplay: true }`. Subscribers used to\n // be missing from this list and notified anyway, so scrubbing a timeline re-ran every\n // `onEvent` handler as though the events had happened again - publishing to peers,\n // writing to sockets and firing analytics, with nothing available to detect it.\n }\n }\n\n /**\n * Emits a typed event `(channel, type, payload)`.\n * Events are queued and processed **sequentially** (FIFO).\n *\n * **Pipeline per event:** the *reduce phase* (steps 1-4) runs **synchronously**,\n * so `getState()` reflects the change as soon as `emit()` returns; the *effect\n * phase* (step 5) runs afterwards, asynchronously.\n * 1. **Deduplication** (opt-in) - Skip when content-dedup is enabled (`dedupWindowMs > 0`) or a matching `dedupKey` recurs; off by default\n * 2. **Middleware** (sync) - Pre-reducer hooks; may cancel by returning `false`\n * 3. **Reducers** (sync) - every matching slice is *staged*; nothing is written yet, so a refusal from the last reducer still stops the first one's write\n * 4. **Commit + subscribers** (sync) - all staged slices are assigned under one new root, then event subscribers (`committed`, then `written` when state actually changed), then coarse listeners\n * 5. **Effects** (async) - side-effects keyed by `(channel, type)`; the returned promise resolves once they complete\n *\n * **Change Detection**: Uses reference equality (`===`) on `this.state` to determine\n * if any slice changed. Works because the commit builds a new state reference via\n * shallow spread when any slice changes.\n *\n * @typeParam C - Channel key in `EM`.\n * @typeParam T - Type key within channel `C`.\n * @param channel - Channel name.\n * @param type - Event type name.\n * @param payload - Payload typed as `EM[C][T]`.\n * @param opts - Optional per-emit options (e.g. `dedupKey` for identity-based dedup).\n * @returns A promise that resolves once this event's effects have finished.\n * State is already updated synchronously before `emit()` returns.\n *\n * @example Basic usage\n * ```ts\n * await store.emit('ui', 'increment', 1);\n * ```\n *\n * @example With middleware cancellation\n * ```ts\n * store.registerMiddleware((state, event) => {\n * if (event.type === 'dangerous') return false; // cancel\n * return true; // allow\n * });\n *\n * await store.emit('ui', 'dangerous', null); // cancelled, no state change\n * ```\n *\n * @public\n */\n public async emit<C extends keyof EM & string, T extends keyof EM[C] & string>(\n channel: C,\n type: T,\n payload: EM[C][T],\n opts?: EmitOptions,\n ): Promise<EmitResult> {\n return this.emitCaused(null, channel, type, payload, opts);\n }\n\n /**\n * The real emit, with an explicitly supplied cause.\n *\n * @remarks\n * Exists so the parent can be passed without a pseudo-private field on the public\n * {@link EmitOptions}. Two callers supply one: the public {@link emit} passes `null` and lets\n * `currentEvent` speak for the synchronous case, and the scoped `emit` handed to effects passes\n * the event that triggered them — effects resume after the drain has ended, so nothing else\n * could still know what caused them.\n *\n * @internal\n */\n private async emitCaused<C extends keyof EM & string, T extends keyof EM[C] & string>(\n scopedParent: { id: string; depth: number; chain: readonly string[] } | null,\n channel: C,\n type: T,\n payload: EM[C][T],\n opts?: EmitOptions,\n ): Promise<EmitResult> {\n // Deduplication is OPT-IN (see EmitOptions / StoreSpec.dedupWindowMs).\n // Content-based dedup runs only when `dedupWindowMs > 0`; identity-based\n // dedup runs when an explicit `dedupKey` is supplied. By default neither is\n // active, so legitimate rapid-fire identical events are never silently dropped.\n const dedupKey = opts?.dedupKey;\n const contentWindow = this.dedupConfig.windowMs;\n // `skipDedup` wins over both the per-emit key and the store-level window: callers that\n // already guarantee distinctness must not have events silently coalesced by payload.\n if (opts?.skipDedup !== true && (contentWindow > 0 || dedupKey !== undefined)) {\n const windowMs =\n dedupKey !== undefined && contentWindow <= 0 ? DEFAULT_DEDUP_KEY_WINDOW_MS : contentWindow;\n const fp =\n dedupKey !== undefined\n ? `${channel}::${type}::#${dedupKey}`\n : this.fingerprint(channel as string, type as string, payload);\n if (this.shouldDedupe(fp, windowMs)) {\n // A suppressed duplicate never reaches middleware or a reducer, so it is neither\n // committed nor written. It carries `reason: \"deduped\"` to say so: a caller handling\n // `committed: false` needs to tell a guard refusing the action from a double-click\n // being collapsed, and those want opposite responses.\n return DEDUPED;\n }\n }\n\n // Assign a unique id and a completion deferred, resolved after this event's\n // effects run. Reducers run synchronously (see drainReduce), so state is\n // already updated before emit() returns; the returned promise tracks the\n // async effect phase for `await emit(...)`.\n const id = opts?.id ?? this.idFactory();\n\n // Causality. `currentEvent` is set only inside the synchronous drain, so if it is set this\n // emit is a consequence of that event — no matter whether the caller used the injected\n // `emit` or reached for `store.emit` directly. Outside the drain, an explicitly scoped\n // parent (given to effects, which resume after the drain has ended) supplies it instead.\n const parent = this.currentEvent ?? scopedParent;\n const depth = parent === null ? 0 : parent.depth + 1;\n\n if (parent !== null && depth > this.maxReduceDepth) {\n // Refused, not thrown: the throw would land in whichever frame happened to be emitting.\n // Guarded on `parent` as well as depth — a root is depth 0 and can only breach a ceiling\n // set below zero, and refusing the caller's own emit is never the right answer.\n this.reportCascade(\n \"maxReduceDepth\",\n this.maxReduceDepth,\n {\n channel,\n type,\n payload,\n id,\n ...(opts?.meta !== undefined ? { meta: opts.meta } : {}),\n parentId: parent.id,\n depth,\n } as EventUnion<EM>,\n depth,\n parent.chain,\n );\n return CASCADE_REFUSED;\n }\n\n let resolve!: (result: EmitResult) => void;\n const done = new Promise<EmitResult>((r) => {\n resolve = r;\n });\n\n this.reduceQueue.push({\n channel: channel as string,\n type: type as string,\n payload,\n id,\n meta: opts?.meta,\n resolve,\n // Only carried for caused events, so a root event's object stays byte-identical to one\n // built before causality existed — the same rule `meta` follows.\n ...(parent !== null ? { parentId: parent.id, depth, chain: parent.chain } : {}),\n });\n\n // Synchronous reduce phase (drains re-entrant emits too), then async effects.\n this.drainReduce();\n\n return done;\n }\n\n /**\n * Drains the reduce queue **synchronously**. For each event it runs middleware,\n * reducers, event subscribers, and coarse listeners in the same tick, so\n * `getState()` reflects the change the moment {@link emit} returns. Re-entrant\n * emits (from middleware or subscribers) are appended and drained in the same\n * pass — preserving FIFO order without interleaving reducers. Each committed\n * event's effects then run in an independent task (see {@link runEventEffects}).\n *\n * @internal\n */\n private drainReduce(): void {\n if (this.isReducing) return;\n this.isReducing = true;\n this.transitionsThisDrain = 0;\n try {\n while (this.reduceQueue.length > 0) {\n const next = this.reduceQueue.shift()!;\n const { channel, type, payload, id, meta, resolve, parentId, depth, chain } = next;\n\n // Conditional spread, not `meta` unconditionally: when no metadata was supplied the\n // event object stays byte-identical to one built before `meta` existed, so\n // Object.keys / JSON.stringify / toStrictEqual behaviour is unchanged. `parentId` and\n // `depth` follow the same rule, and are absent on a root event.\n const event = {\n channel,\n type,\n payload,\n id,\n ...(meta !== undefined ? { meta } : {}),\n ...(parentId !== undefined ? { parentId, depth } : {}),\n } as EventUnion<EM>;\n\n // Width ceiling, checked as the event is dequeued rather than as it is emitted: a burst\n // is only excessive relative to the pass draining it, and at emit time there is no pass\n // yet. Off unless configured — see StoreSpec.maxTransitionsPerDrain.\n //\n // The root is never refused. It is the caller's own emit, not part of any burst, and a\n // ceiling that rejected it would turn \"this store's cascades are bounded\" into \"this\n // store randomly drops the event you just sent\". Only what the drain caused can be\n // excessive, which is also why `depth` and `chain` are known to be set here.\n if (parentId !== undefined && ++this.transitionsThisDrain > this.maxTransitionsPerDrain) {\n this.reportCascade(\n \"maxTransitionsPerDrain\",\n this.maxTransitionsPerDrain,\n event,\n depth as number,\n chain as readonly string[],\n );\n // Resolve rather than abandon: a caller awaiting this emit would otherwise hang, which\n // is the failure the ceiling exists to prevent, arriving by another door.\n resolve(CASCADE_REFUSED);\n continue;\n }\n\n // Anything emitted from here until the end of this iteration is caused by this event.\n // The drain is synchronous, so this is exact rather than a heuristic — and it holds even\n // when a consumer calls `store.emit` directly instead of the injected `emit`.\n this.currentEvent = {\n id,\n depth: depth ?? 0,\n chain: [...(chain ?? []), id].slice(-CASCADE_CHAIN_LIMIT),\n };\n\n // Instrumentation: capture prev state, collect changed paths, and time\n // the synchronous reduce — all skipped entirely when no observers.\n const instrumenting = this.instrumentObservers.size > 0;\n const prevState = instrumenting ? this.state : undefined;\n const sink: string[] | undefined = instrumenting ? [] : undefined;\n if (sink !== undefined) this.changedPathSink = sink;\n const t0 = instrumenting ? now() : 0;\n\n let result: EmitResult = NOT_COMMITTED;\n try {\n result = this.applyEventSync(event);\n } catch (err) {\n console.error(\"Emit reduce error:\", err);\n } finally {\n if (instrumenting) this.changedPathSink = null;\n // Cleared before effects are scheduled. Effects resume in a later task, when this\n // event is no longer what the drain is processing; they carry their cause explicitly\n // through the scoped emit instead.\n this.currentEvent = null;\n }\n\n if (instrumenting) {\n this.emitInstrumentation(\n event,\n result,\n sink ?? [],\n prevState as DeepReadonly<S>,\n now() - t0,\n );\n }\n\n // Run this event's effects as an independent task and resolve its\n // completion deferred when they finish. Independent per-event tasks\n // (rather than one shared serialized loop) let an effect `await` a\n // re-entrant emit without deadlocking.\n void this.runEventEffects(event, result, resolve);\n }\n } finally {\n this.isReducing = false;\n }\n }\n\n /**\n * Runs the **synchronous** part of the pipeline for a single event: middleware\n * (may veto), key- and pattern-based reducers, committed/uncommitted event\n * subscribers (fire-and-forget), and coarse listeners.\n *\n * @returns `true` if the event was committed (passed middleware), `false` if a\n * middleware vetoed it.\n *\n * @internal\n */\n private applyEventSync(event: EventUnion<EM>): EmitResult {\n // Middleware (synchronous). Return `false` to veto; async work belongs in effects.\n for (const { input: mwInput } of this.middleware) {\n const when = getMiddlewareWhen(mwInput);\n if (!matchesWhen(when, event)) continue;\n const mw = getMiddlewareFunction(mwInput);\n let ok: boolean | void;\n try {\n ok = mw(this.state, event, this.emit);\n if (\n process.env.NODE_ENV !== \"production\" &&\n typeof (ok as unknown as { then?: unknown })?.then === \"function\"\n ) {\n // A Promise is truthy, so an async middleware silently allows everything: the event\n // commits while the middleware is still deciding, and the veto it was written to\n // perform can never fire. Caught here because the symptom — a rule that simply does\n // not apply — looks nothing like its cause.\n console.error(\n `[yoltra] Middleware for \"${event.channel}/${event.type}\" returned a Promise. ` +\n `Middleware is synchronous: a Promise is truthy, so this event was allowed ` +\n `without waiting and a \"return false\" inside it can never veto. Do the check ` +\n `synchronously, and put anything that must await in an effect.`,\n );\n }\n } catch (err) {\n // A throw is still a veto: middleware guards things, and a guard that crashed has\n // not decided the event is safe. But say so, because \"the event vanished\" and \"the\n // middleware threw\" look nothing alike from the outside.\n console.error(\n `[yoltra] Middleware threw for \"${event.channel}/${event.type}\"; the event was ` +\n `vetoed and did not reach any reducer.`,\n err,\n );\n ok = false;\n }\n // Only an explicit `false` vetoes. Middleware that does its work and falls off the end\n // has an opinion about nothing, and the safe reading of \"no opinion\" is \"allow\" - the\n // previous `!ok` test made a missing `return` swallow every event the middleware\n // matched, which surfaces as reducers quietly stopping for one channel and looks like\n // a routing, `when` or registration-order problem. Nothing about it points at the\n // middleware.\n if (ok === false) {\n // Rejected by middleware - notify uncommitted subscribers, do not commit.\n this.notifyEventSubscribers(event, \"uncommitted\");\n // Named, so \"the event vanished\" has an author. A reducer refusal has always named\n // its slice; a veto named nobody.\n const vetoedBy =\n typeof mwInput === \"function\" ? mwInput.name || undefined : mwInput.meta?.name;\n return Object.freeze({\n committed: false,\n written: false,\n reason: \"vetoed\" as const,\n ...(vetoedBy !== undefined && vetoedBy !== \"\" ? { vetoedBy } : {}),\n });\n }\n }\n\n // Reduce every matching slice into a staging list. Nothing is written yet, so a refusal\n // arriving from the last reducer can still stop the first one's write.\n const staged: StagedSlice[] = [];\n this.stagingSink = staged;\n let rejection: Rejection | null = null;\n let rejectedBy = \"\";\n\n try {\n // Pass the event itself, not just the payload: keyed reducers are wired through\n // `reducerBus` in `mountSlice` and would otherwise have to invent an id.\n this.reducerBus.emit(\n event.channel as any,\n event.type as any,\n event.payload as any,\n event as any,\n );\n rejection = this.stagedRejection;\n rejectedBy = this.stagedRejectedBy;\n\n for (const [sliceName, when] of this.patternReducers) {\n if (rejection !== null) break;\n if (matchesWhen(when, event)) {\n const refused = this.stageSliceGuarded(sliceName, event as any, staged);\n if (refused !== null) {\n rejection = refused;\n rejectedBy = sliceName as string;\n }\n }\n }\n } finally {\n this.stagingSink = null;\n this.stagedRejection = null;\n this.stagedRejectedBy = \"\";\n }\n\n // A refusal discards every staged slice, not just the refusing one. Authorising a write to\n // one slice while a sibling records it as accepted is not authorisation — and a caller told\n // \"rejected\" must not find half of its event applied.\n if (rejection !== null) {\n this.onRejected?.(rejection, event, rejectedBy);\n this.notifyEventSubscribers(event, \"committed\");\n return { committed: true, written: false, rejected: rejection };\n }\n\n const written = this.commitStaged(staged, event);\n\n // Committed subscribers fire whether or not anything was written — `committed` means \"not\n // vetoed\", which is what a notification or analytics bus depends on. `written` is the\n // stricter fact, and fires after the commit so a handler reading getState() sees it.\n this.notifyEventSubscribers(event, \"committed\");\n if (written) {\n this.notifyEventSubscribers(event, \"written\");\n this.listeners.forEach((l) => l());\n }\n return written ? WRITTEN : COMMITTED_UNWRITTEN;\n }\n\n /**\n * Runs a single committed event's effects as an **independent async task**,\n * then resolves that event's completion deferred so `await emit(...)` settles\n * once its effects finish. Per-event tasks (rather than one shared serialized\n * loop) let an effect `await` a re-entrant emit without deadlocking.\n *\n * @internal\n */\n private async runEventEffects(\n event: EventUnion<EM>,\n result: EmitResult,\n resolve: (result: EmitResult) => void,\n ): Promise<void> {\n this.inFlightEffects++;\n try {\n if (result.committed) await this.notifyEffects(event);\n } catch (err) {\n console.error(\"Effect error:\", err);\n } finally {\n this.inFlightEffects--;\n resolve(result);\n }\n }\n\n /**\n * Registers an instrumentation observer. See {@link StoreInstance.instrument}.\n *\n * @public\n */\n public instrument(observer: InstrumentationObserver<EM>): Unsubscribe {\n this.instrumentObservers.add(observer);\n return () => {\n this.instrumentObservers.delete(observer);\n };\n }\n\n /**\n * Builds an {@link InstrumentedEvent} from the reduce result and notifies\n * observers. `changedPaths` are the exact slice-prefixed leaf paths recorded\n * by {@link commitStaged} during this reduce, so DevTools patches need no\n * re-diff.\n *\n * @internal\n */\n private emitInstrumentation(\n event: EventUnion<EM>,\n result: EmitResult,\n changedPaths: string[],\n prevState: DeepReadonly<S>,\n reduceTimeMs: number,\n ): void {\n const prevValues: Record<string, unknown> = {};\n const nextValues: Record<string, unknown> = {};\n for (const path of changedPaths) {\n prevValues[path] = this.getAtPath(prevState, path);\n nextValues[path] = this.getAtPath(this.state, path);\n }\n const info: InstrumentedEvent<EM> = {\n event: {\n id: event.id,\n channel: event.channel as string,\n type: event.type as string,\n payload: event.payload,\n // Conditional, so an event without metadata produces an observer payload\n // byte-identical to the pre-`meta` shape.\n ...(event.meta !== undefined ? { meta: event.meta } : {}),\n },\n committed: result.committed,\n changedPaths,\n prevValues,\n nextValues,\n reduceTimeMs,\n // Present only when a reducer refused, so an observer can tell a refusal from a veto —\n // identical in state, entirely different in cause.\n ...(result.rejected !== undefined ? { rejected: result.rejected } : {}),\n };\n for (const observer of [...this.instrumentObservers]) {\n try {\n observer(info);\n } catch (e) {\n console.error(\"Instrumentation observer error:\", e);\n }\n }\n }\n\n /**\n * Connects a **fine-grained** listener to a dotted path under a slice.\n *\n * @param spec - `{ reducer, property }` where `property` is a dotted path (e.g., `\"items.0.title\"`).\n * Supports wildcards: `*` (one segment) and `**` (zero or more segments).\n * @param h - Handler receiving a {@link Change} with `{ oldValue, newValue, path }`.\n * @returns Unsubscribe function.\n *\n * @example Exact path\n * ```ts\n * const off = store.connect(\n * { reducer: 'todos', property: 'items.0.title' },\n * (chg) => console.log('title changed:', chg.newValue)\n * );\n * off();\n * ```\n *\n * @example Wildcard pattern\n * ```ts\n * // Listen to any item title change\n * const off = store.connect(\n * { reducer: 'todos', property: 'items.*.title' },\n * (chg) => console.log('some title changed')\n * );\n * ```\n *\n * @public\n */\n public connect(\n spec: { reducer: R; property: string },\n h: (chg: Change) => void,\n options?: ConnectOptions,\n ): () => void {\n // The one place the type/runtime gap after a disposal can be caught. A widened type\n // still promises a slice its owner has unmounted, and TypeScript cannot express\n // \"valid until that call\" - so the silent `undefined` a component would read becomes a\n // named error instead. Development only; one Set and one membership test.\n if (\n process.env.NODE_ENV !== \"production\" &&\n this.disposedSlices.has(spec.reducer as unknown as string)\n ) {\n const owner = this.disposedSlices.get(spec.reducer as unknown as string);\n throw new Error(\n `[yoltra] Slice \"${String(spec.reducer)}\" was unmounted by its owner` +\n `${owner === undefined ? \"\" : ` (${owner})`}. Hooks and subscriptions widened for ` +\n `it are no longer valid.`,\n );\n }\n\n const off = this.connectorBus.on(spec.reducer, spec.property, h);\n\n if (options?.immediate === true) {\n // @ts-expect-error R indexing on DeepReadonly<S> is valid at runtime\n const slice = this.state[spec.reducer] as unknown;\n // A pattern matches a set of paths, and a set has no single current value — so the slice\n // root is delivered instead, at the path a whole-slice subscription would use.\n // Same test the bus uses to tell a pattern from an exact path.\n const path = spec.property.includes(\"*\") ? \"\" : spec.property;\n\n // No `eventId`, `channel` or `type`: nothing caused this, and inventing a cause would be\n // a lie a subscriber could act on. `oldValue` is undefined for the same reason — there is\n // no previous value, only a first one.\n h({ oldValue: undefined, newValue: this.getAtPath(slice, path), path });\n }\n\n return off;\n }\n\n /**\n * Subscribe to reducer, middleware and effect registrations.\n *\n * Delivered as an array, one batch per public call: `replaceReducers` unmounts and then\n * remounts, and a per-change observer would see a spurious unmount of a slice that is only\n * being updated. Observers run after the state broadcast, and a registration made by an\n * observer is queued rather than delivered re-entrantly.\n *\n * Replay never produces a change, so there is no `duringReplay` option here. `dispose()`\n * fires nothing.\n *\n * @param observer - Receives one batch per registration change.\n * @param options - `emitCurrent` synthesizes a `'mounted'` batch for everything already\n * installed, delivered synchronously before this call returns, carrying each registration's\n * real origin rather than a synthetic marker.\n * @returns Unsubscribe function.\n *\n * @example\n * ```ts\n * const off = store.onRegistrationChange((changes) => {\n * for (const c of changes) {\n * console.log(c.op, c.kind, c.name, c.origin);\n * }\n * }, { emitCurrent: true });\n * off();\n * ```\n *\n * @public\n */\n public onRegistrationChange(\n observer: RegistrationObserver<EM>,\n options?: { emitCurrent?: boolean },\n ): Unsubscribe {\n this.registrationObservers.add(observer);\n\n if (options?.emitCurrent === true) {\n const current = this.describeCurrentRegistrations();\n // Synchronously, before returning. Pull-then-subscribe would be two shapes and a race\n // to reason about; this is one shape and no race by construction.\n //\n // Flagged while delivering, so a registration made from inside this very snapshot is\n // queued like any other rather than re-entering the notifier. Without the flag an\n // observer that registers on first sight of the store broke the documented contract\n // on the one call most likely to do it.\n if (current.length > 0) {\n const wasNotifying = this.notifyingRegistrations;\n this.notifyingRegistrations = true;\n try {\n this.invokeRegistrationObserver(observer, current);\n } finally {\n this.notifyingRegistrations = wasNotifying;\n }\n if (!wasNotifying) this.drainQueuedRegistrationBatches();\n }\n }\n\n return () => {\n this.registrationObservers.delete(observer);\n };\n }\n\n /**\n * Everything currently installed, as `\"mounted\"` changes.\n *\n * @internal\n */\n private describeCurrentRegistrations(): RegistrationChange<EM>[] {\n const out: RegistrationChange<EM>[] = [];\n\n for (const name of Object.keys(this.reducers)) {\n out.push({\n kind: \"reducer\",\n op: \"mounted\",\n name,\n // The real origin, never a synthetic \"existing\" marker. Filtering on provenance is\n // the main thing an observer does, and a snapshot that lied about it would break\n // exactly the registrations that were already there.\n origin: this.sliceOrigin.get(name) ?? \"spec\",\n owner: this.sliceOwner.get(name),\n when: this.patternReducers.get(name as R),\n // From this observer's point of view the state exists; it never saw a prior value.\n state: \"initialized\",\n dispatch: this.patternReducers.has(name as R) ? \"pattern\" : \"keyed\",\n });\n }\n for (const entry of this.middleware) {\n const meta = typeof entry.input === \"function\" ? undefined : entry.input.meta;\n out.push({\n kind: \"middleware\",\n op: \"mounted\",\n name: meta?.name ?? (typeof entry.input === \"function\" ? entry.input.name : undefined),\n description: meta?.description,\n origin: entry.origin,\n when: getMiddlewareWhen(entry.input),\n dispatch: \"pattern\",\n });\n }\n for (const [key, set] of this.effects) {\n const [channel, type] = key.split(\"::\");\n for (const entry of set) {\n out.push({\n kind: \"effect\",\n op: \"mounted\",\n name: this.effectMeta.get(entry.effect)?.name,\n description: this.effectMeta.get(entry.effect)?.description,\n origin: entry.origin,\n when: { keys: [[channel, type]] } as When<EM>,\n dispatch: \"keyed\",\n });\n }\n }\n for (const entry of this.patternEffects) {\n out.push({\n kind: \"effect\",\n op: \"mounted\",\n name: this.effectMeta.get(entry.effect)?.name,\n description: this.effectMeta.get(entry.effect)?.description,\n origin: entry.origin,\n when: entry.when,\n dispatch: \"pattern\",\n });\n }\n return out;\n }\n\n /**\n * Runs `fn` as one registration transaction, flushing a single batch at the outermost end.\n *\n * @internal\n */\n private inRegistrationTransaction<T>(fn: () => T): T {\n this.registrationDepth += 1;\n try {\n return fn();\n } finally {\n this.registrationDepth -= 1;\n if (this.registrationDepth === 0) this.flushRegistrationChanges();\n }\n }\n\n /**\n * Records a change, to be delivered when the current transaction ends.\n *\n * @remarks\n * Guarded on observer count **before** anything is allocated. These call sites run inside\n * `createStore`, so a twenty-slice store with nobody listening must build no objects and\n * no arrays at all - the same discipline `emitInstrumentation` already follows.\n *\n * @internal\n */\n private recordRegistrationChange(make: () => RegistrationChange<EM>): void {\n if (this.registrationObservers.size === 0) return;\n (this.pendingRegistrationChanges ??= []).push(make());\n if (this.registrationDepth === 0) this.flushRegistrationChanges();\n }\n\n /** @internal */\n private flushRegistrationChanges(): void {\n const batch = this.pendingRegistrationChanges;\n this.pendingRegistrationChanges = null;\n if (batch === null || batch.length === 0) return;\n\n if (this.notifyingRegistrations) {\n // An observer registered something of its own. That is the legitimate\n // ordering-dependency case, so it is neither forbidden nor delivered re-entrantly:\n // queued, and drained once the current notification finishes.\n this.queuedRegistrationBatches.push(batch);\n return;\n }\n\n this.notifyingRegistrations = true;\n try {\n this.deliverRegistrationBatch(batch);\n this.drainQueuedRegistrationBatches();\n } finally {\n this.notifyingRegistrations = false;\n }\n }\n\n /**\n * Delivers batches an observer produced while being notified.\n *\n * @remarks\n * Bounded like the reduce depth, and for the same reason: two observers registering in\n * response to each other would otherwise loop forever. Logged rather than thrown - the\n * topology is correct at that point, and throwing would truncate the stream *and* unwind a\n * caller that did nothing wrong.\n *\n * @internal\n */\n private drainQueuedRegistrationBatches(): void {\n let drained = 0;\n while (this.queuedRegistrationBatches.length > 0) {\n if (drained >= MAX_REGISTRATION_CASCADE) {\n console.error(\n `[yoltra] Registration notifications exceeded ${MAX_REGISTRATION_CASCADE} rounds; ` +\n `dropping the rest. Two observers are most likely registering in response to ` +\n `each other.`,\n );\n this.queuedRegistrationBatches.length = 0;\n break;\n }\n drained += 1;\n this.deliverRegistrationBatch(this.queuedRegistrationBatches.shift()!);\n }\n }\n\n /** @internal */\n private deliverRegistrationBatch(batch: readonly RegistrationChange<EM>[]): void {\n // Snapshot before iterating, like every other observer seam here: an observer added\n // during a notification does not receive the batch it was added in.\n for (const observer of [...this.registrationObservers]) {\n this.invokeRegistrationObserver(observer, batch);\n }\n }\n\n /** @internal */\n private invokeRegistrationObserver(\n observer: RegistrationObserver<EM>,\n batch: readonly RegistrationChange<EM>[],\n ): void {\n try {\n const result = observer(batch) as unknown;\n if (\n process.env.NODE_ENV !== \"production\" &&\n typeof (result as Promise<unknown>)?.then === \"function\"\n ) {\n // Deliberately not awaited, and deliberately not `.catch`ed either: we are not\n // adopting this promise. Registration notification is synchronous, so by the time it\n // resolves the store has moved on and anything it does lands at an unpredictable\n // point relative to everything else.\n console.error(\n \"[yoltra] A registration observer returned a Promise. Registration notifications \" +\n \"are synchronous: the store has already moved on by the time it resolves. Do the \" +\n \"work synchronously, or schedule it yourself and accept that the topology may \" +\n \"have changed again.\",\n );\n }\n } catch (e) {\n console.error(\"Registration observer error:\", e);\n }\n }\n\n public get isReplaying(): boolean {\n return this.replaying;\n }\n\n /**\n * Subscribe to events by channel and type.\n *\n * Event subscriptions are intended for the View layer (e.g., React components)\n * to react to events without affecting the event flow. They are fire-and-forget\n * and cannot cancel event propagation.\n *\n * **Phases:**\n * - `'committed'` (default): Events that passed middleware and reached reducers.\n * Notified after reducers, before effects.\n * - `'uncommitted'`: Events rejected by middleware. Notified immediately after rejection.\n * - `'written'`: Events that actually changed state. Stricter than `committed`, which\n * fires for every event a store accepts including one with no reducers at all.\n * - `'all'`: Both committed and uncommitted events. Handler receives the phase parameter\n * to distinguish between the two. Deliberately not `written` as well: an event that\n * writes is also committed, so folding it in would notify every existing `all`\n * subscriber twice for one event.\n *\n * **Replay:** a handler is not called while devtools is replaying, unless it opted in with\n * `{ duringReplay: true }`.\n *\n * @typeParam C - Channel key within `EM`.\n * @typeParam T - Event type key within channel `C`.\n * @param channel - Channel to subscribe to.\n * @param type - Event type to subscribe to.\n * @param handler - Handler function `(event, getState, emit, phase)`.\n * @param phase - Event phase to subscribe to (default: `'committed'`).\n * @returns Unsubscribe function.\n *\n * @example Committed events (default)\n * ```ts\n * const off = store.onEvent('ui', 'save', (event, getState, emit, phase) => {\n * console.log('Save committed:', event.payload);\n * });\n * off();\n * ```\n *\n * @example Uncommitted (rejected) events\n * ```ts\n * store.onEvent('ui', 'delete', (event, getState, emit, phase) => {\n * console.log('Delete was rejected by middleware');\n * }, 'uncommitted');\n * ```\n *\n * @example All events\n * ```ts\n * store.onEvent('ui', 'action', (event, getState, emit, phase) => {\n * console.log('Action:', phase); // 'committed' or 'uncommitted'\n * }, 'all');\n * ```\n *\n * @public\n */\n public onEvent<C extends keyof EM & string, T extends keyof EM[C] & string>(\n channel: C,\n type: T,\n handler: NarrowedEventHandler<DeepReadonly<S>, EM, C, T>,\n phase: EventPhase = \"committed\",\n options?: { duringReplay?: boolean },\n ): Unsubscribe {\n const key = `${channel}::${String(type)}`;\n\n const targetMap =\n phase === \"committed\"\n ? this.committedEventSubscribers\n : phase === \"uncommitted\"\n ? this.uncommittedEventSubscribers\n : phase === \"written\"\n ? this.writtenEventSubscribers\n : this.allEventSubscribers;\n\n if (!targetMap.has(key)) {\n targetMap.set(key, new Set());\n }\n // An entry per subscription, not the bare handler. Storing the function meant two\n // subscriptions sharing one handler were one Set member, so disposing either removed\n // both - and it left nowhere to record the replay opt-in.\n const entry: EventSubscriberEntry<DeepReadonly<S>, EM> = {\n handler: handler as EventSubscriptionHandler<DeepReadonly<S>, EM>,\n duringReplay: options?.duringReplay === true,\n };\n targetMap.get(key)!.add(entry);\n\n return () => {\n const set = targetMap.get(key);\n if (set) {\n set.delete(entry);\n if (set.size === 0) targetMap.delete(key);\n }\n };\n }\n\n /**\n * Subscribes to **coarse-grained** commits (called once per successful event, only if state changed).\n *\n * **Use Case**: React's `useSyncExternalStore` or similar external store integrations.\n *\n * @param fn - Listener invoked after reducers/effects have run and state has changed.\n * @returns Unsubscribe function.\n *\n * @example\n * ```ts\n * const off = store.subscribe(() => console.log('state committed'));\n * // Later:\n * off();\n * ```\n *\n * @public\n */\n public subscribe(fn: () => void): () => void {\n this.listeners.add(fn);\n return () => this.listeners.delete(fn);\n }\n\n /**\n * Returns the current immutable state snapshot.\n *\n * @returns Deep-readonly state object.\n *\n * @example\n * ```ts\n * const state = store.getState();\n * console.log(state.counter.value);\n * ```\n *\n * @public\n */\n public getState(): DeepReadonly<S> {\n return this.state;\n }\n\n /**\n * Registers a middleware (runs **before** reducers).\n *\n * @param mw - Middleware `(state, event, emit) => boolean`. Return `false` to cancel event\n * propagation.\n * @returns Unsubscribe function that removes this middleware.\n *\n * @remarks\n * **Synchronous, and that is the contract.** The reduce phase completes before `emit()`\n * returns, so the commit decision has to be available in the same tick. An `async` middleware\n * returns a Promise, every Promise is truthy, and the veto would therefore never fire — the\n * event would commit while the middleware was still deciding. The type rejects it; this note\n * exists because the examples here used to teach it. Do authorization and validation here, and\n * anything that needs to await in an effect.\n *\n * @example Logging middleware\n * ```ts\n * const off = store.registerMiddleware((state, event) => {\n * console.log('Event:', event.channel, event.type, event.payload);\n * return true; // allow\n * });\n * off();\n * ```\n *\n * @example Cancellation middleware\n * ```ts\n * store.registerMiddleware((state, event) => {\n * if (event.type === 'forbidden') return false; // cancel\n * return true;\n * });\n * ```\n *\n * @public\n */\n public registerMiddleware(mw: MiddlewareInput<DeepReadonly<S>, EM>): any {\n const entry = { input: mw, origin: \"dynamic\" as Origin };\n this.middleware.push(entry);\n this.recordMiddlewareChange(entry, \"mounted\");\n return this.asRegistration(() => {\n // Spliced by entry identity. `indexOf` on the function meant registering the same\n // middleware twice and disposing once removed the first registration rather than the\n // one being disposed.\n const i = this.middleware.indexOf(entry);\n // Idempotent: a second call must not re-announce a removal that already happened.\n if (i === -1) return;\n this.middleware.splice(i, 1);\n // Announced *after* the splice, so an observer that reads the store sees it gone.\n this.recordMiddlewareChange(entry, \"unmounted\");\n });\n }\n\n /**\n * Turns a disposer into the callable object `register*` returns.\n *\n * @remarks\n * `Object.assign` onto the function rather than a new object, so every existing call site\n * keeps working verbatim: `const off = store.registerEffect(spec); off();` compiles and\n * runs exactly as before, while `.store` and `.dispose` become available to a library that\n * wants the widened type.\n *\n * A callable object rather than an overload or a second method: an overload cannot change\n * the return shape based on nothing, and a parallel `registerSliceX` family would leave\n * the originals permanently second class and force libraries to branch on the core version.\n *\n * @internal\n */\n private recordMiddlewareChange(\n entry: { input: MiddlewareInput<DeepReadonly<S>, EM>; origin: Origin },\n op: \"mounted\" | \"unmounted\",\n ): void {\n this.recordRegistrationChange(() => {\n const meta = typeof entry.input === \"function\" ? undefined : entry.input.meta;\n return {\n kind: \"middleware\",\n op,\n name: meta?.name ?? (typeof entry.input === \"function\" ? entry.input.name : undefined),\n description: meta?.description,\n origin: entry.origin,\n when: getMiddlewareWhen(entry.input),\n dispatch: \"pattern\",\n };\n });\n }\n\n /**\n * Drops an effect's metadata only once nothing is still registered with it.\n *\n * @remarks\n * `effectMeta` is keyed by the effect *function*, and the same function can legitimately\n * back several registrations. Deleting on the first disposal stripped the name and\n * description of the ones still live, which a devtools panel then showed as unnamed.\n *\n * @internal\n */\n private releaseEffectMeta(effect: EffectFunction<DeepReadonly<S>, EM>): void {\n for (const set of this.effects.values()) {\n for (const entry of set) if (entry.effect === effect) return;\n }\n for (const entry of this.patternEffects) if (entry.effect === effect) return;\n this.effectMeta.delete(effect);\n }\n\n /** @internal */\n private recordEffectChange(\n effect: EffectFunction<DeepReadonly<S>, EM>,\n when: When<EM> | undefined,\n origin: Origin,\n op: \"mounted\" | \"unmounted\",\n dispatch: \"keyed\" | \"pattern\",\n ): void {\n this.recordRegistrationChange(() => ({\n kind: \"effect\",\n op,\n name: this.effectMeta.get(effect)?.name,\n description: this.effectMeta.get(effect)?.description,\n origin,\n when,\n dispatch,\n }));\n }\n\n /** @internal */\n private asRegistration(dispose: () => void): any {\n return Object.assign(dispose, { store: this, dispose });\n }\n\n /**\n * The one place the widening cast lives.\n *\n * @remarks\n * Decoration is type-level only. This returns the **same runtime object**: subscriptions,\n * effects, middleware, the dedup cache, both buses and any in-flight `call()` are\n * untouched, and nothing re-subscribes. Keeping the cast here means no call site needs one,\n * which is the entire point of the feature.\n *\n * @internal\n */\n private widened(): any {\n return this;\n }\n\n /**\n * Dynamically **adds** a named slice reducer at runtime.\n *\n * @param name - New slice name (must not already exist).\n * @param spec - Reducer spec (state, when, reducer).\n * @returns Disposer function that **removes** the slice (and its state).\n *\n * @example\n * ```ts\n * const dispose = store.registerReducer('filters', {\n * state: { q: '' },\n * events: [['ui', 'setQuery']],\n * reducer(s, evt) {\n * return evt.type === 'setQuery' ? { q: evt.payload } : s;\n * }\n * });\n * // Later:\n * dispose();\n * ```\n *\n * @public\n */\n public registerReducer(name: string, spec: ReducerSpec<any, EM>, options?: { owner?: string }): any {\n return this.registerSlice(name, spec as any, options);\n }\n\n /**\n * Mounts a slice and hands back the widened store alongside a disposer.\n *\n * @remarks\n * The name `registerSlice` is what the guide uses; `registerReducer` keeps its broader\n * `name: string` signature and delegates here, so existing call sites are untouched.\n *\n * @public\n */\n public registerSlice(name: string, spec: ReducerSpec<any, EM>, options?: { owner?: string }): any {\n // One transaction, so observers are notified *after* the state broadcast below rather\n // than from inside `mountSlice`. The view layer should learn a fact before a library\n // gets to react to it; reversed, a library's own registration would publish before the\n // originating one had reached the UI.\n return this.inRegistrationTransaction(() => this.registerSliceInner(name, spec, options));\n }\n\n /** @internal */\n private registerSliceInner(\n name: string,\n spec: ReducerSpec<any, EM>,\n options?: { owner?: string },\n ): any {\n // `hasOwnProperty`, not `in`: the registry is a plain object, so `in` also answers true for\n // everything on `Object.prototype`. A slice legitimately named `toString`, `constructor` or\n // `valueOf` was refused as already existing — with a message naming a reducer that does not\n // exist, which is the least useful place to send someone.\n if (Object.prototype.hasOwnProperty.call(this.reducers, name)) {\n throw new Error(`Reducer ${name} already exists`);\n }\n\n this.mountSlice(name as R, spec as ReducerSpec<S[R], EM>, {\n preserveState: false,\n origin: \"dynamic\",\n owner: options?.owner,\n });\n\n this.listeners.forEach((l) => l()); // broadcast new slice\n // And the fine-grained bus, or `useAtomicProp` would never learn the slice exists.\n this.announceMountedSlice(name, (this.state as any)[name]);\n\n return this.asRegistration(() => {\n // Idempotent. A second call used to re-announce the unmount and re-broadcast to every\n // listener, for a slice that had already gone.\n if (!Object.prototype.hasOwnProperty.call(this.reducers, name)) return;\n this.inRegistrationTransaction(() => {\n this.unmountSlice(name as R, { deleteState: true });\n this.listeners.forEach((l) => l());\n });\n });\n }\n\n /**\n * Mounts a slice and returns the widened store, for chaining.\n *\n * @remarks\n * No disposer, deliberately. After a disposer runs, the widened type still promises a\n * slice that is gone, and TypeScript cannot express \"valid until that call\". The chaining\n * API therefore does not hand one out, so the footgun does not exist on the path most\n * people take; {@link registerSlice} carries one for the library that owns the slice, and\n * the documented rule is that a disposer stays library-private.\n *\n * @public\n */\n public withSlice(name: string, spec: ReducerSpec<any, EM>, options?: { owner?: string }): any {\n this.registerSlice(name, spec, options);\n return this.widened();\n }\n\n /**\n * Registers middleware and returns the widened store, for chaining.\n *\n * @public\n */\n public withMiddleware(mw: MiddlewareInput<DeepReadonly<S>, EM>): any {\n this.registerMiddleware(mw);\n return this.widened();\n }\n\n /**\n * Registers an effect and returns the widened store, for chaining.\n *\n * @public\n */\n public withEffect(spec: EffectSpec<DeepReadonly<S>, EM>): any {\n this.registerEffect(spec);\n return this.widened();\n }\n\n /**\n * Registers an **effect** (stateless async event consumer) that runs after reducers.\n *\n * Effects are **keyed** by `(channel, type)` for O(1) lookup (no scanning all effects).\n *\n * @param spec - Effect specification with `when` targeting and `effect` (handler).\n * @returns Unsubscribe function.\n *\n * @example Logging effect\n * ```ts\n * const off = store.registerEffect({\n * events: [['ui', 'increment']],\n * effect: async (evt, getState, emit) => {\n * console.log('increment', evt.payload, getState().counter.value);\n * }\n * });\n * off();\n * ```\n *\n * @example Multi-event effect\n * ```ts\n * store.registerEffect({\n * events: [['ui', 'increment'], ['ui', 'decrement']],\n * effect: async (evt, getState, emit) => {\n * // Runs for both increment and decrement\n * await saveToServer(getState());\n * }\n * });\n * ```\n *\n * @public\n */\n /**\n * Sends a request and waits for the reply, correlating the two automatically.\n *\n * @typeParam C - Request channel.\n * @typeParam T - Request type within `C`.\n * @param channel - Channel to send on.\n * @param type - Event type to send.\n * @param payload - The **request** payload. This is what you are sending; what comes back is\n * described by {@link CallOptions.reply}, not by this.\n * @param opts - Which replies end the call, and how long to wait. See {@link CallOptions}.\n * @returns A {@link CallHandle}: `await` it for the terminal reply, or `for await` it for\n * progress events as they arrive.\n *\n * @remarks\n * Every consumer of an event bus eventually writes request/reply by hand — mint an id,\n * subscribe, match, time out, unsubscribe — and every one of them writes the same eighty lines\n * with the same two bugs: the subscription outlives the call, and a responder that forgets to\n * echo the id produces a timeout with nothing to point at. This is that, once.\n *\n * **Correlation is causal.** The store stamps `parentId` on anything emitted while an event is\n * being handled, so a responder that replies through the `emit` it was handed is already\n * correlated. There is no id to mint, echo, or forget:\n *\n * ```ts\n * store.registerEffect({\n * when: { keys: [[\"rpc\", \"ask\"]] },\n * effect: async (event, _get, emit) => {\n * await emit(\"rpc\", \"answer\", await lookup(event.payload.q));\n * },\n * });\n * ```\n *\n * **The reply carries its own discriminant.** A call resolves to the *event*, not the payload,\n * because a caller often cannot know which kind of reply it will get:\n *\n * ```ts\n * const res = await store.call(\"rpc\", \"ask\", { q }, { reply: [\"rpc\", [\"answer\", \"error\"]] });\n * switch (res.type) {\n * case \"answer\": return res.payload;\n * case \"error\": throw new Error(res.payload.reason);\n * }\n * ```\n *\n * **Progress streams, with backpressure.** Any correlated event that is not terminal is\n * progress, and iterating the call consumes it. The producer genuinely waits: `emit` resolves\n * only once its effects have run, and the collector is an effect that does not return until the\n * consumer has taken the item. A responder writing `await emit(\"rpc\", \"progress\", chunk)` is\n * therefore paced by the reader, with nothing buffering without bound.\n *\n * ```ts\n * const call = store.call(\"job\", \"start\", { id }, {\n * reply: [\"job\", \"done\"],\n * highWaterMark: 4,\n * });\n * for await (const step of call) await render(step.payload); // producer waits on this\n * const { payload } = await call;\n * ```\n *\n * Backpressure engages **once you begin iterating**. A call that is only awaited never pulls,\n * so blocking its producer would deadlock the call itself — progress nobody reads would stop\n * the terminal event from ever being sent. Un-iterated progress therefore buffers to\n * `highWaterMark` and is then counted on {@link CallHandle.dropped} rather than blocking.\n *\n * **This is a local primitive.**\n *\n * @example Timeout is idle, not total\n * ```ts\n * // Survives a job that streams for minutes; fails a responder that goes quiet for 5s.\n * await store.call(\"job\", \"start\", { id }, { reply: [\"job\", \"done\"], timeoutMs: 5_000 });\n * ```\n *\n * @example Cancelling\n * ```ts\n * const call = store.call(\"rpc\", \"ask\", { q }, { reply: [\"rpc\", \"answer\"] });\n * useEffect(() => () => call.cancel(\"unmounted\"), [call]);\n * ```\n *\n * @public\n */\n public call<C extends keyof EM & string, T extends keyof EM[C] & string>(\n channel: C,\n type: T,\n payload: EM[C][T],\n opts: CallOptions<EM>,\n ): CallHandle<EventUnion<EM>, EventUnion<EM>> {\n return performCall<S, EM, C, T>(\n {\n idFactory: this.idFactory,\n // `internal`, so an in-flight call survives even `replaceEffects(next, { scope: \"all\" })`.\n // A test harness resetting a store between cases never means \"and abandon the call\n // that is currently awaiting a reply\", and the symptom would be a hang to the idle\n // timeout with nothing pointing at the reset.\n registerEffect: (effSpec) => this.registerEffectWithOrigin(effSpec, \"internal\"),\n emit: this.emit,\n },\n channel,\n type,\n payload,\n opts,\n );\n }\n\n public registerEffect(spec: EffectSpec<DeepReadonly<S>, EM>): any {\n return this.asRegistration(this.registerEffectWithOrigin(spec, \"dynamic\"));\n }\n\n /**\n * {@link registerEffect}, with the provenance the caller cannot set.\n *\n * @remarks\n * Kept private so no origin parameter leaks into `StoreInstance`. Three callers: the\n * constructor (`spec`), the public method (`dynamic`), and `store.call()` (`internal`).\n *\n * @internal\n */\n private registerEffectWithOrigin(\n spec: EffectSpec<DeepReadonly<S>, EM>,\n origin: Origin,\n ): () => void {\n const { effect, meta, when } = spec;\n const unsubs: Array<() => void> = [];\n\n // Record metadata in a store-owned map keyed by the effect function, rather\n // than mutating the caller's function (which would bleed across stores).\n if (meta) {\n this.effectMeta.set(effect, meta);\n }\n\n // Check if this is a pattern-based effect (any, channel, channels)\n // or a key-based effect (keys, or no targeting = all events)\n const isPatternBased =\n when &&\n ((\"any\" in when && when.any === true) ||\n \"channel\" in when ||\n \"channels\" in when);\n\n if (isPatternBased) {\n // Store as pattern-based effect for runtime matching\n const entry = { effect, when: when!, origin };\n this.patternEffects.add(entry);\n this.recordEffectChange(effect, when!, origin, \"mounted\", \"pattern\");\n\n return () => {\n this.recordEffectChange(effect, when!, origin, \"unmounted\", \"pattern\");\n this.patternEffects.delete(entry);\n this.releaseEffectMeta(effect);\n };\n }\n\n // Key-based effect: normalize to event keys\n const eventKeys = normalizeEventKeys(spec);\n\n // If no keys (no targeting at all), this effect matches ALL events\n // We treat it as a pattern-based effect with `any: true`\n if (eventKeys.length === 0 && !when) {\n // Normalized, not raw: no targeting at all means \"every event\", and an observer told\n // `undefined` would have to re-derive that for itself.\n const normalized = { any: true } as When<EM>;\n const entry = { effect, when: normalized, origin };\n this.patternEffects.add(entry);\n this.recordEffectChange(effect, normalized, origin, \"mounted\", \"pattern\");\n\n return () => {\n this.recordEffectChange(effect, normalized, origin, \"unmounted\", \"pattern\");\n this.patternEffects.delete(entry);\n this.releaseEffectMeta(effect);\n };\n }\n\n // Register for specific event keys\n for (const [channel, type] of eventKeys) {\n const key = `${String(channel)}::${String(type)}`;\n if (!this.effects.has(key)) {\n this.effects.set(key, new Set());\n }\n const entry = { effect, origin };\n this.effects.get(key)!.add(entry);\n const keyedWhen = { keys: [[channel, type]] } as When<EM>;\n this.recordEffectChange(effect, keyedWhen, origin, \"mounted\", \"keyed\");\n\n // Create disposer\n unsubs.push(() => {\n this.recordEffectChange(effect, keyedWhen, origin, \"unmounted\", \"keyed\");\n const set = this.effects.get(key);\n if (set) {\n set.delete(entry);\n if (set.size === 0) this.effects.delete(key);\n }\n });\n }\n\n return () => {\n for (const u of unsubs) u();\n this.releaseEffectMeta(effect);\n };\n }\n\n\n\n /**\n * Convenience helper to register an **effect** filtered by a single `(channel, type)` pair.\n *\n * @typeParam C - Channel key within `EM`.\n * @typeParam T - Event type key within channel `C`.\n * @param channel - Channel to filter.\n * @param type - Event type to filter.\n * @param handler - Effect handler `(payload, getState, emit, event)`.\n * @returns Unsubscribe/teardown function.\n *\n * @example\n * ```ts\n * const off = store.onEffect('ui', 'increment', async (n, get, emit) => {\n * if (n > 10) await emit('ui', 'increment', -10);\n * });\n * // later\n * off();\n * ```\n *\n * @public\n */\n public onEffect<\n C extends keyof EM & string,\n T extends keyof EM[C] & string\n >(\n channel: C,\n type: T,\n handler: (\n payload: EM[C][T],\n getState: () => DeepReadonly<S>,\n emit: Emit<EM>,\n event: Event<EM, C, T>,\n ) => void | Promise<void>,\n ): () => void {\n const effect: EffectFunction<DeepReadonly<S>, EM> = async (evt, getState, emit) => {\n if (evt.channel !== channel || evt.type !== type) return;\n\n const typed = evt as Event<EM, C, T>;\n return handler(typed.payload, getState, emit, typed);\n };\n\n return this.registerEffect({\n when: { keys: [[channel, type] as EventKey<EM>] },\n effect,\n });\n }\n\n /**\n * Replaces the **entire** middleware pipeline (HMR-friendly).\n *\n * @param next - New middleware array.\n *\n * @example Hot module replacement\n * ```ts\n * if (import.meta.hot) {\n * import.meta.hot.accept('./middleware', (newModule) => {\n * store.replaceMiddleware(newModule.middleware);\n * });\n * }\n * ```\n *\n * @public\n */\n public replaceMiddleware(\n next: MiddlewareInput<DeepReadonly<S>, EM>[],\n opts: { scope?: ReplaceScope } = {},\n ): void {\n this.inRegistrationTransaction(() => this.replaceMiddlewareInner(next, opts));\n }\n\n /** @internal */\n private replaceMiddlewareInner(\n next: MiddlewareInput<DeepReadonly<S>, EM>[],\n opts: { scope?: ReplaceScope } = {},\n ): void {\n // Accepts either form. Taking only the bare function meant a hot reload silently discarded\n // the `when` targeting and `meta` of every spec-form middleware, so after an HMR pass a\n // middleware scoped to one channel began running on all of them.\n const scope = opts.scope ?? \"spec\";\n const retained = this.middleware.filter((e) =>\n scope === \"all\" ? e.origin === \"internal\" : e.origin !== \"spec\",\n );\n // Recorded explicitly: this truncates the array rather than going through\n // `registerMiddleware`, so nothing else would notice the entries leaving.\n for (const entry of this.middleware) {\n if (!retained.includes(entry)) this.recordMiddlewareChange(entry, \"unmounted\");\n }\n (this.middleware as any).length = 0;\n // Order matters and is reproduced rather than incidental: spec middleware exists at\n // construction and dynamic middleware is appended after it, so new spec entries go first\n // and retained ones follow. A dynamic auth guard silently moving from first to last\n // changes which events get vetoed, and nothing about the symptom would point here.\n for (const mw of next) {\n const entry = { input: mw, origin: \"spec\" as Origin };\n this.middleware.push(entry);\n this.recordMiddlewareChange(entry, \"mounted\");\n }\n for (const entry of retained) this.middleware.push(entry);\n this.reportPreserved(\"replaceMiddleware\", retained.length, scope);\n }\n\n /**\n * Replaces all registered **effects** (HMR-friendly).\n *\n * @param next - New effects array (as EffectSpecs).\n *\n * @example Hot module replacement\n * ```ts\n * if (import.meta.hot) {\n * import.meta.hot.accept('./effects', (newModule) => {\n * store.replaceEffects(newModule.effects);\n * });\n * }\n * ```\n *\n * @public\n */\n public replaceEffects(\n next: Array<EffectSpec<DeepReadonly<S>, EM>>,\n opts: { scope?: ReplaceScope } = {},\n ): void {\n this.inRegistrationTransaction(() => this.replaceEffectsInner(next, opts));\n }\n\n /** @internal */\n private replaceEffectsInner(\n next: Array<EffectSpec<DeepReadonly<S>, EM>>,\n opts: { scope?: ReplaceScope } = {},\n ): void {\n const scope = opts.scope ?? \"spec\";\n const keeps = (origin: Origin): boolean =>\n scope === \"all\" ? origin === \"internal\" : origin !== \"spec\";\n\n let preserved = 0;\n for (const [key, set] of this.effects) {\n for (const entry of [...set]) {\n if (keeps(entry.origin)) {\n preserved += 1;\n continue;\n }\n this.recordEffectChange(\n entry.effect,\n { keys: [key.split(\"::\") as [string, string]] } as When<EM>,\n entry.origin,\n \"unmounted\",\n \"keyed\",\n );\n set.delete(entry);\n // Pruned per dropped function rather than wholesale. `effectMeta` was never cleared\n // here at all, so it grew stale entries forever; clearing all of it would instead\n // strip the metadata of every effect being preserved.\n this.releaseEffectMeta(entry.effect);\n }\n if (set.size === 0) this.effects.delete(key);\n }\n for (const entry of [...this.patternEffects]) {\n if (keeps(entry.origin)) {\n preserved += 1;\n continue;\n }\n this.recordEffectChange(entry.effect, entry.when, entry.origin, \"unmounted\", \"pattern\");\n this.patternEffects.delete(entry);\n this.releaseEffectMeta(entry.effect);\n }\n\n for (const spec of next) {\n this.registerEffectWithOrigin(spec, \"spec\");\n }\n this.reportPreserved(\"replaceEffects\", preserved, scope);\n }\n\n /**\n * Replaces the entire **reducer set** (HMR-friendly).\n *\n * @param next - Map of slice specs keyed by slice name.\n * @param opts - `{ preserveState?: boolean }` (default `true`) and\n * `{ scope?: \"spec\" | \"all\" }` (default `\"spec\"`).\n *\n * @remarks\n * Replaces **spec-provenance slices only**. A slice mounted after construction with\n * `registerSlice` survives, along with its state: it was never part of the set this call\n * is replacing. Pass `{ scope: \"all\" }` for the pre-0.8.0 wholesale behaviour.\n *\n * Throws, before mutating anything, if `next` names a slice a library mounted at runtime.\n *\n * @example Hot module replacement\n * ```ts\n * if (import.meta.hot) {\n * import.meta.hot.accept('./reducers', (newModule) => {\n * store.replaceReducers(newModule.reducers, { preserveState: true });\n * });\n * }\n * ```\n *\n * @public\n */\n public replaceReducers(\n next: Record<R, ReducerSpec<S[R], EM>>,\n opts: { preserveState?: boolean; scope?: ReplaceScope } = {},\n ): void {\n this.inRegistrationTransaction(() => this.replaceReducersInner(next, opts));\n }\n\n /** @internal */\n private replaceReducersInner(\n next: Record<R, ReducerSpec<S[R], EM>>,\n opts: { preserveState?: boolean; scope?: ReplaceScope } = {},\n ): void {\n const preserveState = opts.preserveState !== false; // default true\n const scope = opts.scope ?? \"spec\";\n\n const currentKeys = new Set(Object.keys(this.reducers as any));\n const nextEntries = Object.entries(next);\n const nextKeys = new Set(nextEntries.map(([k]) => k));\n\n this.assertNoSliceCollision(next, scope);\n\n const rootBefore = this.state;\n\n // Remove slices that no longer exist - but only the ones this call owns. A slice a\n // library mounted with `registerReducer` was never in the set `replaceReducers` is\n // replacing, and no caller of `replaceReducers(myReducers)` means \"and also delete the\n // slice devtools or a decoration mounted, along with its state\".\n let preserved = 0;\n for (const k of currentKeys) {\n if (nextKeys.has(k)) continue;\n const origin = this.sliceOrigin.get(k) ?? \"spec\";\n const removable = scope === \"all\" ? origin !== \"internal\" : origin === \"spec\";\n if (!removable) {\n preserved += 1;\n continue;\n }\n this.unmountSlice(k as R, { deleteState: true });\n }\n\n // Add or update slices\n for (const [k, rSpec] of nextEntries) {\n if (currentKeys.has(k)) {\n // Update reducer impl + event wiring; preserve current state\n this.unmountSlice(k as R, { deleteState: false });\n this.mountSlice(k as R, rSpec as any, { preserveState, origin: \"spec\" });\n } else {\n // New slice\n this.mountSlice(k as R, rSpec as any, { preserveState: false, origin: \"spec\" });\n }\n }\n\n // `registerReducer` has always broadcast after mounting and this never did, so a React\n // tree went on rendering the pre-reload state after an HMR pass until something else\n // happened to wake it. Gated on root identity, so an all-preserving replace costs\n // nothing.\n if (this.state !== rootBefore) this.listeners.forEach((l) => l());\n\n this.reportPreserved(\"replaceReducers\", preserved, scope);\n }\n\n /**\n * Refuses, before anything is mutated, to take over a slice mounted at runtime.\n *\n * @remarks\n * An application authoring a slice a library owns is a real mistake, and a silent takeover\n * is the worst available outcome: the library keeps a disposer for a slice that is no\n * longer its own. Throwing part-way through would be worse still, which is why this runs\n * as a pre-flight and why `hotReplace` calls it before swapping anything at all.\n *\n * @internal\n */\n private assertNoSliceCollision(\n next: Record<string, unknown>,\n scope: ReplaceScope,\n ): void {\n if (scope !== \"spec\") return;\n const collisions = Object.keys(next).filter(\n (k) => this.sliceOrigin.get(k) === \"dynamic\",\n );\n if (collisions.length === 0) return;\n\n const named = collisions\n .map((k) => {\n const owner = this.sliceOwner.get(k);\n return owner === undefined ? `\"${k}\"` : `\"${k}\" (owner: ${owner})`;\n })\n .join(\", \");\n throw new Error(\n `[yoltra] replaceReducers would take over ${collisions.length === 1 ? \"a slice\" : \"slices\"} ` +\n `mounted at runtime: ${named}. Rename the slice, or pass { scope: \"all\" } to replace ` +\n `it deliberately.`,\n );\n }\n\n /**\n * Says what a `replace*` call left alone, when it left anything alone.\n *\n * @remarks\n * Development only, and silent unless something was actually preserved, so the normal HMR\n * path stays quiet. `console.debug` rather than `warn`: this is correct operation, and\n * every existing `warn` in this file marks a genuine problem. It exists so \"why is that\n * effect still firing after a reload\" has an answer that does not require reading core.\n *\n * @internal\n */\n private reportPreserved(method: string, count: number, scope: ReplaceScope): void {\n if (count === 0) return;\n if (process.env.NODE_ENV === \"production\") return;\n console.debug(\n `[yoltra] ${method} preserved ${count} registration${count === 1 ? \"\" : \"s\"} made after ` +\n `construction.${scope === \"spec\" ? ' Pass { scope: \"all\" } to replace them too.' : \"\"}`,\n );\n }\n\n /**\n * Convenience API to replace **any subset** of store parts (HMR patterns).\n *\n * @param partial - Partial replacement set.\n *\n * @example Replace everything\n * ```ts\n * store.hotReplace({\n * reducer: newReducers,\n * middleware: newMiddleware,\n * effects: newEffects,\n * preserveState: true\n * });\n * ```\n *\n * @public\n */\n public hotReplace(partial: {\n reducer?: Record<R, ReducerSpec<S[R], EM>>;\n middleware?: MiddlewareInput<DeepReadonly<S>, EM>[];\n effects?: Array<EffectSpec<DeepReadonly<S>, EM>>;\n preserveState?: boolean;\n scope?: ReplaceScope;\n }): void {\n // `scope` is forwarded to all three rather than living on `replaceReducers` alone: this\n // is the documented HMR entry point, and a harness that wants the old wholesale\n // semantics should need one flag, not three.\n const scope = partial.scope;\n\n // Checked up front, across the whole call. `replaceReducers` refuses to take over a\n // slice a library owns, and that refusal used to fire *after* middleware and effects had\n // already been swapped - leaving the new module's middleware running against the old\n // reducers, which is a worse state than either before or after. A partial hot reload is\n // harder to diagnose than a refused one.\n if (partial.reducer) this.assertNoSliceCollision(partial.reducer, scope ?? \"spec\");\n\n // One transaction across all three, so a hot reload produces a single batch rather than\n // three snapshots of a topology mid-rebuild.\n this.inRegistrationTransaction(() => {\n if (partial.middleware) this.replaceMiddleware(partial.middleware, { scope });\n if (partial.effects) this.replaceEffects(partial.effects, { scope });\n if (partial.reducer)\n this.replaceReducers(partial.reducer, { preserveState: partial.preserveState, scope });\n });\n }\n\n /**\n * Mounts a slice: installs reducer, initializes state (unless preserved),\n * and wires `(channel, type)` listeners on the reducer bus.\n *\n * @param name - Slice name.\n * @param rSpec - Reducer spec (state, when, reducer).\n * @param opts - `{ preserveState: boolean }` whether to keep existing state.\n *\n * @internal\n */\n private mountSlice(\n name: R,\n rSpec: ReducerSpec<S[R], EM>,\n opts: { preserveState: boolean; origin?: Origin; owner?: string },\n ): void {\n this.mountSliceInner(name, rSpec, opts);\n // Recorded here, not inside the body. The body returns early for a pattern-based slice,\n // so a record placed at its end fired only for keyed slices and `{ any: true }` slices\n // were never reported at all.\n this.recordSliceChange(\n name as unknown as string,\n \"mounted\",\n opts.preserveState ? \"preserved\" : \"initialized\",\n );\n }\n\n /** @internal */\n private mountSliceInner(\n name: R,\n rSpec: ReducerSpec<S[R], EM>,\n opts: { preserveState: boolean; origin?: Origin; owner?: string },\n ): void {\n const rName = name as unknown as string;\n this.sliceOrigin.set(rName, opts.origin ?? \"spec\");\n if (opts.owner !== undefined) this.sliceOwner.set(rName, opts.owner);\n // Remounting under the same name makes the slice valid again.\n this.disposedSlices.delete(rName);\n const { reducer, state, when } = rSpec;\n\n // Install reducer instance (FIXED: only pass reducer function)\n this.reducers[name] = new Reducer(reducer);\n\n // Initialize state unless preserving an existing value\n if (!opts.preserveState || (this.state as any)[rName] === undefined) {\n // A NEW root, not a write into the existing one. Mounting a slice is a state change, and\n // anything keyed on root identity — `useSelector` bailing out on `Object.is`, a memo, a\n // devtools snapshot differ — could not see it when the root object stayed the same.\n // Clone the caller's initial state so the store owns an independent copy; freeze is\n // dev-only.\n this.state = {\n ...(this.state as object),\n [rName]: freezeInDev(cloneInitialState(rName, state)),\n } as DeepReadonly<S>;\n }\n\n // Check if this is a pattern-based reducer (any, channel, channels)\n const isPatternBased =\n when &&\n ((\"any\" in when && when.any === true) ||\n \"channel\" in when ||\n \"channels\" in when);\n\n if (isPatternBased) {\n // Store as pattern-based reducer for runtime matching\n this.patternReducers.set(name, when);\n // No unsubs needed for pattern reducers - they're called from emit loop\n this.sliceUnsubs.set(rName, []);\n return;\n }\n\n // Normalize event keys from `when: { keys }`\n const eventKeys = normalizeEventKeys(rSpec);\n\n // If no targeting at all, treat as \"all events\" (pattern-based)\n if (eventKeys.length === 0 && !when) {\n this.patternReducers.set(name, { any: true });\n this.sliceUnsubs.set(rName, []);\n return;\n }\n\n // Wire reducerBus listeners and save disposers for HMR\n const unsubs: Array<() => void> = [];\n for (const [ch, tp] of eventKeys) {\n const u = this.reducerBus.on(ch, tp, (payload, sourceEvent) => {\n // Prefer the source event so keyed reducers see the same `id` (and `meta`) as\n // pattern reducers, effects, event subscribers and instrumentation. The fallback\n // only applies when something emits on `reducerBus` without an event.\n const event = (sourceEvent ?? {\n channel: ch,\n type: tp,\n payload,\n id: this.idFactory(),\n }) as Event<EM, typeof ch, typeof tp>;\n // Staged, not committed. `reducerBus` delivers to handlers and has no return channel,\n // so a refusal is recorded on the store for `applyEventSync` to read — the same reason\n // `changedPathSink` exists. The sink is null outside a reduce, which is the only path\n // that can reach here.\n if (this.stagingSink === null) return;\n const refused = this.stageSliceGuarded(name, event as any, this.stagingSink);\n if (refused !== null && this.stagedRejection === null) {\n this.stagedRejection = refused;\n this.stagedRejectedBy = name as string;\n }\n });\n\n unsubs.push(u);\n }\n\n this.sliceUnsubs.set(rName, unsubs);\n }\n\n /**\n * Records a slice mount or unmount for {@link onRegistrationChange}.\n *\n * @internal\n */\n private recordSliceChange(\n rName: string,\n op: \"mounted\" | \"unmounted\",\n state: \"initialized\" | \"preserved\" | \"deleted\" | \"retained\",\n ): void {\n this.recordRegistrationChange(() => ({\n kind: \"reducer\",\n op,\n name: rName,\n origin: this.sliceOrigin.get(rName) ?? \"spec\",\n owner: this.sliceOwner.get(rName),\n when: this.patternReducers.get(rName as R),\n state,\n dispatch: this.patternReducers.has(rName as R) ? \"pattern\" : \"keyed\",\n }));\n }\n\n /**\n * Announces a newly mounted slice on the connector bus.\n *\n * @remarks\n * `registerReducer` has always broadcast to `listeners`, which wakes `subscribe` and so\n * `useSelector`. It emitted **nothing** on `connectorBus`, which is what `connect` rides,\n * so `useAtomicProp`, `useAtomicProps` and the Suspense hooks never woke for a slice\n * mounted after creation: a component subscribed to a path inside it simply never\n * re-rendered. That makes the decoration story ship a documented-as-working path that does\n * not work, which is why this is here rather than filed as a follow-up.\n *\n * Scope, stated precisely because it is narrower than it looks: this emits the slice root\n * and its **top-level** keys, which is exactly what an ordinary commit emits when a\n * subtree first appears - `detectChangedProps` reports a newly-appearing branch at its\n * root, not leaf by leaf. So a `connect` on `\"deep.n\"` does not fire here, and does not\n * fire on a normal commit that first creates `deep` either. Consistent, not complete.\n *\n * Skipped when nothing is subscribed, and skipped entirely during construction, where no\n * subscriber can exist yet.\n *\n * @internal\n */\n private announceMountedSlice(rName: string, nextSlice: unknown): void {\n // Diffed against an empty object rather than `undefined`. `detectChangedProps(undefined,\n // x)` reports only `\"\"`, the root, so a subscriber watching `\"n\"` inside the new slice\n // would hear nothing at all - which is the very failure this method exists to fix.\n const isObjectLike = typeof nextSlice === \"object\" && nextSlice !== null;\n const leafPaths = detectChangedProps(isObjectLike ? {} : undefined, nextSlice);\n\n // The root always appears: a whole-slice subscription (`property: \"\"`) is watching for\n // exactly this, and a slice that *is* one value has no leaf to report.\n const toEmit = new Set<string>([\"\"]);\n for (const p of leafPaths) {\n if (p === \"\") continue;\n for (const a of Store.buildAncestorPaths(p)) toEmit.add(a);\n }\n\n for (const path of toEmit) {\n const newValue = this.getAtPath((this.state as any)[rName], path);\n this.connectorBus.emit(rName as R, path as any, {\n oldValue: undefined,\n newValue,\n path,\n });\n }\n }\n\n /**\n * Unmounts a slice: disposes reducer-bus listeners, removes reducer,\n * and optionally deletes the slice state.\n *\n * @param name - Slice name.\n * @param opts - `{ deleteState: boolean }`.\n *\n * @internal\n */\n private unmountSlice(name: R, opts: { deleteState: boolean }): void {\n const rName = name as unknown as string;\n // Recorded before the registries are torn down, while origin and owner are still known.\n // `retained` rather than `deleted` when the state survives: `replaceReducers` updates a\n // slice by unmounting and remounting it, and an observer that treated every unmount as\n // destruction would tear down a subscription it is about to need.\n this.recordSliceChange(rName, \"unmounted\", opts.deleteState ? \"deleted\" : \"retained\");\n\n // Remove from pattern reducers if present\n this.patternReducers.delete(name);\n if (process.env.NODE_ENV !== \"production\") {\n const origin = this.sliceOrigin.get(rName);\n if (origin === \"dynamic\" || origin === \"internal\") {\n this.disposedSlices.set(rName, this.sliceOwner.get(rName));\n while (this.disposedSlices.size > MAX_REMEMBERED_DISPOSED_SLICES) {\n // Map preserves insertion order, so the first key is the oldest.\n this.disposedSlices.delete(this.disposedSlices.keys().next().value as string);\n }\n }\n }\n this.sliceOrigin.delete(rName);\n this.sliceOwner.delete(rName);\n\n // Dispose reducerBus listeners\n const unsubs = this.sliceUnsubs.get(rName);\n if (unsubs) {\n for (const u of unsubs)\n try {\n u();\n } catch (e) {\n console.error(`[Store error]: ${e}`);\n }\n\n this.sliceUnsubs.delete(rName);\n }\n\n // Remove reducer instance\n delete this.reducers[name];\n\n // Optionally drop state\n if (opts.deleteState) {\n const { [rName]: _removed, ...rest } = this.state as Record<string, unknown>;\n this.state = rest as DeepReadonly<S>;\n }\n }\n\n /**\n * Reads a dotted path from an object (supports numeric array indices via string keys).\n *\n * @param obj - Root object (slice or value).\n * @param path - Dotted path; leading dot is ignored.\n * @returns The value at the path, or `undefined`.\n *\n * @remarks\n * A member rather than a bare import: a test replaces this on the instance to count how many\n * walks describing a change costs, which only works while the callers go through `this`.\n *\n * @internal\n */\n private getAtPath(obj: any, path: string): any {\n return readAtPath(obj, path);\n }\n\n /**\n * Builds ancestor paths for a dotted path.\n *\n * For `\"a.b.c\"`, returns `[\"a\", \"a.b\", \"a.b.c\"]`. Leading dots are trimmed.\n *\n * @param path - Dotted path string.\n * @returns Array of ancestor paths.\n *\n * @example\n * ```ts\n * Store.buildAncestorPaths('x.y.z'); // ['x','x.y','x.y.z']\n * ```\n *\n * @public\n */\n static buildAncestorPaths(path: string): string[] {\n return ancestorPaths(path);\n }\n}\n\n/**\n * Creates a store with explicit State and EventMap types.\n *\n * Use this overload for:\n * - **Event-only stores** (no reducers, just middleware/effects)\n * - When TypeScript inference from reducers isn't sufficient\n * - When you want to define the EventMap independently of reducers\n *\n * @typeParam S - State record type (can be empty `{}` for event-only stores).\n * @typeParam EM - Event map type defining all `channel → type → payload` combinations.\n * @param cfg - Configuration with `name`, optional `reducer`, optional `middleware`, optional `effects`.\n * @returns A typed {@link StoreInstance}.\n *\n * @example Event-only store\n * ```ts\n * type AppEM = {\n * notifications: { show: { message: string }; hide: void };\n * };\n *\n * const store = createStore<{}, AppEM>({\n * name: 'NotificationBus',\n * effects: [{\n * when: { channel: 'notifications' },\n * effect: (evt) => {\n * if (evt.type === 'show') showToast(evt.payload.message);\n * },\n * }],\n * });\n * ```\n *\n * @example Explicit generics with reducers\n * ```ts\n * const store = createStore<AppState, AppEM>({\n * name: 'App',\n * reducer: { counter: counterSpec },\n * middleware: [loggingMiddleware],\n * });\n * ```\n *\n * @public\n */\nexport function createStore<\n S extends Record<string, any>,\n EM extends EventMapBase,\n>(cfg: {\n name: string;\n reducer?: { [K in keyof S]?: ReducerSpec<S[K], EM> };\n middleware?: MiddlewareInput<DeepReadonly<S>, EM>[];\n effects?: Array<EffectSpec<DeepReadonly<S>, EM>>;\n dedupWindowMs?: number;\n idFactory?: () => string;\n devtools?: { allowReplay?: boolean };\n onEffectError?: (error: unknown, event: EventUnion<EM>) => void;\n onReducerError?: (error: unknown, event: EventUnion<EM>, slice: string) => void;\n onSubscriberError?: (error: unknown, event: EventUnion<EM>, phase: NotifiedPhase) => void;\n maxReduceDepth?: number;\n maxTransitionsPerDrain?: number;\n onCascade?: (info: CascadeInfo<EM>) => void;\n onRejected?: (rejection: Rejection, event: EventUnion<EM>, slice: string) => void;\n}): StoreInstance<keyof S & string, S, EM>;\n\n/**\n * Creates a store with types inferred from the reducers map.\n *\n * This is the primary overload for most use cases where reducers define\n * both the state shape and the event map.\n *\n * @typeParam RM - Reducers map object with each slice's `ReducerSpec`.\n * @param cfg - Configuration with `name`, `reducer`, optional `middleware`, optional `effects`.\n * @returns A typed {@link StoreInstance}.\n *\n * @example\n * ```ts\n * const store = createStore({\n * name: 'App',\n * reducer: {\n * counter: {\n * state: { value: 0 },\n * when: { keys: eventKeys<MyEM>()([['ui', 'increment']]) },\n * reducer: (s, evt) => evt.type === 'increment' ? { value: s.value + evt.payload } : s\n * }\n * },\n * middleware: [],\n * effects: []\n * });\n * ```\n *\n * @public\n */\nexport function createStore<RM extends ReducersMapAny>(cfg: {\n name: string;\n reducer: RM;\n middleware?: MiddlewareInput<\n DeepReadonly<StateFromReducers<RM>>,\n EMFromReducersStrict<RM>\n >[];\n effects?: Array<EffectSpec<DeepReadonly<StateFromReducers<RM>>, EMFromReducersStrict<RM>>>;\n dedupWindowMs?: number;\n idFactory?: () => string;\n devtools?: { allowReplay?: boolean };\n onEffectError?: (error: unknown, event: EventUnion<EMFromReducersStrict<RM>>) => void;\n onReducerError?: (\n error: unknown,\n event: EventUnion<EMFromReducersStrict<RM>>,\n slice: string,\n ) => void;\n onSubscriberError?: (\n error: unknown,\n event: EventUnion<EMFromReducersStrict<RM>>,\n phase: NotifiedPhase,\n ) => void;\n maxReduceDepth?: number;\n maxTransitionsPerDrain?: number;\n onCascade?: (info: CascadeInfo<EMFromReducersStrict<RM>>) => void;\n onRejected?: (\n rejection: Rejection,\n event: EventUnion<EMFromReducersStrict<RM>>,\n slice: string,\n ) => void;\n}): StoreInstance<keyof RM & string, StateFromReducers<RM>, EMFromReducersStrict<RM>>;\n\nexport function createStore(cfg: any) {\n type RM = typeof cfg.reducer;\n type S = StateFromReducers<RM>;\n type EM = EMFromReducersStrict<RM>;\n type RN = keyof RM & string;\n\n // Spread, then override the three fields that need a default. Copying the option list by hand\n // meant every option added to `StoreSpec` had to be added here too, and forgetting was silent:\n // the option type-checked at the call site, reached `createStore`, and was dropped on the\n // floor. `maxReduceDepth` was lost exactly that way. The Store constructor reads named fields,\n // so anything extra in `cfg` is ignored rather than harmful.\n return new Store<EM, RN, S>({\n ...cfg,\n reducer: (cfg.reducer ?? {}) as unknown as Record<RN, ReducerSpec<S[RN], EM>>,\n middleware: (cfg.middleware ?? []) as any,\n effects: (cfg.effects ?? []) as any,\n });\n}\n\n/**\n * Utility to define **typed** `(channel, events[])` definitions for reducer specs.\n *\n * @typeParam EM - Event map for the store.\n * @param _ - Internal marker parameter (usually `events` array placeholder). Not used at runtime.\n * @returns A helper that, given a `channel` and a readonly `events` array, returns typed event keys.\n *\n * @example\n * ```ts\n * // In a ReducerSpec:\n * const events = typedEvents<EM>([])('ui', ['increment', 'decrement'] as const);\n * // events: ReadonlyArray<EventKey<EM>>\n * ```\n *\n * @public\n */\nexport const typedEvents = <EM extends EventMapBase>(_: string[][]) =>\n <C extends keyof EM & string, Evt extends readonly (keyof EM[C] & string)[]>(\n channel: C,\n events: Evt,\n ): ReadonlyArray<EventKey<EM>> => events.map((e) => [channel, e] as const);","/**\n * @module @yoltra/core\n */\n\nimport type { Rejection } from \"./store/rejection\";\nimport type { CallHandle, CallOptions } from \"./store/call\";\n\n/**\n * A minimal \"record of record\" constraint for EventMaps.\n *\n * @example\n * ```ts\n * type EM = {\n * ui: { toggle: boolean; setTheme: string };\n * data: { loaded: { items: string[] } };\n * };\n * ```\n *\n * @public\n */\nexport type EventMapBase = {\n [C in string]: { [T in string]: unknown };\n};\n\n/**\n * Canonical routing concept: a readonly tuple `[channel, type]` that uniquely identifies an event.\n *\n * @typeParam EM - Event map.\n *\n * @remarks\n * - Used consistently across ReducerSpec, EffectSpec, and React hooks.\n * - Literal key lists narrow channel/type/payload in reducers and effects.\n * - Non-literal usage degrades safely to unions.\n *\n * @example\n * ```ts\n * type EM = {\n * ui: { increment: number; decrement: number };\n * data: { loaded: string[] };\n * };\n *\n * type K = EventKey<EM>;\n * // K = ['ui', 'increment'] | ['ui', 'decrement'] | ['data', 'loaded']\n *\n * const key: EventKey<EM> = ['ui', 'increment'];\n * ```\n *\n * @public\n */\nexport type EventKey<EM extends EventMapBase> = {\n [C in keyof EM & string]: [C, keyof EM[C] & string];\n}[keyof EM & string];\n\n/**\n * Opaque, optional envelope metadata carried alongside an {@link Event}.\n *\n * @remarks\n * The store never reads, validates or acts on this — it only carries it end to end, so\n * reducers, middleware, effects, event subscribers and instrumentation all observe the same\n * value. It is deliberately untyped at this level: consumers namespace their own keys (for\n * example a tracing integration keeping provenance under `meta.trace`) rather than\n * extending core with domain concepts.\n *\n * It is **not** part of the deduplication fingerprint, which is computed from\n * `(channel, type, payload)` only. Two events differing solely in `meta` still dedupe.\n *\n * @example\n * ```ts\n * await store.emit('orders', 'created', payload, {\n * meta: { trace: { origin: 'checkout-service', hop: 1 } },\n * });\n * ```\n *\n * @public\n */\nexport type EventMeta = Readonly<Record<string, unknown>>;\n\n/**\n * A single event object: `{ channel, type, payload, id }`, plus optional `meta`.\n *\n * @typeParam EM - Event map.\n * @typeParam C - Channel key.\n * @typeParam T - Type key within channel `C`.\n * @typeParam P - Payload type (defaults to `EM[C][T]`).\n *\n * @remarks\n * - The `id` field is automatically added by the store to enable deduplication, unless the\n * emitter supplies one via {@link EmitOptions.id}.\n * - Used for preventing duplicate event processing (e.g., React Strict Mode).\n * - `meta` is present only when {@link EmitOptions.meta} was supplied. See {@link EventMeta}.\n *\n * @example\n * ```ts\n * type EM = { ui: { toggle: boolean } };\n * type Evt = Event<EM, 'ui', 'toggle'>;\n * // { channel: 'ui'; type: 'toggle'; payload: boolean; id: string; meta?: EventMeta }\n * ```\n *\n * @public\n */\nexport interface Event<\n EM extends EventMapBase = EventMapBase,\n C extends keyof EM & string = keyof EM & string,\n T extends keyof EM[C] & string = keyof EM[C] & string,\n P = EM[C][T],\n> {\n channel: C;\n type: T;\n payload: P;\n /** Unique identifier for deduplication and devtools tracking (automatically added by store) */\n id: string;\n /**\n * Optional caller-supplied metadata, carried through the pipeline untouched.\n * Absent entirely unless {@link EmitOptions.meta} was supplied. See {@link EventMeta}.\n */\n readonly meta?: EventMeta;\n /**\n * The `id` of the event whose handling caused this one, when there was one.\n *\n * @remarks\n * Absent on a **root** event — one emitted by application code rather than by a middleware,\n * subscriber or effect reacting to another event. Together with {@link Event.depth} this makes\n * a cascade legible after the fact: without it, a runaway chain is a pile of unrelated events\n * with no way to tell which caused which.\n */\n readonly parentId?: string;\n /**\n * How many events deep in a causal chain this one is. A root event is depth `0`; an event\n * emitted while handling it is `1`, and so on.\n *\n * @remarks\n * Absent on a root event rather than present as `0`, so an event emitted by application code\n * stays byte-identical to one built before causality tracking existed — the same treatment\n * {@link Event.meta} gets, and for the same reason: `Object.keys` and `toStrictEqual` are load\n * bearing in consumer tests.\n *\n * This is the value {@link StoreSpec.maxReduceDepth} bounds.\n */\n readonly depth?: number;\n}\n\n/**\n * Generic \"old → new\" wrapper for fine-grained change notifications.\n * Carries the dotted `path` that changed.\n *\n * @typeParam V - Value type at the changed path.\n *\n * @example\n * ```ts\n * const change: Change<string> = {\n * oldValue: 'foo',\n * newValue: 'bar',\n * path: 'user.name'\n * };\n * ```\n *\n * @public\n */\nexport interface Change<V = any> {\n oldValue: V;\n newValue: V;\n /** Dotted path for fine-grained listeners; e.g., \"data.items.0.title\" */\n path?: string;\n /**\n * The `id` of the event that caused this change.\n *\n * @remarks\n * A change used to be anonymous, so a subscriber that needed to know *why* a value moved had\n * to mirror the cause into state and store it twice. Absent when the change did not come from\n * an event — a DevTools time-travel snapshot, for instance — which is itself the signal that\n * no event caused it.\n */\n eventId?: string;\n /** Channel of the causing event. Absent for the same reason as {@link Change.eventId}. */\n channel?: string;\n /** Type of the causing event. Absent for the same reason as {@link Change.eventId}. */\n type?: string;\n}\n\n/**\n * Emit function narrowed to the developer's EventMap.\n * Returns a Promise that resolves when the event has been fully processed.\n *\n * @typeParam EM - Event map.\n *\n * @example\n * ```ts\n * type EM = { ui: { increment: number } };\n * const emit: Emit<EM> = async (channel, type, payload) => { /* ... *\\/ };\n * await emit('ui', 'increment', 1);\n * ```\n *\n * @public\n */\n/**\n * What an `emit` resolves to once its effects have run.\n *\n * @remarks\n * `emit` used to resolve to `void`, so a caller could not tell \"the reducer applied my write\"\n * from \"the reducer looked at my write and returned the state unchanged\". On a single-writer\n * store that distinction is academic; on a contended one it is a lost update the API could not\n * report.\n *\n * Deliberately does **not** carry the changed paths. Building that list costs a string\n * concatenation per changed path on every emit, and almost no caller reads it — the same reason\n * change notifications are built lazily. Instrumentation already provides them to the observers\n * that do want them.\n *\n * @public\n */\nexport interface EmitResult {\n /**\n * The event was not vetoed by middleware.\n *\n * @remarks\n * Unchanged in meaning, and deliberately not narrowed to \"state changed\" — an event-only store\n * commits every event and writes nothing, by construction.\n */\n readonly committed: boolean;\n /** A reducer actually changed state. */\n readonly written: boolean;\n /** Present when a reducer refused the write. See {@link Rejection}. */\n readonly rejected?: Rejection;\n /**\n * Why the event did not commit. Absent when it did.\n *\n * @remarks\n * `committed: false` used to arrive from three unrelated causes through one shared frozen\n * object, so a caller could not tell a guard refusing an action from a double-click being\n * deduplicated - which want opposite responses. A submit button should show the refusal and\n * say nothing about the duplicate.\n *\n * See {@link EmitResult.vetoedBy} for which middleware refused it.\n */\n readonly reason?: NotCommittedReason;\n /**\n * The name of the middleware that vetoed, when it declared one through `meta.name`.\n *\n * @remarks\n * A reducer refusal has always named its slice, through `rejectedBy` and `onRejected`. A\n * middleware veto named nobody, so \"the event vanished\" had no attribution at all. A bare\n * middleware function contributes its own function name; an anonymous one leaves this\n * absent.\n */\n readonly vetoedBy?: string;\n}\n\n/**\n * Why an event did not commit.\n *\n * @remarks\n * - `vetoed` - middleware returned `false`, or threw.\n * - `deduped` - an identical event was seen inside the dedup window.\n * - `cascade` - the event exceeded `maxReduceDepth` or the per-drain transition ceiling, so\n * the store refused it rather than letting a cycle run away.\n *\n * @public\n */\nexport type NotCommittedReason = \"vetoed\" | \"deduped\" | \"cascade\";\n\n/**\n * Options for {@link StoreInstance.connect}.\n *\n * @public\n */\nexport interface ConnectOptions {\n /**\n * Deliver the current value once, immediately, before any change arrives.\n *\n * @remarks\n * A subscription otherwise starts at \"from now on\", so a subscriber's first render has to read\n * the path separately — the same path, spelled twice, which is one place for them to drift.\n *\n * The synthetic change has `oldValue: undefined` and no `eventId`, `channel` or `type`: no\n * event caused it, and claiming one would be a lie a subscriber could act on.\n *\n * For a wildcard pattern the \"current value\" of a match set is not a thing, so the slice root\n * is delivered with `path: \"\"`. React's hooks do not need this at all — `useSyncExternalStore`\n * already reads a snapshot on mount — so it is aimed at imperative subscribers.\n */\n readonly immediate?: boolean;\n}\n\n/**\n * Per-emit options.\n *\n * @public\n */\nexport interface EmitOptions {\n /**\n * Opt this specific emit into **identity-based** deduplication: if another\n * event with the same `(channel, type, dedupKey)` was emitted within the dedup\n * window, this one is skipped. Unlike content-based dedup\n * ({@link StoreSpec.dedupWindowMs}), it never coalesces two *distinct* logical\n * emits that merely share a payload — only re-fires of the *same* keyed emit\n * (e.g. a React Strict Mode double-invoke). Works even when `dedupWindowMs`\n * is 0, using a short default window.\n */\n dedupKey?: string;\n\n /**\n * Use this exact id for the event instead of generating one.\n *\n * @remarks\n * Intended for **idempotent re-emission**: a caller replaying an event from elsewhere (another\n * store, a durable log) can preserve the original id so the same logical event keeps\n * one identity everywhere, which makes it traceable across systems and in DevTools.\n *\n * The store does **not** enforce uniqueness — supplying a duplicate id does not dedupe the\n * event. Deduplication is a separate, opt-in concern; see {@link EmitOptions.dedupKey}.\n */\n id?: string;\n\n /**\n * Metadata to attach to this event, carried through the pipeline untouched and visible to\n * reducers, middleware, effects, subscribers and instrumentation. See {@link EventMeta}.\n *\n * @remarks\n * Omitting this leaves `event.meta` genuinely absent rather than `undefined`, so event\n * objects are byte-identical to those produced before this option existed.\n */\n meta?: EventMeta;\n\n /**\n * Bypass deduplication for this emit entirely, even when the store was created with\n * {@link StoreSpec.dedupWindowMs} greater than 0.\n *\n * @remarks\n * Content-based dedup fingerprints `(channel, type, payload)`, so a store with a dedup\n * window silently collapses genuinely distinct events that happen to share a payload —\n * repeated ticks with an empty payload, or the same event legitimately arriving twice from\n * two different sources. Set this when the caller already guarantees distinctness by other\n * means and needs every emit to land.\n *\n * Takes precedence over both {@link EmitOptions.dedupKey} and the store-level window.\n */\n skipDedup?: boolean;\n}\n\nexport type Emit<EM extends EventMapBase> = <\n C extends keyof EM & string,\n T extends keyof EM[C] & string,\n>(\n channel: C,\n type: T,\n payload: EM[C][T],\n opts?: EmitOptions,\n) => Promise<EmitResult>;\n\n/**\n * Basic unsubscribe handle.\n *\n * @public\n */\nexport type Unsubscribe = () => void;\n\n/**\n * A single observed event delivered to an {@link InstrumentationObserver}.\n *\n * @typeParam EM - Event map.\n *\n * @public\n */\nexport interface InstrumentedEvent<EM extends EventMapBase = EventMapBase> {\n /**\n * The processed event, including its `id` and any {@link EventMeta} the emitter attached.\n * `meta` is absent unless it was supplied.\n */\n event: { id: string; channel: string; type: string; payload: unknown; meta?: EventMeta };\n /** `true` if the event passed middleware and ran reducers; `false` if vetoed. */\n committed: boolean;\n /**\n * Dotted **leaf** paths that changed, prefixed with the slice name (e.g.\n * `\"todos.items.0.title\"`). Empty when nothing changed. These are the exact\n * paths the store computed while reducing — no re-diff required.\n */\n changedPaths: string[];\n /** Old value at each changed path, keyed by path. */\n prevValues: Record<string, unknown>;\n /** New value at each changed path, keyed by path. */\n nextValues: Record<string, unknown>;\n /** Wall-clock milliseconds spent in the synchronous reduce phase for this event. */\n reduceTimeMs: number;\n /**\n * Present when a reducer refused the write, carrying its reason.\n *\n * @remarks\n * Distinct from `committed: false`, which means middleware vetoed the event before any reducer\n * saw it. This is a reducer having considered the write and declined it — the two look\n * identical in state and are entirely different in cause.\n */\n rejected?: Rejection;\n}\n\n/**\n * Observer for {@link StoreInstance.instrument}. Called once per emitted event\n * (committed or vetoed), after the synchronous reduce phase.\n *\n * @typeParam EM - Event map.\n *\n * @public\n */\nexport type InstrumentationObserver<EM extends EventMapBase = EventMapBase> = (\n info: InstrumentedEvent<EM>,\n) => void;\n\n/**\n * Store spec - what you feed into the constructor / factory.\n *\n * @typeParam R - Reducer name union (string literal union).\n * @typeParam S - State record keyed by `R`.\n * @typeParam EM - Event map.\n *\n * @example\n * ```ts\n * type S = { counter: { value: number } };\n * type EM = { ui: { increment: number } };\n *\n * const spec: StoreSpec<'counter', S, EM> = {\n * name: 'App',\n * reducer: {\n * counter: {\n * state: { value: 0 },\n * events: [['ui', 'increment']],\n * reducer(s, evt) {\n * if (evt.type === 'increment') return { value: s.value + evt.payload };\n * return s;\n * }\n * }\n * }\n * };\n * ```\n *\n * @public\n */\n/**\n * Middleware input: accepts either a function (legacy) or a spec object (recommended).\n *\n * @typeParam S - Store state (readonly).\n * @typeParam EM - Event map.\n *\n * @example Function form (legacy)\n * ```ts\n * const mw: MiddlewareInput<AppState, AppEM> = (state, event, emit) => {\n * console.log(event.type);\n * return true;\n * };\n * ```\n *\n * @example Spec form (recommended)\n * ```ts\n * const mw: MiddlewareInput<AppState, AppEM> = {\n * when: { channel: 'admin' },\n * middleware: (state, event, emit) => state.auth.isAdmin,\n * meta: { type: 'middleware', name: 'authGuard' },\n * };\n * ```\n *\n * @public\n */\nexport type MiddlewareInput<S = any, EM extends EventMapBase = EventMapBase> =\n | MiddlewareFunction<S, EM>\n | MiddlewareSpec<S, EM>;\n\n/**\n * Store configuration object passed to the {@link Store} constructor or {@link createStore}.\n *\n * @typeParam R - Reducer name union (string literal union).\n * @typeParam S - State record keyed by `R`.\n * @typeParam EM - Event map.\n *\n * @example\n * ```ts\n * type S = { counter: { value: number } };\n * type EM = { ui: { increment: number } };\n *\n * const spec: StoreSpec<'counter', S, EM> = {\n * name: 'App',\n * reducer: {\n * counter: {\n * state: { value: 0 },\n * when: { keys: eventKeys<EM>()([['ui', 'increment']]) },\n * reducer(s, evt) {\n * if (evt.type === 'increment') return { value: s.value + evt.payload };\n * return s;\n * }\n * }\n * }\n * };\n * ```\n *\n * @public\n */\nexport type StoreSpec<R extends string, S extends Record<R, any>, EM extends EventMapBase> = {\n /**\n * Store name (used by DevTools to identify the instance).\n */\n name: string;\n\n /**\n * Map of slice name → reducer spec.\n * Each entry declares initial state, the reducer function, and the event targeting.\n */\n reducer: Record<R, ReducerSpec<S[R], EM>>;\n\n /**\n * Middleware chain executed before reducers/effects.\n * Accepts either functions (legacy) or MiddlewareSpec objects (recommended).\n *\n * An event stops propagating only when a middleware returns an explicit `false`, or\n * throws. Returning nothing allows it. Middleware is synchronous: a `Promise` is not\n * `false`, so it cannot veto.\n */\n middleware?: MiddlewareInput<DeepReadonly<S>, EM>[];\n\n /**\n * Optional side-effect handlers registered at construction time.\n * Runs after reducers for every propagated event.\n */\n effects?: Array<EffectSpec<DeepReadonly<S>, EM>>;\n\n /**\n * Time window in milliseconds for **content-based** event deduplication.\n * When greater than 0, events with identical fingerprints\n * (channel + type + serialized payload) within this window are treated as\n * duplicates and skipped.\n *\n * **Off by default.** Content-based dedup can silently drop legitimate\n * rapid-fire identical events (double-clicks, repeated `+1`, sliders emitting\n * the same value), so it is opt-in. To safely coalesce a *specific* re-fired\n * emit (e.g. React Strict Mode), prefer the per-emit {@link EmitOptions.dedupKey}.\n *\n * @default 0 (disabled)\n */\n dedupWindowMs?: number;\n\n /**\n * Generates the `id` for each emitted event. Defaults to `crypto.randomUUID()`.\n *\n * @remarks\n * Two reasons to override it. First, portability: `crypto.randomUUID` requires a **secure\n * context** in browsers and is absent on some runtimes (React Native / Hermes), where the\n * default would throw on every emit. Second, determinism: injecting a counter makes event\n * ids stable across runs, which is what allows byte-exact assertions in tests.\n *\n * The factory must return a string. Uniqueness is the caller's responsibility.\n *\n * @default () => crypto.randomUUID()\n *\n * @example\n * ```ts\n * let n = 0;\n * const store = createStore({ name: 'Test', reducer, idFactory: () => `evt-${++n}` });\n * ```\n */\n idFactory?: () => string;\n\n /**\n * DevTools configuration options.\n *\n * @remarks\n * These options control runtime DevTools capabilities such as event replay.\n */\n devtools?: {\n /**\n * Enable event replay via `__replayEvents()`.\n * When `false` (default), calling `__replayEvents()` throws.\n *\n * @default false\n */\n allowReplay?: boolean;\n };\n\n /**\n * Called when an effect throws or its returned promise rejects.\n *\n * @remarks\n * `await emit(...)` **never rejects** on effect failure: the reduce phase has\n * already committed synchronously, and effects run as independent per-event\n * tasks. Effect errors are logged to the console and delivered here (when\n * provided), so this is the single place to observe and route them — e.g.\n * report to a service or emit a failure event. Other effects still run.\n *\n * @param error - The thrown value or rejection reason.\n * @param event - The event whose effect failed.\n */\n onEffectError?: (error: unknown, event: EventUnion<EM>) => void;\n\n /**\n * Invoked when a reducer throws.\n *\n * @remarks\n * A reducer is meant to be pure and total, so a throw is a bug in application code — and it\n * used to be almost invisible. Keyed reducers ran through a bus that logged and moved on,\n * letting the event commit and its effects run; pattern reducers threw straight out of the\n * drain, aborting the commit and notifying nobody. Both paths now isolate the failing slice\n * and report here.\n *\n * The failing slice keeps its previous state; every other slice still reduces, and the event\n * still commits if anything else changed. `emit()` never rejects because of a reducer error,\n * so this hook is how a caller observes one.\n *\n * @param error - The thrown value.\n * @param event - The event being reduced when it threw.\n * @param slice - Name of the slice whose reducer threw.\n */\n onReducerError?: (error: unknown, event: EventUnion<EM>, slice: string) => void;\n\n /**\n * Called when an `onEvent` subscriber throws, or rejects.\n *\n * @remarks\n * The fourth of a set: reducers, effects, rejections and cascades all had a hook, and event\n * subscribers had `console.error` and nothing else - so an application could not route a\n * failing subscriber to its own error reporting. Subscribers are the seam a decoration is\n * told to use, which makes the gap more visible than it was.\n *\n * A throwing subscriber never stops the others, with or without this hook.\n */\n onSubscriberError?: (\n error: unknown,\n event: EventUnion<EM>,\n phase: NotifiedPhase,\n ) => void;\n\n /**\n * Maximum causal depth of an event chain before the store refuses to extend it.\n *\n * @remarks\n * An event emitted while handling another is one deeper than its cause. Two reducers wired to\n * each other, or an effect that emits the event its own reducer answers, climb this without\n * bound — and the reduce queue drains synchronously, so in a browser that is a frozen tab with\n * no error and no stack, and on a server a pinned core.\n *\n * **On by default**, because the whole point is that the failure mode does not require\n * configuration to avoid. The default is far past any legitimate chain: an event caused by an\n * event caused by an event is normal, sixty-four deep is a bug. Raise it if an application\n * genuinely nests deeper, or set `Infinity` to opt out entirely and own the consequences.\n *\n * Breaching does not throw — see {@link StoreSpec.onCascade}.\n *\n * @default 64\n */\n maxReduceDepth?: number;\n\n /**\n * Maximum number of events one synchronous drain will process before refusing more.\n *\n * @remarks\n * A drain processes one root event plus every event emitted *while it runs* — so this counts a\n * single causal burst, not application traffic. A plain loop is unaffected: `emit` drains to\n * completion before it returns, so `for (const row of rows) store.emit(…)` is a thousand drains\n * of one event each, never one drain of a thousand.\n *\n * **Off by default** because a wide burst is not by itself a bug. One `sync` event whose\n * subscriber fans out to five hundred `upsert`s is a legitimate shape, and a default low enough\n * to catch a runaway would refuse it. Depth is what separates a cascade from a fan-out — a\n * fan-out is wide and shallow, a cascade is narrow and deep — which is why\n * {@link StoreSpec.maxReduceDepth} carries the default and this does not.\n *\n * Set it when a store's bursts are known to be bounded and an unexpectedly wide one is itself\n * the symptom worth catching.\n *\n * @default undefined (no limit)\n */\n maxTransitionsPerDrain?: number;\n\n /**\n * Called when a ceiling is breached, instead of throwing.\n *\n * @remarks\n * The offending emit is refused and the chain stops there; everything already committed\n * stands. It does not throw, because the throw would surface in whichever frame happened to be\n * emitting — a subscriber, an effect, a middleware — which is the same species of\n * hard-to-attribute failure the ceiling exists to prevent. A cascade is a wiring bug, and this\n * is where the wiring gets named.\n *\n * @param info - Which ceiling, the event that would have extended the chain, and its causal\n * chain of ids, newest last.\n */\n onCascade?: (info: CascadeInfo<EM>) => void;\n\n /**\n * Called when a reducer refuses a write by returning {@link Rejected}.\n *\n * @remarks\n * The caller learns of its own refusal from the `emit` result; this is for everyone else —\n * logging, metrics, alerting on a rate of rejected writes. Shaped as a callback rather than a\n * subscription for the same reason {@link StoreSpec.onReducerError} is: it is a rare global\n * signal, not something several independent parties register and unregister for.\n *\n * A refusal is a normal outcome, not an error. It means a reducer considered the write and\n * declined it — a stale compare-and-swap, an unmet precondition — and the event is rejected\n * whole, so no slice writes.\n *\n * @param rejection - The refusal and its reason.\n * @param event - The event that was refused.\n * @param slice - Name of the slice whose reducer refused.\n */\n onRejected?: (rejection: Rejection, event: EventUnion<EM>, slice: string) => void;\n};\n\n/**\n * What {@link StoreSpec.onCascade} receives when a ceiling is breached.\n *\n * @typeParam EM - Event map.\n *\n * @public\n */\nexport interface CascadeInfo<EM extends EventMapBase = EventMapBase> {\n /** Which ceiling was hit. */\n readonly limit: \"maxReduceDepth\" | \"maxTransitionsPerDrain\";\n /** The configured value that was exceeded. */\n readonly limitValue: number;\n /** The event that was refused — the one that would have extended the chain. */\n readonly event: EventUnion<EM>;\n /** Causal depth the refused event would have had. */\n readonly depth: number;\n /**\n * Ids from the root of the chain to the refused event's parent, newest last.\n *\n * @remarks\n * Bounded to the most recent entries: a cascade is long by definition, and the useful part is\n * the cycle at the end rather than the thousand identical hops before it.\n */\n readonly chain: readonly string[];\n}\n\n/**\n * Public Store surface.\n *\n * @typeParam R - Reducer name union.\n * @typeParam S - State record (already readonly at the call site).\n * @typeParam EM - Event map.\n *\n * @remarks\n * The concrete Store implements this as `StoreInstance<R, DeepReadonly<S>, EM>`.\n *\n * @public\n */\nexport interface StoreInstance<\n R extends string = string,\n S extends Record<R, any> = Record<string, any>,\n EM extends EventMapBase = EventMapBase,\n> extends StoreDecoration<R, S, EM> {\n /**\n * Store name (used by DevTools to identify the instance).\n */\n name: string;\n\n /**\n * Read the full state (already readonly).\n */\n getState(): DeepReadonly<S>;\n\n /**\n * Emit a typed event `(channel, type, payload)`.\n * Returns a promise that resolves when the event has been processed.\n */\n emit: Emit<EM>;\n\n /**\n * Coarse subscription: runs after any state change (once per committed event).\n */\n subscribe(listener: () => void): Unsubscribe;\n\n /**\n * Fine-grained subscription: listen to a specific `reducer.property` path.\n * Accepts a dotted path string (e.g., \"data.123.title\").\n * Fires when that path (or its ancestors) actually changes.\n *\n * @param spec - `{ reducer, property }` where `property` is a single dotted path string.\n * @param handler - Handler receiving a {@link Change} with `{ oldValue, newValue, path }`.\n */\n connect(\n spec: { reducer: R; property: string },\n handler: (change: Change) => void,\n options?: ConnectOptions,\n ): Unsubscribe;\n\n /**\n * Sends a request and waits for the reply, correlating the two automatically.\n *\n * @remarks\n * Awaitable for the terminal reply, async-iterable for progress. See the implementation on\n * {@link Store.call} for the full contract: correlation, backpressure, timeouts, and why it\n * is a local primitive.\n */\n call<C extends keyof EM & string, T extends keyof EM[C] & string>(\n channel: C,\n type: T,\n payload: EM[C][T],\n opts: CallOptions<EM>,\n ): CallHandle<EventUnion<EM>, EventUnion<EM>>;\n\n /**\n * Convenience helper to register an **effect** filtered by a single `(channel, type)` pair.\n *\n * @typeParam C - Channel key within `EM`.\n * @typeParam T - Event type key within channel `C`.\n * @param channel - Channel to filter.\n * @param type - Event type to filter.\n * @param handler - Effect handler `(payload, getState, emit, event)`.\n * \n * @returns Unsubscribe/teardown function.\n */\n onEffect<\n C extends keyof EM & string,\n T extends keyof EM[C] & string\n >(\n channel: C,\n type: T,\n handler: (\n payload: EM[C][T],\n getState: () => DeepReadonly<S>,\n emit: Emit<EM>,\n event: Event<EM, C, T>,\n ) => void | Promise<void>,\n ): Unsubscribe;\n\n /**\n * Register a post-reducer effect (sees final state). Returns an unsubscribe.\n */\n registerEffect<Spec extends EffectSpec<any, any>>(\n spec: Spec,\n ): Unsubscribe & { store: DecoratableStore<R, S, Merge<EM, EMAddOf<Spec>>>; dispose(): void };\n\n /**\n * Dynamically add middleware, in either the function or the spec form.\n */\n registerMiddleware<M extends MiddlewareInput<any, any>>(\n mw: M,\n ): Unsubscribe & { store: DecoratableStore<R, S, Merge<EM, EMAddOf<M>>>; dispose(): void };\n\n /**\n * Dynamically add/remove a namespaced reducer slice at runtime.\n */\n registerReducer(\n name: string,\n spec: ReducerSpec<any, EM>,\n options?: { owner?: string },\n ): Unsubscribe & { store: StoreInstance<string, Record<string, any>, EM>; dispose(): void };\n\n /**\n * Cleanup resources (timers, etc.) when disposing the store.\n * Call this if you're dynamically creating/destroying stores.\n */\n dispose(): void;\n\n /**\n * Subscribe to events by channel and type.\n *\n * Event subscriptions are intended for the View layer (e.g., React components)\n * to react to events without affecting the event flow. They are fire-and-forget\n * and cannot cancel event propagation.\n *\n * **Phases:**\n * - `'committed'` (default): Events that passed middleware and reached reducers\n * - `'uncommitted'`: Events rejected by middleware\n * - `'written'`: Events that actually changed state\n * - `'all'`: Both committed and uncommitted events (handler receives phase parameter).\n * Deliberately not `written` as well: an event that writes is also committed, so folding\n * it in would notify every existing `all` subscriber twice for one event.\n *\n * @typeParam C - Channel key within `EM`.\n * @typeParam T - Event type key within channel `C`.\n * @param channel - Channel to subscribe to.\n * @param type - Event type to subscribe to.\n * @param handler - Handler function `(event, getState, emit, phase)`.\n * @param phase - Event phase to subscribe to (default: `'committed'`).\n * @returns Unsubscribe function.\n *\n * @example Committed events (default)\n * ```ts\n * const off = store.onEvent('ui', 'save', (event, getState, emit, phase) => {\n * console.log('Save committed:', event.payload);\n * });\n * ```\n *\n * @example Uncommitted (rejected) events\n * ```ts\n * store.onEvent('ui', 'delete', (event, getState, emit, phase) => {\n * console.log('Delete was rejected by middleware');\n * }, 'uncommitted');\n * ```\n *\n * @example All events\n * ```ts\n * store.onEvent('ui', 'action', (event, getState, emit, phase) => {\n * console.log('Action:', phase); // 'committed' or 'uncommitted'\n * }, 'all');\n * ```\n */\n onEvent<C extends keyof EM & string, T extends keyof EM[C] & string>(\n channel: C,\n type: T,\n handler: NarrowedEventHandler<DeepReadonly<S>, EM, C, T>,\n phase?: EventPhase,\n options?: {\n /**\n * Also call this handler while devtools is replaying, which it does not by default.\n *\n * @remarks\n * Opt in only for a handler that derives view state purely from the event stream and\n * performs no I/O. A handler that publishes, writes or notifies must stay out: replay\n * is a debugging operation, and a scrub of the timeline should not reach a peer, a\n * socket or an analytics endpoint.\n */\n duringReplay?: boolean;\n },\n ): Unsubscribe;\n\n /**\n * Called when the store gains or loses a reducer, middleware or effect.\n *\n * @remarks\n * A push seam, because `__devtoolsIntrospect()` is pull-only: a devtools panel's\n * subscription list goes stale the moment a decoration mounts anything, and a library that\n * needs to react to another library has nothing to wait on.\n *\n * Delivered as an **array, one batch per public call**. `replaceReducers` unmounts and then\n * remounts, so between those steps a slice that is merely being updated does not exist; a\n * per-change observer would see a spurious unmount. `hotReplace` delivers a single batch\n * spanning all three kinds.\n *\n * Observers run **after** the state broadcast, so the view layer has already been told a\n * fact before a library gets to react to it. A registration made *by* an observer is\n * legitimate and is queued rather than delivered re-entrantly: depth-first work,\n * breadth-first notification, so no observer ever sees a half-built topology.\n *\n * Synchronous. A `Promise` returned from an observer is not awaited, and is reported in\n * development, because the store has already moved on by the time it would resolve.\n *\n * **Replay never produces a change.** `__replayEvents` and `__applyExternalState` alter\n * state and never topology, so there is no `duringReplay` option here and none is needed.\n *\n * `dispose()` fires nothing: the store is going away, not being dismantled slice by slice.\n *\n * @param observer - Receives one batch per registration change.\n * @param options - `emitCurrent` synthesizes a `\"mounted\"` batch for everything already\n * installed, delivered synchronously before this call returns. Spec-time registrations\n * happen inside `createStore`, so a decorator applied afterwards never saw them arrive;\n * this closes that gap without a separate pull API to race against. The synthesized\n * changes carry their **real** origins, never a synthetic marker, because filtering on\n * provenance is the main thing an observer does.\n * @returns Unsubscribe function.\n */\n onRegistrationChange(\n observer: RegistrationObserver<EM>,\n options?: { emitCurrent?: boolean },\n ): Unsubscribe;\n\n /**\n * `true` while devtools is applying a snapshot or replaying events.\n *\n * @remarks\n * For anything that must branch rather than simply skip. Most code needs nothing: replay\n * does not notify event subscribers unless they opted in.\n *\n * A getter, so destructuring it takes a snapshot rather than a live view.\n */\n readonly isReplaying: boolean;\n\n /**\n * Replaces the entire middleware pipeline (HMR-friendly).\n *\n * @param next - New middleware array.\n */\n replaceMiddleware(\n next: MiddlewareInput<DeepReadonly<S>, EM>[],\n opts?: { scope?: ReplaceScope },\n ): void;\n\n /**\n * Replaces all registered effects (HMR-friendly).\n *\n * @param next - New effects array (as EffectSpecs).\n */\n replaceEffects(\n next: Array<EffectSpec<DeepReadonly<S>, EM>>,\n opts?: { scope?: ReplaceScope },\n ): void;\n\n /**\n * Replaces the entire reducer set (HMR-friendly).\n *\n * @param next - Map of slice specs keyed by slice name.\n * @param opts - `{ preserveState?: boolean }` (default `true`).\n */\n replaceReducers(\n next: Record<R, ReducerSpec<S[R], EM>>,\n opts?: { preserveState?: boolean; scope?: ReplaceScope },\n ): void;\n\n /**\n * Convenience API to replace any subset of store parts (HMR patterns).\n *\n * @param partial - Partial replacement set.\n */\n hotReplace(partial: {\n reducer?: Record<R, ReducerSpec<S[R], EM>>;\n middleware?: MiddlewareInput<DeepReadonly<S>, EM>[];\n effects?: Array<EffectSpec<DeepReadonly<S>, EM>>;\n preserveState?: boolean;\n scope?: ReplaceScope;\n }): void;\n\n /**\n * Replays a sequence of events from a snapshot through reducers and event\n * subscribers ONLY. Skips dedup, middleware, and effects.\n *\n * Gated by `createStore({ devtools: { allowReplay: true } })`.\n * Throws if replay is not enabled.\n *\n * @param snapshot - The state snapshot to restore before replaying.\n * @param events - Array of events to replay (in order).\n *\n * @internal\n */\n __replayEvents(\n snapshot: any,\n events: Array<{ channel: string; type: string; payload: any; id: string; meta?: EventMeta }>,\n ): void;\n\n /**\n * Returns a structured introspection snapshot for DevTools UIs.\n *\n * @returns Reducers, effects, middleware, event subscriptions, coarse\n * subscriber count, dedup hit count, and current queue depth.\n *\n * @internal\n */\n __devtoolsIntrospect(): {\n reducers: Array<{ name: string; when?: unknown; origin: Origin; owner?: string }>;\n effects: Array<{\n channel: string;\n type: string;\n name?: string;\n description?: string;\n origin: Origin;\n }>;\n middleware: Array<{\n name?: string;\n description?: string;\n when?: unknown;\n origin: Origin;\n }>;\n atomic: Array<{ reducer: string; property: string }>;\n /** `duringReplay` says whether a subscription hears replayed events. */\n event: Array<{ channel: string; type: string; phase: string; duringReplay: boolean }>;\n coarse: number;\n dedupHits: number;\n queueDepth: number;\n };\n\n /**\n * Registers an instrumentation observer, called once per emitted event\n * (committed or vetoed) after the synchronous reduce phase, with the exact\n * changed paths, their old/new values, and reduce timing. This is the typed\n * seam DevTools agents consume — no `as any` bridging required.\n *\n * @param observer - Receives an {@link InstrumentedEvent} per emit.\n * @returns Unsubscribe function.\n */\n instrument(observer: InstrumentationObserver<EM>): Unsubscribe;\n\n /**\n * Applies an externally-provided whole-state snapshot (DevTools time-travel),\n * emitting fine-grained path changes and notifying coarse subscribers.\n *\n * @param next - Plain state object to apply.\n *\n * @internal\n */\n __applyExternalState(next: unknown): void;\n}\n\n\n/**\n * One reducer's definition blob (stateful event consumer).\n *\n * @typeParam S - State managed by this reducer.\n * @typeParam EM - Event map.\n *\n * @remarks\n * Use `when` for event targeting. An earlier `events` array was removed; this remark\n * outlived it and described a property that no longer exists.\n *\n * @example\n * Using `when` (recommended)\n * ```ts\n * const counterSpec: ReducerSpec<{ value: number }, MyEM> = {\n * state: { value: 0 },\n * when: { keys: eventKeys<MyEM>()([['ui', 'increment'], ['ui', 'decrement']]) },\n * reducer(s, evt) {\n * if (evt.type === 'increment') return { value: s.value + evt.payload };\n * if (evt.type === 'decrement') return { value: s.value - evt.payload };\n * return s;\n * },\n * meta: { type: 'reducer', name: 'counter' },\n * };\n * ```\n *\n * @public\n */\nexport interface ReducerSpec<S = any, EM extends EventMapBase = EventMapBase> {\n /**\n * Initial state for this reducer.\n */\n state: S;\n\n /**\n * Event targeting using the unified `When` matcher.\n */\n when?: When<EM>;\n\n /**\n * Pure reducer function: `(state, event) => nextState`.\n */\n reducer: ReducerFunction<S, EM>;\n\n /**\n * Optional metadata for debugging tools and DevTools integration.\n */\n meta?: EventConsumerMeta<\"reducer\">;\n}\n\n/**\n * Pure reducer function (stateful event consumer).\n *\n * @typeParam S - State type.\n * @typeParam EM - Event map.\n *\n * @public\n */\nexport type ReducerFunction<S = any, EM extends EventMapBase = EventMapBase> = (\n state: S,\n event: EventUnion<EM>,\n) => S | Rejection;\n\n/**\n * Effect specification (stateless async event consumer).\n *\n * @typeParam S - Store state type (readonly).\n * @typeParam EM - Event map.\n *\n * @remarks\n * - Effects run after reducers see the event.\n * - Effects are async-safe and do not own state.\n * - Effects are keyed by event for O(1) lookup (no scanning).\n * - Use `when` for event targeting (preferred over `events`).\n *\n * @example\n * Using `when` (recommended)\n * ```ts\n * const logEffect: EffectSpec<AppState, MyEM> = {\n * when: { keys: eventKeys<MyEM>()([['ui', 'increment']]) },\n * effect: async (evt, getState, emit) => {\n * console.log('increment', evt.payload, getState().counter.value);\n * },\n * meta: { type: 'effect', name: 'logEffect', description: 'Logs increment events' },\n * };\n * ```\n *\n * @example Match all events in a channel\n * ```ts\n * const notificationEffect: EffectSpec<AppState, MyEM> = {\n * when: { channel: 'notifications' },\n * effect: (evt, getState, emit) => {\n * if (evt.type === 'show') showToast(evt.payload.message);\n * },\n * };\n * ```\n *\n * @public\n */\nexport interface EffectSpec<S = any, EM extends EventMapBase = EventMapBase> {\n /**\n * Event targeting using the unified `When` matcher.\n */\n when?: When<EM>;\n\n /**\n * Async effect handler: `(event, getState, emit) => void | Promise<void>`.\n */\n effect: EffectFunction<S, EM>;\n\n /**\n * Optional metadata for debugging tools and DevTools integration.\n */\n meta?: EventConsumerMeta<\"effect\">;\n}\n\n/**\n * Every legal `{ channel, type, payload, id }` as a *distinct* object type.\n *\n * @typeParam EM - Event map.\n *\n * @public\n */\nexport type EventUnion<EM extends EventMapBase> = {\n [C in keyof EM & string]: {\n [T in keyof EM[C] & string]: Event<EM, C, T>;\n }[keyof EM[C] & string];\n}[keyof EM & string];\n\n/**\n * Middleware function: log, guard, or veto an event **synchronously**.\n *\n * @remarks\n * **Only an explicit `false` vetoes.** Returning `true`, or returning nothing at all, allows\n * the event, so middleware that only logs or measures can simply fall off the end.\n *\n * The return type is `boolean | void` rather than `boolean` for that reason: under these\n * semantics an omitted `return` is correct, so making the compiler demand one would be\n * wrong. It was `boolean` while any falsy value vetoed, which made a missing `return`\n * silently swallow every event the middleware matched.\n *\n * Middleware runs in the synchronous reduce phase (so `getState()` is correct\n * immediately after `emit()`), and therefore must be synchronous. Perform async\n * work in effects instead - a `Promise` is not `false`, so an async middleware allows the\n * event while it is still deciding, and the store logs an error in development when it sees\n * one returned.\n *\n * A middleware that **throws** vetoes the event and logs, naming the event: a guard that\n * crashed has not decided the event is safe.\n *\n * @typeParam S - Store state (readonly).\n * @typeParam EM - Event map.\n *\n * @public\n */\nexport type MiddlewareFunction<S = any, EM extends EventMapBase = EventMapBase> = (\n state: S,\n event: EventUnion<EM>,\n emit: Emit<EM>,\n) => boolean | void;\n\n/**\n * Middleware specification with optional event targeting and metadata.\n *\n * @typeParam S - Store state (readonly).\n * @typeParam EM - Event map.\n *\n * @remarks\n * - If `when` is omitted, middleware receives ALL events.\n * - Use `when` to filter which events the middleware processes.\n * - Middleware runs BEFORE reducers and can cancel event propagation.\n *\n * @example Global logging middleware (all events)\n * ```ts\n * const loggingMiddleware: MiddlewareSpec<AppState, AppEM> = {\n * middleware: (state, event, emit) => {\n * console.log('Event:', event.channel, event.type);\n * return true; // allow propagation\n * },\n * meta: { type: 'middleware', name: 'logger' },\n * };\n * ```\n *\n * @example Filtered middleware (specific events)\n * ```ts\n * const authMiddleware: MiddlewareSpec<AppState, AppEM> = {\n * when: { channel: 'admin' },\n * middleware: (state, event, emit) => {\n * if (!state.auth.isAdmin) return false; // cancel\n * return true;\n * },\n * meta: { type: 'middleware', name: 'authGuard', description: 'Guards admin events' },\n * };\n * ```\n *\n * @public\n */\nexport interface MiddlewareSpec<S = any, EM extends EventMapBase = EventMapBase> {\n /**\n * Event targeting (optional). If omitted, middleware receives ALL events.\n */\n when?: When<EM>;\n\n /**\n * Middleware function: `(state, event, emit) => boolean` (synchronous).\n * Return `false` to cancel event propagation.\n */\n middleware: MiddlewareFunction<S, EM>;\n\n /**\n * Optional metadata for debugging tools and DevTools integration.\n */\n meta?: EventConsumerMeta<\"middleware\">;\n}\n\n/**\n * Effect handler: runs AFTER reducers, sees the final state.\n *\n * @typeParam S - Store state (readonly).\n * @typeParam EM - Event map.\n *\n * @public\n */\nexport type EffectFunction<S = any, EM extends EventMapBase = EventMapBase> = (\n event: EventUnion<EM>,\n getState: () => S,\n emit: Emit<EM>,\n) => void | Promise<void>;\n\n/**\n * Helper: extract state shape from a reducers map.\n *\n * @internal\n */\nexport type ReducersMapAny = Record<string, ReducerSpec<any, any>>;\n\n/**\n * Helper: derive state type from a reducers map.\n *\n * @internal\n */\nexport type StateFromReducers<R> = {\n [K in keyof R]: R[K] extends ReducerSpec<infer S, any> ? S : never;\n};\n\n/**\n * Helper: turn a union into an intersection.\n *\n * @internal\n */\nexport type UnionToIntersection<U> = (U extends unknown ? (k: U) => void : never) extends (\n k: infer I,\n) => void\n ? I\n : never;\n\n/**\n * Helper: the event map of a single reducer spec.\n *\n * @internal\n */\nexport type EMOfSpec<Spec> = Spec extends ReducerSpec<any, infer EM> ? EM : never;\n\n/**\n * Helper: derive the combined event map from a reducers map (strict).\n * Used by the createStore inference overload.\n *\n * Each slice contributes its own event map; those maps are **merged** (channels,\n * and each channel's `type → payload` entries, combined across slices) rather\n * than collapsed to a single slice's map. `EMOfSpec` distributes over the union\n * of specs to yield the union of per-slice event maps, and `UnionToIntersection`\n * merges them — so a store whose slices declare divergent event maps still types\n * `emit` against the union of every slice's channels/types.\n *\n * @internal\n */\nexport type EMFromReducersStrict<RM extends ReducersMapAny> = UnionToIntersection<\n EMOfSpec<RM[keyof RM]>\n> extends infer Merged\n ? Merged extends EventMapBase\n ? Merged\n : EventMapBase\n : EventMapBase;\n\n// ============================================\n// Event Targeting (When Matcher)\n// ============================================\n\n/**\n * Matcher for event targeting across reducers, effects, middleware, and subscriptions.\n *\n * Supports four targeting modes:\n * - `{ any: true }` — match all events\n * - `{ keys: [...] }` — match specific `[channel, type]` pairs (correlated)\n * - `{ channel: 'x' }` — match all events in a channel\n * - `{ channels: ['x', 'y'] }` — match all events in multiple channels\n *\n * @typeParam EM - Event map.\n *\n * @example Match all events\n * ```ts\n * const mw: MiddlewareSpec<S, EM> = {\n * when: { any: true },\n * middleware: (state, event, emit) => true,\n * };\n * ```\n *\n * @example Match specific event keys\n * ```ts\n * const reducer: ReducerSpec<S, EM> = {\n * state: { value: 0 },\n * when: { keys: eventKeys<EM>()([['ui', 'increment'], ['ui', 'decrement']]) },\n * reducer: (s, e) => { ... },\n * };\n * ```\n *\n * @example Match entire channel\n * ```ts\n * const effect: EffectSpec<S, EM> = {\n * when: { channel: 'notifications' },\n * effect: (e, getState, emit) => { ... },\n * };\n * ```\n *\n * @public\n */\nexport type When<EM extends EventMapBase> =\n | { any: true }\n | { keys: ReadonlyArray<EventKey<EM>> }\n | { channel: keyof EM & string }\n | { channels: ReadonlyArray<keyof EM & string> };\n\n/**\n * Helper to create type-safe EventKey arrays without requiring `as const`.\n * Preserves literal tuple types for proper type correlation in handlers.\n *\n * @typeParam EM - Event map.\n *\n * @example\n * ```ts\n * type AppEM = {\n * ui: { increment: number; decrement: number };\n * data: { loaded: string[] };\n * };\n *\n * // Without helper (requires `as const`):\n * const keys = [['ui', 'increment'], ['ui', 'decrement']] as const;\n *\n * // With helper (no `as const` needed):\n * const keys = eventKeys<AppEM>()([\n * ['ui', 'increment'],\n * ['ui', 'decrement'],\n * ]);\n * // Type: readonly [['ui', 'increment'], ['ui', 'decrement']]\n * ```\n *\n * @public\n */\nexport const eventKeys =\n <EM extends EventMapBase>() =>\n <const K extends ReadonlyArray<EventKey<EM>>>(keys: K): K =>\n keys;\n\n/**\n * Extracts the event union from a `When` matcher.\n * Used internally to narrow handler `event` parameter types based on the matcher.\n *\n * @typeParam EM - Event map.\n * @typeParam W - When matcher type.\n *\n * @internal\n */\nexport type EventFromWhen<EM extends EventMapBase, W extends When<EM>> = W extends { any: true }\n ? EventUnion<EM>\n : W extends { keys: ReadonlyArray<infer K> }\n ? K extends readonly [infer C, infer T]\n ? C extends keyof EM & string\n ? T extends keyof EM[C] & string\n ? Event<EM, C, T>\n : never\n : never\n : never\n : W extends { channel: infer C }\n ? C extends keyof EM & string\n ? { [T in keyof EM[C] & string]: Event<EM, C, T> }[keyof EM[C] & string]\n : never\n : W extends { channels: ReadonlyArray<infer C> }\n ? C extends keyof EM & string\n ? { [T in keyof EM[C] & string]: Event<EM, C, T> }[keyof EM[C] & string]\n : never\n : never;\n\n// ============================================\n// Path Value Resolution\n// ============================================\n\n/**\n * Resolves the value type at a dotted path `P` inside object/array `T`.\n * Supports numeric segments for array indexing (e.g., `\"items.0.title\"`).\n *\n * @typeParam T - Root type to index into.\n * @typeParam P - Dotted path string.\n *\n * @example\n * ```ts\n * type S = { todos: Array<{ title: string; done: boolean }> };\n * type T1 = PathValue<S['todos'], '0.title'>; // string\n * type T2 = PathValue<S, 'todos.0'>; // { title: string; done: boolean }\n * type T3 = PathValue<S, 'todos'>; // Array<{ title: string; done: boolean }>\n * ```\n *\n * @remarks\n * The empty path resolves to `T` itself, matching what the code has always done: both the\n * store's internal path reader and the React one return the object unchanged for `\"\"`. The type\n * used to say `never`, so a subscription to a root-value slice was typed as nothing at all.\n *\n * @public\n */\nexport type PathValue<T, P extends string> = P extends \"\"\n ? T\n : P extends `${infer K}.${infer Rest}`\n ? K extends keyof T\n ? PathValue<T[K], Rest>\n : K extends `${number}`\n ? T extends readonly (infer E)[]\n ? PathValue<E, Rest>\n : never\n : never\n : P extends keyof T\n ? T[P]\n : P extends `${number}`\n ? T extends readonly (infer E)[]\n ? E\n : never\n : never;\n\n// ============================================\n// Metadata for Debugging Tools\n// ============================================\n\n/**\n * Type discriminator for event consumers.\n *\n * @public\n */\nexport type EventConsumerType = \"reducer\" | \"middleware\" | \"effect\";\n\n/**\n * Metadata for event consumers (reducers, effects, middleware).\n * Useful for debugging tools, DevTools integration, and introspection.\n *\n * @typeParam T - Consumer type discriminator.\n *\n * @example\n * ```ts\n * const counterReducer: ReducerSpec<CounterState, AppEM> = {\n * state: { value: 0 },\n * when: { keys: eventKeys<AppEM>()([['ui', 'increment']]) },\n * reducer: (s, e) => ({ value: s.value + e.payload }),\n * meta: {\n * type: 'reducer',\n * name: 'counterReducer',\n * description: 'Handles counter increment/decrement events',\n * },\n * };\n * ```\n *\n * @public\n */\nexport interface EventConsumerMeta<T extends EventConsumerType = EventConsumerType> {\n /** Consumer type discriminator */\n type: T;\n\n /** Unique identifier for this consumer */\n name: string;\n\n /** Brief one-liner description of what this consumer does */\n description?: string;\n}\n\n/**\n * Alias for DeepReadonly.\n *\n * @public\n */\nexport type DeepRO<T> = DeepReadonly<T>;\n\n/**\n * Primitive types (terminal leaves in deep traversal).\n *\n * @public\n */\nexport type Primitive =\n | string\n | number\n | boolean\n | bigint\n | symbol\n | null\n | undefined\n | Date\n | RegExp;\n\n/**\n * A value with **no addressable interior**: its changes are reported at the slice root rather\n * than at a path beneath it.\n *\n * @remarks\n * The distinction the path types were missing. `Map` and `Set` keep their contents outside own\n * enumerable keys, so walking them with `keyof` yields the names of their *methods* — which is\n * how `\"byId.get\"` and `\"byId.size\"` came to be offered as subscribable paths, and why a slice\n * holding a plain number autocompleted `\"toFixed\"`. Neither ever notified anything, because\n * `detectChangedProps` reports such a value at its own path and never descends into it.\n *\n * This is the type-level counterpart of that runtime rule: what the diff reports at the root,\n * the types address at the root, with the empty path.\n *\n * @public\n */\nexport type RootValue = Primitive | ReadonlyMap<unknown, unknown> | ReadonlySet<unknown>;\n\n/**\n * Compute dotted paths of T, including nested objects and arrays.\n *\n * @typeParam T - Type to compute paths for.\n *\n * @public\n */\nexport type Path<T> = T extends RootValue\n ? never\n : T extends readonly (infer U)[]\n ? `${number}` | (Path<U> extends never ? never : `${number}.${Path<U>}`)\n : {\n [K in keyof T & string]: T[K] extends Primitive\n ? K\n : K | (Path<T[K]> extends never ? never : `${K}.${Path<T[K]>}`);\n }[keyof T & string];\n\n/**\n * Allow wildcard patterns like \"*\" and \"**\" anywhere in the string.\n *\n * @typeParam T - Base string type.\n *\n * @public\n */\nexport type WithGlob<T extends string> = T | `${string}*${string}`;\n\n/**\n * Dotted keys of a slice: top-level keys or any nested path.\n *\n * @typeParam Slice - Slice state type.\n *\n * @remarks\n * A slice that **is** one value — a primitive, a `Map`, a `Set`, a `Date` — has no key to\n * address, and its only subscribable path is the empty one. Saying so is what makes\n * `{ reducer, property: \"\" }` type-check where it can actually fire, instead of falling through\n * to the untyped `property: string` overload and returning `unknown`.\n *\n * The conditional distributes over unions, which is why a nullable object slice gets both:\n * `Dotted<{ a: number } | null>` is `\"\" | \"a\"`. That is exactly right — such a slice really does\n * change at its root when it becomes `null`, and at `\"a\"` otherwise.\n *\n * @public\n */\nexport type Dotted<Slice> = Slice extends RootValue\n ? \"\"\n : (keyof Slice & string) | Path<Slice>;\n\n/**\n * Deep readonly type: recursively makes all properties readonly.\n *\n * @remarks\n * The built-in object types are handled before the general mapped-object case, because\n * mapping over one destroys it. `{ readonly [K in keyof Map<K, V>]: ... }` produces an object\n * carrying the *names* of a Map's methods with their signatures rewritten, so reading a Map\n * out of state and calling `.get()` on it was a type error even though the value at runtime\n * is an ordinary Map. The same applied to `Set`, `Date`, `RegExp` and any function stored in\n * state.\n *\n * Collections become their `Readonly*` counterparts, which is the same treatment arrays\n * already had. Functions are returned untouched: a function's properties are not state, and\n * mapping over them makes it uncallable.\n *\n * @typeParam T - Type to make readonly.\n *\n * @public\n */\nexport type DeepReadonly<T> = T extends (...args: never[]) => unknown\n ? T\n : T extends (infer A)[]\n ? ReadonlyArray<DeepReadonly<A>>\n : T extends ReadonlyMap<infer K, infer V>\n ? ReadonlyMap<DeepReadonly<K>, DeepReadonly<V>>\n : T extends ReadonlySet<infer V>\n ? ReadonlySet<DeepReadonly<V>>\n : T extends Date | RegExp | Promise<unknown> | Error\n ? T\n : T extends object\n ? { readonly [K in keyof T]: DeepReadonly<T[K]> }\n : T;\n\n/**\n * Phase of event subscription notification.\n *\n * - `'committed'`: Events that passed middleware and reached reducers (default)\n * - `'uncommitted'`: Events rejected by middleware\n * - `'written'`: Events that actually changed state\n * - `'all'`: Both committed and uncommitted events\n *\n * @remarks\n * `'committed'` means **not vetoed**, and always has. It fires for an event that passed\n * middleware whether or not any reducer wrote anything — including every event in a store with\n * no reducers at all, which is the shape a notification or analytics bus takes. Toasts,\n * animations and tracking depend on that, so it is not narrowed.\n *\n * `'written'` is the stricter fact, added rather than substituted: state changed. It fires\n * **after** the commit, so a subscriber reading `getState()` from it sees the new value — which\n * is what people tend to assume `'committed'` does.\n *\n * `'all'` deliberately stays `committed | uncommitted`. Folding `'written'` into it would hand\n * every existing `'all'` subscriber a second notification per written event and quietly double\n * their counts.\n *\n * @public\n */\nexport type EventPhase = \"committed\" | \"uncommitted\" | \"written\" | \"all\";\n\n/**\n * The phases a handler is actually *told about*.\n *\n * @remarks\n * `'all'` is a subscription selector, not an outcome — nothing is ever delivered \"in the all\n * phase\". Naming the difference keeps the two from being conflated in a handler signature, which\n * is where they were previously spelled out by hand and drifted: adding `'written'` to\n * {@link EventPhase} left three copies in `@yoltra/react` still claiming a handler could only\n * ever see two phases, and the build failed on the mismatch.\n *\n * @public\n */\nexport type NotifiedPhase = Exclude<EventPhase, \"all\">;\n\n/**\n * Handler function for event subscriptions (receives full event union).\n *\n * Event subscriptions are intended for the View layer (e.g., React components)\n * to react to events without affecting the event flow. They are fire-and-forget\n * and cannot cancel event propagation.\n *\n * @typeParam S - Store state type (readonly).\n * @typeParam EM - Event map.\n *\n * @param event - The event that was emitted\n * @param getState - Function to get current state\n * @param emit - Function to emit new events\n * @param phase - The phase ('committed' or 'uncommitted') indicating how the event was processed\n *\n * @example\n * ```ts\n * const handler: EventSubscriptionHandler<AppState, AppEM> = (event, getState, emit, phase) => {\n * if (phase === 'committed') {\n * console.log('Event committed:', event.type);\n * } else {\n * console.log('Event rejected:', event.type);\n * }\n * };\n * ```\n *\n * @public\n */\nexport type EventSubscriptionHandler<S = any, EM extends EventMapBase = EventMapBase> = (\n event: EventUnion<EM>,\n getState: () => S,\n emit: Emit<EM>,\n phase: NotifiedPhase,\n) => void | Promise<void>;\n\n/**\n * One change to a store's registrations.\n *\n * @remarks\n * Self-sufficient on purpose: an observer should never need a follow-up\n * `__devtoolsIntrospect()` call to act on what it was told.\n *\n * @public\n */\nexport interface RegistrationChange<EM extends EventMapBase = EventMapBase> {\n readonly kind: \"reducer\" | \"middleware\" | \"effect\";\n readonly op: \"mounted\" | \"unmounted\";\n /** Slice name for a reducer; `meta.name` for middleware and effects; absent when unnamed. */\n readonly name?: string;\n readonly origin: Origin;\n /** Introspection only, and only ever what a library passed. */\n readonly owner?: string;\n readonly description?: string;\n /**\n * The **normalized** matcher, as `matchesWhen` will actually use it.\n *\n * @remarks\n * Not the raw spec's `when`. `registerEffect` normalizes three ways, including turning no\n * targeting at all into `{ any: true }`, so handing back the raw form would describe\n * something other than what will fire.\n */\n readonly when?: When<EM>;\n /**\n * Reducers only: what happened to the slice's state.\n *\n * @remarks\n * Four values, and the fourth is the one that matters. `replaceReducers` updates an\n * existing slice by unmounting it with its state intact and remounting, so an observer\n * treating every `\"unmounted\"` as destruction would tear down a subscription it is about\n * to need. `\"retained\"` says the state survived; `\"deleted\"` says it did not.\n */\n readonly state?: \"initialized\" | \"preserved\" | \"deleted\" | \"retained\";\n /** Whether this registration is dispatched by key (O(1)) or by runtime matching. */\n readonly dispatch?: \"keyed\" | \"pattern\";\n}\n\n/**\n * Observer for {@link StoreInstance.onRegistrationChange}.\n *\n * @public\n */\nexport type RegistrationObserver<EM extends EventMapBase = EventMapBase> = (\n changes: readonly RegistrationChange<EM>[],\n) => void;\n\n/**\n * Where a registration came from.\n *\n * @remarks\n * The distinction already existed in the API surface and simply was not honoured. `replace*`\n * exists to replace *what the application authored*; a registration a library made through\n * `registerReducer` / `registerMiddleware` / `registerEffect` after construction was never in\n * that set, and no caller of `replaceReducers(myReducers)` means \"and also delete the slice\n * devtools or a decoration mounted\".\n *\n * - `spec` - supplied to `createStore`, or installed by a `replace*` call.\n * - `dynamic` - registered after construction, which is the only way to decorate a store\n * that already exists.\n * - `internal` - the store's own machinery, currently the reply listener behind\n * `store.call()`. Preserved even under `{ scope: \"all\" }`, because a test harness resetting\n * a store between cases never means \"and abandon the call that is in flight\".\n *\n * Recorded internally. No public signature takes it, and **no library declares it**: getting\n * this right must not depend on anyone remembering to pass a string.\n *\n * @public\n */\nexport type Origin = \"spec\" | \"dynamic\" | \"internal\";\n\n/**\n * Which registrations a `replace*` call is allowed to remove.\n *\n * @remarks\n * `\"spec\"` is the default and replaces only what the application authored. `\"all\"` restores\n * the pre-0.8.0 behaviour exactly, for a caller that genuinely wants it, such as a test\n * harness resetting a store between cases. `internal` registrations survive both.\n *\n * @public\n */\nexport type ReplaceScope = \"spec\" | \"all\";\n\n/**\n * One `onEvent` subscription: the handler plus whether it asked to hear replayed events.\n *\n * @remarks\n * An entry per subscription rather than the bare handler, for two reasons. It is where the\n * replay opt-in lives; and it gives each subscription its own identity, so two subscriptions\n * sharing one handler function are two Set members and disposing one no longer removes both.\n *\n * @internal\n */\nexport interface EventSubscriberEntry<S, EM extends EventMapBase> {\n readonly handler: EventSubscriptionHandler<S, EM>;\n readonly duringReplay: boolean;\n}\n\n/**\n * Narrowed event subscription handler for specific `(channel, type)` pairs.\n * Provides better type inference when subscribing to a single event type.\n *\n * @typeParam S - Store state type (readonly).\n * @typeParam EM - Event map.\n * @typeParam C - Channel key within `EM`.\n * @typeParam T - Event type key within channel `C`.\n *\n * @example\n * ```ts\n * const handler: NarrowedEventHandler<AppState, AppEM, 'ui', 'increment'> = (\n * event, // Event<AppEM, 'ui', 'increment'> - narrowed!\n * getState,\n * emit,\n * phase,\n * ) => {\n * // event.payload is typed as number (from EM['ui']['increment'])\n * console.log('Increment by:', event.payload);\n * };\n * ```\n *\n * @public\n */\nexport type NarrowedEventHandler<\n S,\n EM extends EventMapBase,\n C extends keyof EM & string,\n T extends keyof EM[C] & string,\n> = (\n event: Event<EM, C, T>,\n getState: () => S,\n emit: Emit<EM>,\n phase: NotifiedPhase,\n) => void | Promise<void>;\n// ============================================\n// Typed growth: decorating a store after construction\n// ============================================\n\n/**\n * Flattens an intersection into a single object type.\n *\n * @remarks\n * Chaining decorations produces `S & Record<\"a\", A> & Record<\"b\", B>`, which is correct but\n * displays as an intersection in every hover and error message. This collapses it.\n *\n * Apply it at the **top level only**. It is a homomorphic mapped type, so running it over a\n * slice whose state *is* a `Map`, `Set` or `Date` destroys that type - the same failure\n * {@link DeepReadonly} handles the built-ins explicitly to avoid.\n *\n * @public\n */\nexport type Prettify<T> = { [K in keyof T]: T[K] } & {};\n\n/**\n * Merges `B` into `A`, flattening the result. An empty `B` leaves `A` untouched, so a\n * decoration that adds no events costs nothing at the type level.\n *\n * @public\n */\nexport type Merge<A, B> = [keyof B] extends [never] ? A : Prettify<A & B>;\n\n/**\n * The slice-name union after adding `N`.\n *\n * @remarks\n * The `string extends N` guard is load-bearing. Passing a `string`-typed variable rather than\n * a literal would otherwise widen the union to `string`, and every `S[R1]` lookup downstream\n * would resolve to the union of every slice's state - silently destroying `useAtomicProp`\n * inference across the whole application. Degrading to \"no widening\" is the safe failure.\n *\n * @public\n */\nexport type WidenNames<R extends string, N extends string> = string extends N ? R : R | N;\n\n/**\n * The state record after adding slice `N` with state `St`. Degrades to `S` when `N` is not a\n * string literal, for the reason given on {@link WidenNames}.\n *\n * @public\n */\nexport type WidenState<S, N extends string, St> = string extends N\n ? S\n : Prettify<S & Record<N, St>>;\n\n/**\n * Phantom carrier for the event map a spec contributes.\n *\n * @remarks\n * `EMAdd` cannot be inferred from a spec's `when`: `{ keys: [[\"chan\", \"evt\"]] }` carries\n * channel and type strings and no payload types, so there is nothing to infer a map from. And\n * TypeScript has no partial type-argument inference, so a `registerSlice<N, St, EMAdd>` would\n * force a caller who names `EMAdd` to hand-write `N` and `St` too.\n *\n * The way out is to put `EMAdd` in a **value** position, where inference works. The builders\n * ({@link defineSlice}, {@link defineMiddleware}, {@link defineEffect}) brand a spec with this\n * interface, and the register methods read it back with {@link EMAddOf}. Nothing exists at\n * runtime; the property is never assigned.\n *\n * The property is **required, not optional**: an optional one makes\n * `X extends EventMapCarrier<infer E>` match every object and infer `unknown`. And it is a\n * *function* type so `EMAdd` sits in both co- and contravariant position, which keeps the\n * inference exact rather than widening to a supertype.\n *\n * @public\n */\nexport interface EventMapCarrier<EMAdd extends EventMapBase> {\n /** Phantom. Never present at runtime, and never read. */\n readonly \"~yoltraEventMap\": (em: EMAdd) => EMAdd;\n}\n\n/**\n * Reads the event map a spec contributes, or `{}` when it declares none.\n *\n * @remarks\n * Only a branded spec widens the event map. An unbranded object literal contributes `{}`,\n * which is today's behaviour and therefore always safe.\n *\n * @public\n */\nexport type EMAddOf<X> = X extends { readonly \"~yoltraEventMap\": (em: infer E) => unknown }\n ? E extends EventMapBase\n ? E\n : EmptyEventMap\n : EmptyEventMap;\n\n/**\n * The event map a spec contributes when it declares none.\n *\n * @remarks\n * `Record<never, never>` rather than `{}`: the bare empty-object type accepts any non-nullish\n * value, including `0` and `\"\"`, so it would let nonsense through {@link Merge}. This has no\n * keys, which is the actual claim being made, and {@link Merge} short-circuits on it.\n *\n * @public\n */\nexport type EmptyEventMap = Record<never, never>;\n\n/**\n * Reads a reducer spec's state type.\n *\n * @public\n */\nexport type StateOfSpec<X> = X extends ReducerSpec<infer St, any> ? St : never;\n\n/**\n * What a decoration contributes to a store: some slices, some events, either possibly empty.\n *\n * @remarks\n * Phantom. Never constructed, and never present at runtime; it exists so a library can state\n * its contribution once and have {@link Decorated} and {@link StoreDecorator} read it back.\n *\n * @example\n * ```ts\n * type TransfersDecoration = Decoration<{ transfers: TransferState }, TransfersEM>;\n * ```\n *\n * @public\n */\nexport interface Decoration<\n AddS extends Record<string, any> = Record<never, never>,\n AddEM extends EventMapBase = EmptyEventMap,\n> {\n readonly slices: AddS;\n readonly events: AddEM;\n}\n\n/**\n * The store type that results from applying a {@link Decoration}.\n *\n * @public\n */\nexport type Decorated<R extends string, S extends Record<R, any>, EM extends EventMapBase, D> =\n D extends Decoration<infer AddS, infer AddEM>\n ? StoreInstance<\n WidenNames<R, keyof AddS & string>,\n SatisfiesSlices<Prettify<S & AddS>, WidenNames<R, keyof AddS & string>>,\n Merge<EM, AddEM>\n >\n : never;\n\n/**\n * The shape a `withX(store, config)` decorator conforms to, with `config` curried away.\n *\n * @remarks\n * **Generic over the incoming store on purpose**, and that is what makes composition work\n * rather than a variance rule. `R`, `S` and `EM` are inference sites, so at each call in a\n * nest TypeScript instantiates them from whatever the argument actually is: an EM-only\n * decorator nested inside one that also adds a slice infers the already-widened `R` and `S`\n * and carries them through untouched. Either order composes, and nothing is lost.\n *\n * Nesting is the composition mechanism; there is no `pipe`. Every decorator takes\n * `(store, config)`, so each step in a pipe needs a lambda to become unary, which makes\n * `pipe(store, s => withA(s, cfgA), s => withB(s, cfgB))` **longer** than\n * `withB(withA(store, cfgA), cfgB)`. A pipe only pays for curried decorators, which would be\n * a different convention from the one `withDevtools` already set.\n *\n * A dependency on another decoration needs no registry either: constrain the input.\n * `EM extends EventMapBase & RequiredEM` fails at the call site naming the channels that are\n * missing, and still composes, because TypeScript infers `EM` and then checks the constraint.\n *\n * @example\n * ```ts\n * export function withTransfers<\n * R extends string,\n * S extends Record<R, any>,\n * EM extends EventMapBase,\n * >(store: StoreInstance<R, S, EM>, config: TransfersConfig) {\n * return store.withSlice(\"transfers\", defineSlice<TransfersEM>()({ ... }), {\n * owner: \"@scope/transfers\",\n * });\n * }\n * ```\n *\n * @public\n */\nexport type StoreDecorator<D extends Decoration<any, any>> = <\n R extends string,\n S extends Record<R, any>,\n EM extends EventMapBase,\n>(\n store: StoreInstance<R, S, EM>,\n) => Decorated<R, S, EM, D>;\n\n/**\n * A store that can be decorated, and whose type grows as it is.\n *\n * @public\n */\nexport type DecoratableStore<\n R extends string,\n S extends Record<R, any>,\n EM extends EventMapBase,\n> = StoreInstance<R, S, EM>;\n\n/**\n * Proves to the compiler that a widened state record still covers every slice name.\n *\n * @remarks\n * `StoreInstance` constrains `S extends Record<R, any>`, and TypeScript cannot correlate\n * {@link WidenState} with {@link WidenNames} well enough to see that the widened record\n * always carries the widened key set - both branch on `string extends N`, but it checks each\n * in isolation.\n *\n * The intersection is with `unknown`, **never `any`**. `T & unknown` reduces to `T`, so every\n * slice keeps its exact type; `T & any` is `any`, which silently collapses every slice's\n * state and destroys the inference this feature exists to provide. That was a real bug caught\n * by the spike, and it is the reason this helper is written out rather than inlined.\n *\n * @public\n */\nexport type SatisfiesSlices<T, K extends string> = Prettify<T & Record<K, unknown>>;\n\n/**\n * The store type after mounting slice `N` from `Spec`.\n *\n * @public\n */\nexport type WidenedSlice<\n R extends string,\n S extends Record<R, any>,\n EM extends EventMapBase,\n N extends string,\n Spec,\n> = DecoratableStore<\n WidenNames<R, N>,\n SatisfiesSlices<WidenState<S, N, StateOfSpec<Spec>>, WidenNames<R, N>>,\n Merge<EM, EMAddOf<Spec>>\n>;\n\n/**\n * The registration surface whose return types carry the widening.\n *\n * @remarks\n * Every method returns the **same runtime object**, re-typed. Subscriptions, effects,\n * middleware, the dedup cache, both buses and any in-flight `call()` are untouched; the only\n * runtime effect is the registration itself.\n *\n * Note there is no explicit type parameter for the added event map anywhere. It is inferred\n * from a single value position, so the partial-inference problem never arises and no call\n * site needs a type argument or a cast.\n *\n * @public\n */\nexport interface StoreDecoration<\n R extends string,\n S extends Record<R, any>,\n EM extends EventMapBase,\n> {\n /**\n * Mounts a slice and hands back both the widened store and a disposer.\n *\n * The disposer is **library-private**: after it runs, the widened type still promises a\n * slice that is gone. Application code should take {@link StoreDecoration.withSlice}\n * instead, which returns no disposer at all.\n */\n registerSlice<N extends string, Spec extends ReducerSpec<any, any>>(\n name: N,\n spec: Spec,\n options?: { owner?: string },\n ): Unsubscribe & { store: WidenedSlice<R, S, EM, N, Spec>; dispose(): void };\n\n /** Mounts a slice and returns the widened store, for chaining. */\n withSlice<N extends string, Spec extends ReducerSpec<any, any>>(\n name: N,\n spec: Spec,\n options?: { owner?: string },\n ): WidenedSlice<R, S, EM, N, Spec>;\n\n /**\n * Registers middleware and returns the store widened by whatever event map it declares.\n *\n * Only the **spec form** can widen: `MiddlewareFunction`'s event parameter is\n * `EventUnion<EM>`, a mapped type TypeScript cannot infer `EM` back out of. A bare function\n * therefore contributes `{}`.\n */\n withMiddleware<M extends MiddlewareInput<any, any>>(\n mw: M,\n ): DecoratableStore<R, S, Merge<EM, EMAddOf<M>>>;\n\n /** Registers an effect and returns the store widened by whatever event map it declares. */\n withEffect<Spec extends EffectSpec<any, any>>(\n spec: Spec,\n ): DecoratableStore<R, S, Merge<EM, EMAddOf<Spec>>>;\n}\n\n/**\n * Declares a reducer spec together with the event map it contributes.\n *\n * @remarks\n * Curried so `EMAdd` is named once and `St` is inferred from `state`, which is what lets every\n * registration site stay free of type arguments. Identity at runtime.\n *\n * @example\n * ```ts\n * type LibEM = { \"lib.transfer\": { granted: { id: string } } };\n *\n * const transfers = defineSlice<LibEM>()({\n * state: { granted: [] as string[] },\n * when: { keys: [[\"lib.transfer\", \"granted\"]] },\n * reducer: (s, e) => (e.type === \"granted\" ? { granted: [...s.granted, e.payload.id] } : s),\n * });\n *\n * const widened = store.withSlice(\"transfers\", transfers);\n * // widened.getState().transfers.granted is string[], and `lib.transfer` is emittable\n * ```\n *\n * @public\n */\nexport const defineSlice =\n <EMAdd extends EventMapBase>() =>\n <St>(spec: ReducerSpec<St, EMAdd>): ReducerSpec<St, EMAdd> & EventMapCarrier<EMAdd> =>\n spec as ReducerSpec<St, EMAdd> & EventMapCarrier<EMAdd>;\n\n/**\n * Declares a middleware spec together with the event map it contributes.\n *\n * @remarks\n * The spec form is the **only** form that can widen an event map. Identity at runtime.\n *\n * @public\n */\nexport const defineMiddleware =\n <EMAdd extends EventMapBase, St = any>() =>\n (\n spec: MiddlewareSpec<DeepReadonly<St>, EMAdd>,\n ): MiddlewareSpec<DeepReadonly<St>, EMAdd> & EventMapCarrier<EMAdd> =>\n spec as MiddlewareSpec<DeepReadonly<St>, EMAdd> & EventMapCarrier<EMAdd>;\n\n/**\n * Declares an effect spec together with the event map it contributes.\n *\n * @remarks\n * Identity at runtime.\n *\n * @public\n */\nexport const defineEffect =\n <EMAdd extends EventMapBase, St = any>() =>\n (\n spec: EffectSpec<DeepReadonly<St>, EMAdd>,\n ): EffectSpec<DeepReadonly<St>, EMAdd> & EventMapCarrier<EMAdd> =>\n spec as EffectSpec<DeepReadonly<St>, EMAdd> & EventMapCarrier<EMAdd>;\n","/**\n * Normalised collections, so a list stops paying O(N) for an O(1) change.\n *\n * @remarks\n * Path notification is positional for arrays. `detectChangedProps` walks indices and reports\n * `items.0.title`, which names a *slot*, not a thing. So `unshift`, `splice(0, 1)` and `sort`\n * move nearly every element into a different slot, and the diff correctly reports that nearly\n * every leaf changed. Inserting one row at the front of a thousand wakes a thousand\n * subscribers.\n *\n * The remedy is the state shape, not a quieter diff. A key-stable array diff would need an\n * identity key the diff has no business knowing, and even then the *paths* would still be\n * positional — `items.0.title` names position zero, and so does the RFC-6902 pointer the\n * devtools agents build from it.\n *\n * Normalising to `{ ids, entities }` makes `entities.abc.title` stable across insert, remove\n * and reorder.\n *\n * **What this does not do:** `ids` is still an array, so a reorder still reports `ids.0`,\n * `ids.1` and so on. That cost is confined rather than removed. A list container subscribes to\n * `ids` and reorders its children; rows subscribe to `entities.<id>.<field>` and stay asleep.\n * The promise is cost proportional to what actually changed.\n *\n * @module @yoltra/core\n */\n\n/** What an entity may be keyed by. */\nexport type EntityId = string | number;\n\n/**\n * A normalised collection.\n *\n * @typeParam T - The entity.\n * @typeParam Id - Its key type.\n *\n * @public\n */\nexport interface EntityState<T, Id extends EntityId = string> {\n /** Order. Reordering touches this and nothing under `entities`. */\n readonly ids: readonly Id[];\n /** Identity-keyed, so a path to one entity survives every change to the others. */\n readonly entities: Readonly<Record<Id, T>>;\n}\n\n/** A change to apply to one entity. */\nexport interface EntityUpdate<T, Id extends EntityId> {\n readonly id: Id;\n readonly changes: Partial<T>;\n}\n\n/** How an adapter identifies and orders its entities. */\nexport interface EntityAdapterOptions<T, Id extends EntityId> {\n /** Defaults to reading `id`. */\n readonly selectId?: (entity: T) => Id;\n /**\n * Keeps `ids` sorted.\n *\n * @remarks\n * Omit it and `ids` holds insertion order, which is cheaper: with a comparer, any change\n * that could affect position re-sorts. The sorted array is only adopted when it actually\n * differs, so a sort that changes nothing reports nothing.\n */\n readonly sortComparer?: (a: T, b: T) => number;\n}\n\n/**\n * Reducer helpers, selectors, and the subscription paths that make the shape worth having.\n *\n * @public\n */\nexport interface EntityAdapter<T, Id extends EntityId = string> {\n getInitialState(): EntityState<T, Id>;\n getInitialState<Extra extends object>(extra: Extra): EntityState<T, Id> & Extra;\n\n /** Adds an entity. Existing ids are left alone — this is not an upsert. */\n addOne<S extends EntityState<T, Id>>(state: S, entity: T): S;\n addMany<S extends EntityState<T, Id>>(state: S, entities: readonly T[]): S;\n /** Adds or replaces one entity wholesale. */\n setOne<S extends EntityState<T, Id>>(state: S, entity: T): S;\n setMany<S extends EntityState<T, Id>>(state: S, entities: readonly T[]): S;\n /** Replaces the whole collection. */\n setAll<S extends EntityState<T, Id>>(state: S, entities: readonly T[]): S;\n /** Merges `changes` into one entity. Unknown ids are ignored. */\n updateOne<S extends EntityState<T, Id>>(state: S, update: EntityUpdate<T, Id>): S;\n updateMany<S extends EntityState<T, Id>>(state: S, updates: readonly EntityUpdate<T, Id>[]): S;\n /** Adds, or merges into an existing entity. */\n upsertOne<S extends EntityState<T, Id>>(state: S, entity: T): S;\n upsertMany<S extends EntityState<T, Id>>(state: S, entities: readonly T[]): S;\n removeOne<S extends EntityState<T, Id>>(state: S, id: Id): S;\n removeMany<S extends EntityState<T, Id>>(state: S, ids: readonly Id[]): S;\n removeAll<S extends EntityState<T, Id>>(state: S): S;\n\n selectIds(state: EntityState<T, Id>): readonly Id[];\n selectEntities(state: EntityState<T, Id>): Readonly<Record<Id, T>>;\n selectAll(state: EntityState<T, Id>): readonly T[];\n selectById(state: EntityState<T, Id>, id: Id): T | undefined;\n selectTotal(state: EntityState<T, Id>): number;\n\n /** Path to the order array. Subscribe here for a list that reorders. */\n readonly idsPath: string;\n /** Path to one entity, or to a field of it. */\n pathTo(id: Id, field?: string): string;\n /** Wildcard across every entity's `field`, for the loose subscription registry. */\n anyField(field: string): string;\n}\n\n/** @internal */\nconst warnedDottedIds = new Set<string>();\n\n/** @internal */\nfunction warnDottedId(id: EntityId): void {\n const key = String(id);\n if (warnedDottedIds.has(key)) return;\n warnedDottedIds.add(key);\n console.warn(\n `[yoltra] Entity id \"${key}\" contains a dot. Paths are dotted, so a subscription to ` +\n `\"entities.${key}\" is indistinguishable from one to a nested object of the same name. ` +\n `Use ids without dots.`,\n );\n}\n\n/**\n * Returns `next` only when it differs from `current`, element by element.\n *\n * @remarks\n * Reusing the existing array when the order did not change is what keeps `ids` out of the\n * changed-path list. Without it, every update to a sorted collection would report the order\n * as changed and wake the list container for nothing.\n *\n * @internal\n */\nfunction sameOrder<Id extends EntityId>(\n current: readonly Id[],\n next: readonly Id[],\n): readonly Id[] {\n if (current.length !== next.length) return next;\n for (let i = 0; i < current.length; i++) {\n if (current[i] !== next[i]) return next;\n }\n return current;\n}\n\n/**\n * Builds an adapter for one entity type.\n *\n * @example\n * ```ts\n * const todos = createEntityAdapter<Todo>();\n *\n * const spec: ReducerSpec<EntityState<Todo>, EM> = {\n * state: todos.getInitialState(),\n * when: { keys: eventKeys<EM>()([['todos', 'toggled']]) },\n * reducer: (state, event) =>\n * todos.updateOne(state, { id: event.payload.id, changes: { done: event.payload.done } }),\n * };\n *\n * // and in a component\n * useAtomicProp({ reducer: 'todos', property: todos.pathTo(id, 'title') });\n * ```\n *\n * @public\n */\nexport function createEntityAdapter<T, Id extends EntityId = string>(\n options: EntityAdapterOptions<T, Id> = {},\n): EntityAdapter<T, Id> {\n const selectId = options.selectId ?? ((entity: T) => (entity as { id: Id }).id);\n const { sortComparer } = options;\n\n const order = <S extends EntityState<T, Id>>(state: S, ids: readonly Id[]): readonly Id[] => {\n if (sortComparer === undefined) return ids;\n const sorted = [...ids].sort((a, b) => {\n const left = state.entities[a];\n const right = state.entities[b];\n if (left === undefined || right === undefined) return 0;\n return sortComparer(left, right);\n });\n return sameOrder(ids, sorted);\n };\n\n const write = <S extends EntityState<T, Id>>(\n state: S,\n entities: Record<Id, T>,\n ids: readonly Id[],\n ): S => {\n const next = { ...state, entities, ids } as S;\n return { ...next, ids: order(next, ids) };\n };\n\n const put = <S extends EntityState<T, Id>>(\n state: S,\n incoming: readonly T[],\n mode: \"add\" | \"set\" | \"upsert\",\n ): S => {\n let entities: Record<Id, T> | null = null;\n let ids: Id[] | null = null;\n\n for (const entity of incoming) {\n const id = selectId(entity);\n if (process.env.NODE_ENV !== \"production\" && String(id).includes(\".\")) warnDottedId(id);\n\n const existing = (entities ?? state.entities)[id];\n if (existing !== undefined && mode === \"add\") continue;\n\n const value =\n existing !== undefined && mode === \"upsert\" ? { ...existing, ...entity } : entity;\n\n entities ??= { ...state.entities };\n entities[id] = value;\n if (existing === undefined) {\n ids ??= [...state.ids];\n ids.push(id);\n }\n }\n\n if (entities === null) return state;\n return write(state, entities, ids ?? state.ids);\n };\n\n const merge = <S extends EntityState<T, Id>>(\n state: S,\n updates: readonly EntityUpdate<T, Id>[],\n ): S => {\n let entities: Record<Id, T> | null = null;\n\n for (const { id, changes } of updates) {\n const existing = (entities ?? state.entities)[id];\n if (existing === undefined) continue;\n entities ??= { ...state.entities };\n // Only the touched entity gets a new reference. Cloning the rest would report every\n // entity as changed, which is the defect this whole module exists to remove.\n entities[id] = { ...existing, ...changes };\n }\n\n if (entities === null) return state;\n return write(state, entities, state.ids);\n };\n\n const drop = <S extends EntityState<T, Id>>(state: S, ids: readonly Id[]): S => {\n const doomed = new Set<Id>(ids.filter((id) => state.entities[id] !== undefined));\n if (doomed.size === 0) return state;\n\n const entities = { ...state.entities };\n for (const id of doomed) delete entities[id];\n return write(\n state,\n entities,\n state.ids.filter((id) => !doomed.has(id)),\n );\n };\n\n return {\n getInitialState<Extra extends object>(extra?: Extra) {\n const base: EntityState<T, Id> = { ids: [], entities: {} as Record<Id, T> };\n return (extra === undefined ? base : { ...base, ...extra }) as EntityState<T, Id> & Extra;\n },\n\n addOne: (state, entity) => put(state, [entity], \"add\"),\n addMany: (state, entities) => put(state, entities, \"add\"),\n setOne: (state, entity) => put(state, [entity], \"set\"),\n setMany: (state, entities) => put(state, entities, \"set\"),\n setAll: (state, entities) => {\n const next = {} as Record<Id, T>;\n const ids: Id[] = [];\n for (const entity of entities) {\n const id = selectId(entity);\n if (next[id] === undefined) ids.push(id);\n next[id] = entity;\n }\n return write(state, next, ids);\n },\n updateOne: (state, update) => merge(state, [update]),\n updateMany: (state, updates) => merge(state, updates),\n upsertOne: (state, entity) => put(state, [entity], \"upsert\"),\n upsertMany: (state, entities) => put(state, entities, \"upsert\"),\n removeOne: (state, id) => drop(state, [id]),\n removeMany: (state, ids) => drop(state, ids),\n removeAll: (state) => (state.ids.length === 0 ? state : write(state, {} as Record<Id, T>, [])),\n\n selectIds: (state) => state.ids,\n selectEntities: (state) => state.entities,\n selectAll: (state) => state.ids.map((id) => state.entities[id]!),\n selectById: (state, id) => state.entities[id],\n selectTotal: (state) => state.ids.length,\n\n idsPath: \"ids\",\n pathTo: (id, field) => (field === undefined ? `entities.${id}` : `entities.${id}.${field}`),\n anyField: (field) => `entities.*.${field}`,\n };\n}\n","/**\n * Saving state, and starting from saved state.\n *\n * @remarks\n * The two halves happen on opposite sides of the store's existence, which is why this is two\n * functions rather than one. {@link hydrate} produces *initial slice state*, so the store is\n * born hydrated; {@link persist} subscribes to a store that already exists.\n *\n * Restoring after construction is the obvious alternative and the wrong one. It means applying\n * a whole-state snapshot to a live store, which emits a change across every path: a visible\n * flash on boot, a burst of instrumentation entries describing changes nobody made, and\n * effects observing a transition that never happened.\n *\n * @module @yoltra/core\n */\n\nimport { decodeState, encodeState } from \"../serialize/codec\";\n\n/** Where persisted state lives. Bring your own; core imports no platform global. */\nexport interface PersistenceAdapter {\n read(key: string): string | null | Promise<string | null>;\n write(key: string, value: string): void | Promise<void>;\n remove(key: string): void | Promise<void>;\n}\n\n/** Where a failure happened, so a handler can tell a bad write from a bad payload. */\nexport type PersistencePhase = \"read\" | \"write\" | \"decode\" | \"migrate\" | \"encode\";\n\n/** Shared configuration. */\nexport interface PersistOptions {\n /** Storage key. */\n readonly key: string;\n readonly adapter: PersistenceAdapter;\n /**\n * Schema version of what is written.\n *\n * @remarks\n * Compared on read. A mismatch is handed to {@link PersistOptions.migrate}, and without one\n * the stored value is discarded rather than trusted — reducers change, and a snapshot\n * written against an older shape is not merely stale, it may not be valid state at all.\n */\n readonly version: number;\n /** Slices to persist. Every slice by default. */\n readonly slices?: readonly string[];\n /** Coalescing window for writes, in milliseconds. Defaults to 250. */\n readonly throttleMs?: number;\n /**\n * Upgrades a payload written by an older version.\n *\n * @returns The slices to restore, or `null` to start fresh.\n */\n readonly migrate?: (persisted: unknown, from: number) => Record<string, unknown> | null;\n /**\n * Called on any failure.\n *\n * @remarks\n * Persistence never throws into the application it is persisting. A store that will not\n * start because storage holds stale JSON is worse than one that starts fresh, and a full\n * disk should not take down a page.\n */\n readonly onError?: (error: unknown, phase: PersistencePhase) => void;\n}\n\n/** What {@link hydrate} recovered. */\nexport interface Hydration {\n /** Slice states to start from. Empty when there was nothing usable to restore. */\n readonly slices: Readonly<Record<string, unknown>>;\n /** `true` when a payload was found, decoded and accepted. */\n readonly restored: boolean;\n}\n\n/** What is written to storage. */\ninterface Envelope {\n readonly version: number;\n readonly slices: Record<string, unknown>;\n}\n\n/** @internal */\nfunction report(\n options: Pick<PersistOptions, \"onError\">,\n error: unknown,\n phase: PersistencePhase,\n): void {\n options.onError?.(error, phase);\n}\n\n/**\n * Reads persisted state, ready to seed a store.\n *\n * @remarks\n * Every read-side failure — missing, unparseable, wrong version with no migration, a\n * migration that declines — resolves to \"nothing to restore\" and reports through\n * {@link PersistOptions.onError}. Nothing throws.\n *\n * @example\n * ```ts\n * const hydration = await hydrate({ key: 'app', adapter, version: 3 });\n * const store = createStore({\n * name: 'App',\n * reducer: withHydration({ todos: todosSpec }, hydration),\n * });\n * ```\n *\n * @public\n */\nexport async function hydrate(\n options: PersistOptions & { readonly source?: string },\n): Promise<Hydration> {\n const empty: Hydration = { slices: {}, restored: false };\n\n let raw: string | null | undefined;\n try {\n raw = options.source ?? (await options.adapter.read(options.key));\n } catch (error) {\n report(options, error, \"read\");\n return empty;\n }\n if (raw === null || raw === undefined || raw === \"\") return empty;\n\n let envelope: Envelope;\n try {\n envelope = decodeState(JSON.parse(raw)) as Envelope;\n } catch (error) {\n report(options, error, \"decode\");\n return empty;\n }\n\n if (envelope === null || typeof envelope !== \"object\" || typeof envelope.version !== \"number\") {\n report(options, new Error(\"persisted payload is not a recognisable envelope\"), \"decode\");\n return empty;\n }\n\n if (envelope.version !== options.version) {\n if (options.migrate === undefined) {\n report(\n options,\n new Error(\n `persisted state is version ${envelope.version}, this build expects ${options.version}, and no migrate was supplied`,\n ),\n \"migrate\",\n );\n return empty;\n }\n try {\n const migrated = options.migrate(envelope.slices, envelope.version);\n if (migrated === null) return empty;\n return { slices: migrated, restored: true };\n } catch (error) {\n report(options, error, \"migrate\");\n return empty;\n }\n }\n\n return { slices: envelope.slices ?? {}, restored: true };\n}\n\n/**\n * Replaces each reducer's initial state with what was restored for it.\n *\n * @remarks\n * Slices absent from the payload keep their declared defaults, so adding a reducer does not\n * invalidate everything written before it existed.\n *\n * @public\n */\nexport function withHydration<R extends Record<string, { state: unknown }>>(\n reducers: R,\n hydration: Hydration,\n): R {\n if (!hydration.restored) return reducers;\n\n const next = {} as Record<string, { state: unknown }>;\n for (const [name, spec] of Object.entries(reducers)) {\n const restored = hydration.slices[name];\n next[name] = restored === undefined ? spec : { ...spec, state: restored };\n }\n return next as R;\n}\n\n/** The store surface persistence needs, which is two methods wide. */\nexport interface PersistableStore {\n getState(): unknown;\n instrument(observer: (info: { changedPaths?: readonly string[] }) => void): () => void;\n}\n\n/**\n * Serializes the slices being persisted.\n *\n * @remarks\n * The encode report used to be dropped on the floor, so a value the codec could not\n * represent was written as a lossy stand-in and **nothing anywhere said so** - the loss only\n * surfaced later, as a slice that came back wrong. It is now reported through\n * {@link PersistOptions.onError} under the `\"encode\"` phase. Its own phase rather than\n * `\"write\"`: a serialization loss and an adapter failure need different responses, and\n * telling them apart is what `onError` is for.\n *\n * Reporting never blocks the write. Partial state is better than none, and the caller is the\n * one who decides what a loss means.\n */\nfunction encodeEnvelope(\n state: unknown,\n options: Pick<PersistOptions, \"version\" | \"slices\" | \"onError\">,\n): string {\n const all = (state ?? {}) as Record<string, unknown>;\n const slices: Record<string, unknown> =\n options.slices === undefined\n ? all\n : Object.fromEntries(options.slices.filter((s) => s in all).map((s) => [s, all[s]]));\n\n const { value, report: encodeReport } = encodeState({ version: options.version, slices });\n\n if (encodeReport.truncated || encodeReport.unsupported.length > 0) {\n // Both, when both. A ternary reported only the truncation and threw away the paths,\n // which are the actionable half: \"too large\" says retry with less, a named path says\n // which value to change.\n const parts: string[] = [];\n if (encodeReport.truncated) parts.push(\"state was too large to encode in full\");\n if (encodeReport.unsupported.length > 0) {\n parts.push(`values with no faithful representation at: ${encodeReport.unsupported.join(\", \")}`);\n }\n const detail = parts.join(\"; \");\n report(\n options,\n new Error(`[yoltra] Persisted state is incomplete - ${detail}.`),\n \"encode\",\n );\n }\n\n return JSON.stringify(value);\n}\n\n/**\n * Writes state as it changes.\n *\n * @returns A function that stops persisting and flushes anything pending.\n *\n * @remarks\n * Driven by `instrument` rather than the coarse subscription, so a change confined to a slice\n * that is not persisted costs nothing at all. Writes are coalesced on the trailing edge.\n *\n * @public\n */\nexport function persist(store: PersistableStore, options: PersistOptions): () => void {\n const throttleMs = options.throttleMs ?? 250;\n const watched = options.slices;\n let timer: ReturnType<typeof setTimeout> | null = null;\n let pending = false;\n\n const flush = (): void => {\n if (!pending) return;\n pending = false;\n try {\n const written = options.adapter.write(options.key, encodeEnvelope(store.getState(), options));\n if (written instanceof Promise) {\n void written.catch((error: unknown) => report(options, error, \"write\"));\n }\n } catch (error) {\n // Storage being full, or unavailable in private mode, must not surface to the caller.\n report(options, error, \"write\");\n }\n };\n\n const schedule = (): void => {\n pending = true;\n if (throttleMs <= 0) {\n flush();\n return;\n }\n if (timer !== null) return;\n timer = setTimeout(() => {\n timer = null;\n flush();\n }, throttleMs);\n // Never hold a process open for a pending write.\n (timer as unknown as { unref?: () => void }).unref?.();\n };\n\n const stop = store.instrument((info) => {\n if (watched === undefined) {\n schedule();\n return;\n }\n // A changed path is `slice.rest`; only a watched slice is worth a write.\n const touched = (info.changedPaths ?? []).some((path) =>\n watched.some((slice) => path === slice || path.startsWith(`${slice}.`)),\n );\n if (touched) schedule();\n });\n\n return () => {\n stop();\n if (timer !== null) {\n clearTimeout(timer);\n timer = null;\n }\n flush();\n };\n}\n\n/**\n * Serializes a store for handoff, for example from a server render to the client.\n *\n * @public\n */\nexport function dehydrate(\n store: Pick<PersistableStore, \"getState\">,\n options: Pick<PersistOptions, \"version\" | \"slices\" | \"onError\">,\n): string {\n return encodeEnvelope(store.getState(), options);\n}\n","/**\n * Storage adapters for the environments core can reach without importing them.\n *\n * @remarks\n * Each is built by a factory that takes the storage object rather than reaching for a global,\n * so this module stays isomorphic: nothing here breaks a Worker, a server render or a test.\n *\n * @module @yoltra/core\n */\n\nimport type { PersistenceAdapter } from \"./persist\";\n\n/** The slice of the Web Storage API used here. */\nexport interface WebStorageLike {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n removeItem(key: string): void;\n}\n\n/**\n * Wraps a Web Storage object.\n *\n * @remarks\n * Pass `localStorage` or `sessionStorage` explicitly. Reading the global here would make this\n * module unusable anywhere one does not exist, which includes a server render — exactly where\n * hydration payloads are produced.\n *\n * @example\n * ```ts\n * const adapter = createWebStorageAdapter(localStorage);\n * ```\n *\n * @public\n */\nexport function createWebStorageAdapter(storage: WebStorageLike): PersistenceAdapter {\n return {\n read: (key) => storage.getItem(key),\n write: (key, value) => storage.setItem(key, value),\n remove: (key) => storage.removeItem(key),\n };\n}\n\n/**\n * Keeps state in memory.\n *\n * @remarks\n * For tests, and for a server render that wants the persistence path exercised without a\n * store behind it. It forgets on restart, which is the whole of what it claims.\n *\n * @public\n */\nexport function createMemoryAdapter(initial?: Record<string, string>): PersistenceAdapter {\n const store = new Map<string, string>(Object.entries(initial ?? {}));\n return {\n read: (key) => store.get(key) ?? null,\n write: (key, value) => {\n store.set(key, value);\n },\n remove: (key) => {\n store.delete(key);\n },\n };\n}\n"],"names":["EventBus","channel","type","handler","byType","set","payload","event","h","err","LooseEventBus","typeStr","pattern","pmap","key","map","normalizedType","cMap","list","i","pMap","exactList","patternLists","called","deliver","arr","exc","make","s","p","index","segments","entry","head","bucket","at","e","patternMap","subject","lists","test","entries","handlers","pSegs","sSegs","j","star","matchIdx","result","Reducer","reduce","state","warnedDottedKeys","warnDottedKey","path","full","detectChangedProps","oldState","newState","ancestors","out","walk","oldObj","newObj","active","onPath","isArrOld","isArrNew","a","b","overlap","oldKeys","newKeys","sameKeys","hasOld","nextPath","freezeState","obj","seen","alias","desc","sym","REJECTED","Rejected","reason","isRejected","value","CallTimeoutError","idleMs","CallAbortedError","parseReply","reply","types","t","isReplyTo","requestId","correlationId","CallQueue","highWaterMark","item","taker","release","buffered","putter","next","DEFAULT_CALL_TIMEOUT_MS","DEFAULT_CALL_WATERMARK","performCall","deps","opts","replyChannel","isTerminal","queue","settle","fail","settled","terminal","resolve","reject","timer","unregister","finish","fn","graceful","onAbort","arm","onOk","onErr","onDone","getAtPath","parts","cur","seg","buildAncestorPaths","TAG","BINARY_CONSTRUCTORS","resolveBinaryKind","view","own","name","Ctor","bytesToBase64","bytes","maybeBuffer","CHUNK","binary","base64ToBytes","b64","buf","encodeState","input","options","maxNodes","sanitize","unsupported","nodes","truncated","asObject","previous","k","v","values","kind","proto","ctorName","escapePointer","decodeState","byPath","pending","isRef","tagged","error","copy","restored","walkPlain","childPath","root","target","encodeStateBounded","maxBytes","nodeBudget","attempt","report","size","scaled","FINGERPRINT_MAX_NODES","stableStringify","fingerprint","base","matchesWhen","when","getMiddlewareFunction","getMiddlewareWhen","normalizeEventKeys","spec","cloneInitialState","sliceName","freezeInDev","DEFAULT_DEDUP_KEY_WINDOW_MS","MAX_REGISTRATION_CASCADE","MAX_REMEMBERED_DISPOSED_SLICES","DEFAULT_MAX_REDUCE_DEPTH","CASCADE_CHAIN_LIMIT","NOT_COMMITTED","DEDUPED","CASCADE_REFUSED","COMMITTED_UNWRITTEN","WRITTEN","now","Store","rSpec","effSpec","fingerprintOf","fp","windowMs","existing","effectiveWindow","cutoff","timestamp","limit","limitValue","depth","chain","emit","effectSet","effect","cause","parent","phase","phaseSet","allSet","rName","staged","prev","leafPaths","nextState","slice","toEmit","prop","reducers","effects","meta","middleware","mwInput","origin","atomic","collectSubscribers","coarse","nextPlain","wasReplaying","anyChanged","prevSlice","nextSlice","frozenNextSlice","oldValue","newValue","l","snapshot","events","evt","rejection","refused","anySliceChanged","scopedParent","dedupKey","contentWindow","id","done","r","parentId","instrumenting","prevState","sink","t0","mw","ok","vetoedBy","rejectedBy","written","observer","changedPaths","reduceTimeMs","prevValues","nextValues","info","owner","off","current","wasNotifying","batch","drained","targetMap","op","dispatch","dispose","unsubs","eventKeys","normalized","keyedWhen","u","getState","typed","scope","retained","keeps","preserved","preserveState","currentKeys","nextEntries","nextKeys","rootBefore","collisions","named","method","count","partial","reducer","ch","tp","sourceEvent","_removed","rest","readAtPath","ancestorPaths","createStore","cfg","typedEvents","_","keys","defineSlice","defineMiddleware","defineEffect","warnedDottedIds","warnDottedId","sameOrder","createEntityAdapter","selectId","entity","sortComparer","order","ids","sorted","left","right","write","entities","put","incoming","mode","merge","updates","changes","drop","doomed","extra","update","field","hydrate","empty","raw","envelope","migrated","withHydration","hydration","encodeEnvelope","all","slices","encodeReport","detail","persist","store","throttleMs","watched","flush","schedule","stop","dehydrate","createWebStorageAdapter","storage","createMemoryAdapter","initial"],"mappings":"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"}
|