@flurryx/store 1.0.1 → 1.1.1

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/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/base-store.ts","../src/store-clone.ts","../src/store-replay.ts","../src/store-messages.ts","../src/store-channels.ts","../src/store-registry.ts","../src/store-message-consumer.ts","../src/lazy-store.ts","../src/store-builder.ts","../src/dynamic-store.ts","../src/mirror-key.ts","../src/collect-keyed.ts","../src/resource.ts"],"sourcesContent":["import { signal, type Signal, WritableSignal } from \"@angular/core\";\nimport { ResourceState, type KeyedResourceKey } from \"@flurryx/core\";\nimport type { IStore, StoreDataShape, StoreKey, StoreOptions } from \"./types\";\nimport { cloneValue } from \"./store-clone\";\nimport {\n createStoreHistory,\n type StoreHistoryDriver,\n type StoreHistoryEntry,\n} from \"./store-replay\";\nimport type { StoreMessageRecord } from \"./store-channels\";\nimport { trackStore } from \"./store-registry\";\nimport {\n createDefaultState,\n createStoreMessageConsumer,\n createUpdateMessage,\n createClearMessage,\n createClearAllMessage,\n createStartLoadingMessage,\n createStopLoadingMessage,\n createUpdateKeyedOneMessage,\n createClearKeyedOneMessage,\n createStartKeyedLoadingMessage,\n} from \"./store-message-consumer\";\n\ntype UpdateHooksMap = Map<\n unknown,\n Array<\n (\n nextState: ResourceState<unknown>,\n previousState: ResourceState<unknown>\n ) => void\n >\n>;\n\nconst updateHooksMap = new WeakMap<object, UpdateHooksMap>();\n\n/**\n * Abstract base class for flurryx stores.\n *\n * Backed by Angular `signal()` per slot, providing read-only `Signal` access\n * and immutable updates. All writes go through the store's own methods to\n * enforce single-owner encapsulation.\n *\n * Use the {@link Store} builder to create instances — do not subclass directly.\n *\n * @template TEnum - Record mapping slot names to their string/number keys.\n * @template TData - Record mapping slot names to `ResourceState<T>` types.\n */\nexport abstract class BaseStore<\n TEnum extends Record<string, string | number>,\n TData extends StoreDataShape<TData> & {\n [K in keyof TEnum]: ResourceState<unknown>;\n }\n> implements IStore<TData>\n{\n private readonly signalsState = new Map<\n string,\n WritableSignal<ResourceState<unknown>>\n >();\n private readonly storeKeys: readonly StoreKey<TData>[];\n private readonly historyDriver: StoreHistoryDriver<TData>;\n\n /** @inheritDoc */\n readonly travelTo = (index: number): void =>\n this.historyDriver.travelTo(index);\n\n /** @inheritDoc */\n readonly undo = (): boolean => this.historyDriver.undo();\n\n /** @inheritDoc */\n readonly redo = (): boolean => this.historyDriver.redo();\n\n /** @inheritDoc */\n readonly getDeadLetters = () => this.historyDriver.getDeadLetters();\n\n /** @inheritDoc */\n readonly replayDeadLetter = (id: number): boolean =>\n this.historyDriver.replayDeadLetter(id);\n\n /** @inheritDoc */\n readonly replayDeadLetters = (): number =>\n this.historyDriver.replayDeadLetters();\n\n /** @inheritDoc */\n readonly getCurrentIndex = () => this.historyDriver.getCurrentIndex();\n\n /** @inheritDoc */\n readonly history: Signal<readonly StoreHistoryEntry<TData>[]>;\n\n /** @inheritDoc */\n readonly messages: Signal<readonly StoreMessageRecord<TData>[]>;\n\n /** @inheritDoc */\n readonly currentIndex: Signal<number>;\n\n /** @inheritDoc */\n readonly keys: Signal<readonly StoreKey<TData>[]>;\n\n /** @inheritDoc */\n replay(id: number): number;\n\n /** @inheritDoc */\n replay(ids: readonly number[]): number;\n\n replay(idOrIds: number | readonly number[]): number {\n if (Array.isArray(idOrIds)) {\n return this.historyDriver.replay(idOrIds as readonly number[]);\n }\n\n return this.historyDriver.replay(idOrIds as number);\n }\n\n /** @inheritDoc */\n getHistory(): readonly StoreHistoryEntry<TData>[];\n\n /** @inheritDoc */\n getHistory<K extends StoreKey<TData>>(\n key: K\n ): readonly StoreHistoryEntry<TData, K>[];\n\n getHistory<K extends StoreKey<TData>>(key?: K) {\n if (key === undefined) {\n return this.historyDriver.getHistory();\n }\n\n return this.historyDriver.getHistory(key);\n }\n\n /** @inheritDoc */\n getMessages(): readonly StoreMessageRecord<TData>[];\n\n /** @inheritDoc */\n getMessages<K extends StoreKey<TData>>(\n key: K\n ): readonly StoreMessageRecord<TData, K>[];\n\n getMessages<K extends StoreKey<TData>>(key?: K) {\n if (key === undefined) {\n return this.historyDriver.getMessages();\n }\n\n return this.historyDriver.getMessages(key);\n }\n\n protected constructor(\n protected readonly storeEnum: TEnum,\n options?: StoreOptions<TData>\n ) {\n this.storeKeys = Object.keys(storeEnum) as StoreKey<TData>[];\n this.initializeState();\n updateHooksMap.set(this, new Map());\n\n const consumer = createStoreMessageConsumer<TData>(\n {\n getOrCreate: <K extends StoreKey<TData>>(key: K) =>\n this.signalsState.get(key) as WritableSignal<TData[K]>,\n getAllKeys: () => this.storeKeys,\n },\n {\n notify: <K extends StoreKey<TData>>(\n key: K,\n next: TData[K],\n prev: TData[K]\n ) => this.notifyUpdateHooks(key, next, prev),\n }\n );\n\n this.historyDriver = createStoreHistory<TData>({\n captureSnapshot: () => consumer.createSnapshot(),\n applySnapshot: (snapshot) => consumer.applySnapshot(snapshot),\n applyMessage: (message) => consumer.applyMessage(message),\n channel: options?.channel,\n });\n\n this.history = this.historyDriver.historySignal;\n this.messages = this.historyDriver.messagesSignal;\n this.currentIndex = this.historyDriver.currentIndexSignal;\n this.keys = signal([...this.storeKeys]).asReadonly();\n\n trackStore(this);\n }\n\n /**\n * Returns a **read-only** `Signal` for the given store slot.\n *\n * @param key - The slot name to read.\n * @returns A `Signal` wrapping the slot's current {@link ResourceState}.\n */\n get<K extends StoreKey<TData>>(key: K): Signal<TData[K]> {\n return this.signalsState.get(key.toString()) as unknown as Signal<TData[K]>;\n }\n\n /**\n * Registers a callback fired after every `update` or `clear` on the given slot.\n *\n * @param key - The slot to watch.\n * @param callback - Receives the new state and the previous state.\n * @returns A cleanup function that removes the listener when called.\n */\n onUpdate<K extends StoreKey<TData>>(\n key: K,\n callback: (state: TData[K], previousState: TData[K]) => void\n ): () => void {\n const hooks = updateHooksMap.get(this)!;\n if (!hooks.has(key)) {\n hooks.set(key, []);\n }\n hooks\n .get(key)!\n .push(\n callback as (\n nextState: ResourceState<unknown>,\n previousState: ResourceState<unknown>\n ) => void\n );\n\n return () => {\n const hooksMap = hooks.get(key);\n if (!hooksMap) {\n return;\n }\n const index = hooksMap.indexOf(\n callback as (\n nextState: ResourceState<unknown>,\n previousState: ResourceState<unknown>\n ) => void\n );\n if (index > -1) {\n hooksMap.splice(index, 1);\n }\n };\n }\n\n /**\n * Partially updates a slot by merging `newState` into the current value (immutable spread).\n *\n * @param key - The slot to update.\n * @param newState - Partial state to merge (e.g. `{ data: newData, status: 'Success' }`).\n */\n update<K extends StoreKey<TData>>(key: K, newState: Partial<TData[K]>): void {\n this.historyDriver.publish(\n createUpdateMessage<TData, K>(key, cloneValue(newState))\n );\n }\n\n /** Resets every slot in this store to its initial idle state. */\n clearAll(): void {\n this.historyDriver.publish(createClearAllMessage<TData>());\n }\n\n /**\n * Resets a single slot to `{ data: undefined, isLoading: false, status: undefined, errors: undefined }`.\n *\n * @param key - The slot to clear.\n */\n clear<K extends StoreKey<TData>>(key: K): void {\n this.historyDriver.publish(createClearMessage<TData, K>(key));\n }\n\n /**\n * Marks a slot as loading: sets `isLoading: true` and clears `status` and `errors`.\n *\n * @param key - The slot to mark as loading.\n */\n startLoading<K extends StoreKey<TData>>(key: K): void {\n this.historyDriver.publish(createStartLoadingMessage<TData, K>(key));\n }\n\n /**\n * Marks a slot as no longer loading: sets `isLoading: false`.\n * Does **not** clear `status` or `errors`.\n *\n * @param key - The slot to stop loading.\n */\n stopLoading<K extends StoreKey<TData>>(key: K): void {\n this.historyDriver.publish(createStopLoadingMessage<TData, K>(key));\n }\n\n /**\n * Merges a single entity into a {@link KeyedResourceData} slot.\n * Sets its status to `'Success'` and clears per-key errors.\n * The top-level `isLoading` is recalculated based on remaining loading keys.\n *\n * @param key - The keyed slot name.\n * @param resourceKey - The entity identifier (e.g. `'inv-123'`).\n * @param entity - The entity value to store.\n */\n updateKeyedOne<K extends StoreKey<TData>>(\n key: K,\n resourceKey: KeyedResourceKey,\n entity: unknown\n ): void {\n this.historyDriver.publish(\n createUpdateKeyedOneMessage<TData, K>(\n key,\n resourceKey,\n cloneValue(entity)\n )\n );\n }\n\n /**\n * Removes a single entity from a {@link KeyedResourceData} slot,\n * including its loading flag, status, and errors.\n * Recalculates the top-level `isLoading` from the remaining keys.\n *\n * @param key - The keyed slot name.\n * @param resourceKey - The entity identifier to remove.\n */\n clearKeyedOne<K extends StoreKey<TData>>(\n key: K,\n resourceKey: KeyedResourceKey\n ): void {\n this.historyDriver.publish(\n createClearKeyedOneMessage<TData, K>(key, resourceKey)\n );\n }\n\n /**\n * Marks a single entity within a keyed slot as loading.\n * Clears its status and errors. If the slot data is not yet a {@link KeyedResourceData},\n * falls back to `startLoading(key)`.\n *\n * @param key - The keyed slot name.\n * @param resourceKey - The entity identifier to mark as loading.\n */\n startKeyedLoading<K extends StoreKey<TData>>(\n key: K,\n resourceKey: KeyedResourceKey\n ): void {\n this.historyDriver.publish(\n createStartKeyedLoadingMessage<TData, K>(key, resourceKey)\n );\n }\n\n private notifyUpdateHooks<K extends StoreKey<TData>>(\n key: K,\n nextState: TData[K],\n previousState: TData[K]\n ): void {\n const hooks = updateHooksMap.get(this);\n const keyHooks = hooks?.get(key);\n if (!keyHooks) {\n return;\n }\n\n const errors: unknown[] = [];\n\n keyHooks.forEach((hook) => {\n try {\n hook(\n nextState as ResourceState<unknown>,\n previousState as ResourceState<unknown>\n );\n } catch (error: unknown) {\n errors.push(error);\n }\n });\n\n if (errors.length > 0) {\n queueMicrotask(() => {\n if (errors.length === 1) {\n throw errors[0];\n }\n throw new AggregateError(\n errors,\n `${errors.length} onUpdate hooks threw for key \"${String(key)}\"`\n );\n });\n }\n }\n\n private initializeState(): void {\n this.storeKeys.forEach((key) => {\n this.signalsState.set(\n key,\n signal<TData[typeof key]>(createDefaultState() as TData[typeof key])\n );\n });\n }\n}\n","import type { ResourceState } from \"@flurryx/core\";\n\n/**\n * Creates a deep clone of the given value.\n *\n * **Warning:** Class instances with constructor logic, private fields, or\n * non-enumerable state will not clone correctly. The clone preserves the\n * prototype chain via `Object.create(Object.getPrototypeOf(...))` but does\n * **not** invoke the constructor, so any side-effects or hidden state set\n * during construction will be missing from the clone.\n */\nexport function cloneValue<T>(value: T): T {\n if (value !== null && typeof value === \"object\") {\n const existingClone = cloneReference(value, new WeakMap<object, unknown>());\n return existingClone as T;\n }\n\n return value;\n}\n\nfunction cloneReference<T extends object>(\n value: T,\n seen: WeakMap<object, unknown>\n): T {\n const seenClone = seen.get(value);\n if (seenClone) {\n return seenClone as T;\n }\n\n if (value instanceof Date) {\n return new Date(value.getTime()) as T;\n }\n\n if (value instanceof Map) {\n const clonedMap = new Map<unknown, unknown>();\n seen.set(value, clonedMap);\n value.forEach((entryValue, key) => {\n clonedMap.set(\n cloneValueWithSeen(key, seen),\n cloneValueWithSeen(entryValue, seen)\n );\n });\n return clonedMap as T;\n }\n\n if (value instanceof Set) {\n const clonedSet = new Set<unknown>();\n seen.set(value, clonedSet);\n value.forEach((entryValue) => {\n clonedSet.add(cloneValueWithSeen(entryValue, seen));\n });\n return clonedSet as T;\n }\n\n if (Array.isArray(value)) {\n const clonedArray: unknown[] = [];\n seen.set(value, clonedArray);\n value.forEach((item, index) => {\n clonedArray[index] = cloneValueWithSeen(item, seen);\n });\n\n return clonedArray as T;\n }\n\n const clonedObject = Object.create(Object.getPrototypeOf(value)) as Record<\n PropertyKey,\n unknown\n >;\n seen.set(value, clonedObject);\n\n Reflect.ownKeys(value).forEach((key) => {\n const descriptor = Object.getOwnPropertyDescriptor(value, key);\n if (!descriptor) {\n return;\n }\n\n if (\"value\" in descriptor) {\n descriptor.value = cloneValueWithSeen(descriptor.value, seen);\n }\n\n Object.defineProperty(clonedObject, key, descriptor);\n });\n\n return clonedObject as T;\n}\n\nfunction cloneValueWithSeen<T>(value: T, seen: WeakMap<object, unknown>): T {\n if (value !== null && typeof value === \"object\") {\n return cloneReference(value, seen);\n }\n\n return value;\n}\n\n/**\n * Creates a minimal patch object that, when spread onto `currentState`, produces `snapshotState`.\n * Properties present in the snapshot are cloned; properties absent from the snapshot are set to `undefined`.\n *\n * @param currentState - The current slot state.\n * @param snapshotState - The target snapshot state to restore.\n * @returns A partial state object suitable for `Signal.update()`.\n */\nexport function createSnapshotRestorePatch<\n TState extends ResourceState<unknown>\n>(currentState: TState, snapshotState: TState): Partial<TState> {\n const patch: Record<PropertyKey, unknown> = {};\n const keys = new Set([\n ...Reflect.ownKeys(currentState),\n ...Reflect.ownKeys(snapshotState),\n ]);\n\n keys.forEach((key) => {\n if (Object.prototype.hasOwnProperty.call(snapshotState, key)) {\n patch[key] = cloneValue(\n (snapshotState as Record<PropertyKey, unknown>)[key]\n );\n return;\n }\n\n patch[key] = undefined;\n });\n\n return patch as Partial<TState>;\n}\n","import { signal, computed, type Signal } from \"@angular/core\";\nimport type { StoreDataShape, StoreKey } from \"./types\";\nimport type {\n StoreMessage,\n StoreSnapshot,\n StoreMessageStatus,\n} from \"./store-messages\";\nimport {\n INVALID_HISTORY_INDEX_ERROR,\n INVALID_HISTORY_MESSAGE_ID_ERROR,\n MESSAGE_NOT_ACKNOWLEDGED_ERROR,\n} from \"./store-messages\";\nimport { cloneValue } from \"./store-clone\";\nimport {\n createInMemoryStoreMessageChannel,\n type StoreMessageChannel,\n type StoreMessageRecord,\n} from \"./store-channels\";\n\n// ---------------------------------------------------------------------------\n// Re-exports — keep existing consumers working\n// ---------------------------------------------------------------------------\n\nexport { cloneValue, createSnapshotRestorePatch } from \"./store-clone\";\nexport type {\n StoreMessage,\n StoreSnapshot,\n StoreMessageStatus,\n UpdateStoreMessage,\n ClearStoreMessage,\n ClearAllStoreMessage,\n StartLoadingStoreMessage,\n StopLoadingStoreMessage,\n UpdateKeyedOneStoreMessage,\n ClearKeyedOneStoreMessage,\n StartKeyedLoadingStoreMessage,\n} from \"./store-messages\";\nexport {\n INVALID_HISTORY_INDEX_ERROR,\n INVALID_HISTORY_MESSAGE_ID_ERROR,\n MESSAGE_NOT_ACKNOWLEDGED_ERROR,\n} from \"./store-messages\";\nexport {\n createInMemoryStoreMessageChannel,\n createStorageStoreMessageChannel,\n createLocalStorageStoreMessageChannel,\n createSessionStorageStoreMessageChannel,\n createCompositeStoreMessageChannel,\n} from \"./store-channels\";\nexport type {\n StoreMessageChannel,\n StoreMessageChannelStorage,\n StoreMessageChannelOptions,\n CompositeStoreMessageChannelOptions,\n StorageStoreMessageChannelOptions,\n BrowserStorageStoreMessageChannelOptions,\n StoreMessageRecord,\n} from \"./store-channels\";\n\n// ---------------------------------------------------------------------------\n// History types\n// ---------------------------------------------------------------------------\n\n/**\n * Single acknowledged point in store history.\n *\n * Entry `0` is always the initial snapshot captured when the history driver is\n * created, so its `id`, `message`, and `acknowledgedAt` are `null`.\n */\nexport interface StoreHistoryEntry<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> {\n /** Stable message id used by `replay(...)`; `null` for the initial snapshot entry. */\n readonly id: number | null;\n /** Snapshot position used by `travelTo(index)`, `undo()`, and `redo()`. */\n readonly index: number;\n /** Acknowledged message that produced this snapshot; `null` for the initial entry. */\n readonly message: StoreMessage<TData, TKey> | null;\n /** Full store snapshot captured immediately after the message was acknowledged. */\n readonly snapshot: StoreSnapshot<TData, TKey>;\n /** Acknowledgement timestamp for the message; `null` for the initial snapshot entry. */\n readonly acknowledgedAt: number | null;\n}\n\n/**\n * Failed message tracked by the internal broker when the store consumer does not\n * acknowledge a published message.\n */\nexport interface StoreDeadLetterEntry<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> {\n /** Stable dead-letter id used by `replayDeadLetter(id)`. */\n readonly id: number;\n /** Original message that failed acknowledgement. */\n readonly message: StoreMessage<TData, TKey>;\n /** Number of failed acknowledgement attempts for this dead letter. */\n readonly attempts: number;\n /** Last acknowledgement error captured for this dead letter. */\n readonly error: string;\n /** Timestamp of the most recent failure. */\n readonly failedAt: number;\n}\n\n/**\n * Public history and recovery API exposed on every store instance.\n *\n * `travelTo(...)` navigates snapshots by history index, while `replay(...)`\n * re-executes previously published channel messages by their stable message ids.\n */\nexport interface StoreHistory<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> {\n /**\n * Re-executes one previously published message by id.\n *\n * The message does not need to have been acknowledged before. Replay resolves it\n * from the configured message channel, sends it back through the broker/consumer\n * flow, and may create a fresh acknowledged history entry if the replay succeeds.\n *\n * @throws {Error} When the id does not point to a persisted channel message.\n * @returns Number of successfully acknowledged replayed messages.\n */\n replay(id: number): number;\n\n /**\n * Re-executes multiple previously published messages in the provided order.\n *\n * Every id must resolve to a persisted channel message. Replay stops with an error\n * if any supplied id is invalid.\n *\n * @throws {Error} When any id does not point to a persisted channel message.\n * @returns Number of successfully acknowledged replayed messages.\n */\n replay(ids: readonly number[]): number;\n\n /**\n * Restores the store to the snapshot recorded at a specific history index.\n *\n * This is snapshot navigation only. It does not publish or acknowledge any\n * message and does not create a new history entry.\n *\n * @throws {Error} When the index is outside the recorded history range.\n */\n travelTo(index: number): void;\n\n /**\n * Moves to the previous recorded snapshot.\n *\n * Equivalent to `travelTo(getCurrentIndex() - 1)` when possible.\n *\n * @returns `true` when the pointer moved, otherwise `false` at the initial snapshot.\n */\n undo(): boolean;\n\n /**\n * Moves to the next recorded snapshot when history exists ahead of the current pointer.\n *\n * Equivalent to `travelTo(getCurrentIndex() + 1)` when possible.\n *\n * @returns `true` when the pointer moved, otherwise `false` at the latest snapshot.\n */\n redo(): boolean;\n\n /** Returns a defensive copy of every recorded history entry, including the initial snapshot entry. */\n getHistory(): readonly StoreHistoryEntry<TData, TKey>[];\n\n /**\n * Returns the history entries that affected a specific store key.\n *\n * The initial snapshot entry is always included as the first item. Messages such\n * as `clearAll` that affect every key are included in every filtered view.\n */\n getHistory<K extends TKey>(key: K): readonly StoreHistoryEntry<TData, K>[];\n\n /** Returns a defensive copy of the current dead-letter collection. */\n getDeadLetters(): readonly StoreDeadLetterEntry<TData, TKey>[];\n\n /** Returns every message currently stored in the configured channel. */\n getMessages(): readonly StoreMessageRecord<TData, TKey>[];\n\n /** Returns channel messages that affected a specific store key. */\n getMessages<K extends TKey>(key: K): readonly StoreMessageRecord<TData, K>[];\n\n /**\n * Republishes a single dead-letter message by dead-letter id.\n *\n * On success the dead letter is removed and a new acknowledged history entry is recorded.\n *\n * @returns `true` when the dead letter was acknowledged on replay, otherwise `false`.\n */\n replayDeadLetter(id: number): boolean;\n\n /**\n * Attempts to republish every current dead letter once.\n *\n * Successfully acknowledged dead letters are removed. Failures remain in the\n * dead-letter collection with incremented attempt counts.\n *\n * @returns Number of dead letters successfully acknowledged during the replay attempt.\n */\n replayDeadLetters(): number;\n\n /** Returns the currently restored history index used by snapshot navigation. */\n getCurrentIndex(): number;\n\n /** Reactive signal containing the full history entries. */\n readonly historySignal: Signal<readonly StoreHistoryEntry<TData, TKey>[]>;\n /** Reactive signal containing all channel message records. */\n readonly messagesSignal: Signal<readonly StoreMessageRecord<TData, TKey>[]>;\n /** Reactive signal containing the current history index. */\n readonly currentIndexSignal: Signal<number>;\n}\n\nexport interface StoreHistoryDriver<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> extends StoreHistory<TData, TKey> {\n publish(message: StoreMessage<TData, TKey>): boolean;\n}\n\ninterface CreateStoreHistoryConfig<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> {\n readonly captureSnapshot: () => StoreSnapshot<TData, TKey>;\n readonly applySnapshot: (snapshot: StoreSnapshot<TData, TKey>) => void;\n readonly applyMessage: (message: StoreMessage<TData, TKey>) => boolean;\n readonly channel?: StoreMessageChannel<TData, TKey>;\n readonly clock?: () => number;\n}\n\ninterface StableReadonlyCollectionAppendInput<TItem> {\n readonly items: readonly TItem[];\n readonly item: TItem;\n}\n\ninterface StableReadonlyCollectionUpsertInput<\n TItem extends {\n readonly id: number;\n }\n> {\n readonly items: readonly TItem[];\n readonly item: TItem;\n}\n\ninterface StableReadonlyCollectionSyncInput<\n TSource,\n TItem extends {\n readonly id: number;\n }\n> {\n readonly items: readonly TItem[];\n readonly sourceItems: readonly TSource[];\n readonly getSourceId: (item: TSource) => number;\n readonly createItem: (item: TSource) => TItem;\n readonly areEquivalent: (sourceItem: TSource, cachedItem: TItem) => boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction messageAffectsKey<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData>,\n K extends TKey\n>(\n message: StoreMessage<TData, TKey>,\n key: K\n): message is StoreMessage<TData, K> {\n if (message.type === \"clearAll\") {\n return true;\n }\n\n return \"key\" in message && message.key === key;\n}\n\nfunction toDeadLetterEntry<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData>\n>(record: StoreMessageRecord<TData, TKey>): StoreDeadLetterEntry<TData, TKey> {\n return {\n id: record.id,\n message: cloneValue(record.message),\n attempts: record.attempts,\n error: record.error ?? MESSAGE_NOT_ACKNOWLEDGED_ERROR,\n failedAt: record.lastAttemptedAt ?? record.createdAt,\n };\n}\n\nfunction areValuesEquivalent(\n left: unknown,\n right: unknown,\n seen: WeakMap<object, WeakSet<object>> = new WeakMap<object, WeakSet<object>>()\n): boolean {\n if (Object.is(left, right)) {\n return true;\n }\n\n if (typeof left !== typeof right || left === null || right === null) {\n return false;\n }\n\n if (typeof left !== \"object\" || typeof right !== \"object\") {\n return false;\n }\n\n let seenRights = seen.get(left);\n if (seenRights?.has(right)) {\n return true;\n }\n\n if (!seenRights) {\n seenRights = new WeakSet<object>();\n seen.set(left, seenRights);\n }\n seenRights.add(right);\n\n if (left instanceof Date || right instanceof Date) {\n return (\n left instanceof Date &&\n right instanceof Date &&\n left.getTime() === right.getTime()\n );\n }\n\n if (left instanceof Map || right instanceof Map) {\n if (!(left instanceof Map) || !(right instanceof Map)) {\n return false;\n }\n\n const leftEntries = Array.from(left.entries());\n const rightEntries = Array.from(right.entries());\n if (leftEntries.length !== rightEntries.length) {\n return false;\n }\n\n return leftEntries.every(([leftKey, leftValue], index) => {\n const rightEntry = rightEntries[index];\n if (!rightEntry) {\n return false;\n }\n\n return (\n areValuesEquivalent(leftKey, rightEntry[0], seen) &&\n areValuesEquivalent(leftValue, rightEntry[1], seen)\n );\n });\n }\n\n if (left instanceof Set || right instanceof Set) {\n if (!(left instanceof Set) || !(right instanceof Set)) {\n return false;\n }\n\n const leftValues = Array.from(left.values());\n const rightValues = Array.from(right.values());\n if (leftValues.length !== rightValues.length) {\n return false;\n }\n\n return leftValues.every((leftValue, index) =>\n areValuesEquivalent(leftValue, rightValues[index], seen)\n );\n }\n\n if (Array.isArray(left) || Array.isArray(right)) {\n if (!Array.isArray(left) || !Array.isArray(right)) {\n return false;\n }\n\n if (left.length !== right.length) {\n return false;\n }\n\n return left.every((leftValue, index) =>\n areValuesEquivalent(leftValue, right[index], seen)\n );\n }\n\n if (Object.getPrototypeOf(left) !== Object.getPrototypeOf(right)) {\n return false;\n }\n\n const leftRecord = left as Record<PropertyKey, unknown>;\n const rightRecord = right as Record<PropertyKey, unknown>;\n const leftKeys = Reflect.ownKeys(leftRecord);\n const rightKeys = Reflect.ownKeys(rightRecord);\n\n if (leftKeys.length !== rightKeys.length) {\n return false;\n }\n\n return leftKeys.every((key) => {\n if (!Object.prototype.hasOwnProperty.call(rightRecord, key)) {\n return false;\n }\n\n return areValuesEquivalent(leftRecord[key], rightRecord[key], seen);\n });\n}\n\nfunction areStoreMessageRecordsEquivalent<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData>\n>(\n sourceRecord: StoreMessageRecord<TData, TKey>,\n cachedRecord: StoreMessageRecord<TData, TKey>\n): boolean {\n return (\n sourceRecord.id === cachedRecord.id &&\n sourceRecord.status === cachedRecord.status &&\n sourceRecord.attempts === cachedRecord.attempts &&\n sourceRecord.createdAt === cachedRecord.createdAt &&\n sourceRecord.lastAttemptedAt === cachedRecord.lastAttemptedAt &&\n sourceRecord.acknowledgedAt === cachedRecord.acknowledgedAt &&\n sourceRecord.error === cachedRecord.error &&\n areValuesEquivalent(sourceRecord.message, cachedRecord.message)\n );\n}\n\nfunction createStableReadonlyCollection<TItem>(\n items: readonly TItem[]\n): readonly TItem[] {\n return Object.freeze([...items]);\n}\n\nfunction appendStableReadonlyCollectionItem<TItem>(\n input: StableReadonlyCollectionAppendInput<TItem>\n): readonly TItem[] {\n return createStableReadonlyCollection([...input.items, input.item]);\n}\n\nfunction upsertStableReadonlyCollectionItem<\n TItem extends {\n readonly id: number;\n }\n>(input: StableReadonlyCollectionUpsertInput<TItem>): readonly TItem[] {\n const existingIndex = input.items.findIndex(\n (candidate) => candidate.id === input.item.id\n );\n\n if (existingIndex === -1) {\n return appendStableReadonlyCollectionItem(input);\n }\n\n if (Object.is(input.items[existingIndex], input.item)) {\n return input.items;\n }\n\n const nextItems = [...input.items];\n nextItems[existingIndex] = input.item;\n return createStableReadonlyCollection(nextItems);\n}\n\nfunction syncStableReadonlyCollectionById<\n TSource,\n TItem extends {\n readonly id: number;\n }\n>(input: StableReadonlyCollectionSyncInput<TSource, TItem>): readonly TItem[] {\n const cachedItemsById = new Map<number, TItem>();\n input.items.forEach((item) => {\n cachedItemsById.set(item.id, item);\n });\n\n let didChange = input.items.length !== input.sourceItems.length;\n const nextItems = input.sourceItems.map((sourceItem, index) => {\n const cachedItem = cachedItemsById.get(input.getSourceId(sourceItem));\n const nextItem =\n cachedItem && input.areEquivalent(sourceItem, cachedItem)\n ? cachedItem\n : input.createItem(sourceItem);\n\n if (!didChange && input.items[index] !== nextItem) {\n didChange = true;\n }\n\n return nextItem;\n });\n\n return didChange ? createStableReadonlyCollection(nextItems) : input.items;\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\nexport function createStoreHistory<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n>(\n config: CreateStoreHistoryConfig<TData, TKey>\n): StoreHistoryDriver<TData, TKey> {\n const messageChannel =\n config.channel ?? createInMemoryStoreMessageChannel<TData, TKey>();\n const clock = config.clock ?? Date.now;\n let history: readonly StoreHistoryEntry<TData, TKey>[] = [\n {\n id: null,\n index: 0,\n message: null,\n snapshot: config.captureSnapshot(),\n acknowledgedAt: null,\n },\n ];\n let currentIndex = 0;\n let historyCollection = createStableReadonlyCollection(\n history.map((entry) => cloneValue(entry))\n );\n let messageCollection = createStableReadonlyCollection(\n messageChannel.getMessages().map((record) => cloneValue(record))\n );\n\n const version = signal(0);\n function notifyVersion(): void {\n version.update((v) => v + 1);\n }\n\n function recordSnapshot(record: StoreMessageRecord<TData, TKey>): void {\n const nextIndex = history.length;\n const nextHistoryEntry: StoreHistoryEntry<TData, TKey> = {\n id: record.id,\n index: nextIndex,\n message: cloneValue(record.message),\n snapshot: config.captureSnapshot(),\n acknowledgedAt: record.acknowledgedAt,\n };\n\n history = [...history, nextHistoryEntry];\n historyCollection = appendStableReadonlyCollectionItem({\n items: historyCollection,\n item: cloneValue(nextHistoryEntry),\n });\n currentIndex = nextIndex;\n }\n\n function truncateFutureHistory(): void {\n if (currentIndex === history.length - 1) {\n return;\n }\n\n history = history.slice(0, currentIndex + 1);\n historyCollection = createStableReadonlyCollection(\n historyCollection.slice(0, currentIndex + 1)\n );\n }\n\n function ensureIndexInRange(index: number): void {\n if (!Number.isInteger(index) || index < 0 || index >= history.length) {\n throw new Error(INVALID_HISTORY_INDEX_ERROR);\n }\n }\n\n function travelTo(index: number): void {\n ensureIndexInRange(index);\n config.applySnapshot(history[index]!.snapshot);\n currentIndex = index;\n notifyVersion();\n }\n\n function undo(): boolean {\n if (currentIndex === 0) {\n return false;\n }\n\n travelTo(currentIndex - 1);\n return true;\n }\n\n function redo(): boolean {\n if (currentIndex >= history.length - 1) {\n return false;\n }\n\n travelTo(currentIndex + 1);\n return true;\n }\n\n function getErrorMessage(error: unknown): string {\n if (error instanceof Error && error.message) {\n return error.message;\n }\n\n return MESSAGE_NOT_ACKNOWLEDGED_ERROR;\n }\n\n function persistMessageAttempt(\n record: StoreMessageRecord<TData, TKey>,\n status: StoreMessageStatus,\n error: string | null,\n attemptedAt: number\n ): StoreMessageRecord<TData, TKey> {\n const nextRecord: StoreMessageRecord<TData, TKey> = {\n ...record,\n message: cloneValue(record.message),\n status,\n attempts: record.attempts + 1,\n lastAttemptedAt: attemptedAt,\n acknowledgedAt:\n status === \"acknowledged\" ? attemptedAt : record.acknowledgedAt,\n error,\n };\n\n messageChannel.saveMessage(nextRecord);\n messageCollection = upsertStableReadonlyCollectionItem({\n items: messageCollection,\n item: cloneValue(nextRecord),\n });\n return nextRecord;\n }\n\n function consumeRecord(\n record: StoreMessageRecord<TData, TKey>,\n options?: {\n readonly recordHistory?: boolean;\n }\n ): boolean {\n const clonedMessage = cloneValue(record.message);\n const attemptedAt = clock();\n\n try {\n const acknowledged = config.applyMessage(clonedMessage);\n if (!acknowledged) {\n throw new Error(MESSAGE_NOT_ACKNOWLEDGED_ERROR);\n }\n\n const acknowledgedRecord = persistMessageAttempt(\n {\n ...record,\n message: clonedMessage,\n },\n \"acknowledged\",\n null,\n attemptedAt\n );\n\n if (options?.recordHistory !== false) {\n truncateFutureHistory();\n recordSnapshot(acknowledgedRecord);\n }\n\n notifyVersion();\n return true;\n } catch (error) {\n persistMessageAttempt(\n {\n ...record,\n message: clonedMessage,\n },\n \"dead-letter\",\n getErrorMessage(error),\n attemptedAt\n );\n notifyVersion();\n return false;\n }\n }\n\n function resolveReplayRecords(\n ids: readonly number[]\n ): StoreMessageRecord<TData, TKey>[] {\n return ids.map((id) => {\n if (!Number.isInteger(id) || id < 1) {\n throw new Error(INVALID_HISTORY_MESSAGE_ID_ERROR);\n }\n\n const record = messageChannel.getMessage(id);\n if (!record) {\n throw new Error(INVALID_HISTORY_MESSAGE_ID_ERROR);\n }\n\n return cloneValue(record);\n });\n }\n\n function replayByIds(input: number | readonly number[]): number {\n const ids = Array.isArray(input) ? input : [input];\n const records = resolveReplayRecords(ids);\n let acknowledgedCount = 0;\n\n records.forEach((record) => {\n if (consumeRecord(record)) {\n acknowledgedCount += 1;\n }\n });\n\n return acknowledgedCount;\n }\n\n function replayDeadLetter(id: number): boolean {\n const record = messageChannel.getMessage(id);\n if (!record || record.status !== \"dead-letter\") {\n return false;\n }\n\n return consumeRecord(record);\n }\n\n function replayDeadLetters(): number {\n const ids = messageChannel\n .getMessages()\n .filter((record) => record.status === \"dead-letter\")\n .map((record) => record.id);\n let acknowledgedCount = 0;\n\n ids.forEach((id) => {\n if (replayDeadLetter(id)) {\n acknowledgedCount += 1;\n }\n });\n\n return acknowledgedCount;\n }\n\n const historySignal = computed(() => {\n version();\n return historyCollection;\n });\n\n const messagesSignal = computed(() => {\n version();\n messageCollection = syncStableReadonlyCollectionById({\n items: messageCollection,\n sourceItems: messageChannel.getMessages(),\n getSourceId: (record) => record.id,\n createItem: (record) => cloneValue(record),\n areEquivalent: areStoreMessageRecordsEquivalent,\n });\n return messageCollection;\n });\n\n const currentIndexSignal = computed(() => {\n version();\n return currentIndex;\n });\n\n return {\n historySignal,\n messagesSignal,\n currentIndexSignal,\n publish(message) {\n const record = messageChannel.publish(message);\n messageCollection = appendStableReadonlyCollectionItem({\n items: messageCollection,\n item: cloneValue(record),\n });\n return consumeRecord(record);\n },\n replay(input: number | readonly number[]) {\n return replayByIds(input);\n },\n travelTo,\n undo,\n redo,\n getHistory<K extends TKey>(key?: K) {\n if (key === undefined) {\n return history.map((entry) => cloneValue(entry));\n }\n\n return history\n .filter((entry) => {\n if (entry.message === null) {\n return true;\n }\n\n return messageAffectsKey(entry.message, key);\n })\n .map((entry) => cloneValue(entry) as StoreHistoryEntry<TData, K>);\n },\n getMessages<K extends TKey>(key?: K) {\n const records = messageChannel.getMessages();\n if (key === undefined) {\n return records.map((record) => cloneValue(record));\n }\n\n return records\n .filter((record) => messageAffectsKey(record.message, key))\n .map((record) => cloneValue(record) as StoreMessageRecord<TData, K>);\n },\n getDeadLetters() {\n return messageChannel\n .getMessages()\n .filter((record) => record.status === \"dead-letter\")\n .map((record) => toDeadLetterEntry(record));\n },\n replayDeadLetter,\n replayDeadLetters,\n getCurrentIndex() {\n return currentIndex;\n },\n };\n}\n","import type {\n KeyedResourceEntryKey,\n KeyedResourceEntryValue,\n KeyedStoreKey,\n StoreDataShape,\n StoreKey,\n} from \"./types\";\n\n/** Message produced by `store.update(key, partial)` — merges partial state into a slot. */\nexport type UpdateStoreMessage<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> = {\n readonly [K in TKey]: {\n readonly type: \"update\";\n readonly key: K;\n readonly state: Partial<TData[K]>;\n };\n}[TKey];\n\n/** Message produced by `store.clear(key)` — resets a single slot to its initial state. */\nexport type ClearStoreMessage<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> = {\n readonly [K in TKey]: {\n readonly type: \"clear\";\n readonly key: K;\n };\n}[TKey];\n\n/** Message produced by `store.clearAll()` — resets every slot in the store. */\nexport interface ClearAllStoreMessage<TData extends StoreDataShape<TData>> {\n readonly type: \"clearAll\";\n}\n\n/** Message produced by `store.startLoading(key)` — sets `isLoading: true` and clears `status`/`errors`. */\nexport type StartLoadingStoreMessage<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> = {\n readonly [K in TKey]: {\n readonly type: \"startLoading\";\n readonly key: K;\n };\n}[TKey];\n\n/** Message produced by `store.stopLoading(key)` — sets `isLoading: false`. */\nexport type StopLoadingStoreMessage<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> = {\n readonly [K in TKey]: {\n readonly type: \"stopLoading\";\n readonly key: K;\n };\n}[TKey];\n\n/** Message produced by `store.updateKeyedOne(key, resourceKey, entity)` — merges a single entity into a keyed slot. */\nexport type UpdateKeyedOneStoreMessage<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> = {\n readonly [K in KeyedStoreKey<TData, TKey>]: {\n readonly type: \"updateKeyedOne\";\n readonly key: K;\n readonly resourceKey: KeyedResourceEntryKey<TData, K>;\n readonly entity: KeyedResourceEntryValue<TData, K>;\n };\n}[KeyedStoreKey<TData, TKey>];\n\n/** Message produced by `store.clearKeyedOne(key, resourceKey)` — removes a single entity from a keyed slot. */\nexport type ClearKeyedOneStoreMessage<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> = {\n readonly [K in KeyedStoreKey<TData, TKey>]: {\n readonly type: \"clearKeyedOne\";\n readonly key: K;\n readonly resourceKey: KeyedResourceEntryKey<TData, K>;\n };\n}[KeyedStoreKey<TData, TKey>];\n\n/** Message produced by `store.startKeyedLoading(key, resourceKey)` — marks a single entity as loading. */\nexport type StartKeyedLoadingStoreMessage<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> = {\n readonly [K in KeyedStoreKey<TData, TKey>]: {\n readonly type: \"startKeyedLoading\";\n readonly key: K;\n readonly resourceKey: KeyedResourceEntryKey<TData, K>;\n };\n}[KeyedStoreKey<TData, TKey>];\n\n/** Discriminated union of all typed store messages published to the broker channel. */\nexport type StoreMessage<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> =\n | UpdateStoreMessage<TData, TKey>\n | ClearStoreMessage<TData, TKey>\n | ClearAllStoreMessage<TData>\n | StartLoadingStoreMessage<TData, TKey>\n | StopLoadingStoreMessage<TData, TKey>\n | UpdateKeyedOneStoreMessage<TData, TKey>\n | ClearKeyedOneStoreMessage<TData, TKey>\n | StartKeyedLoadingStoreMessage<TData, TKey>;\n\n/** Full store state captured at a point in time, keyed by slot name. Used by history and time travel. */\nexport type StoreSnapshot<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> = Partial<{\n readonly [K in TKey]: TData[K];\n}>;\n\n/** Delivery status of a broker message: `\"pending\"` → `\"acknowledged\"` or `\"dead-letter\"`. */\nexport type StoreMessageStatus = \"pending\" | \"acknowledged\" | \"dead-letter\";\n\n/** Error message thrown when `travelTo()` receives an index outside the recorded history range. */\nexport const INVALID_HISTORY_INDEX_ERROR = \"History index is out of range\";\n/** Error message thrown when `replay()` receives an id that does not match a persisted channel message. */\nexport const INVALID_HISTORY_MESSAGE_ID_ERROR =\n \"History message id is out of range\";\n/** Error message recorded in dead-letter entries when the store consumer does not acknowledge a message. */\nexport const MESSAGE_NOT_ACKNOWLEDGED_ERROR = \"Message was not acknowledged\";\n","import type { StoreDataShape, StoreKey } from \"./types\";\nimport type { StoreMessage, StoreMessageStatus } from \"./store-messages\";\nimport { cloneValue } from \"./store-clone\";\n\n/**\n * Persisted broker message record stored in the active message channel.\n *\n * Message ids are allocated when the message is first published and remain stable\n * across acknowledgement, replay, and dead-letter transitions.\n */\nexport interface StoreMessageRecord<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> {\n /** Stable message id used by `replay(...)` and dead-letter recovery APIs. */\n readonly id: number;\n /** Published store message payload. */\n readonly message: StoreMessage<TData, TKey>;\n /** Latest delivery status stored by the broker channel. */\n readonly status: StoreMessageStatus;\n /** Number of delivery attempts made for this message. */\n readonly attempts: number;\n /** Timestamp when the message was first published to the channel. */\n readonly createdAt: number;\n /** Timestamp of the most recent delivery attempt. */\n readonly lastAttemptedAt: number | null;\n /** Timestamp of the most recent successful acknowledgement, if any. */\n readonly acknowledgedAt: number | null;\n /** Last recorded delivery error, or `null` when the latest attempt succeeded. */\n readonly error: string | null;\n}\n\n/** Minimal string-based storage adapter used by storage-backed message channels. */\nexport interface StoreMessageChannelStorage {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n removeItem(key: string): void;\n}\n\n/**\n * Pluggable persistence channel used by the broker to store published messages.\n *\n * The default channel is in-memory, but storage-backed or custom providers can be\n * supplied to keep messages available across refreshes or offline sessions.\n */\nexport interface StoreMessageChannel<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> {\n /** Stores a newly published message and allocates its stable message id. */\n publish(message: StoreMessage<TData, TKey>): StoreMessageRecord<TData, TKey>;\n /** Reads a single persisted message record by id. */\n getMessage(id: number): StoreMessageRecord<TData, TKey> | undefined;\n /** Reads every persisted message record from the channel. */\n getMessages(): readonly StoreMessageRecord<TData, TKey>[];\n /** Persists a new state for an existing message record. */\n saveMessage(entry: StoreMessageRecord<TData, TKey>): void;\n}\n\n/** Optional store configuration used to override the default in-memory message channel. */\nexport interface StoreMessageChannelOptions<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> {\n readonly channel?: StoreMessageChannel<TData, TKey>;\n}\n\n/** Options for {@link createCompositeStoreMessageChannel}. The first channel is the primary (reads + id allocation); replicas receive all writes. */\nexport interface CompositeStoreMessageChannelOptions<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> {\n readonly channels: readonly StoreMessageChannel<TData, TKey>[];\n}\n\n/** Options for {@link createStorageStoreMessageChannel}. Provide a custom storage adapter, key, and optional serialize/deserialize hooks. */\nexport interface StorageStoreMessageChannelOptions<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> {\n readonly storage: StoreMessageChannelStorage;\n readonly storageKey: string;\n readonly serialize?: (\n state: PersistedStoreMessageChannelState<TData, TKey>\n ) => string;\n readonly deserialize?: (\n value: string\n ) => PersistedStoreMessageChannelState<TData, TKey>;\n}\n\n/** Options for {@link createLocalStorageStoreMessageChannel} and {@link createSessionStorageStoreMessageChannel}. Storage defaults to the browser global. */\nexport interface BrowserStorageStoreMessageChannelOptions<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> extends Omit<StorageStoreMessageChannelOptions<TData, TKey>, \"storage\"> {\n readonly storage?: StoreMessageChannelStorage;\n}\n\n// ---------------------------------------------------------------------------\n// Internal types\n// ---------------------------------------------------------------------------\n\ninterface PersistedStoreMessageChannelState<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> {\n readonly nextId: number;\n readonly messages: readonly StoreMessageRecord<TData, TKey>[];\n}\n\ntype SerializedStoreMessageChannelValue =\n | null\n | boolean\n | number\n | string\n | {\n readonly __flurryxType: \"undefined\";\n }\n | {\n readonly __flurryxType: \"date\";\n readonly value: string;\n }\n | {\n readonly __flurryxType: \"array\";\n readonly values: readonly SerializedStoreMessageChannelValue[];\n }\n | {\n readonly __flurryxType: \"set\";\n readonly values: readonly SerializedStoreMessageChannelValue[];\n }\n | {\n readonly __flurryxType: \"map\";\n readonly entries: readonly [\n SerializedStoreMessageChannelValue,\n SerializedStoreMessageChannelValue\n ][];\n }\n | {\n readonly __flurryxType: \"object\";\n readonly entries: readonly [string, SerializedStoreMessageChannelValue][];\n };\n\n// ---------------------------------------------------------------------------\n// Serialization\n// ---------------------------------------------------------------------------\n\nfunction serializeStoreMessageChannelValue(\n value: unknown\n): SerializedStoreMessageChannelValue {\n if (value === undefined) {\n return { __flurryxType: \"undefined\" };\n }\n\n if (\n value === null ||\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\"\n ) {\n return value;\n }\n\n if (value instanceof Date) {\n return {\n __flurryxType: \"date\",\n value: value.toISOString(),\n };\n }\n\n if (value instanceof Map) {\n return {\n __flurryxType: \"map\",\n entries: Array.from(value.entries(), ([key, entryValue]) => [\n serializeStoreMessageChannelValue(key),\n serializeStoreMessageChannelValue(entryValue),\n ]),\n };\n }\n\n if (value instanceof Set) {\n return {\n __flurryxType: \"set\",\n values: Array.from(value.values(), (entryValue) =>\n serializeStoreMessageChannelValue(entryValue)\n ),\n };\n }\n\n if (Array.isArray(value)) {\n return {\n __flurryxType: \"array\",\n values: value.map((entryValue) =>\n serializeStoreMessageChannelValue(entryValue)\n ),\n };\n }\n\n if (typeof value === \"object\") {\n return {\n __flurryxType: \"object\",\n entries: Object.entries(value as Record<string, unknown>).map(\n ([key, entryValue]) => [\n key,\n serializeStoreMessageChannelValue(entryValue),\n ]\n ),\n };\n }\n\n throw new Error(\"Store message channel cannot serialize this value\");\n}\n\nfunction deserializeStoreMessageChannelValue(\n value: SerializedStoreMessageChannelValue\n): unknown {\n if (\n value === null ||\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\"\n ) {\n return value;\n }\n\n switch (value.__flurryxType) {\n case \"undefined\":\n return undefined;\n case \"date\":\n return new Date(value.value);\n case \"array\":\n return value.values.map((entryValue) =>\n deserializeStoreMessageChannelValue(entryValue)\n );\n case \"set\":\n return new Set(\n value.values.map((entryValue) =>\n deserializeStoreMessageChannelValue(entryValue)\n )\n );\n case \"map\":\n return new Map(\n value.entries.map(([key, entryValue]) => [\n deserializeStoreMessageChannelValue(key),\n deserializeStoreMessageChannelValue(entryValue),\n ])\n );\n case \"object\": {\n const result: Record<string, unknown> = {};\n value.entries.forEach(([key, entryValue]) => {\n result[key] = deserializeStoreMessageChannelValue(entryValue);\n });\n return result;\n }\n }\n}\n\nfunction defaultSerializeStoreMessageChannelState<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData>\n>(state: PersistedStoreMessageChannelState<TData, TKey>): string {\n return JSON.stringify(serializeStoreMessageChannelValue(state));\n}\n\nfunction defaultDeserializeStoreMessageChannelState<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData>\n>(value: string): PersistedStoreMessageChannelState<TData, TKey> {\n return deserializeStoreMessageChannelValue(\n JSON.parse(value) as SerializedStoreMessageChannelValue\n ) as PersistedStoreMessageChannelState<TData, TKey>;\n}\n\n// ---------------------------------------------------------------------------\n// Utilities\n// ---------------------------------------------------------------------------\n\nfunction normalizeStoreMessageChannelState<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData>\n>(\n state: PersistedStoreMessageChannelState<TData, TKey>\n): PersistedStoreMessageChannelState<TData, TKey> {\n const maxId = state.messages.reduce(\n (currentMax, entry) => Math.max(currentMax, entry.id),\n 0\n );\n\n return {\n nextId: Math.max(state.nextId, maxId + 1),\n messages: state.messages.map((entry) => cloneValue(entry)),\n };\n}\n\nexport function createInitialStoreMessageRecord<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData>\n>(\n id: number,\n message: StoreMessage<TData, TKey>,\n clock: () => number = Date.now\n): StoreMessageRecord<TData, TKey> {\n return {\n id,\n message: cloneValue(message),\n status: \"pending\",\n attempts: 0,\n createdAt: clock(),\n lastAttemptedAt: null,\n acknowledgedAt: null,\n error: null,\n };\n}\n\nfunction isQuotaExceededError(error: unknown): boolean {\n return (\n error instanceof DOMException &&\n (error.code === 22 ||\n error.code === 1014 ||\n error.name === \"QuotaExceededError\" ||\n error.name === \"NS_ERROR_DOM_QUOTA_REACHED\")\n );\n}\n\nfunction resolveGlobalStorage(\n name: \"localStorage\" | \"sessionStorage\"\n): StoreMessageChannelStorage {\n const storage = globalThis[name];\n if (!storage) {\n throw new Error(`${name} is not available in this environment`);\n }\n\n return storage as StoreMessageChannelStorage;\n}\n\n// ---------------------------------------------------------------------------\n// Channel factories\n// ---------------------------------------------------------------------------\n\n/**\n * Creates an in-memory message channel. Messages are stored in a JavaScript array\n * and lost on page refresh. This is the default channel when no `channel` option is provided.\n */\nexport function createInMemoryStoreMessageChannel<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n>(): StoreMessageChannel<TData, TKey> {\n let messages: StoreMessageRecord<TData, TKey>[] = [];\n let nextId = 1;\n\n return {\n publish(message) {\n const record = createInitialStoreMessageRecord(nextId++, message);\n messages = [...messages, record];\n return cloneValue(record);\n },\n getMessage(id) {\n const record = messages.find((entry) => entry.id === id);\n return record ? cloneValue(record) : undefined;\n },\n getMessages() {\n return messages.map((entry) => cloneValue(entry));\n },\n saveMessage(entry) {\n const record = cloneValue(entry);\n const existingIndex = messages.findIndex(\n (candidate) => candidate.id === record.id\n );\n\n if (existingIndex === -1) {\n messages = [...messages, record];\n } else {\n messages = messages.map((c, i) => (i === existingIndex ? record : c));\n }\n\n nextId = Math.max(nextId, record.id + 1);\n },\n };\n}\n\n/**\n * Creates a message channel backed by a custom storage adapter.\n * Messages are serialized and persisted via the provided `storage` object.\n * When the storage quota is exceeded, the oldest messages are evicted automatically.\n *\n * @param options - Storage adapter, key, and optional serialize/deserialize hooks.\n */\nexport function createStorageStoreMessageChannel<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n>(\n options: StorageStoreMessageChannelOptions<TData, TKey>\n): StoreMessageChannel<TData, TKey> {\n const serialize =\n options.serialize ?? defaultSerializeStoreMessageChannelState<TData, TKey>;\n const deserialize =\n options.deserialize ??\n defaultDeserializeStoreMessageChannelState<TData, TKey>;\n\n function readState(): PersistedStoreMessageChannelState<TData, TKey> {\n const rawState = options.storage.getItem(options.storageKey);\n if (rawState === null) {\n return { nextId: 1, messages: [] };\n }\n try {\n return normalizeStoreMessageChannelState(deserialize(rawState));\n } catch {\n return { nextId: 1, messages: [] };\n }\n }\n\n function writeState(\n state: PersistedStoreMessageChannelState<TData, TKey>\n ): void {\n const normalized = normalizeStoreMessageChannelState(state);\n try {\n options.storage.setItem(options.storageKey, serialize(normalized));\n } catch (error: unknown) {\n if (!isQuotaExceededError(error) || normalized.messages.length === 0) {\n throw error;\n }\n // Evict oldest messages one at a time until the write succeeds\n let remaining = [...normalized.messages];\n while (remaining.length > 0) {\n remaining = remaining.slice(1);\n try {\n options.storage.setItem(\n options.storageKey,\n serialize({ nextId: normalized.nextId, messages: remaining })\n );\n return;\n } catch (retryError: unknown) {\n if (!isQuotaExceededError(retryError)) {\n throw retryError;\n }\n }\n }\n // All messages evicted — write empty state\n options.storage.setItem(\n options.storageKey,\n serialize({ nextId: normalized.nextId, messages: [] })\n );\n }\n }\n\n return {\n publish(message) {\n const state = readState();\n const record = createInitialStoreMessageRecord(state.nextId, message);\n\n writeState({\n nextId: state.nextId + 1,\n messages: [...state.messages, record],\n });\n\n return cloneValue(record);\n },\n getMessage(id) {\n const record = readState().messages.find((entry) => entry.id === id);\n return record ? cloneValue(record) : undefined;\n },\n getMessages() {\n return readState().messages.map((entry) => cloneValue(entry));\n },\n saveMessage(entry) {\n const state = readState();\n const record = cloneValue(entry);\n const existingIndex = state.messages.findIndex(\n (candidate) => candidate.id === record.id\n );\n\n if (existingIndex === -1) {\n writeState({\n nextId: Math.max(state.nextId, record.id + 1),\n messages: [...state.messages, record],\n });\n return;\n }\n\n const nextMessages = state.messages.map((c, i) =>\n i === existingIndex ? record : c\n );\n\n writeState({\n nextId: Math.max(state.nextId, record.id + 1),\n messages: nextMessages,\n });\n },\n };\n}\n\n/**\n * Creates a message channel backed by `localStorage`.\n * Messages survive page refreshes and browser restarts (same-origin only).\n *\n * @param options - Storage key and optional serialize/deserialize hooks.\n */\nexport function createLocalStorageStoreMessageChannel<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n>(\n options: BrowserStorageStoreMessageChannelOptions<TData, TKey>\n): StoreMessageChannel<TData, TKey> {\n return createStorageStoreMessageChannel({\n ...options,\n storage: options.storage ?? resolveGlobalStorage(\"localStorage\"),\n });\n}\n\n/**\n * Creates a message channel backed by `sessionStorage`.\n * Messages survive page refreshes but are lost when the browser tab closes.\n *\n * @param options - Storage key and optional serialize/deserialize hooks.\n */\nexport function createSessionStorageStoreMessageChannel<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n>(\n options: BrowserStorageStoreMessageChannelOptions<TData, TKey>\n): StoreMessageChannel<TData, TKey> {\n return createStorageStoreMessageChannel({\n ...options,\n storage: options.storage ?? resolveGlobalStorage(\"sessionStorage\"),\n });\n}\n\n/**\n * Creates a composite message channel that fans out writes to multiple channels.\n * The first channel is the primary (handles reads and id allocation); all channels receive writes.\n *\n * @param options - Array of channels. Must contain at least one.\n */\nexport function createCompositeStoreMessageChannel<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n>(\n options: CompositeStoreMessageChannelOptions<TData, TKey>\n): StoreMessageChannel<TData, TKey> {\n if (options.channels.length === 0) {\n throw new Error(\n \"createCompositeStoreMessageChannel: 'channels' option must contain at least one channel\"\n );\n }\n\n const primaryChannel = options.channels[0]!;\n const replicaChannels = options.channels.slice(1);\n\n return {\n publish(message) {\n const record = primaryChannel.publish(message);\n replicaChannels.forEach((channel) => {\n channel.saveMessage(record);\n });\n return cloneValue(record);\n },\n getMessage(id) {\n const record = primaryChannel.getMessage(id);\n return record ? cloneValue(record) : undefined;\n },\n getMessages() {\n return primaryChannel.getMessages().map((record) => cloneValue(record));\n },\n saveMessage(entry) {\n primaryChannel.saveMessage(entry);\n replicaChannels.forEach((channel) => {\n channel.saveMessage(entry);\n });\n },\n };\n}\n","interface Clearable {\n clearAll(): void;\n}\n\nconst trackedStores = new Set<Clearable>();\n\nexport function trackStore(store: Clearable): void {\n trackedStores.add(store);\n}\n\n/**\n * Clears every store instance tracked by flurryx.\n *\n * Calls `clearAll()` on each registered store, resetting all slots to their\n * initial idle state. Useful for logout, tenant switching, or test cleanup.\n *\n * @example\n * ```ts\n * import { clearAllStores } from '@flurryx/store';\n *\n * logout() {\n * clearAllStores();\n * }\n * ```\n */\nexport function clearAllStores(): void {\n for (const store of [...trackedStores]) {\n store.clearAll();\n }\n}\n\nexport function resetTrackedStoresForTests(): void {\n trackedStores.clear();\n}\n","import type { WritableSignal } from \"@angular/core\";\nimport {\n type ResourceState,\n type KeyedResourceKey,\n isKeyedResourceData,\n createKeyedResourceData,\n isAnyKeyLoading,\n} from \"@flurryx/core\";\nimport type { StoreDataShape, StoreKey } from \"./types\";\nimport type { StoreMessage, StoreSnapshot } from \"./store-messages\";\nimport { cloneValue, createSnapshotRestorePatch } from \"./store-clone\";\n\nexport function createDefaultState<T>(): ResourceState<T> {\n return {\n data: undefined,\n isLoading: false,\n status: undefined,\n errors: undefined,\n };\n}\n\n/**\n * Abstraction over how a store manages its writable signals.\n * BaseStore uses a pre-allocated Map; LazyStore creates signals on demand.\n */\nexport interface SignalAccessor<TData extends StoreDataShape<TData>> {\n getOrCreate<K extends StoreKey<TData>>(key: K): WritableSignal<TData[K]>;\n getAllKeys(): Iterable<StoreKey<TData>>;\n}\n\n/**\n * Abstraction over how a store notifies update hooks after state changes.\n */\nexport interface StoreNotifier<TData extends StoreDataShape<TData>> {\n notify<K extends StoreKey<TData>>(\n key: K,\n next: TData[K],\n prev: TData[K]\n ): void;\n}\n\n/**\n * Consumer returned by {@link createStoreMessageConsumer} that both\n * BaseStore and LazyStore delegate to for message application, snapshot\n * capture, and snapshot restore.\n */\nexport interface StoreMessageConsumer<TData extends StoreDataShape<TData>> {\n applyMessage(message: StoreMessage<TData>): boolean;\n applySnapshot(snapshot: StoreSnapshot<TData>): void;\n createSnapshot(): StoreSnapshot<TData>;\n}\n\n/**\n * Creates a shared message consumer that encapsulates all apply logic.\n *\n * Both BaseStore and LazyStore delegate to this consumer, eliminating\n * ~300 lines of duplicated implementation between the two stores.\n */\nexport function createStoreMessageConsumer<TData extends StoreDataShape<TData>>(\n signals: SignalAccessor<TData>,\n notifier: StoreNotifier<TData>\n): StoreMessageConsumer<TData> {\n function applyUpdate<K extends StoreKey<TData>>(\n key: K,\n newState: Partial<TData[K]>,\n notify = true\n ): boolean {\n const sig = signals.getOrCreate(key);\n const previousState = sig();\n sig.update((state) => ({ ...state, ...newState }));\n\n if (notify) {\n const updatedState = sig();\n notifier.notify(key, updatedState, previousState);\n }\n\n return true;\n }\n\n function applyClear<K extends StoreKey<TData>>(key: K): boolean {\n const sig = signals.getOrCreate(key);\n const previousState = sig();\n sig.set(createDefaultState() as TData[K]);\n\n const nextState = sig();\n notifier.notify(key, nextState, previousState);\n return true;\n }\n\n function applyClearAll(): boolean {\n const keys = Array.from(signals.getAllKeys());\n if (keys.length === 0) {\n return false;\n }\n\n keys.forEach((key) => {\n applyClear(key);\n });\n\n return true;\n }\n\n function applyStartLoading<K extends StoreKey<TData>>(key: K): boolean {\n const sig = signals.getOrCreate(key);\n sig.update(\n (state) =>\n ({\n ...state,\n status: undefined,\n isLoading: true,\n errors: undefined,\n } as TData[K])\n );\n return true;\n }\n\n function applyStopLoading<K extends StoreKey<TData>>(key: K): boolean {\n const sig = signals.getOrCreate(key);\n sig.update(\n (state) =>\n ({\n ...state,\n isLoading: false,\n } as TData[K])\n );\n return true;\n }\n\n function applyUpdateKeyedOne<K extends StoreKey<TData>>(\n key: K,\n resourceKey: KeyedResourceKey,\n entity: unknown\n ): boolean {\n const sig = signals.getOrCreate(key);\n const state = sig();\n const data = isKeyedResourceData(state.data)\n ? state.data\n : createKeyedResourceData();\n\n const nextErrors = { ...data.errors };\n delete nextErrors[resourceKey];\n\n const nextData = {\n ...data,\n entities: { ...data.entities, [resourceKey]: entity },\n isLoading: { ...data.isLoading, [resourceKey]: false },\n status: { ...data.status, [resourceKey]: \"Success\" as const },\n errors: nextErrors,\n };\n\n return applyUpdate(key, {\n data: nextData as unknown,\n isLoading: isAnyKeyLoading(nextData.isLoading),\n status: undefined,\n errors: undefined,\n } as Partial<TData[K]>);\n }\n\n function applyClearKeyedOne<K extends StoreKey<TData>>(\n key: K,\n resourceKey: KeyedResourceKey\n ): boolean {\n const sig = signals.getOrCreate(key);\n const previousState = sig();\n const state = previousState as ResourceState<unknown>;\n if (!isKeyedResourceData(state.data)) {\n return true;\n }\n\n const data = state.data;\n\n const nextEntities = { ...data.entities };\n delete nextEntities[resourceKey];\n\n const nextIsLoading = { ...data.isLoading };\n delete nextIsLoading[resourceKey];\n\n const nextStatus = { ...data.status };\n delete nextStatus[resourceKey];\n\n const nextErrors = { ...data.errors };\n delete nextErrors[resourceKey];\n\n const nextData = {\n ...data,\n entities: nextEntities,\n isLoading: nextIsLoading,\n status: nextStatus,\n errors: nextErrors,\n };\n\n sig.update(\n (prev) =>\n ({\n ...prev,\n data: nextData as unknown,\n status: undefined,\n isLoading: isAnyKeyLoading(nextIsLoading),\n errors: undefined,\n } as TData[K])\n );\n\n const updatedState = sig();\n notifier.notify(key, updatedState, previousState);\n return true;\n }\n\n function applyStartKeyedLoading<K extends StoreKey<TData>>(\n key: K,\n resourceKey: KeyedResourceKey\n ): boolean {\n const sig = signals.getOrCreate(key);\n const state = sig();\n if (!isKeyedResourceData(state.data)) {\n return applyStartLoading(key);\n }\n\n const previousState = state as TData[K];\n const data = state.data;\n\n const nextIsLoading = {\n ...data.isLoading,\n [resourceKey]: true,\n } as typeof data.isLoading;\n\n const nextStatus: typeof data.status = { ...data.status };\n delete nextStatus[resourceKey];\n\n const nextErrors: typeof data.errors = { ...data.errors };\n delete nextErrors[resourceKey];\n\n const nextData = {\n ...data,\n isLoading: nextIsLoading,\n status: nextStatus,\n errors: nextErrors,\n };\n\n sig.update(\n (previous) =>\n ({\n ...previous,\n data: nextData,\n status: undefined,\n isLoading: isAnyKeyLoading(nextIsLoading),\n errors: undefined,\n } as TData[K])\n );\n\n const updatedState = sig();\n notifier.notify(key, updatedState, previousState);\n return true;\n }\n\n function applyMessage(message: StoreMessage<TData>): boolean {\n switch (message.type) {\n case \"update\":\n return applyUpdate(message.key, cloneValue(message.state));\n case \"clear\":\n return applyClear(message.key);\n case \"clearAll\":\n return applyClearAll();\n case \"startLoading\":\n return applyStartLoading(message.key);\n case \"stopLoading\":\n return applyStopLoading(message.key);\n case \"updateKeyedOne\":\n return applyUpdateKeyedOne(\n message.key,\n message.resourceKey,\n cloneValue(message.entity)\n );\n case \"clearKeyedOne\":\n return applyClearKeyedOne(message.key, message.resourceKey);\n case \"startKeyedLoading\":\n return applyStartKeyedLoading(message.key, message.resourceKey);\n }\n }\n\n function applySnapshot(snapshot: StoreSnapshot<TData>): void {\n const keys = new Set<string>([\n ...Array.from(signals.getAllKeys()),\n ...Object.keys(snapshot),\n ]);\n\n keys.forEach((rawKey) => {\n const key = rawKey as StoreKey<TData>;\n const sig = signals.getOrCreate(key);\n const snapshotState =\n snapshot[key] ?? (createDefaultState() as TData[typeof key]);\n\n applyUpdate(key, createSnapshotRestorePatch(sig(), snapshotState), true);\n });\n }\n\n function captureSnapshot(): StoreSnapshot<TData> {\n const entries = Array.from(signals.getAllKeys()).map((key) => [\n key,\n cloneValue(signals.getOrCreate(key)()),\n ]);\n\n return Object.fromEntries(entries) as StoreSnapshot<TData>;\n }\n\n return {\n applyMessage,\n applySnapshot,\n createSnapshot: captureSnapshot,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Typed message factory functions — eliminate `as StoreMessage<TData>` casts\n// ---------------------------------------------------------------------------\n\nexport function createUpdateMessage<\n TData extends StoreDataShape<TData>,\n K extends StoreKey<TData>\n>(key: K, state: Partial<TData[K]>): StoreMessage<TData> {\n return { type: \"update\", key, state } as StoreMessage<TData>;\n}\n\nexport function createClearMessage<\n TData extends StoreDataShape<TData>,\n K extends StoreKey<TData>\n>(key: K): StoreMessage<TData> {\n return { type: \"clear\", key } as StoreMessage<TData>;\n}\n\nexport function createClearAllMessage<\n TData extends StoreDataShape<TData>\n>(): StoreMessage<TData> {\n return { type: \"clearAll\" };\n}\n\nexport function createStartLoadingMessage<\n TData extends StoreDataShape<TData>,\n K extends StoreKey<TData>\n>(key: K): StoreMessage<TData> {\n return { type: \"startLoading\", key } as StoreMessage<TData>;\n}\n\nexport function createStopLoadingMessage<\n TData extends StoreDataShape<TData>,\n K extends StoreKey<TData>\n>(key: K): StoreMessage<TData> {\n return { type: \"stopLoading\", key } as StoreMessage<TData>;\n}\n\nexport function createUpdateKeyedOneMessage<\n TData extends StoreDataShape<TData>,\n K extends StoreKey<TData>\n>(key: K, resourceKey: KeyedResourceKey, entity: unknown): StoreMessage<TData> {\n return {\n type: \"updateKeyedOne\",\n key,\n resourceKey,\n entity,\n } as unknown as StoreMessage<TData>;\n}\n\nexport function createClearKeyedOneMessage<\n TData extends StoreDataShape<TData>,\n K extends StoreKey<TData>\n>(key: K, resourceKey: KeyedResourceKey): StoreMessage<TData> {\n return {\n type: \"clearKeyedOne\",\n key,\n resourceKey,\n } as unknown as StoreMessage<TData>;\n}\n\nexport function createStartKeyedLoadingMessage<\n TData extends StoreDataShape<TData>,\n K extends StoreKey<TData>\n>(key: K, resourceKey: KeyedResourceKey): StoreMessage<TData> {\n return {\n type: \"startKeyedLoading\",\n key,\n resourceKey,\n } as unknown as StoreMessage<TData>;\n}\n","import { signal, type Signal, WritableSignal } from \"@angular/core\";\nimport { type ResourceState, type KeyedResourceKey } from \"@flurryx/core\";\nimport type { IStore, StoreDataShape, StoreKey, StoreOptions } from \"./types\";\nimport { cloneValue } from \"./store-clone\";\nimport {\n createStoreHistory,\n type StoreHistoryDriver,\n type StoreHistoryEntry,\n} from \"./store-replay\";\nimport type { StoreMessageRecord } from \"./store-channels\";\nimport { trackStore } from \"./store-registry\";\nimport {\n createDefaultState,\n createStoreMessageConsumer,\n createUpdateMessage,\n createClearMessage,\n createClearAllMessage,\n createStartLoadingMessage,\n createStopLoadingMessage,\n createUpdateKeyedOneMessage,\n createClearKeyedOneMessage,\n createStartKeyedLoadingMessage,\n} from \"./store-message-consumer\";\n\ntype UpdateCallback = (\n nextState: ResourceState<unknown>,\n previousState: ResourceState<unknown>\n) => void;\n\n/**\n * Lazy store that creates signals on first access.\n * Used by the `Store.for<Config>().build()` API where keys are\n * known only at the type level (no runtime enum).\n */\nexport class LazyStore<TData extends StoreDataShape<TData>>\n implements IStore<TData>\n{\n private readonly signals = new Map<\n string,\n WritableSignal<ResourceState<unknown>>\n >();\n private readonly hooks = new Map<string, UpdateCallback[]>();\n private readonly historyDriver: StoreHistoryDriver<TData>;\n\n /** @inheritDoc */\n readonly travelTo = (index: number): void =>\n this.historyDriver.travelTo(index);\n\n /** @inheritDoc */\n readonly undo = (): boolean => this.historyDriver.undo();\n\n /** @inheritDoc */\n readonly redo = (): boolean => this.historyDriver.redo();\n\n /** @inheritDoc */\n getMessages(): readonly StoreMessageRecord<TData>[];\n\n /** @inheritDoc */\n getMessages<K extends StoreKey<TData>>(\n key: K\n ): readonly StoreMessageRecord<TData, K>[];\n\n getMessages<K extends StoreKey<TData>>(key?: K) {\n if (key === undefined) {\n return this.historyDriver.getMessages();\n }\n\n return this.historyDriver.getMessages(key);\n }\n\n readonly getDeadLetters = () => this.historyDriver.getDeadLetters();\n\n /** @inheritDoc */\n readonly replayDeadLetter = (id: number): boolean =>\n this.historyDriver.replayDeadLetter(id);\n\n /** @inheritDoc */\n readonly replayDeadLetters = (): number =>\n this.historyDriver.replayDeadLetters();\n\n /** @inheritDoc */\n readonly getCurrentIndex = () => this.historyDriver.getCurrentIndex();\n\n /** @inheritDoc */\n readonly history: Signal<readonly StoreHistoryEntry<TData>[]>;\n\n /** @inheritDoc */\n readonly messages: Signal<readonly StoreMessageRecord<TData>[]>;\n\n /** @inheritDoc */\n readonly currentIndex: Signal<number>;\n\n /** @inheritDoc */\n readonly keys: Signal<readonly StoreKey<TData>[]>;\n\n private readonly keysSignal = signal<readonly StoreKey<TData>[]>([]);\n\n /** @inheritDoc */\n replay(id: number): number;\n\n /** @inheritDoc */\n replay(ids: readonly number[]): number;\n\n replay(idOrIds: number | readonly number[]): number {\n if (Array.isArray(idOrIds)) {\n return this.historyDriver.replay(idOrIds as readonly number[]);\n }\n\n return this.historyDriver.replay(idOrIds as number);\n }\n\n /** @inheritDoc */\n getHistory(): readonly StoreHistoryEntry<TData>[];\n\n /** @inheritDoc */\n getHistory<K extends StoreKey<TData>>(\n key: K\n ): readonly StoreHistoryEntry<TData, K>[];\n\n getHistory<K extends StoreKey<TData>>(key?: K) {\n if (key === undefined) {\n return this.historyDriver.getHistory();\n }\n\n return this.historyDriver.getHistory(key);\n }\n\n constructor(options?: StoreOptions<TData>) {\n const consumer = createStoreMessageConsumer<TData>(\n {\n getOrCreate: <K extends StoreKey<TData>>(key: K) =>\n this.getOrCreate(key),\n getAllKeys: () => this.signals.keys() as Iterable<StoreKey<TData>>,\n },\n {\n notify: <K extends StoreKey<TData>>(\n key: K,\n next: TData[K],\n prev: TData[K]\n ) => this.notifyHooks(key, next, prev),\n }\n );\n\n this.historyDriver = createStoreHistory<TData>({\n captureSnapshot: () => consumer.createSnapshot(),\n applySnapshot: (snapshot) => consumer.applySnapshot(snapshot),\n applyMessage: (message) => consumer.applyMessage(message),\n channel: options?.channel,\n });\n\n this.history = this.historyDriver.historySignal;\n this.messages = this.historyDriver.messagesSignal;\n this.currentIndex = this.historyDriver.currentIndexSignal;\n this.keys = this.keysSignal.asReadonly();\n\n trackStore(this);\n }\n\n private getOrCreate<K extends StoreKey<TData>>(\n key: K\n ): WritableSignal<TData[K]> {\n let sig = this.signals.get(key);\n if (!sig) {\n sig = signal<ResourceState<unknown>>(createDefaultState());\n this.signals.set(key, sig);\n this.keysSignal.update((prev) => [...prev, key]);\n }\n return sig as WritableSignal<TData[K]>;\n }\n\n /** @inheritDoc */\n get<K extends StoreKey<TData>>(key: K): Signal<TData[K]> {\n return this.getOrCreate(key);\n }\n\n /** @inheritDoc */\n update<K extends StoreKey<TData>>(key: K, newState: Partial<TData[K]>): void {\n this.historyDriver.publish(\n createUpdateMessage<TData, K>(key, cloneValue(newState))\n );\n }\n\n /** @inheritDoc */\n clear<K extends StoreKey<TData>>(key: K): void {\n this.historyDriver.publish(createClearMessage<TData, K>(key));\n }\n\n /** @inheritDoc */\n clearAll(): void {\n this.historyDriver.publish(createClearAllMessage<TData>());\n }\n\n /** @inheritDoc */\n startLoading<K extends StoreKey<TData>>(key: K): void {\n this.historyDriver.publish(createStartLoadingMessage<TData, K>(key));\n }\n\n /** @inheritDoc */\n stopLoading<K extends StoreKey<TData>>(key: K): void {\n this.historyDriver.publish(createStopLoadingMessage<TData, K>(key));\n }\n\n /** @inheritDoc */\n updateKeyedOne<K extends StoreKey<TData>>(\n key: K,\n resourceKey: KeyedResourceKey,\n entity: unknown\n ): void {\n this.historyDriver.publish(\n createUpdateKeyedOneMessage<TData, K>(\n key,\n resourceKey,\n cloneValue(entity)\n )\n );\n }\n\n /** @inheritDoc */\n clearKeyedOne<K extends StoreKey<TData>>(\n key: K,\n resourceKey: KeyedResourceKey\n ): void {\n this.historyDriver.publish(\n createClearKeyedOneMessage<TData, K>(key, resourceKey)\n );\n }\n\n /** @inheritDoc */\n startKeyedLoading<K extends StoreKey<TData>>(\n key: K,\n resourceKey: KeyedResourceKey\n ): void {\n this.historyDriver.publish(\n createStartKeyedLoadingMessage<TData, K>(key, resourceKey)\n );\n }\n\n /** @inheritDoc */\n onUpdate<K extends StoreKey<TData>>(\n key: K,\n callback: (state: TData[K], previousState: TData[K]) => void\n ): () => void {\n if (!this.hooks.has(key)) {\n this.hooks.set(key, []);\n }\n const typedCallback = callback as UpdateCallback;\n this.hooks.get(key)!.push(typedCallback);\n\n return () => {\n const keyHooks = this.hooks.get(key);\n if (!keyHooks) {\n return;\n }\n const index = keyHooks.indexOf(typedCallback);\n if (index > -1) {\n keyHooks.splice(index, 1);\n }\n };\n }\n\n private notifyHooks<K extends StoreKey<TData>>(\n key: K,\n nextState: TData[K],\n previousState: TData[K]\n ): void {\n const keyHooks = this.hooks.get(key);\n if (!keyHooks) {\n return;\n }\n\n const errors: unknown[] = [];\n\n keyHooks.forEach((hook) => {\n try {\n hook(\n nextState as ResourceState<unknown>,\n previousState as ResourceState<unknown>\n );\n } catch (error: unknown) {\n errors.push(error);\n }\n });\n\n if (errors.length > 0) {\n queueMicrotask(() => {\n if (errors.length === 1) {\n throw errors[0];\n }\n throw new AggregateError(\n errors,\n `${errors.length} onUpdate hooks threw for key \"${String(key)}\"`\n );\n });\n }\n }\n}\n","import { InjectionToken, inject } from \"@angular/core\";\nimport { BaseStore } from \"./base-store\";\nimport { DynamicStore } from \"./dynamic-store\";\nimport { LazyStore } from \"./lazy-store\";\nimport { mirrorKey } from \"./mirror-key\";\nimport { collectKeyed } from \"./collect-keyed\";\nimport { resource } from \"./resource\";\nimport type { ResourceState, KeyedResourceKey } from \"@flurryx/core\";\nimport type {\n StoreConfig,\n ResourceDef,\n InferEnum,\n InferData,\n ConfigToData,\n IStore,\n StoreOptions,\n StoreDataShape,\n StoreKey,\n} from \"./types\";\n\ntype AnyStoreData = Record<string, ResourceState<unknown>>;\n\n// ---------------------------------------------------------------------------\n// Mirror definition — accumulated by builders, wired up in build() factory\n// ---------------------------------------------------------------------------\n\ninterface MirrorDef {\n readonly sourceToken: InjectionToken<unknown>;\n readonly sourceKey: string;\n readonly targetKey: string;\n}\n\nfunction wireMirrors<TData extends StoreDataShape<TData>>(\n store: IStore<TData>,\n mirrors: readonly MirrorDef[]\n): void {\n for (const def of mirrors) {\n const sourceStore = inject(def.sourceToken) as IStore<AnyStoreData>;\n mirrorKey(\n sourceStore,\n def.sourceKey as StoreKey<AnyStoreData>,\n store,\n def.targetKey as StoreKey<TData>\n );\n }\n}\n\n// ---------------------------------------------------------------------------\n// MirrorKeyed definition — accumulated by builders, wired up in build()\n// ---------------------------------------------------------------------------\n\ninterface MirrorKeyedDef {\n readonly sourceToken: InjectionToken<unknown>;\n readonly sourceKey: string;\n readonly targetKey: string;\n readonly extractId: (data: unknown) => KeyedResourceKey | undefined;\n}\n\nfunction wireMirrorKeyed<TData extends StoreDataShape<TData>>(\n store: IStore<TData>,\n defs: readonly MirrorKeyedDef[]\n): void {\n for (const def of defs) {\n const sourceStore = inject(def.sourceToken) as IStore<AnyStoreData>;\n collectKeyed(\n sourceStore,\n def.sourceKey as StoreKey<AnyStoreData>,\n store,\n def.targetKey as StoreKey<TData>,\n {\n extractId: def.extractId,\n }\n );\n }\n}\n\ninterface SelfMirrorDef {\n readonly sourceKey: string;\n readonly targetKey: string;\n}\n\nconst MIRROR_SELF_SAME_KEY_ERROR =\n \"mirrorSelf source and target keys must be different\";\n\nfunction wireSelfMirrors<TData extends StoreDataShape<TData>>(\n store: IStore<TData>,\n defs: readonly SelfMirrorDef[]\n): void {\n for (const def of defs) {\n if (def.sourceKey === def.targetKey) {\n throw new Error(MIRROR_SELF_SAME_KEY_ERROR);\n }\n\n mirrorKey(\n store,\n def.sourceKey as StoreKey<TData>,\n store,\n def.targetKey as StoreKey<TData>\n );\n }\n}\n\n// ---------------------------------------------------------------------------\n// Unconstrained builder (existing API)\n// ---------------------------------------------------------------------------\n\n/**\n * Intermediate builder step after .resource('key') — awaits .as<T>().\n */\ninterface AsStep<TAccum extends StoreConfig, TKey extends string> {\n /**\n * Assign the resource value type for the previously declared key.\n *\n * Returns the main fluent builder so you can define more resources, configure\n * mirrors, or call `.build()`.\n *\n * @example\n * ```ts\n * const CustomersStore = Store\n * .resource('CUSTOMERS').as<Customer[]>()\n * .build();\n * ```\n */\n as<T>(): StoreBuilder<TAccum & Record<TKey, ResourceDef<T>>>;\n}\n\n/**\n * Fluent builder for creating stores.\n * Accumulates resource definitions then produces an `InjectionToken` on `.build()`.\n */\ninterface StoreBuilder<TAccum extends StoreConfig> {\n /** Define a new resource slot. Chain `.as<T>()` to set its type. */\n resource<TKey extends string>(key: TKey): AsStep<TAccum, TKey>;\n\n /**\n * Mirror a slot from another store. When the source updates, the target is kept in sync.\n *\n * @param source - The source store's `InjectionToken`.\n * @param sourceKey - The key to watch on the source store.\n * @param targetKey - The key on this store to write to. Defaults to `sourceKey`.\n */\n mirror<TSourceData extends StoreDataShape<TSourceData>>(\n source: InjectionToken<IStore<TSourceData>>,\n sourceKey: StoreKey<TSourceData>,\n targetKey?: StoreKey<TAccum>\n ): StoreBuilder<TAccum>;\n\n /**\n * Mirror one slot to another **within the same store**.\n * Source and target keys must be different.\n *\n * @param sourceKey - The slot to read from.\n * @param targetKey - The slot to write to.\n */\n mirrorSelf(\n sourceKey: StoreKey<TAccum>,\n targetKey: StoreKey<TAccum>\n ): StoreBuilder<TAccum>;\n\n /**\n * Accumulate single-entity fetches from a source store into a `KeyedResourceData` slot.\n *\n * @param source - The source store's `InjectionToken`.\n * @param sourceKey - The single-entity key on the source store.\n * @param options - Must include `extractId` to derive the entity's key from its data.\n * @param targetKey - The keyed slot on this store. Defaults to `sourceKey`.\n */\n mirrorKeyed<TSourceData extends StoreDataShape<TSourceData>, TEntity>(\n source: InjectionToken<IStore<TSourceData>>,\n sourceKey: StoreKey<TSourceData>,\n options: {\n extractId: (data: TEntity | undefined) => KeyedResourceKey | undefined;\n },\n targetKey?: StoreKey<TAccum>\n ): StoreBuilder<TAccum>;\n\n /**\n * Finalize the builder and create an `InjectionToken` (`providedIn: 'root'`).\n * All mirrors are wired up automatically when Angular creates the store.\n */\n build(\n options?: StoreOptions<InferData<TAccum>>\n ): InjectionToken<BaseStore<InferEnum<TAccum>, InferData<TAccum>>>;\n}\n\nfunction createBuilder<TAccum extends StoreConfig>(\n accum: TAccum,\n mirrors: readonly MirrorDef[] = [],\n mirrorKeyedDefs: readonly MirrorKeyedDef[] = [],\n selfMirrors: readonly SelfMirrorDef[] = []\n): StoreBuilder<TAccum> {\n return {\n resource<TKey extends string>(key: TKey): AsStep<TAccum, TKey> {\n return {\n as<T>(): StoreBuilder<TAccum & Record<TKey, ResourceDef<T>>> {\n const nextAccum = {\n ...accum,\n [key]: resource<T>(),\n } as TAccum & Record<TKey, ResourceDef<T>>;\n return createBuilder(\n nextAccum,\n mirrors,\n mirrorKeyedDefs,\n selfMirrors\n );\n },\n };\n },\n mirror(source, sourceKey, targetKey?) {\n const def: MirrorDef = {\n sourceToken: source as InjectionToken<unknown>,\n sourceKey,\n targetKey: targetKey ?? sourceKey,\n };\n return createBuilder(\n accum,\n [...mirrors, def],\n mirrorKeyedDefs,\n selfMirrors\n );\n },\n mirrorSelf(sourceKey, targetKey) {\n const def: SelfMirrorDef = {\n sourceKey,\n targetKey,\n };\n return createBuilder(accum, mirrors, mirrorKeyedDefs, [\n ...selfMirrors,\n def,\n ]);\n },\n mirrorKeyed(source, sourceKey, options, targetKey?) {\n const def: MirrorKeyedDef = {\n sourceToken: source as InjectionToken<unknown>,\n sourceKey,\n targetKey: targetKey ?? sourceKey,\n extractId: options.extractId as (\n data: unknown\n ) => KeyedResourceKey | undefined,\n };\n return createBuilder(\n accum,\n mirrors,\n [...mirrorKeyedDefs, def],\n selfMirrors\n );\n },\n build(options?: StoreOptions<InferData<TAccum>>) {\n return new InjectionToken<\n BaseStore<InferEnum<TAccum>, InferData<TAccum>>\n >(\"FlurryxStore\", {\n providedIn: \"root\",\n factory: () => {\n const store = new DynamicStore(accum, options) as IStore<InferData<TAccum>>;\n wireMirrors(store, mirrors);\n wireMirrorKeyed(store, mirrorKeyedDefs);\n wireSelfMirrors(store, selfMirrors);\n return store as BaseStore<InferEnum<TAccum>, InferData<TAccum>>;\n },\n });\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Constrained builder (.for(enum) API)\n// ---------------------------------------------------------------------------\n\n/** Keys from the enum that have NOT yet been defined. */\ntype Remaining<\n TEnum extends Record<string, string>,\n TAccum extends StoreConfig\n> = Exclude<keyof TEnum & string, keyof TAccum>;\n\n/** Intermediate .as<T>() step for the constrained builder. */\ninterface ConstrainedAsStep<\n TEnum extends Record<string, string>,\n TAccum extends StoreConfig,\n TKey extends string\n> {\n /**\n * Assign the resource value type for the selected enum key.\n *\n * Returns the constrained builder for the remaining enum keys.\n */\n as<T>(): ConstrainedBuilder<TEnum, TAccum & Record<TKey, ResourceDef<T>>>;\n}\n\n/**\n * Constrained builder — only allows keys from the enum that haven't been\n * defined yet. `.build()` is only available when all keys are accounted for.\n */\ntype ConstrainedBuilder<\n TEnum extends Record<string, string>,\n TAccum extends StoreConfig\n> = [Remaining<TEnum, TAccum>] extends [never]\n ? {\n /**\n * Mirror a slot from another store. When the source updates, the target is kept in sync.\n *\n * @param source - The source store's `InjectionToken`.\n * @param sourceKey - The key to watch on the source store.\n * @param targetKey - The key on this store to write to. Defaults to `sourceKey`.\n */\n mirror<TSourceData extends StoreDataShape<TSourceData>>(\n source: InjectionToken<IStore<TSourceData>>,\n sourceKey: StoreKey<TSourceData>,\n targetKey?: StoreKey<TAccum>\n ): ConstrainedBuilder<TEnum, TAccum>;\n /**\n * Mirror one slot to another within the same store.\n * Source and target keys must be different.\n *\n * @param sourceKey - The slot to read from.\n * @param targetKey - The slot to write to.\n */\n mirrorSelf(\n sourceKey: StoreKey<TAccum>,\n targetKey: StoreKey<TAccum>\n ): ConstrainedBuilder<TEnum, TAccum>;\n /**\n * Accumulate single-entity fetches from a source store into a keyed slot.\n *\n * @param source - The source store's `InjectionToken`.\n * @param sourceKey - The single-entity key on the source store.\n * @param options - Must include `extractId` to derive the entity's key from its data.\n * @param targetKey - The keyed slot on this store. Defaults to `sourceKey`.\n */\n mirrorKeyed<TSourceData extends StoreDataShape<TSourceData>, TEntity>(\n source: InjectionToken<IStore<TSourceData>>,\n sourceKey: StoreKey<TSourceData>,\n options: {\n extractId: (\n data: TEntity | undefined\n ) => KeyedResourceKey | undefined;\n },\n targetKey?: StoreKey<TAccum>\n ): ConstrainedBuilder<TEnum, TAccum>;\n /**\n * Finalize the builder and create an `InjectionToken` (`providedIn: 'root'`).\n * Available only after all enum keys have been defined.\n */\n build(\n options?: StoreOptions<InferData<TAccum>>\n ): InjectionToken<BaseStore<InferEnum<TAccum>, InferData<TAccum>>>;\n }\n : {\n /** Define the next resource slot from the remaining enum keys. */\n resource<TKey extends Remaining<TEnum, TAccum>>(\n key: TKey\n ): ConstrainedAsStep<TEnum, TAccum, TKey>;\n };\n\nfunction createConstrainedBuilder<\n TEnum extends Record<string, string>,\n TAccum extends StoreConfig\n>(\n _enumObj: TEnum,\n accum: TAccum,\n mirrors: readonly MirrorDef[] = [],\n mirrorKeyedDefs: readonly MirrorKeyedDef[] = [],\n selfMirrors: readonly SelfMirrorDef[] = []\n): ConstrainedBuilder<TEnum, TAccum> {\n return {\n resource<TKey extends string>(\n key: TKey\n ): ConstrainedAsStep<TEnum, TAccum, TKey> {\n return {\n as<T>(): ConstrainedBuilder<\n TEnum,\n TAccum & Record<TKey, ResourceDef<T>>\n > {\n const nextAccum = {\n ...accum,\n [key]: resource<T>(),\n } as TAccum & Record<TKey, ResourceDef<T>>;\n return createConstrainedBuilder(\n _enumObj,\n nextAccum,\n mirrors,\n mirrorKeyedDefs,\n selfMirrors\n );\n },\n };\n },\n mirror(\n source: InjectionToken<IStore<AnyStoreData>>,\n sourceKey: string,\n targetKey?: string\n ) {\n const def: MirrorDef = {\n sourceToken: source,\n sourceKey,\n targetKey: targetKey ?? sourceKey,\n };\n return createConstrainedBuilder(\n _enumObj,\n accum,\n [...mirrors, def],\n mirrorKeyedDefs,\n selfMirrors\n );\n },\n mirrorSelf(sourceKey: string, targetKey: string) {\n const def: SelfMirrorDef = {\n sourceKey,\n targetKey,\n };\n return createConstrainedBuilder(\n _enumObj,\n accum,\n mirrors,\n mirrorKeyedDefs,\n [...selfMirrors, def]\n );\n },\n mirrorKeyed(\n source: InjectionToken<IStore<AnyStoreData>>,\n sourceKey: string,\n options: {\n extractId: (data: unknown) => KeyedResourceKey | undefined;\n },\n targetKey?: string\n ) {\n const def: MirrorKeyedDef = {\n sourceToken: source,\n sourceKey,\n targetKey: targetKey ?? sourceKey,\n extractId: options.extractId,\n };\n return createConstrainedBuilder(\n _enumObj,\n accum,\n mirrors,\n [...mirrorKeyedDefs, def],\n selfMirrors\n );\n },\n build(options?: StoreOptions<InferData<TAccum>>) {\n return new InjectionToken<\n BaseStore<InferEnum<TAccum>, InferData<TAccum>>\n >(\"FlurryxStore\", {\n providedIn: \"root\",\n factory: () => {\n const store = new DynamicStore(accum, options) as IStore<InferData<TAccum>>;\n wireMirrors(store, mirrors);\n wireMirrorKeyed(store, mirrorKeyedDefs);\n wireSelfMirrors(store, selfMirrors);\n return store as BaseStore<InferEnum<TAccum>, InferData<TAccum>>;\n },\n });\n },\n } as ConstrainedBuilder<TEnum, TAccum>;\n}\n\n// ---------------------------------------------------------------------------\n// Interface-based builder (Store.for<Config>() API)\n// ---------------------------------------------------------------------------\n\n/**\n * Interface-based builder for `Store.for<Config>()`.\n *\n * Uses a config interface for compile-time shape only, so no runtime enum is required.\n */\ninterface InterfaceBuilder<TConfig extends object> {\n /**\n * Mirror a slot from another store. When the source updates, the target is kept in sync.\n *\n * @param source - The source store's `InjectionToken`.\n * @param sourceKey - The key to watch on the source store.\n * @param targetKey - The key on this store to write to. Defaults to `sourceKey`.\n */\n mirror<TSourceData extends StoreDataShape<TSourceData>>(\n source: InjectionToken<IStore<TSourceData>>,\n sourceKey: StoreKey<TSourceData>,\n targetKey?: StoreKey<ConfigToData<TConfig>>\n ): InterfaceBuilder<TConfig>;\n /**\n * Mirror one slot to another within the same store.\n * Source and target keys must be different.\n *\n * @param sourceKey - The slot to read from.\n * @param targetKey - The slot to write to.\n */\n mirrorSelf(\n sourceKey: StoreKey<ConfigToData<TConfig>>,\n targetKey: StoreKey<ConfigToData<TConfig>>\n ): InterfaceBuilder<TConfig>;\n /**\n * Accumulate single-entity fetches from a source store into a keyed slot.\n *\n * @param source - The source store's `InjectionToken`.\n * @param sourceKey - The single-entity key on the source store.\n * @param options - Must include `extractId` to derive the entity's key from its data.\n * @param targetKey - The keyed slot on this store. Defaults to `sourceKey`.\n */\n mirrorKeyed<TSourceData extends StoreDataShape<TSourceData>, TEntity>(\n source: InjectionToken<IStore<TSourceData>>,\n sourceKey: StoreKey<TSourceData>,\n options: {\n extractId: (data: TEntity | undefined) => KeyedResourceKey | undefined;\n },\n targetKey?: StoreKey<ConfigToData<TConfig>>\n ): InterfaceBuilder<TConfig>;\n /**\n * Finalize the interface-based builder and create a store `InjectionToken`.\n *\n * The resulting token is registered with `providedIn: 'root'` and resolves to\n * a `LazyStore` implementing `IStore<ConfigToData<TConfig>>`.\n *\n * @returns An Angular `InjectionToken` for the configured store.\n *\n * @example\n * ```ts\n * interface ChatStoreConfig {\n * SESSIONS: ChatSession[];\n * MESSAGES: ChatMessage[];\n * }\n *\n * export const ChatStore = Store.for<ChatStoreConfig>().build();\n * ```\n */\n build(\n options?: StoreOptions<ConfigToData<TConfig>>\n ): InjectionToken<IStore<ConfigToData<TConfig>>>;\n}\n\nfunction createInterfaceBuilder<TConfig extends object>(\n mirrors: readonly MirrorDef[] = [],\n mirrorKeyedDefs: readonly MirrorKeyedDef[] = [],\n selfMirrors: readonly SelfMirrorDef[] = []\n): InterfaceBuilder<TConfig> {\n return {\n mirror(source, sourceKey, targetKey?) {\n const def: MirrorDef = {\n sourceToken: source as InjectionToken<unknown>,\n sourceKey,\n targetKey: targetKey ?? sourceKey,\n };\n return createInterfaceBuilder<TConfig>(\n [...mirrors, def],\n mirrorKeyedDefs,\n selfMirrors\n );\n },\n mirrorSelf(sourceKey, targetKey) {\n const def: SelfMirrorDef = {\n sourceKey,\n targetKey,\n };\n return createInterfaceBuilder<TConfig>(mirrors, mirrorKeyedDefs, [\n ...selfMirrors,\n def,\n ]);\n },\n mirrorKeyed(source, sourceKey, options, targetKey?) {\n const def: MirrorKeyedDef = {\n sourceToken: source as InjectionToken<unknown>,\n sourceKey,\n targetKey: targetKey ?? sourceKey,\n extractId: options.extractId as (\n data: unknown\n ) => KeyedResourceKey | undefined,\n };\n return createInterfaceBuilder<TConfig>(\n mirrors,\n [...mirrorKeyedDefs, def],\n selfMirrors\n );\n },\n build(options?: StoreOptions<ConfigToData<TConfig>>) {\n return new InjectionToken(\"FlurryxStore\", {\n providedIn: \"root\",\n factory: () => {\n const store = new LazyStore(options) as IStore<AnyStoreData>;\n wireMirrors(store, mirrors);\n wireMirrorKeyed(store, mirrorKeyedDefs);\n wireSelfMirrors(store, selfMirrors);\n return store as unknown as IStore<ConfigToData<TConfig>>;\n },\n });\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Public entry point\n// ---------------------------------------------------------------------------\n\ninterface StoreEntry {\n /**\n * Define a named resource slot.\n * Chain .as<T>() to assign its type, then continue with more .resource() calls\n * or call .build() when done.\n */\n resource<TKey extends string>(\n key: TKey\n ): {\n /**\n * Set the resource value type and continue the fluent builder chain.\n *\n * @example\n * ```ts\n * const UsersStore = Store\n * .resource('USERS').as<User[]>()\n * .build();\n * ```\n */\n as<T>(): StoreBuilder<Record<TKey, ResourceDef<T>>>;\n };\n\n /**\n * Interface-based builder: pass a config interface as a generic.\n * No runtime argument needed — keys and types are inferred from the interface.\n *\n * @example\n * interface ChatStoreConfig {\n * SESSIONS: ChatSession[];\n * MESSAGES: ChatMessage[];\n * }\n * const ChatStore = Store.for<ChatStoreConfig>().build();\n */\n for<TConfig extends object>(): InterfaceBuilder<TConfig>;\n\n /**\n * Bind the builder to an enum object for compile-time key validation.\n *\n * @example\n * const Enum = { A: 'A', B: 'B' } as const;\n * const MyStore = Store.for(Enum)\n * .resource('A').as<string>()\n * .resource('B').as<number>()\n * .build();\n */\n for<TEnum extends Record<string, string>>(\n enumObj: TEnum\n ): ConstrainedBuilder<TEnum, Record<never, never>>;\n}\n\n/**\n * Fluent store builder entry point.\n *\n * @example\n * // Unconstrained\n * export const CustomersStore = Store\n * .resource('customers').as<Customer[]>()\n * .resource('customerDetails').as<Customer>()\n * .build();\n *\n * @example\n * // Constrained with enum\n * const Enum = { SESSIONS: 'SESSIONS', MESSAGES: 'MESSAGES' } as const;\n * export const ChatStore = Store.for(Enum)\n * .resource('SESSIONS').as<Session[]>()\n * .resource('MESSAGES').as<Message[]>()\n * .build();\n */\nexport const Store: StoreEntry = {\n ...createBuilder({} as StoreConfig),\n for: createStoreFor,\n};\n\nfunction createStoreFor<TConfig extends object>(): InterfaceBuilder<TConfig>;\nfunction createStoreFor<TEnum extends Record<string, string>>(\n enumObj: TEnum\n): ConstrainedBuilder<TEnum, Record<never, never>>;\nfunction createStoreFor(enumObj?: Record<string, string>) {\n if (arguments.length === 0) {\n return createInterfaceBuilder();\n }\n\n return createConstrainedBuilder(enumObj!, {} as Record<never, never>);\n}\n","import { BaseStore } from './base-store';\nimport type { StoreConfig, InferEnum, InferData, StoreOptions } from './types';\n\n/**\n * Internal concrete subclass of BaseStore.\n * Auto-generates an identity enum from config keys.\n * NOT publicly exported — consumers interact via BaseStore interface.\n */\nexport class DynamicStore<\n TConfig extends StoreConfig,\n> extends BaseStore<InferEnum<TConfig>, InferData<TConfig>> {\n constructor(config: TConfig, options?: StoreOptions<InferData<TConfig>>) {\n const identityEnum = Object.keys(config).reduce(\n (acc, key) => ({ ...acc, [key]: key }),\n {} as InferEnum<TConfig>\n );\n super(identityEnum, options);\n }\n}\n","import type { IStore, StoreDataShape, StoreKey } from \"./types\";\n\n/**\n * Options for {@link mirrorKey}.\n */\nexport interface MirrorOptions {\n /**\n * Angular `DestroyRef` (or any object with an `onDestroy` method) for\n * automatic cleanup. When provided, the mirror stops when the ref is destroyed.\n */\n destroyRef?: { onDestroy: (fn: () => void) => void };\n}\n\n/**\n * Mirrors a resource key from a source store to a target store.\n * When the source key updates, the target key is updated with the same state.\n *\n * @param source - The store to mirror from\n * @param sourceKey - The key to watch on the source store\n * @param target - The store to mirror to\n * @param targetKeyOrOptions - Either the target key name or options (defaults source key)\n * @param options - Mirror options when a target key is provided\n * @returns Cleanup function to stop mirroring\n */\nexport function mirrorKey<\n TSource extends StoreDataShape<TSource>,\n TTarget extends StoreDataShape<TTarget>\n>(\n source: IStore<TSource>,\n sourceKey: StoreKey<TSource>,\n target: IStore<TTarget>,\n targetKeyOrOptions?: StoreKey<TTarget> | MirrorOptions,\n options?: MirrorOptions\n): () => void {\n const resolvedTargetKey = (\n typeof targetKeyOrOptions === \"string\" ? targetKeyOrOptions : sourceKey\n ) as StoreKey<TTarget>;\n\n const resolvedOptions =\n typeof targetKeyOrOptions === \"object\" ? targetKeyOrOptions : options;\n\n const cleanup = source.onUpdate(sourceKey, (state) => {\n target.update(\n resolvedTargetKey,\n state as unknown as Partial<TTarget[StoreKey<TTarget>]>\n );\n });\n\n if (resolvedOptions?.destroyRef) {\n resolvedOptions.destroyRef.onDestroy(cleanup);\n }\n\n return cleanup;\n}\n","import type {\n ResourceState,\n KeyedResourceKey,\n KeyedResourceData,\n} from \"@flurryx/core\";\nimport { createKeyedResourceData, isAnyKeyLoading } from \"@flurryx/core\";\nimport type { IStore, StoreDataShape, StoreKey } from \"./types\";\n\n/**\n * Options for {@link collectKeyed}.\n *\n * @template TEntity - The entity type emitted by the source store.\n */\nexport interface CollectKeyedOptions<TEntity> {\n /**\n * Extracts the entity identifier from the source data.\n * Return `undefined` to skip accumulation for that emission.\n */\n extractId: (data: TEntity | undefined) => KeyedResourceKey | undefined;\n /**\n * Angular `DestroyRef` (or any object with an `onDestroy` method) for\n * automatic cleanup. When provided, collection stops when the ref is destroyed.\n */\n destroyRef?: { onDestroy: (fn: () => void) => void };\n}\n\n/**\n * Accumulates single-entity resource fetches into a keyed cache on a target store.\n *\n * On each source update:\n * - If status is 'Success' and extractId returns a valid key, merges the entity\n * into the target's keyed resource data.\n * - If the source data is cleared and a previous entity existed, removes it from\n * the target's keyed data.\n *\n * @param source - The store containing the single-entity resource\n * @param sourceKey - The key to watch on the source store\n * @param target - The store to accumulate entities into\n * @param targetKeyOrOptions - Either the target key name or options (defaults source key)\n * @param options - Collect options when a target key is provided\n * @returns Cleanup function to stop collecting\n */\nexport function collectKeyed<\n TSource extends StoreDataShape<TSource>,\n TTarget extends StoreDataShape<TTarget>,\n TEntity = unknown\n>(\n source: IStore<TSource>,\n sourceKey: StoreKey<TSource>,\n target: IStore<TTarget>,\n targetKeyOrOptions?: StoreKey<TTarget> | CollectKeyedOptions<TEntity>,\n options?: CollectKeyedOptions<TEntity>\n): () => void {\n const resolvedTargetKey = (\n typeof targetKeyOrOptions === \"string\" ? targetKeyOrOptions : sourceKey\n ) as StoreKey<TTarget>;\n\n const resolvedOptions = (\n typeof targetKeyOrOptions === \"object\" ? targetKeyOrOptions : options\n ) as CollectKeyedOptions<TEntity>;\n\n // Initialize target with empty keyed resource data\n target.update(resolvedTargetKey, {\n data: createKeyedResourceData(),\n } as Partial<TTarget[StoreKey<TTarget>]>);\n\n let previousId: KeyedResourceKey | undefined;\n\n const cleanup = source.onUpdate(sourceKey, (state) => {\n const resourceState = state as ResourceState<TEntity>;\n const currentId = resolvedOptions.extractId(resourceState.data);\n const currentTarget = target.get(resolvedTargetKey)();\n const currentKeyed = (currentTarget as ResourceState<unknown>).data as\n | KeyedResourceData<KeyedResourceKey, TEntity>\n | undefined;\n\n if (!currentKeyed) {\n return;\n }\n\n if (resourceState.status === \"Success\" && currentId !== undefined) {\n const newEntities = {\n ...currentKeyed.entities,\n [currentId]: resourceState.data,\n };\n const newIsLoading = { ...currentKeyed.isLoading, [currentId]: false };\n const newStatus = {\n ...currentKeyed.status,\n [currentId]: resourceState.status,\n };\n const newErrors = { ...currentKeyed.errors };\n delete newErrors[currentId];\n\n const updatedKeyed: KeyedResourceData<KeyedResourceKey, TEntity> = {\n entities: newEntities,\n isLoading: newIsLoading,\n status: newStatus,\n errors: newErrors,\n };\n\n target.update(resolvedTargetKey, {\n data: updatedKeyed,\n isLoading: isAnyKeyLoading(newIsLoading),\n status: \"Success\",\n } as Partial<TTarget[StoreKey<TTarget>]>);\n\n previousId = currentId;\n } else if (resourceState.status === \"Error\" && currentId !== undefined) {\n const newIsLoading = { ...currentKeyed.isLoading, [currentId]: false };\n const newStatus = {\n ...currentKeyed.status,\n [currentId]: resourceState.status,\n };\n const newErrors = {\n ...currentKeyed.errors,\n [currentId]: resourceState.errors,\n };\n\n const updatedKeyed: KeyedResourceData<KeyedResourceKey, TEntity> = {\n entities: { ...currentKeyed.entities },\n isLoading: newIsLoading,\n status: newStatus,\n errors: newErrors,\n };\n\n target.update(resolvedTargetKey, {\n data: updatedKeyed,\n isLoading: isAnyKeyLoading(newIsLoading),\n } as Partial<TTarget[StoreKey<TTarget>]>);\n\n previousId = currentId;\n } else if (resourceState.data === undefined && previousId !== undefined) {\n // Source cleared — remove previous entity from cache\n const { [previousId]: _removed, ...remainingEntities } =\n currentKeyed.entities;\n const { [previousId]: _removedLoading, ...remainingLoading } =\n currentKeyed.isLoading;\n const { [previousId]: _removedStatus, ...remainingStatus } =\n currentKeyed.status;\n const { [previousId]: _removedErrors, ...remainingErrors } =\n currentKeyed.errors;\n\n const updatedKeyed: KeyedResourceData<KeyedResourceKey, TEntity> = {\n entities: remainingEntities,\n isLoading: remainingLoading,\n status: remainingStatus,\n errors: remainingErrors,\n };\n\n target.update(resolvedTargetKey, {\n data: updatedKeyed,\n isLoading: isAnyKeyLoading(remainingLoading),\n } as Partial<TTarget[StoreKey<TTarget>]>);\n\n previousId = undefined;\n } else if (resourceState.isLoading && currentId !== undefined) {\n const newIsLoading = { ...currentKeyed.isLoading, [currentId]: true };\n\n const updatedKeyed: KeyedResourceData<KeyedResourceKey, TEntity> = {\n entities: { ...currentKeyed.entities },\n isLoading: newIsLoading,\n status: { ...currentKeyed.status },\n errors: { ...currentKeyed.errors },\n };\n\n target.update(resolvedTargetKey, {\n data: updatedKeyed,\n isLoading: true,\n } as Partial<TTarget[StoreKey<TTarget>]>);\n\n previousId = currentId;\n }\n });\n\n if (resolvedOptions?.destroyRef) {\n resolvedOptions.destroyRef.onDestroy(cleanup);\n }\n\n return cleanup;\n}\n","import type { ResourceDef } from './types';\n\n/**\n * Creates a phantom-typed resource definition marker.\n * Zero runtime cost — returns an empty object that only carries type info.\n *\n * @example\n * const config = {\n * customers: resource<Customer[]>(),\n * customerDetails: resource<Customer>(),\n * };\n */\nexport function resource<T>(): ResourceDef<T> {\n return {} as ResourceDef<T>;\n}\n"],"mappings":"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","names":["signal","signal","signal","signal","createKeyedResourceData","isAnyKeyLoading"]}
1
+ {"version":3,"sources":["../src/base-store.ts","../src/store-clone.ts","../src/store-replay.ts","../src/store-messages.ts","../src/store-message-consumer.ts","../src/store-channels.ts","../src/store-registry.ts","../src/lazy-store.ts","../src/store-builder.ts","../src/dynamic-store.ts","../src/mirror-key.ts","../src/collect-keyed.ts","../src/resource.ts"],"sourcesContent":["import { signal, type Signal, WritableSignal } from \"@angular/core\";\nimport { ResourceState, type KeyedResourceKey } from \"@flurryx/core\";\nimport type { IStore, StoreDataShape, StoreKey, StoreOptions } from \"./types\";\nimport { cloneValue } from \"./store-clone\";\nimport {\n createStoreHistory,\n type StoreHistoryDriver,\n type StoreHistoryEntry,\n} from \"./store-replay\";\nimport type { StoreMessageRecord } from \"./store-channels\";\nimport { trackStore } from \"./store-registry\";\nimport {\n createDefaultState,\n createStoreMessageConsumer,\n createUpdateMessage,\n createClearMessage,\n createClearAllMessage,\n createStartLoadingMessage,\n createStopLoadingMessage,\n createUpdateKeyedOneMessage,\n createClearKeyedOneMessage,\n createStartKeyedLoadingMessage,\n} from \"./store-message-consumer\";\n\ntype UpdateHooksMap = Map<\n unknown,\n Array<\n (\n nextState: ResourceState<unknown>,\n previousState: ResourceState<unknown>\n ) => void\n >\n>;\n\nconst updateHooksMap = new WeakMap<object, UpdateHooksMap>();\n\n/**\n * Abstract base class for flurryx stores.\n *\n * Backed by Angular `signal()` per slot, providing read-only `Signal` access\n * and immutable updates. All writes go through the store's own methods to\n * enforce single-owner encapsulation.\n *\n * Use the {@link Store} builder to create instances — do not subclass directly.\n *\n * @template TEnum - Record mapping slot names to their string/number keys.\n * @template TData - Record mapping slot names to `ResourceState<T>` types.\n */\nexport abstract class BaseStore<\n TEnum extends Record<string, string | number>,\n TData extends StoreDataShape<TData> & {\n [K in keyof TEnum]: ResourceState<unknown>;\n }\n> implements IStore<TData>\n{\n private readonly signalsState = new Map<\n string,\n WritableSignal<ResourceState<unknown>>\n >();\n private readonly storeKeys: readonly StoreKey<TData>[];\n private readonly historyDriver: StoreHistoryDriver<TData>;\n\n /** @inheritDoc */\n readonly restoreStoreAt = (index: number): void =>\n this.historyDriver.restoreStoreAt(index);\n\n /** @inheritDoc */\n readonly restoreResource = <K extends StoreKey<TData>>(key: K, index?: number): void =>\n this.historyDriver.restoreResource(key, index);\n\n /** @inheritDoc */\n readonly undo = (): boolean => this.historyDriver.undo();\n\n /** @inheritDoc */\n readonly redo = (): boolean => this.historyDriver.redo();\n\n /** @inheritDoc */\n readonly getDeadLetters = () => this.historyDriver.getDeadLetters();\n\n /** @inheritDoc */\n readonly replayDeadLetter = (id: number): boolean =>\n this.historyDriver.replayDeadLetter(id);\n\n /** @inheritDoc */\n readonly replayDeadLetters = (): number =>\n this.historyDriver.replayDeadLetters();\n\n /** @inheritDoc */\n readonly getCurrentIndex = () => this.historyDriver.getCurrentIndex();\n\n /** @inheritDoc */\n readonly history: Signal<readonly StoreHistoryEntry<TData>[]>;\n\n /** @inheritDoc */\n readonly messages: Signal<readonly StoreMessageRecord<TData>[]>;\n\n /** @inheritDoc */\n readonly currentIndex: Signal<number>;\n\n /** @inheritDoc */\n readonly keys: Signal<readonly StoreKey<TData>[]>;\n\n /** @inheritDoc */\n replay(id: number): number;\n\n /** @inheritDoc */\n replay(ids: readonly number[]): number;\n\n replay(idOrIds: number | readonly number[]): number {\n if (Array.isArray(idOrIds)) {\n return this.historyDriver.replay(idOrIds as readonly number[]);\n }\n\n return this.historyDriver.replay(idOrIds as number);\n }\n\n /** @inheritDoc */\n getHistory(): readonly StoreHistoryEntry<TData>[];\n\n /** @inheritDoc */\n getHistory<K extends StoreKey<TData>>(\n key: K\n ): readonly StoreHistoryEntry<TData, K>[];\n\n getHistory<K extends StoreKey<TData>>(key?: K) {\n if (key === undefined) {\n return this.historyDriver.getHistory();\n }\n\n return this.historyDriver.getHistory(key);\n }\n\n /** @inheritDoc */\n getMessages(): readonly StoreMessageRecord<TData>[];\n\n /** @inheritDoc */\n getMessages<K extends StoreKey<TData>>(\n key: K\n ): readonly StoreMessageRecord<TData, K>[];\n\n getMessages<K extends StoreKey<TData>>(key?: K) {\n if (key === undefined) {\n return this.historyDriver.getMessages();\n }\n\n return this.historyDriver.getMessages(key);\n }\n\n protected constructor(\n protected readonly storeEnum: TEnum,\n options?: StoreOptions<TData>\n ) {\n this.storeKeys = Object.keys(storeEnum) as StoreKey<TData>[];\n this.initializeState();\n updateHooksMap.set(this, new Map());\n\n const consumer = createStoreMessageConsumer<TData>(\n {\n getOrCreate: <K extends StoreKey<TData>>(key: K) =>\n this.signalsState.get(key) as WritableSignal<TData[K]>,\n getAllKeys: () => this.storeKeys,\n },\n {\n notify: <K extends StoreKey<TData>>(\n key: K,\n next: TData[K],\n prev: TData[K]\n ) => this.notifyUpdateHooks(key, next, prev),\n }\n );\n\n this.historyDriver = createStoreHistory<TData>({\n captureSnapshot: () => consumer.createSnapshot(),\n applySnapshot: (snapshot) => consumer.applySnapshot(snapshot),\n applyKeyUpdate: (key, snapshotState) => consumer.applyKeyUpdate(key, snapshotState),\n getAllKeys: () => this.storeKeys,\n applyMessage: (message) => consumer.applyMessage(message),\n channel: options?.channel,\n });\n\n this.history = this.historyDriver.historySignal;\n this.messages = this.historyDriver.messagesSignal;\n this.currentIndex = this.historyDriver.currentIndexSignal;\n this.keys = signal([...this.storeKeys]).asReadonly();\n\n trackStore(this);\n }\n\n /**\n * Returns a **read-only** `Signal` for the given store slot.\n *\n * @param key - The slot name to read.\n * @returns A `Signal` wrapping the slot's current {@link ResourceState}.\n */\n get<K extends StoreKey<TData>>(key: K): Signal<TData[K]> {\n return this.signalsState.get(key.toString()) as unknown as Signal<TData[K]>;\n }\n\n /**\n * Registers a callback fired after every `update` or `clear` on the given slot.\n *\n * @param key - The slot to watch.\n * @param callback - Receives the new state and the previous state.\n * @returns A cleanup function that removes the listener when called.\n */\n onUpdate<K extends StoreKey<TData>>(\n key: K,\n callback: (state: TData[K], previousState: TData[K]) => void\n ): () => void {\n const hooks = updateHooksMap.get(this)!;\n if (!hooks.has(key)) {\n hooks.set(key, []);\n }\n hooks\n .get(key)!\n .push(\n callback as (\n nextState: ResourceState<unknown>,\n previousState: ResourceState<unknown>\n ) => void\n );\n\n return () => {\n const hooksMap = hooks.get(key);\n if (!hooksMap) {\n return;\n }\n const index = hooksMap.indexOf(\n callback as (\n nextState: ResourceState<unknown>,\n previousState: ResourceState<unknown>\n ) => void\n );\n if (index > -1) {\n hooksMap.splice(index, 1);\n }\n };\n }\n\n /**\n * Partially updates a slot by merging `newState` into the current value (immutable spread).\n *\n * @param key - The slot to update.\n * @param newState - Partial state to merge (e.g. `{ data: newData, status: 'Success' }`).\n */\n update<K extends StoreKey<TData>>(key: K, newState: Partial<TData[K]>): void {\n this.historyDriver.publish(\n createUpdateMessage<TData, K>(key, cloneValue(newState))\n );\n }\n\n /** Resets every slot in this store to its initial idle state. */\n clearAll(): void {\n this.historyDriver.publish(createClearAllMessage<TData>());\n }\n\n /**\n * Resets a single slot to `{ data: undefined, isLoading: false, status: undefined, errors: undefined }`.\n *\n * @param key - The slot to clear.\n */\n clear<K extends StoreKey<TData>>(key: K): void {\n this.historyDriver.publish(createClearMessage<TData, K>(key));\n }\n\n /**\n * Marks a slot as loading: sets `isLoading: true` and clears `status` and `errors`.\n *\n * @param key - The slot to mark as loading.\n */\n startLoading<K extends StoreKey<TData>>(key: K): void {\n this.historyDriver.publish(createStartLoadingMessage<TData, K>(key));\n }\n\n /**\n * Marks a slot as no longer loading: sets `isLoading: false`.\n * Does **not** clear `status` or `errors`.\n *\n * @param key - The slot to stop loading.\n */\n stopLoading<K extends StoreKey<TData>>(key: K): void {\n this.historyDriver.publish(createStopLoadingMessage<TData, K>(key));\n }\n\n /**\n * Merges a single entity into a {@link KeyedResourceData} slot.\n * Sets its status to `'Success'` and clears per-key errors.\n * The top-level `isLoading` is recalculated based on remaining loading keys.\n *\n * @param key - The keyed slot name.\n * @param resourceKey - The entity identifier (e.g. `'inv-123'`).\n * @param entity - The entity value to store.\n */\n updateKeyedOne<K extends StoreKey<TData>>(\n key: K,\n resourceKey: KeyedResourceKey,\n entity: unknown\n ): void {\n this.historyDriver.publish(\n createUpdateKeyedOneMessage<TData, K>(\n key,\n resourceKey,\n cloneValue(entity)\n )\n );\n }\n\n /**\n * Removes a single entity from a {@link KeyedResourceData} slot,\n * including its loading flag, status, and errors.\n * Recalculates the top-level `isLoading` from the remaining keys.\n *\n * @param key - The keyed slot name.\n * @param resourceKey - The entity identifier to remove.\n */\n clearKeyedOne<K extends StoreKey<TData>>(\n key: K,\n resourceKey: KeyedResourceKey\n ): void {\n this.historyDriver.publish(\n createClearKeyedOneMessage<TData, K>(key, resourceKey)\n );\n }\n\n /**\n * Marks a single entity within a keyed slot as loading.\n * Clears its status and errors. If the slot data is not yet a {@link KeyedResourceData},\n * falls back to `startLoading(key)`.\n *\n * @param key - The keyed slot name.\n * @param resourceKey - The entity identifier to mark as loading.\n */\n startKeyedLoading<K extends StoreKey<TData>>(\n key: K,\n resourceKey: KeyedResourceKey\n ): void {\n this.historyDriver.publish(\n createStartKeyedLoadingMessage<TData, K>(key, resourceKey)\n );\n }\n\n private notifyUpdateHooks<K extends StoreKey<TData>>(\n key: K,\n nextState: TData[K],\n previousState: TData[K]\n ): void {\n const hooks = updateHooksMap.get(this);\n const keyHooks = hooks?.get(key);\n if (!keyHooks) {\n return;\n }\n\n const errors: unknown[] = [];\n\n keyHooks.forEach((hook) => {\n try {\n hook(\n nextState as ResourceState<unknown>,\n previousState as ResourceState<unknown>\n );\n } catch (error: unknown) {\n errors.push(error);\n }\n });\n\n if (errors.length > 0) {\n queueMicrotask(() => {\n if (errors.length === 1) {\n throw errors[0];\n }\n throw new AggregateError(\n errors,\n `${errors.length} onUpdate hooks threw for key \"${String(key)}\"`\n );\n });\n }\n }\n\n private initializeState(): void {\n this.storeKeys.forEach((key) => {\n this.signalsState.set(\n key,\n signal<TData[typeof key]>(createDefaultState() as TData[typeof key])\n );\n });\n }\n}\n","import type { ResourceState } from \"@flurryx/core\";\n\n/**\n * Creates a deep clone of the given value.\n *\n * **Warning:** Class instances with constructor logic, private fields, or\n * non-enumerable state will not clone correctly. The clone preserves the\n * prototype chain via `Object.create(Object.getPrototypeOf(...))` but does\n * **not** invoke the constructor, so any side-effects or hidden state set\n * during construction will be missing from the clone.\n */\nexport function cloneValue<T>(value: T): T {\n if (value !== null && typeof value === \"object\") {\n const existingClone = cloneReference(value, new WeakMap<object, unknown>());\n return existingClone as T;\n }\n\n return value;\n}\n\nfunction cloneReference<T extends object>(\n value: T,\n seen: WeakMap<object, unknown>\n): T {\n const seenClone = seen.get(value);\n if (seenClone) {\n return seenClone as T;\n }\n\n if (value instanceof Date) {\n return new Date(value.getTime()) as T;\n }\n\n if (value instanceof Map) {\n const clonedMap = new Map<unknown, unknown>();\n seen.set(value, clonedMap);\n value.forEach((entryValue, key) => {\n clonedMap.set(\n cloneValueWithSeen(key, seen),\n cloneValueWithSeen(entryValue, seen)\n );\n });\n return clonedMap as T;\n }\n\n if (value instanceof Set) {\n const clonedSet = new Set<unknown>();\n seen.set(value, clonedSet);\n value.forEach((entryValue) => {\n clonedSet.add(cloneValueWithSeen(entryValue, seen));\n });\n return clonedSet as T;\n }\n\n if (Array.isArray(value)) {\n const clonedArray: unknown[] = [];\n seen.set(value, clonedArray);\n value.forEach((item, index) => {\n clonedArray[index] = cloneValueWithSeen(item, seen);\n });\n\n return clonedArray as T;\n }\n\n const clonedObject = Object.create(Object.getPrototypeOf(value)) as Record<\n PropertyKey,\n unknown\n >;\n seen.set(value, clonedObject);\n\n Reflect.ownKeys(value).forEach((key) => {\n const descriptor = Object.getOwnPropertyDescriptor(value, key);\n if (!descriptor) {\n return;\n }\n\n if (\"value\" in descriptor) {\n descriptor.value = cloneValueWithSeen(descriptor.value, seen);\n }\n\n Object.defineProperty(clonedObject, key, descriptor);\n });\n\n return clonedObject as T;\n}\n\nfunction cloneValueWithSeen<T>(value: T, seen: WeakMap<object, unknown>): T {\n if (value !== null && typeof value === \"object\") {\n return cloneReference(value, seen);\n }\n\n return value;\n}\n\n/**\n * Creates a minimal patch object that, when spread onto `currentState`, produces `snapshotState`.\n * Properties present in the snapshot are cloned; properties absent from the snapshot are set to `undefined`.\n *\n * @param currentState - The current slot state.\n * @param snapshotState - The target snapshot state to restore.\n * @returns A partial state object suitable for `Signal.update()`.\n */\nexport function createSnapshotRestorePatch<\n TState extends ResourceState<unknown>\n>(currentState: TState, snapshotState: TState): Partial<TState> {\n const patch: Record<PropertyKey, unknown> = {};\n const keys = new Set([\n ...Reflect.ownKeys(currentState),\n ...Reflect.ownKeys(snapshotState),\n ]);\n\n keys.forEach((key) => {\n if (Object.prototype.hasOwnProperty.call(snapshotState, key)) {\n patch[key] = cloneValue(\n (snapshotState as Record<PropertyKey, unknown>)[key]\n );\n return;\n }\n\n patch[key] = undefined;\n });\n\n return patch as Partial<TState>;\n}\n","import { signal, computed, type Signal } from \"@angular/core\";\nimport type { StoreDataShape, StoreKey } from \"./types\";\nimport type {\n StoreMessage,\n StoreSnapshot,\n StoreMessageStatus,\n} from \"./store-messages\";\nimport {\n INVALID_HISTORY_INDEX_ERROR,\n INVALID_HISTORY_MESSAGE_ID_ERROR,\n INVALID_STORE_KEY_ERROR,\n MESSAGE_NOT_ACKNOWLEDGED_ERROR,\n} from \"./store-messages\";\nimport { cloneValue } from \"./store-clone\";\nimport { createDefaultState } from \"./store-message-consumer\";\nimport {\n createInMemoryStoreMessageChannel,\n type StoreMessageChannel,\n type StoreMessageRecord,\n} from \"./store-channels\";\n\n// ---------------------------------------------------------------------------\n// Re-exports — keep existing consumers working\n// ---------------------------------------------------------------------------\n\nexport { cloneValue, createSnapshotRestorePatch } from \"./store-clone\";\nexport type {\n StoreMessage,\n StoreSnapshot,\n StoreMessageStatus,\n UpdateStoreMessage,\n ClearStoreMessage,\n ClearAllStoreMessage,\n StartLoadingStoreMessage,\n StopLoadingStoreMessage,\n UpdateKeyedOneStoreMessage,\n ClearKeyedOneStoreMessage,\n StartKeyedLoadingStoreMessage,\n} from \"./store-messages\";\nexport {\n INVALID_HISTORY_INDEX_ERROR,\n INVALID_HISTORY_MESSAGE_ID_ERROR,\n INVALID_STORE_KEY_ERROR,\n MESSAGE_NOT_ACKNOWLEDGED_ERROR,\n} from \"./store-messages\";\nexport {\n createInMemoryStoreMessageChannel,\n createStorageStoreMessageChannel,\n createLocalStorageStoreMessageChannel,\n createSessionStorageStoreMessageChannel,\n createCompositeStoreMessageChannel,\n} from \"./store-channels\";\nexport type {\n StoreMessageChannel,\n StoreMessageChannelStorage,\n StoreMessageChannelOptions,\n CompositeStoreMessageChannelOptions,\n StorageStoreMessageChannelOptions,\n BrowserStorageStoreMessageChannelOptions,\n StoreMessageRecord,\n} from \"./store-channels\";\n\n// ---------------------------------------------------------------------------\n// History types\n// ---------------------------------------------------------------------------\n\n/**\n * Single acknowledged point in store history.\n *\n * Entry `0` is always the initial snapshot captured when the history driver is\n * created, so its `id`, `message`, and `acknowledgedAt` are `null`.\n */\nexport interface StoreHistoryEntry<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> {\n /** Stable message id used by `replay(...)`; `null` for the initial snapshot entry. */\n readonly id: number | null;\n /** Snapshot position used by `restoreStoreAt(index)`, `undo()`, and `redo()`. */\n readonly index: number;\n /** Acknowledged message that produced this snapshot; `null` for the initial entry. */\n readonly message: StoreMessage<TData, TKey> | null;\n /** Full store snapshot captured immediately after the message was acknowledged. */\n readonly snapshot: StoreSnapshot<TData, TKey>;\n /** Acknowledgement timestamp for the message; `null` for the initial snapshot entry. */\n readonly acknowledgedAt: number | null;\n}\n\n/**\n * Failed message tracked by the internal broker when the store consumer does not\n * acknowledge a published message.\n */\nexport interface StoreDeadLetterEntry<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> {\n /** Stable dead-letter id used by `replayDeadLetter(id)`. */\n readonly id: number;\n /** Original message that failed acknowledgement. */\n readonly message: StoreMessage<TData, TKey>;\n /** Number of failed acknowledgement attempts for this dead letter. */\n readonly attempts: number;\n /** Last acknowledgement error captured for this dead letter. */\n readonly error: string;\n /** Timestamp of the most recent failure. */\n readonly failedAt: number;\n}\n\n/**\n * Public history and recovery API exposed on every store instance.\n *\n * `restoreStoreAt(...)` navigates snapshots by history index, while `replay(...)`\n * re-executes previously published channel messages by their stable message ids.\n */\nexport interface StoreHistory<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> {\n /**\n * Re-executes one previously published message by id.\n *\n * The message does not need to have been acknowledged before. Replay resolves it\n * from the configured message channel, sends it back through the broker/consumer\n * flow, and may create a fresh acknowledged history entry if the replay succeeds.\n *\n * @throws {Error} When the id does not point to a persisted channel message.\n * @returns Number of successfully acknowledged replayed messages.\n */\n replay(id: number): number;\n\n /**\n * Re-executes multiple previously published messages in the provided order.\n *\n * Every id must resolve to a persisted channel message. Replay stops with an error\n * if any supplied id is invalid.\n *\n * @throws {Error} When any id does not point to a persisted channel message.\n * @returns Number of successfully acknowledged replayed messages.\n */\n replay(ids: readonly number[]): number;\n\n /**\n * Restores the store to the snapshot recorded at a specific history index.\n *\n * This is snapshot navigation only. It does not publish or acknowledge any\n * message and does not create a new history entry.\n *\n * @throws {Error} When the index is outside the recorded history range.\n */\n restoreStoreAt(index: number): void;\n\n /**\n * Restores a single store key to its state at a specific history index.\n *\n * Unlike `restoreStoreAt(index)` which restores the full snapshot, this method\n * only restores the specified key while leaving other keys unaffected.\n * This is snapshot navigation only. It does not publish or acknowledge any\n * message and does not create a new history entry.\n *\n * @param key - The store key to restore.\n * @param index - Optional history index. Defaults to the current index.\n * @throws {Error} When the key is not a valid store key.\n * @throws {Error} When the index is outside the recorded history range.\n */\n restoreResource<K extends TKey>(key: K, index?: number): void;\n\n /**\n * Moves to the previous recorded snapshot.\n *\n * Equivalent to `restoreStoreAt(getCurrentIndex() - 1)` when possible.\n *\n * @returns `true` when the pointer moved, otherwise `false` at the initial snapshot.\n */\n undo(): boolean;\n\n /**\n * Moves to the next recorded snapshot when history exists ahead of the current pointer.\n *\n * Equivalent to `restoreStoreAt(getCurrentIndex() + 1)` when possible.\n *\n * @returns `true` when the pointer moved, otherwise `false` at the latest snapshot.\n */\n redo(): boolean;\n\n /** Returns a defensive copy of every recorded history entry, including the initial snapshot entry. */\n getHistory(): readonly StoreHistoryEntry<TData, TKey>[];\n\n /**\n * Returns the history entries that affected a specific store key.\n *\n * The initial snapshot entry is always included as the first item. Messages such\n * as `clearAll` that affect every key are included in every filtered view.\n */\n getHistory<K extends TKey>(key: K): readonly StoreHistoryEntry<TData, K>[];\n\n /** Returns a defensive copy of the current dead-letter collection. */\n getDeadLetters(): readonly StoreDeadLetterEntry<TData, TKey>[];\n\n /** Returns every message currently stored in the configured channel. */\n getMessages(): readonly StoreMessageRecord<TData, TKey>[];\n\n /** Returns channel messages that affected a specific store key. */\n getMessages<K extends TKey>(key: K): readonly StoreMessageRecord<TData, K>[];\n\n /**\n * Republishes a single dead-letter message by dead-letter id.\n *\n * On success the dead letter is removed and a new acknowledged history entry is recorded.\n *\n * @returns `true` when the dead letter was acknowledged on replay, otherwise `false`.\n */\n replayDeadLetter(id: number): boolean;\n\n /**\n * Attempts to republish every current dead letter once.\n *\n * Successfully acknowledged dead letters are removed. Failures remain in the\n * dead-letter collection with incremented attempt counts.\n *\n * @returns Number of dead letters successfully acknowledged during the replay attempt.\n */\n replayDeadLetters(): number;\n\n /** Returns the currently restored history index used by snapshot navigation. */\n getCurrentIndex(): number;\n\n /** Reactive signal containing the full history entries. */\n readonly historySignal: Signal<readonly StoreHistoryEntry<TData, TKey>[]>;\n /** Reactive signal containing all channel message records. */\n readonly messagesSignal: Signal<readonly StoreMessageRecord<TData, TKey>[]>;\n /** Reactive signal containing the current history index. */\n readonly currentIndexSignal: Signal<number>;\n}\n\nexport interface StoreHistoryDriver<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> extends StoreHistory<TData, TKey> {\n publish(message: StoreMessage<TData, TKey>): boolean;\n}\n\ninterface CreateStoreHistoryConfig<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> {\n readonly captureSnapshot: () => StoreSnapshot<TData, TKey>;\n readonly applySnapshot: (snapshot: StoreSnapshot<TData, TKey>) => void;\n readonly applyKeyUpdate: <K extends TKey>(key: K, snapshotState: TData[K]) => void;\n readonly getAllKeys: () => Iterable<TKey>;\n readonly applyMessage: (message: StoreMessage<TData, TKey>) => boolean;\n readonly channel?: StoreMessageChannel<TData, TKey>;\n readonly clock?: () => number;\n}\n\ninterface StableReadonlyCollectionAppendInput<TItem> {\n readonly items: readonly TItem[];\n readonly item: TItem;\n}\n\ninterface StableReadonlyCollectionUpsertInput<\n TItem extends {\n readonly id: number;\n }\n> {\n readonly items: readonly TItem[];\n readonly item: TItem;\n}\n\ninterface StableReadonlyCollectionSyncInput<\n TSource,\n TItem extends {\n readonly id: number;\n }\n> {\n readonly items: readonly TItem[];\n readonly sourceItems: readonly TSource[];\n readonly getSourceId: (item: TSource) => number;\n readonly createItem: (item: TSource) => TItem;\n readonly areEquivalent: (sourceItem: TSource, cachedItem: TItem) => boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction messageAffectsKey<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData>,\n K extends TKey\n>(\n message: StoreMessage<TData, TKey>,\n key: K\n): message is StoreMessage<TData, K> {\n if (message.type === \"clearAll\") {\n return true;\n }\n\n return \"key\" in message && message.key === key;\n}\n\nfunction toDeadLetterEntry<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData>\n>(record: StoreMessageRecord<TData, TKey>): StoreDeadLetterEntry<TData, TKey> {\n return {\n id: record.id,\n message: cloneValue(record.message),\n attempts: record.attempts,\n error: record.error ?? MESSAGE_NOT_ACKNOWLEDGED_ERROR,\n failedAt: record.lastAttemptedAt ?? record.createdAt,\n };\n}\n\nfunction areValuesEquivalent(\n left: unknown,\n right: unknown,\n seen: WeakMap<object, WeakSet<object>> = new WeakMap<object, WeakSet<object>>()\n): boolean {\n if (Object.is(left, right)) {\n return true;\n }\n\n if (typeof left !== typeof right || left === null || right === null) {\n return false;\n }\n\n if (typeof left !== \"object\" || typeof right !== \"object\") {\n return false;\n }\n\n let seenRights = seen.get(left);\n if (seenRights?.has(right)) {\n return true;\n }\n\n if (!seenRights) {\n seenRights = new WeakSet<object>();\n seen.set(left, seenRights);\n }\n seenRights.add(right);\n\n if (left instanceof Date || right instanceof Date) {\n return (\n left instanceof Date &&\n right instanceof Date &&\n left.getTime() === right.getTime()\n );\n }\n\n if (left instanceof Map || right instanceof Map) {\n if (!(left instanceof Map) || !(right instanceof Map)) {\n return false;\n }\n\n const leftEntries = Array.from(left.entries());\n const rightEntries = Array.from(right.entries());\n if (leftEntries.length !== rightEntries.length) {\n return false;\n }\n\n return leftEntries.every(([leftKey, leftValue], index) => {\n const rightEntry = rightEntries[index];\n if (!rightEntry) {\n return false;\n }\n\n return (\n areValuesEquivalent(leftKey, rightEntry[0], seen) &&\n areValuesEquivalent(leftValue, rightEntry[1], seen)\n );\n });\n }\n\n if (left instanceof Set || right instanceof Set) {\n if (!(left instanceof Set) || !(right instanceof Set)) {\n return false;\n }\n\n const leftValues = Array.from(left.values());\n const rightValues = Array.from(right.values());\n if (leftValues.length !== rightValues.length) {\n return false;\n }\n\n return leftValues.every((leftValue, index) =>\n areValuesEquivalent(leftValue, rightValues[index], seen)\n );\n }\n\n if (Array.isArray(left) || Array.isArray(right)) {\n if (!Array.isArray(left) || !Array.isArray(right)) {\n return false;\n }\n\n if (left.length !== right.length) {\n return false;\n }\n\n return left.every((leftValue, index) =>\n areValuesEquivalent(leftValue, right[index], seen)\n );\n }\n\n if (Object.getPrototypeOf(left) !== Object.getPrototypeOf(right)) {\n return false;\n }\n\n const leftRecord = left as Record<PropertyKey, unknown>;\n const rightRecord = right as Record<PropertyKey, unknown>;\n const leftKeys = Reflect.ownKeys(leftRecord);\n const rightKeys = Reflect.ownKeys(rightRecord);\n\n if (leftKeys.length !== rightKeys.length) {\n return false;\n }\n\n return leftKeys.every((key) => {\n if (!Object.prototype.hasOwnProperty.call(rightRecord, key)) {\n return false;\n }\n\n return areValuesEquivalent(leftRecord[key], rightRecord[key], seen);\n });\n}\n\nfunction areStoreMessageRecordsEquivalent<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData>\n>(\n sourceRecord: StoreMessageRecord<TData, TKey>,\n cachedRecord: StoreMessageRecord<TData, TKey>\n): boolean {\n return (\n sourceRecord.id === cachedRecord.id &&\n sourceRecord.status === cachedRecord.status &&\n sourceRecord.attempts === cachedRecord.attempts &&\n sourceRecord.createdAt === cachedRecord.createdAt &&\n sourceRecord.lastAttemptedAt === cachedRecord.lastAttemptedAt &&\n sourceRecord.acknowledgedAt === cachedRecord.acknowledgedAt &&\n sourceRecord.error === cachedRecord.error &&\n areValuesEquivalent(sourceRecord.message, cachedRecord.message)\n );\n}\n\nfunction createStableReadonlyCollection<TItem>(\n items: readonly TItem[]\n): readonly TItem[] {\n return Object.freeze([...items]);\n}\n\nfunction appendStableReadonlyCollectionItem<TItem>(\n input: StableReadonlyCollectionAppendInput<TItem>\n): readonly TItem[] {\n return createStableReadonlyCollection([...input.items, input.item]);\n}\n\nfunction upsertStableReadonlyCollectionItem<\n TItem extends {\n readonly id: number;\n }\n>(input: StableReadonlyCollectionUpsertInput<TItem>): readonly TItem[] {\n const existingIndex = input.items.findIndex(\n (candidate) => candidate.id === input.item.id\n );\n\n if (existingIndex === -1) {\n return appendStableReadonlyCollectionItem(input);\n }\n\n if (Object.is(input.items[existingIndex], input.item)) {\n return input.items;\n }\n\n const nextItems = [...input.items];\n nextItems[existingIndex] = input.item;\n return createStableReadonlyCollection(nextItems);\n}\n\nfunction syncStableReadonlyCollectionById<\n TSource,\n TItem extends {\n readonly id: number;\n }\n>(input: StableReadonlyCollectionSyncInput<TSource, TItem>): readonly TItem[] {\n const cachedItemsById = new Map<number, TItem>();\n input.items.forEach((item) => {\n cachedItemsById.set(item.id, item);\n });\n\n let didChange = input.items.length !== input.sourceItems.length;\n const nextItems = input.sourceItems.map((sourceItem, index) => {\n const cachedItem = cachedItemsById.get(input.getSourceId(sourceItem));\n const nextItem =\n cachedItem && input.areEquivalent(sourceItem, cachedItem)\n ? cachedItem\n : input.createItem(sourceItem);\n\n if (!didChange && input.items[index] !== nextItem) {\n didChange = true;\n }\n\n return nextItem;\n });\n\n return didChange ? createStableReadonlyCollection(nextItems) : input.items;\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\nexport function createStoreHistory<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n>(\n config: CreateStoreHistoryConfig<TData, TKey>\n): StoreHistoryDriver<TData, TKey> {\n const messageChannel =\n config.channel ?? createInMemoryStoreMessageChannel<TData, TKey>();\n const clock = config.clock ?? Date.now;\n let history: readonly StoreHistoryEntry<TData, TKey>[] = [\n {\n id: null,\n index: 0,\n message: null,\n snapshot: config.captureSnapshot(),\n acknowledgedAt: null,\n },\n ];\n let currentIndex = 0;\n let historyCollection = createStableReadonlyCollection(\n history.map((entry) => cloneValue(entry))\n );\n let messageCollection = createStableReadonlyCollection(\n messageChannel.getMessages().map((record) => cloneValue(record))\n );\n\n const version = signal(0);\n function notifyVersion(): void {\n version.update((v) => v + 1);\n }\n\n function recordSnapshot(record: StoreMessageRecord<TData, TKey>): void {\n const nextIndex = history.length;\n const nextHistoryEntry: StoreHistoryEntry<TData, TKey> = {\n id: record.id,\n index: nextIndex,\n message: cloneValue(record.message),\n snapshot: config.captureSnapshot(),\n acknowledgedAt: record.acknowledgedAt,\n };\n\n history = [...history, nextHistoryEntry];\n historyCollection = appendStableReadonlyCollectionItem({\n items: historyCollection,\n item: cloneValue(nextHistoryEntry),\n });\n currentIndex = nextIndex;\n }\n\n function truncateFutureHistory(): void {\n if (currentIndex === history.length - 1) {\n return;\n }\n\n history = history.slice(0, currentIndex + 1);\n historyCollection = createStableReadonlyCollection(\n historyCollection.slice(0, currentIndex + 1)\n );\n }\n\n function ensureIndexInRange(index: number): void {\n if (!Number.isInteger(index) || index < 0 || index >= history.length) {\n throw new Error(INVALID_HISTORY_INDEX_ERROR);\n }\n }\n\n function restoreStoreAt(index: number): void {\n ensureIndexInRange(index);\n config.applySnapshot(history[index]!.snapshot);\n currentIndex = index;\n notifyVersion();\n }\n\n function restoreResource<K extends TKey>(key: K, index?: number): void {\n const targetIndex = index !== undefined ? index : currentIndex;\n ensureIndexInRange(targetIndex);\n\n // Validate that the key is a valid store key\n const allKeys = new Set(Array.from(config.getAllKeys()));\n if (!allKeys.has(key)) {\n throw new Error(INVALID_STORE_KEY_ERROR);\n }\n\n const snapshot = history[targetIndex]!.snapshot;\n const snapshotState = snapshot[key] as TData[K] | undefined;\n\n config.applyKeyUpdate(key, snapshotState ?? createDefaultState() as TData[K]);\n notifyVersion();\n }\n\n function undo(): boolean {\n if (currentIndex === 0) {\n return false;\n }\n\n restoreStoreAt(currentIndex - 1);\n return true;\n }\n\n function redo(): boolean {\n if (currentIndex >= history.length - 1) {\n return false;\n }\n\n restoreStoreAt(currentIndex + 1);\n return true;\n }\n\n function getErrorMessage(error: unknown): string {\n if (error instanceof Error && error.message) {\n return error.message;\n }\n\n return MESSAGE_NOT_ACKNOWLEDGED_ERROR;\n }\n\n function persistMessageAttempt(\n record: StoreMessageRecord<TData, TKey>,\n status: StoreMessageStatus,\n error: string | null,\n attemptedAt: number\n ): StoreMessageRecord<TData, TKey> {\n const nextRecord: StoreMessageRecord<TData, TKey> = {\n ...record,\n message: cloneValue(record.message),\n status,\n attempts: record.attempts + 1,\n lastAttemptedAt: attemptedAt,\n acknowledgedAt:\n status === \"acknowledged\" ? attemptedAt : record.acknowledgedAt,\n error,\n };\n\n messageChannel.saveMessage(nextRecord);\n messageCollection = upsertStableReadonlyCollectionItem({\n items: messageCollection,\n item: cloneValue(nextRecord),\n });\n return nextRecord;\n }\n\n function consumeRecord(\n record: StoreMessageRecord<TData, TKey>,\n options?: {\n readonly recordHistory?: boolean;\n }\n ): boolean {\n const clonedMessage = cloneValue(record.message);\n const attemptedAt = clock();\n\n try {\n const acknowledged = config.applyMessage(clonedMessage);\n if (!acknowledged) {\n throw new Error(MESSAGE_NOT_ACKNOWLEDGED_ERROR);\n }\n\n const acknowledgedRecord = persistMessageAttempt(\n {\n ...record,\n message: clonedMessage,\n },\n \"acknowledged\",\n null,\n attemptedAt\n );\n\n if (options?.recordHistory !== false) {\n truncateFutureHistory();\n recordSnapshot(acknowledgedRecord);\n }\n\n notifyVersion();\n return true;\n } catch (error) {\n persistMessageAttempt(\n {\n ...record,\n message: clonedMessage,\n },\n \"dead-letter\",\n getErrorMessage(error),\n attemptedAt\n );\n notifyVersion();\n return false;\n }\n }\n\n function resolveReplayRecords(\n ids: readonly number[]\n ): StoreMessageRecord<TData, TKey>[] {\n return ids.map((id) => {\n if (!Number.isInteger(id) || id < 1) {\n throw new Error(INVALID_HISTORY_MESSAGE_ID_ERROR);\n }\n\n const record = messageChannel.getMessage(id);\n if (!record) {\n throw new Error(INVALID_HISTORY_MESSAGE_ID_ERROR);\n }\n\n return cloneValue(record);\n });\n }\n\n function replayByIds(input: number | readonly number[]): number {\n const ids = Array.isArray(input) ? input : [input];\n const records = resolveReplayRecords(ids);\n let acknowledgedCount = 0;\n\n records.forEach((record) => {\n if (consumeRecord(record)) {\n acknowledgedCount += 1;\n }\n });\n\n return acknowledgedCount;\n }\n\n function replayDeadLetter(id: number): boolean {\n const record = messageChannel.getMessage(id);\n if (!record || record.status !== \"dead-letter\") {\n return false;\n }\n\n return consumeRecord(record);\n }\n\n function replayDeadLetters(): number {\n const ids = messageChannel\n .getMessages()\n .filter((record) => record.status === \"dead-letter\")\n .map((record) => record.id);\n let acknowledgedCount = 0;\n\n ids.forEach((id) => {\n if (replayDeadLetter(id)) {\n acknowledgedCount += 1;\n }\n });\n\n return acknowledgedCount;\n }\n\n const historySignal = computed(() => {\n version();\n return historyCollection;\n });\n\n const messagesSignal = computed(() => {\n version();\n messageCollection = syncStableReadonlyCollectionById({\n items: messageCollection,\n sourceItems: messageChannel.getMessages(),\n getSourceId: (record) => record.id,\n createItem: (record) => cloneValue(record),\n areEquivalent: areStoreMessageRecordsEquivalent,\n });\n return messageCollection;\n });\n\n const currentIndexSignal = computed(() => {\n version();\n return currentIndex;\n });\n\n return {\n historySignal,\n messagesSignal,\n currentIndexSignal,\n publish(message) {\n const record = messageChannel.publish(message);\n messageCollection = appendStableReadonlyCollectionItem({\n items: messageCollection,\n item: cloneValue(record),\n });\n return consumeRecord(record);\n },\n replay(input: number | readonly number[]) {\n return replayByIds(input);\n },\n restoreStoreAt,\n restoreResource,\n undo,\n redo,\n getHistory<K extends TKey>(key?: K) {\n if (key === undefined) {\n return history.map((entry) => cloneValue(entry));\n }\n\n return history\n .filter((entry) => {\n if (entry.message === null) {\n return true;\n }\n\n return messageAffectsKey(entry.message, key);\n })\n .map((entry) => cloneValue(entry) as StoreHistoryEntry<TData, K>);\n },\n getMessages<K extends TKey>(key?: K) {\n const records = messageChannel.getMessages();\n if (key === undefined) {\n return records.map((record) => cloneValue(record));\n }\n\n return records\n .filter((record) => messageAffectsKey(record.message, key))\n .map((record) => cloneValue(record) as StoreMessageRecord<TData, K>);\n },\n getDeadLetters() {\n return messageChannel\n .getMessages()\n .filter((record) => record.status === \"dead-letter\")\n .map((record) => toDeadLetterEntry(record));\n },\n replayDeadLetter,\n replayDeadLetters,\n getCurrentIndex() {\n return currentIndex;\n },\n };\n}\n","import type {\n KeyedResourceEntryKey,\n KeyedResourceEntryValue,\n KeyedStoreKey,\n StoreDataShape,\n StoreKey,\n} from \"./types\";\n\n/** Message produced by `store.update(key, partial)` — merges partial state into a slot. */\nexport type UpdateStoreMessage<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> = {\n readonly [K in TKey]: {\n readonly type: \"update\";\n readonly key: K;\n readonly state: Partial<TData[K]>;\n };\n}[TKey];\n\n/** Message produced by `store.clear(key)` — resets a single slot to its initial state. */\nexport type ClearStoreMessage<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> = {\n readonly [K in TKey]: {\n readonly type: \"clear\";\n readonly key: K;\n };\n}[TKey];\n\n/** Message produced by `store.clearAll()` — resets every slot in the store. */\nexport interface ClearAllStoreMessage<TData extends StoreDataShape<TData>> {\n readonly type: \"clearAll\";\n}\n\n/** Message produced by `store.startLoading(key)` — sets `isLoading: true` and clears `status`/`errors`. */\nexport type StartLoadingStoreMessage<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> = {\n readonly [K in TKey]: {\n readonly type: \"startLoading\";\n readonly key: K;\n };\n}[TKey];\n\n/** Message produced by `store.stopLoading(key)` — sets `isLoading: false`. */\nexport type StopLoadingStoreMessage<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> = {\n readonly [K in TKey]: {\n readonly type: \"stopLoading\";\n readonly key: K;\n };\n}[TKey];\n\n/** Message produced by `store.updateKeyedOne(key, resourceKey, entity)` — merges a single entity into a keyed slot. */\nexport type UpdateKeyedOneStoreMessage<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> = {\n readonly [K in KeyedStoreKey<TData, TKey>]: {\n readonly type: \"updateKeyedOne\";\n readonly key: K;\n readonly resourceKey: KeyedResourceEntryKey<TData, K>;\n readonly entity: KeyedResourceEntryValue<TData, K>;\n };\n}[KeyedStoreKey<TData, TKey>];\n\n/** Message produced by `store.clearKeyedOne(key, resourceKey)` — removes a single entity from a keyed slot. */\nexport type ClearKeyedOneStoreMessage<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> = {\n readonly [K in KeyedStoreKey<TData, TKey>]: {\n readonly type: \"clearKeyedOne\";\n readonly key: K;\n readonly resourceKey: KeyedResourceEntryKey<TData, K>;\n };\n}[KeyedStoreKey<TData, TKey>];\n\n/** Message produced by `store.startKeyedLoading(key, resourceKey)` — marks a single entity as loading. */\nexport type StartKeyedLoadingStoreMessage<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> = {\n readonly [K in KeyedStoreKey<TData, TKey>]: {\n readonly type: \"startKeyedLoading\";\n readonly key: K;\n readonly resourceKey: KeyedResourceEntryKey<TData, K>;\n };\n}[KeyedStoreKey<TData, TKey>];\n\n/** Discriminated union of all typed store messages published to the broker channel. */\nexport type StoreMessage<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> =\n | UpdateStoreMessage<TData, TKey>\n | ClearStoreMessage<TData, TKey>\n | ClearAllStoreMessage<TData>\n | StartLoadingStoreMessage<TData, TKey>\n | StopLoadingStoreMessage<TData, TKey>\n | UpdateKeyedOneStoreMessage<TData, TKey>\n | ClearKeyedOneStoreMessage<TData, TKey>\n | StartKeyedLoadingStoreMessage<TData, TKey>;\n\n/** Full store state captured at a point in time, keyed by slot name. Used by history and time travel. */\nexport type StoreSnapshot<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> = Partial<{\n readonly [K in TKey]: TData[K];\n}>;\n\n/** Delivery status of a broker message: `\"pending\"` → `\"acknowledged\"` or `\"dead-letter\"`. */\nexport type StoreMessageStatus = \"pending\" | \"acknowledged\" | \"dead-letter\";\n\n/** Error message thrown when `restoreStoreAt()` receives an index outside the recorded history range. */\nexport const INVALID_HISTORY_INDEX_ERROR = \"History index is out of range\";\n/** Error message thrown when `replay()` receives an id that does not match a persisted channel message. */\nexport const INVALID_HISTORY_MESSAGE_ID_ERROR =\n \"History message id is out of range\";\n/** Error message recorded in dead-letter entries when the store consumer does not acknowledge a message. */\nexport const MESSAGE_NOT_ACKNOWLEDGED_ERROR = \"Message was not acknowledged\";\n/** Error message thrown when `restoreResource()` receives a key that is not a valid store key. */\nexport const INVALID_STORE_KEY_ERROR = \"Invalid store key\";\n","import type { WritableSignal } from \"@angular/core\";\nimport {\n type ResourceState,\n type KeyedResourceKey,\n isKeyedResourceData,\n createKeyedResourceData,\n isAnyKeyLoading,\n} from \"@flurryx/core\";\nimport type { StoreDataShape, StoreKey } from \"./types\";\nimport type { StoreMessage, StoreSnapshot } from \"./store-messages\";\nimport { cloneValue, createSnapshotRestorePatch } from \"./store-clone\";\n\nexport function createDefaultState<T>(): ResourceState<T> {\n return {\n data: undefined,\n isLoading: false,\n status: undefined,\n errors: undefined,\n };\n}\n\n/**\n * Abstraction over how a store manages its writable signals.\n * BaseStore uses a pre-allocated Map; LazyStore creates signals on demand.\n */\nexport interface SignalAccessor<TData extends StoreDataShape<TData>> {\n getOrCreate<K extends StoreKey<TData>>(key: K): WritableSignal<TData[K]>;\n getAllKeys(): Iterable<StoreKey<TData>>;\n}\n\n/**\n * Abstraction over how a store notifies update hooks after state changes.\n */\nexport interface StoreNotifier<TData extends StoreDataShape<TData>> {\n notify<K extends StoreKey<TData>>(\n key: K,\n next: TData[K],\n prev: TData[K]\n ): void;\n}\n\n/**\n * Consumer returned by {@link createStoreMessageConsumer} that both\n * BaseStore and LazyStore delegate to for message application, snapshot\n * capture, and snapshot restore.\n */\nexport interface StoreMessageConsumer<TData extends StoreDataShape<TData>> {\n applyMessage(message: StoreMessage<TData>): boolean;\n applySnapshot(snapshot: StoreSnapshot<TData>): void;\n applyKeyUpdate<K extends StoreKey<TData>>(\n key: K,\n snapshotState: TData[K]\n ): void;\n createSnapshot(): StoreSnapshot<TData>;\n}\n\n/**\n * Creates a shared message consumer that encapsulates all apply logic.\n *\n * Both BaseStore and LazyStore delegate to this consumer, eliminating\n * ~300 lines of duplicated implementation between the two stores.\n */\nexport function createStoreMessageConsumer<TData extends StoreDataShape<TData>>(\n signals: SignalAccessor<TData>,\n notifier: StoreNotifier<TData>\n): StoreMessageConsumer<TData> {\n function applyUpdate<K extends StoreKey<TData>>(\n key: K,\n newState: Partial<TData[K]>,\n notify = true\n ): boolean {\n const sig = signals.getOrCreate(key);\n const previousState = sig();\n sig.update((state) => ({ ...state, ...newState }));\n\n if (notify) {\n const updatedState = sig();\n notifier.notify(key, updatedState, previousState);\n }\n\n return true;\n }\n\n function applyClear<K extends StoreKey<TData>>(key: K): boolean {\n const sig = signals.getOrCreate(key);\n const previousState = sig();\n sig.set(createDefaultState() as TData[K]);\n\n const nextState = sig();\n notifier.notify(key, nextState, previousState);\n return true;\n }\n\n function applyClearAll(): boolean {\n const keys = Array.from(signals.getAllKeys());\n if (keys.length === 0) {\n return false;\n }\n\n keys.forEach((key) => {\n applyClear(key);\n });\n\n return true;\n }\n\n function applyStartLoading<K extends StoreKey<TData>>(key: K): boolean {\n const sig = signals.getOrCreate(key);\n sig.update(\n (state) =>\n ({\n ...state,\n status: undefined,\n isLoading: true,\n errors: undefined,\n } as TData[K])\n );\n return true;\n }\n\n function applyStopLoading<K extends StoreKey<TData>>(key: K): boolean {\n const sig = signals.getOrCreate(key);\n sig.update(\n (state) =>\n ({\n ...state,\n isLoading: false,\n } as TData[K])\n );\n return true;\n }\n\n function applyUpdateKeyedOne<K extends StoreKey<TData>>(\n key: K,\n resourceKey: KeyedResourceKey,\n entity: unknown\n ): boolean {\n const sig = signals.getOrCreate(key);\n const state = sig();\n const data = isKeyedResourceData(state.data)\n ? state.data\n : createKeyedResourceData();\n\n const nextErrors = { ...data.errors };\n delete nextErrors[resourceKey];\n\n const nextData = {\n ...data,\n entities: { ...data.entities, [resourceKey]: entity },\n isLoading: { ...data.isLoading, [resourceKey]: false },\n status: { ...data.status, [resourceKey]: \"Success\" as const },\n errors: nextErrors,\n };\n\n return applyUpdate(key, {\n data: nextData as unknown,\n isLoading: isAnyKeyLoading(nextData.isLoading),\n status: undefined,\n errors: undefined,\n } as Partial<TData[K]>);\n }\n\n function applyClearKeyedOne<K extends StoreKey<TData>>(\n key: K,\n resourceKey: KeyedResourceKey\n ): boolean {\n const sig = signals.getOrCreate(key);\n const previousState = sig();\n const state = previousState as ResourceState<unknown>;\n if (!isKeyedResourceData(state.data)) {\n return true;\n }\n\n const data = state.data;\n\n const nextEntities = { ...data.entities };\n delete nextEntities[resourceKey];\n\n const nextIsLoading = { ...data.isLoading };\n delete nextIsLoading[resourceKey];\n\n const nextStatus = { ...data.status };\n delete nextStatus[resourceKey];\n\n const nextErrors = { ...data.errors };\n delete nextErrors[resourceKey];\n\n const nextData = {\n ...data,\n entities: nextEntities,\n isLoading: nextIsLoading,\n status: nextStatus,\n errors: nextErrors,\n };\n\n sig.update(\n (prev) =>\n ({\n ...prev,\n data: nextData as unknown,\n status: undefined,\n isLoading: isAnyKeyLoading(nextIsLoading),\n errors: undefined,\n } as TData[K])\n );\n\n const updatedState = sig();\n notifier.notify(key, updatedState, previousState);\n return true;\n }\n\n function applyStartKeyedLoading<K extends StoreKey<TData>>(\n key: K,\n resourceKey: KeyedResourceKey\n ): boolean {\n const sig = signals.getOrCreate(key);\n const state = sig();\n if (!isKeyedResourceData(state.data)) {\n return applyStartLoading(key);\n }\n\n const previousState = state as TData[K];\n const data = state.data;\n\n const nextIsLoading = {\n ...data.isLoading,\n [resourceKey]: true,\n } as typeof data.isLoading;\n\n const nextStatus: typeof data.status = { ...data.status };\n delete nextStatus[resourceKey];\n\n const nextErrors: typeof data.errors = { ...data.errors };\n delete nextErrors[resourceKey];\n\n const nextData = {\n ...data,\n isLoading: nextIsLoading,\n status: nextStatus,\n errors: nextErrors,\n };\n\n sig.update(\n (previous) =>\n ({\n ...previous,\n data: nextData,\n status: undefined,\n isLoading: isAnyKeyLoading(nextIsLoading),\n errors: undefined,\n } as TData[K])\n );\n\n const updatedState = sig();\n notifier.notify(key, updatedState, previousState);\n return true;\n }\n\n function applyMessage(message: StoreMessage<TData>): boolean {\n switch (message.type) {\n case \"update\":\n return applyUpdate(message.key, cloneValue(message.state));\n case \"clear\":\n return applyClear(message.key);\n case \"clearAll\":\n return applyClearAll();\n case \"startLoading\":\n return applyStartLoading(message.key);\n case \"stopLoading\":\n return applyStopLoading(message.key);\n case \"updateKeyedOne\":\n return applyUpdateKeyedOne(\n message.key,\n message.resourceKey,\n cloneValue(message.entity)\n );\n case \"clearKeyedOne\":\n return applyClearKeyedOne(message.key, message.resourceKey);\n case \"startKeyedLoading\":\n return applyStartKeyedLoading(message.key, message.resourceKey);\n }\n }\n\n function applySnapshot(snapshot: StoreSnapshot<TData>): void {\n const keys = new Set<string>([\n ...Array.from(signals.getAllKeys()),\n ...Object.keys(snapshot),\n ]);\n\n keys.forEach((rawKey) => {\n const key = rawKey as StoreKey<TData>;\n const sig = signals.getOrCreate(key);\n const snapshotState =\n snapshot[key] ?? (createDefaultState() as TData[typeof key]);\n\n applyUpdate(key, createSnapshotRestorePatch(sig(), snapshotState), true);\n });\n }\n\n function captureSnapshot(): StoreSnapshot<TData> {\n const entries = Array.from(signals.getAllKeys()).map((key) => [\n key,\n cloneValue(signals.getOrCreate(key)()),\n ]);\n\n return Object.fromEntries(entries) as StoreSnapshot<TData>;\n }\n\n function applyKeyUpdate<K extends StoreKey<TData>>(\n key: K,\n snapshotState: TData[K]\n ): void {\n const sig = signals.getOrCreate(key);\n const currentState = sig();\n const patch = createSnapshotRestorePatch(currentState, snapshotState);\n applyUpdate(key, patch, true);\n }\n\n return {\n applyMessage,\n applySnapshot,\n applyKeyUpdate,\n createSnapshot: captureSnapshot,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Typed message factory functions — eliminate `as StoreMessage<TData>` casts\n// ---------------------------------------------------------------------------\n\nexport function createUpdateMessage<\n TData extends StoreDataShape<TData>,\n K extends StoreKey<TData>\n>(key: K, state: Partial<TData[K]>): StoreMessage<TData> {\n return { type: \"update\", key, state } as StoreMessage<TData>;\n}\n\nexport function createClearMessage<\n TData extends StoreDataShape<TData>,\n K extends StoreKey<TData>\n>(key: K): StoreMessage<TData> {\n return { type: \"clear\", key } as StoreMessage<TData>;\n}\n\nexport function createClearAllMessage<\n TData extends StoreDataShape<TData>\n>(): StoreMessage<TData> {\n return { type: \"clearAll\" };\n}\n\nexport function createStartLoadingMessage<\n TData extends StoreDataShape<TData>,\n K extends StoreKey<TData>\n>(key: K): StoreMessage<TData> {\n return { type: \"startLoading\", key } as StoreMessage<TData>;\n}\n\nexport function createStopLoadingMessage<\n TData extends StoreDataShape<TData>,\n K extends StoreKey<TData>\n>(key: K): StoreMessage<TData> {\n return { type: \"stopLoading\", key } as StoreMessage<TData>;\n}\n\nexport function createUpdateKeyedOneMessage<\n TData extends StoreDataShape<TData>,\n K extends StoreKey<TData>\n>(key: K, resourceKey: KeyedResourceKey, entity: unknown): StoreMessage<TData> {\n return {\n type: \"updateKeyedOne\",\n key,\n resourceKey,\n entity,\n } as unknown as StoreMessage<TData>;\n}\n\nexport function createClearKeyedOneMessage<\n TData extends StoreDataShape<TData>,\n K extends StoreKey<TData>\n>(key: K, resourceKey: KeyedResourceKey): StoreMessage<TData> {\n return {\n type: \"clearKeyedOne\",\n key,\n resourceKey,\n } as unknown as StoreMessage<TData>;\n}\n\nexport function createStartKeyedLoadingMessage<\n TData extends StoreDataShape<TData>,\n K extends StoreKey<TData>\n>(key: K, resourceKey: KeyedResourceKey): StoreMessage<TData> {\n return {\n type: \"startKeyedLoading\",\n key,\n resourceKey,\n } as unknown as StoreMessage<TData>;\n}\n","import type { StoreDataShape, StoreKey } from \"./types\";\nimport type { StoreMessage, StoreMessageStatus } from \"./store-messages\";\nimport { cloneValue } from \"./store-clone\";\n\n/**\n * Persisted broker message record stored in the active message channel.\n *\n * Message ids are allocated when the message is first published and remain stable\n * across acknowledgement, replay, and dead-letter transitions.\n */\nexport interface StoreMessageRecord<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> {\n /** Stable message id used by `replay(...)` and dead-letter recovery APIs. */\n readonly id: number;\n /** Published store message payload. */\n readonly message: StoreMessage<TData, TKey>;\n /** Latest delivery status stored by the broker channel. */\n readonly status: StoreMessageStatus;\n /** Number of delivery attempts made for this message. */\n readonly attempts: number;\n /** Timestamp when the message was first published to the channel. */\n readonly createdAt: number;\n /** Timestamp of the most recent delivery attempt. */\n readonly lastAttemptedAt: number | null;\n /** Timestamp of the most recent successful acknowledgement, if any. */\n readonly acknowledgedAt: number | null;\n /** Last recorded delivery error, or `null` when the latest attempt succeeded. */\n readonly error: string | null;\n}\n\n/** Minimal string-based storage adapter used by storage-backed message channels. */\nexport interface StoreMessageChannelStorage {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n removeItem(key: string): void;\n}\n\n/**\n * Pluggable persistence channel used by the broker to store published messages.\n *\n * The default channel is in-memory, but storage-backed or custom providers can be\n * supplied to keep messages available across refreshes or offline sessions.\n */\nexport interface StoreMessageChannel<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> {\n /** Stores a newly published message and allocates its stable message id. */\n publish(message: StoreMessage<TData, TKey>): StoreMessageRecord<TData, TKey>;\n /** Reads a single persisted message record by id. */\n getMessage(id: number): StoreMessageRecord<TData, TKey> | undefined;\n /** Reads every persisted message record from the channel. */\n getMessages(): readonly StoreMessageRecord<TData, TKey>[];\n /** Persists a new state for an existing message record. */\n saveMessage(entry: StoreMessageRecord<TData, TKey>): void;\n}\n\n/** Optional store configuration used to override the default in-memory message channel. */\nexport interface StoreMessageChannelOptions<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> {\n readonly channel?: StoreMessageChannel<TData, TKey>;\n}\n\n/** Options for {@link createCompositeStoreMessageChannel}. The first channel is the primary (reads + id allocation); replicas receive all writes. */\nexport interface CompositeStoreMessageChannelOptions<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> {\n readonly channels: readonly StoreMessageChannel<TData, TKey>[];\n}\n\n/** Options for {@link createStorageStoreMessageChannel}. Provide a custom storage adapter, key, and optional serialize/deserialize hooks. */\nexport interface StorageStoreMessageChannelOptions<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> {\n readonly storage: StoreMessageChannelStorage;\n readonly storageKey: string;\n readonly serialize?: (\n state: PersistedStoreMessageChannelState<TData, TKey>\n ) => string;\n readonly deserialize?: (\n value: string\n ) => PersistedStoreMessageChannelState<TData, TKey>;\n}\n\n/** Options for {@link createLocalStorageStoreMessageChannel} and {@link createSessionStorageStoreMessageChannel}. Storage defaults to the browser global. */\nexport interface BrowserStorageStoreMessageChannelOptions<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> extends Omit<StorageStoreMessageChannelOptions<TData, TKey>, \"storage\"> {\n readonly storage?: StoreMessageChannelStorage;\n}\n\n// ---------------------------------------------------------------------------\n// Internal types\n// ---------------------------------------------------------------------------\n\ninterface PersistedStoreMessageChannelState<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n> {\n readonly nextId: number;\n readonly messages: readonly StoreMessageRecord<TData, TKey>[];\n}\n\ntype SerializedStoreMessageChannelValue =\n | null\n | boolean\n | number\n | string\n | {\n readonly __flurryxType: \"undefined\";\n }\n | {\n readonly __flurryxType: \"date\";\n readonly value: string;\n }\n | {\n readonly __flurryxType: \"array\";\n readonly values: readonly SerializedStoreMessageChannelValue[];\n }\n | {\n readonly __flurryxType: \"set\";\n readonly values: readonly SerializedStoreMessageChannelValue[];\n }\n | {\n readonly __flurryxType: \"map\";\n readonly entries: readonly [\n SerializedStoreMessageChannelValue,\n SerializedStoreMessageChannelValue\n ][];\n }\n | {\n readonly __flurryxType: \"object\";\n readonly entries: readonly [string, SerializedStoreMessageChannelValue][];\n };\n\n// ---------------------------------------------------------------------------\n// Serialization\n// ---------------------------------------------------------------------------\n\nfunction serializeStoreMessageChannelValue(\n value: unknown\n): SerializedStoreMessageChannelValue {\n if (value === undefined) {\n return { __flurryxType: \"undefined\" };\n }\n\n if (\n value === null ||\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\"\n ) {\n return value;\n }\n\n if (value instanceof Date) {\n return {\n __flurryxType: \"date\",\n value: value.toISOString(),\n };\n }\n\n if (value instanceof Map) {\n return {\n __flurryxType: \"map\",\n entries: Array.from(value.entries(), ([key, entryValue]) => [\n serializeStoreMessageChannelValue(key),\n serializeStoreMessageChannelValue(entryValue),\n ]),\n };\n }\n\n if (value instanceof Set) {\n return {\n __flurryxType: \"set\",\n values: Array.from(value.values(), (entryValue) =>\n serializeStoreMessageChannelValue(entryValue)\n ),\n };\n }\n\n if (Array.isArray(value)) {\n return {\n __flurryxType: \"array\",\n values: value.map((entryValue) =>\n serializeStoreMessageChannelValue(entryValue)\n ),\n };\n }\n\n if (typeof value === \"object\") {\n return {\n __flurryxType: \"object\",\n entries: Object.entries(value as Record<string, unknown>).map(\n ([key, entryValue]) => [\n key,\n serializeStoreMessageChannelValue(entryValue),\n ]\n ),\n };\n }\n\n throw new Error(\"Store message channel cannot serialize this value\");\n}\n\nfunction deserializeStoreMessageChannelValue(\n value: SerializedStoreMessageChannelValue\n): unknown {\n if (\n value === null ||\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\"\n ) {\n return value;\n }\n\n switch (value.__flurryxType) {\n case \"undefined\":\n return undefined;\n case \"date\":\n return new Date(value.value);\n case \"array\":\n return value.values.map((entryValue) =>\n deserializeStoreMessageChannelValue(entryValue)\n );\n case \"set\":\n return new Set(\n value.values.map((entryValue) =>\n deserializeStoreMessageChannelValue(entryValue)\n )\n );\n case \"map\":\n return new Map(\n value.entries.map(([key, entryValue]) => [\n deserializeStoreMessageChannelValue(key),\n deserializeStoreMessageChannelValue(entryValue),\n ])\n );\n case \"object\": {\n const result: Record<string, unknown> = {};\n value.entries.forEach(([key, entryValue]) => {\n result[key] = deserializeStoreMessageChannelValue(entryValue);\n });\n return result;\n }\n }\n}\n\nfunction defaultSerializeStoreMessageChannelState<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData>\n>(state: PersistedStoreMessageChannelState<TData, TKey>): string {\n return JSON.stringify(serializeStoreMessageChannelValue(state));\n}\n\nfunction defaultDeserializeStoreMessageChannelState<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData>\n>(value: string): PersistedStoreMessageChannelState<TData, TKey> {\n return deserializeStoreMessageChannelValue(\n JSON.parse(value) as SerializedStoreMessageChannelValue\n ) as PersistedStoreMessageChannelState<TData, TKey>;\n}\n\n// ---------------------------------------------------------------------------\n// Utilities\n// ---------------------------------------------------------------------------\n\nfunction normalizeStoreMessageChannelState<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData>\n>(\n state: PersistedStoreMessageChannelState<TData, TKey>\n): PersistedStoreMessageChannelState<TData, TKey> {\n const maxId = state.messages.reduce(\n (currentMax, entry) => Math.max(currentMax, entry.id),\n 0\n );\n\n return {\n nextId: Math.max(state.nextId, maxId + 1),\n messages: state.messages.map((entry) => cloneValue(entry)),\n };\n}\n\nexport function createInitialStoreMessageRecord<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData>\n>(\n id: number,\n message: StoreMessage<TData, TKey>,\n clock: () => number = Date.now\n): StoreMessageRecord<TData, TKey> {\n return {\n id,\n message: cloneValue(message),\n status: \"pending\",\n attempts: 0,\n createdAt: clock(),\n lastAttemptedAt: null,\n acknowledgedAt: null,\n error: null,\n };\n}\n\nfunction isQuotaExceededError(error: unknown): boolean {\n return (\n error instanceof DOMException &&\n (error.code === 22 ||\n error.code === 1014 ||\n error.name === \"QuotaExceededError\" ||\n error.name === \"NS_ERROR_DOM_QUOTA_REACHED\")\n );\n}\n\nfunction resolveGlobalStorage(\n name: \"localStorage\" | \"sessionStorage\"\n): StoreMessageChannelStorage {\n const storage = globalThis[name];\n if (!storage) {\n throw new Error(`${name} is not available in this environment`);\n }\n\n return storage as StoreMessageChannelStorage;\n}\n\n// ---------------------------------------------------------------------------\n// Channel factories\n// ---------------------------------------------------------------------------\n\n/**\n * Creates an in-memory message channel. Messages are stored in a JavaScript array\n * and lost on page refresh. This is the default channel when no `channel` option is provided.\n */\nexport function createInMemoryStoreMessageChannel<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n>(): StoreMessageChannel<TData, TKey> {\n let messages: StoreMessageRecord<TData, TKey>[] = [];\n let nextId = 1;\n\n return {\n publish(message) {\n const record = createInitialStoreMessageRecord(nextId++, message);\n messages = [...messages, record];\n return cloneValue(record);\n },\n getMessage(id) {\n const record = messages.find((entry) => entry.id === id);\n return record ? cloneValue(record) : undefined;\n },\n getMessages() {\n return messages.map((entry) => cloneValue(entry));\n },\n saveMessage(entry) {\n const record = cloneValue(entry);\n const existingIndex = messages.findIndex(\n (candidate) => candidate.id === record.id\n );\n\n if (existingIndex === -1) {\n messages = [...messages, record];\n } else {\n messages = messages.map((c, i) => (i === existingIndex ? record : c));\n }\n\n nextId = Math.max(nextId, record.id + 1);\n },\n };\n}\n\n/**\n * Creates a message channel backed by a custom storage adapter.\n * Messages are serialized and persisted via the provided `storage` object.\n * When the storage quota is exceeded, the oldest messages are evicted automatically.\n *\n * @param options - Storage adapter, key, and optional serialize/deserialize hooks.\n */\nexport function createStorageStoreMessageChannel<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n>(\n options: StorageStoreMessageChannelOptions<TData, TKey>\n): StoreMessageChannel<TData, TKey> {\n const serialize =\n options.serialize ?? defaultSerializeStoreMessageChannelState<TData, TKey>;\n const deserialize =\n options.deserialize ??\n defaultDeserializeStoreMessageChannelState<TData, TKey>;\n\n function readState(): PersistedStoreMessageChannelState<TData, TKey> {\n const rawState = options.storage.getItem(options.storageKey);\n if (rawState === null) {\n return { nextId: 1, messages: [] };\n }\n try {\n return normalizeStoreMessageChannelState(deserialize(rawState));\n } catch {\n return { nextId: 1, messages: [] };\n }\n }\n\n function writeState(\n state: PersistedStoreMessageChannelState<TData, TKey>\n ): void {\n const normalized = normalizeStoreMessageChannelState(state);\n try {\n options.storage.setItem(options.storageKey, serialize(normalized));\n } catch (error: unknown) {\n if (!isQuotaExceededError(error) || normalized.messages.length === 0) {\n throw error;\n }\n // Evict oldest messages one at a time until the write succeeds\n let remaining = [...normalized.messages];\n while (remaining.length > 0) {\n remaining = remaining.slice(1);\n try {\n options.storage.setItem(\n options.storageKey,\n serialize({ nextId: normalized.nextId, messages: remaining })\n );\n return;\n } catch (retryError: unknown) {\n if (!isQuotaExceededError(retryError)) {\n throw retryError;\n }\n }\n }\n // All messages evicted — write empty state\n options.storage.setItem(\n options.storageKey,\n serialize({ nextId: normalized.nextId, messages: [] })\n );\n }\n }\n\n return {\n publish(message) {\n const state = readState();\n const record = createInitialStoreMessageRecord(state.nextId, message);\n\n writeState({\n nextId: state.nextId + 1,\n messages: [...state.messages, record],\n });\n\n return cloneValue(record);\n },\n getMessage(id) {\n const record = readState().messages.find((entry) => entry.id === id);\n return record ? cloneValue(record) : undefined;\n },\n getMessages() {\n return readState().messages.map((entry) => cloneValue(entry));\n },\n saveMessage(entry) {\n const state = readState();\n const record = cloneValue(entry);\n const existingIndex = state.messages.findIndex(\n (candidate) => candidate.id === record.id\n );\n\n if (existingIndex === -1) {\n writeState({\n nextId: Math.max(state.nextId, record.id + 1),\n messages: [...state.messages, record],\n });\n return;\n }\n\n const nextMessages = state.messages.map((c, i) =>\n i === existingIndex ? record : c\n );\n\n writeState({\n nextId: Math.max(state.nextId, record.id + 1),\n messages: nextMessages,\n });\n },\n };\n}\n\n/**\n * Creates a message channel backed by `localStorage`.\n * Messages survive page refreshes and browser restarts (same-origin only).\n *\n * @param options - Storage key and optional serialize/deserialize hooks.\n */\nexport function createLocalStorageStoreMessageChannel<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n>(\n options: BrowserStorageStoreMessageChannelOptions<TData, TKey>\n): StoreMessageChannel<TData, TKey> {\n return createStorageStoreMessageChannel({\n ...options,\n storage: options.storage ?? resolveGlobalStorage(\"localStorage\"),\n });\n}\n\n/**\n * Creates a message channel backed by `sessionStorage`.\n * Messages survive page refreshes but are lost when the browser tab closes.\n *\n * @param options - Storage key and optional serialize/deserialize hooks.\n */\nexport function createSessionStorageStoreMessageChannel<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n>(\n options: BrowserStorageStoreMessageChannelOptions<TData, TKey>\n): StoreMessageChannel<TData, TKey> {\n return createStorageStoreMessageChannel({\n ...options,\n storage: options.storage ?? resolveGlobalStorage(\"sessionStorage\"),\n });\n}\n\n/**\n * Creates a composite message channel that fans out writes to multiple channels.\n * The first channel is the primary (handles reads and id allocation); all channels receive writes.\n *\n * @param options - Array of channels. Must contain at least one.\n */\nexport function createCompositeStoreMessageChannel<\n TData extends StoreDataShape<TData>,\n TKey extends StoreKey<TData> = StoreKey<TData>\n>(\n options: CompositeStoreMessageChannelOptions<TData, TKey>\n): StoreMessageChannel<TData, TKey> {\n if (options.channels.length === 0) {\n throw new Error(\n \"createCompositeStoreMessageChannel: 'channels' option must contain at least one channel\"\n );\n }\n\n const primaryChannel = options.channels[0]!;\n const replicaChannels = options.channels.slice(1);\n\n return {\n publish(message) {\n const record = primaryChannel.publish(message);\n replicaChannels.forEach((channel) => {\n channel.saveMessage(record);\n });\n return cloneValue(record);\n },\n getMessage(id) {\n const record = primaryChannel.getMessage(id);\n return record ? cloneValue(record) : undefined;\n },\n getMessages() {\n return primaryChannel.getMessages().map((record) => cloneValue(record));\n },\n saveMessage(entry) {\n primaryChannel.saveMessage(entry);\n replicaChannels.forEach((channel) => {\n channel.saveMessage(entry);\n });\n },\n };\n}\n","interface Clearable {\n clearAll(): void;\n}\n\nconst trackedStores = new Set<Clearable>();\n\nexport function trackStore(store: Clearable): void {\n trackedStores.add(store);\n}\n\n/**\n * Clears every store instance tracked by flurryx.\n *\n * Calls `clearAll()` on each registered store, resetting all slots to their\n * initial idle state. Useful for logout, tenant switching, or test cleanup.\n *\n * @example\n * ```ts\n * import { clearAllStores } from '@flurryx/store';\n *\n * logout() {\n * clearAllStores();\n * }\n * ```\n */\nexport function clearAllStores(): void {\n for (const store of [...trackedStores]) {\n store.clearAll();\n }\n}\n\nexport function resetTrackedStoresForTests(): void {\n trackedStores.clear();\n}\n","import { signal, type Signal, WritableSignal } from \"@angular/core\";\nimport { type ResourceState, type KeyedResourceKey } from \"@flurryx/core\";\nimport type { IStore, StoreDataShape, StoreKey, StoreOptions } from \"./types\";\nimport { cloneValue } from \"./store-clone\";\nimport {\n createStoreHistory,\n type StoreHistoryDriver,\n type StoreHistoryEntry,\n} from \"./store-replay\";\nimport type { StoreMessageRecord } from \"./store-channels\";\nimport { trackStore } from \"./store-registry\";\nimport {\n createDefaultState,\n createStoreMessageConsumer,\n createUpdateMessage,\n createClearMessage,\n createClearAllMessage,\n createStartLoadingMessage,\n createStopLoadingMessage,\n createUpdateKeyedOneMessage,\n createClearKeyedOneMessage,\n createStartKeyedLoadingMessage,\n} from \"./store-message-consumer\";\n\ntype UpdateCallback = (\n nextState: ResourceState<unknown>,\n previousState: ResourceState<unknown>\n) => void;\n\n/**\n * Lazy store that creates signals on first access.\n * Used by the `Store.for<Config>().build()` API where keys are\n * known only at the type level (no runtime enum).\n */\nexport class LazyStore<TData extends StoreDataShape<TData>>\n implements IStore<TData>\n{\n private readonly signals = new Map<\n string,\n WritableSignal<ResourceState<unknown>>\n >();\n private readonly hooks = new Map<string, UpdateCallback[]>();\n private readonly historyDriver: StoreHistoryDriver<TData>;\n\n /** @inheritDoc */\n readonly restoreStoreAt = (index: number): void =>\n this.historyDriver.restoreStoreAt(index);\n\n /** @inheritDoc */\n readonly restoreResource = <K extends StoreKey<TData>>(key: K, index?: number): void =>\n this.historyDriver.restoreResource(key, index);\n\n /** @inheritDoc */\n readonly undo = (): boolean => this.historyDriver.undo();\n\n /** @inheritDoc */\n readonly redo = (): boolean => this.historyDriver.redo();\n\n /** @inheritDoc */\n getMessages(): readonly StoreMessageRecord<TData>[];\n\n /** @inheritDoc */\n getMessages<K extends StoreKey<TData>>(\n key: K\n ): readonly StoreMessageRecord<TData, K>[];\n\n getMessages<K extends StoreKey<TData>>(key?: K) {\n if (key === undefined) {\n return this.historyDriver.getMessages();\n }\n\n return this.historyDriver.getMessages(key);\n }\n\n readonly getDeadLetters = () => this.historyDriver.getDeadLetters();\n\n /** @inheritDoc */\n readonly replayDeadLetter = (id: number): boolean =>\n this.historyDriver.replayDeadLetter(id);\n\n /** @inheritDoc */\n readonly replayDeadLetters = (): number =>\n this.historyDriver.replayDeadLetters();\n\n /** @inheritDoc */\n readonly getCurrentIndex = () => this.historyDriver.getCurrentIndex();\n\n /** @inheritDoc */\n readonly history: Signal<readonly StoreHistoryEntry<TData>[]>;\n\n /** @inheritDoc */\n readonly messages: Signal<readonly StoreMessageRecord<TData>[]>;\n\n /** @inheritDoc */\n readonly currentIndex: Signal<number>;\n\n /** @inheritDoc */\n readonly keys: Signal<readonly StoreKey<TData>[]>;\n\n private readonly keysSignal = signal<readonly StoreKey<TData>[]>([]);\n\n /** @inheritDoc */\n replay(id: number): number;\n\n /** @inheritDoc */\n replay(ids: readonly number[]): number;\n\n replay(idOrIds: number | readonly number[]): number {\n if (Array.isArray(idOrIds)) {\n return this.historyDriver.replay(idOrIds as readonly number[]);\n }\n\n return this.historyDriver.replay(idOrIds as number);\n }\n\n /** @inheritDoc */\n getHistory(): readonly StoreHistoryEntry<TData>[];\n\n /** @inheritDoc */\n getHistory<K extends StoreKey<TData>>(\n key: K\n ): readonly StoreHistoryEntry<TData, K>[];\n\n getHistory<K extends StoreKey<TData>>(key?: K) {\n if (key === undefined) {\n return this.historyDriver.getHistory();\n }\n\n return this.historyDriver.getHistory(key);\n }\n\n constructor(options?: StoreOptions<TData>) {\n const consumer = createStoreMessageConsumer<TData>(\n {\n getOrCreate: <K extends StoreKey<TData>>(key: K) =>\n this.getOrCreate(key),\n getAllKeys: () => this.signals.keys() as Iterable<StoreKey<TData>>,\n },\n {\n notify: <K extends StoreKey<TData>>(\n key: K,\n next: TData[K],\n prev: TData[K]\n ) => this.notifyHooks(key, next, prev),\n }\n );\n\n this.historyDriver = createStoreHistory<TData>({\n captureSnapshot: () => consumer.createSnapshot(),\n applySnapshot: (snapshot) => consumer.applySnapshot(snapshot),\n applyKeyUpdate: (key, snapshotState) => consumer.applyKeyUpdate(key, snapshotState),\n getAllKeys: () => this.signals.keys() as Iterable<StoreKey<TData>>,\n applyMessage: (message) => consumer.applyMessage(message),\n channel: options?.channel,\n });\n\n this.history = this.historyDriver.historySignal;\n this.messages = this.historyDriver.messagesSignal;\n this.currentIndex = this.historyDriver.currentIndexSignal;\n this.keys = this.keysSignal.asReadonly();\n\n trackStore(this);\n }\n\n private getOrCreate<K extends StoreKey<TData>>(\n key: K\n ): WritableSignal<TData[K]> {\n let sig = this.signals.get(key);\n if (!sig) {\n sig = signal<ResourceState<unknown>>(createDefaultState());\n this.signals.set(key, sig);\n this.keysSignal.update((prev) => [...prev, key]);\n }\n return sig as WritableSignal<TData[K]>;\n }\n\n /** @inheritDoc */\n get<K extends StoreKey<TData>>(key: K): Signal<TData[K]> {\n return this.getOrCreate(key);\n }\n\n /** @inheritDoc */\n update<K extends StoreKey<TData>>(key: K, newState: Partial<TData[K]>): void {\n this.historyDriver.publish(\n createUpdateMessage<TData, K>(key, cloneValue(newState))\n );\n }\n\n /** @inheritDoc */\n clear<K extends StoreKey<TData>>(key: K): void {\n this.historyDriver.publish(createClearMessage<TData, K>(key));\n }\n\n /** @inheritDoc */\n clearAll(): void {\n this.historyDriver.publish(createClearAllMessage<TData>());\n }\n\n /** @inheritDoc */\n startLoading<K extends StoreKey<TData>>(key: K): void {\n this.historyDriver.publish(createStartLoadingMessage<TData, K>(key));\n }\n\n /** @inheritDoc */\n stopLoading<K extends StoreKey<TData>>(key: K): void {\n this.historyDriver.publish(createStopLoadingMessage<TData, K>(key));\n }\n\n /** @inheritDoc */\n updateKeyedOne<K extends StoreKey<TData>>(\n key: K,\n resourceKey: KeyedResourceKey,\n entity: unknown\n ): void {\n this.historyDriver.publish(\n createUpdateKeyedOneMessage<TData, K>(\n key,\n resourceKey,\n cloneValue(entity)\n )\n );\n }\n\n /** @inheritDoc */\n clearKeyedOne<K extends StoreKey<TData>>(\n key: K,\n resourceKey: KeyedResourceKey\n ): void {\n this.historyDriver.publish(\n createClearKeyedOneMessage<TData, K>(key, resourceKey)\n );\n }\n\n /** @inheritDoc */\n startKeyedLoading<K extends StoreKey<TData>>(\n key: K,\n resourceKey: KeyedResourceKey\n ): void {\n this.historyDriver.publish(\n createStartKeyedLoadingMessage<TData, K>(key, resourceKey)\n );\n }\n\n /** @inheritDoc */\n onUpdate<K extends StoreKey<TData>>(\n key: K,\n callback: (state: TData[K], previousState: TData[K]) => void\n ): () => void {\n if (!this.hooks.has(key)) {\n this.hooks.set(key, []);\n }\n const typedCallback = callback as UpdateCallback;\n this.hooks.get(key)!.push(typedCallback);\n\n return () => {\n const keyHooks = this.hooks.get(key);\n if (!keyHooks) {\n return;\n }\n const index = keyHooks.indexOf(typedCallback);\n if (index > -1) {\n keyHooks.splice(index, 1);\n }\n };\n }\n\n private notifyHooks<K extends StoreKey<TData>>(\n key: K,\n nextState: TData[K],\n previousState: TData[K]\n ): void {\n const keyHooks = this.hooks.get(key);\n if (!keyHooks) {\n return;\n }\n\n const errors: unknown[] = [];\n\n keyHooks.forEach((hook) => {\n try {\n hook(\n nextState as ResourceState<unknown>,\n previousState as ResourceState<unknown>\n );\n } catch (error: unknown) {\n errors.push(error);\n }\n });\n\n if (errors.length > 0) {\n queueMicrotask(() => {\n if (errors.length === 1) {\n throw errors[0];\n }\n throw new AggregateError(\n errors,\n `${errors.length} onUpdate hooks threw for key \"${String(key)}\"`\n );\n });\n }\n }\n}\n","import { InjectionToken, inject } from \"@angular/core\";\nimport { BaseStore } from \"./base-store\";\nimport { DynamicStore } from \"./dynamic-store\";\nimport { LazyStore } from \"./lazy-store\";\nimport { mirrorKey } from \"./mirror-key\";\nimport { collectKeyed } from \"./collect-keyed\";\nimport { resource } from \"./resource\";\nimport type { ResourceState, KeyedResourceKey } from \"@flurryx/core\";\nimport type {\n StoreConfig,\n ResourceDef,\n InferEnum,\n InferData,\n ConfigToData,\n IStore,\n StoreOptions,\n StoreDataShape,\n StoreKey,\n} from \"./types\";\n\ntype AnyStoreData = Record<string, ResourceState<unknown>>;\n\n// ---------------------------------------------------------------------------\n// Mirror definition — accumulated by builders, wired up in build() factory\n// ---------------------------------------------------------------------------\n\ninterface MirrorDef {\n readonly sourceToken: InjectionToken<unknown>;\n readonly sourceKey: string;\n readonly targetKey: string;\n}\n\nfunction wireMirrors<TData extends StoreDataShape<TData>>(\n store: IStore<TData>,\n mirrors: readonly MirrorDef[]\n): void {\n for (const def of mirrors) {\n const sourceStore = inject(def.sourceToken) as IStore<AnyStoreData>;\n mirrorKey(\n sourceStore,\n def.sourceKey as StoreKey<AnyStoreData>,\n store,\n def.targetKey as StoreKey<TData>\n );\n }\n}\n\n// ---------------------------------------------------------------------------\n// MirrorKeyed definition — accumulated by builders, wired up in build()\n// ---------------------------------------------------------------------------\n\ninterface MirrorKeyedDef {\n readonly sourceToken: InjectionToken<unknown>;\n readonly sourceKey: string;\n readonly targetKey: string;\n readonly extractId: (data: unknown) => KeyedResourceKey | undefined;\n}\n\nfunction wireMirrorKeyed<TData extends StoreDataShape<TData>>(\n store: IStore<TData>,\n defs: readonly MirrorKeyedDef[]\n): void {\n for (const def of defs) {\n const sourceStore = inject(def.sourceToken) as IStore<AnyStoreData>;\n collectKeyed(\n sourceStore,\n def.sourceKey as StoreKey<AnyStoreData>,\n store,\n def.targetKey as StoreKey<TData>,\n {\n extractId: def.extractId,\n }\n );\n }\n}\n\ninterface SelfMirrorDef {\n readonly sourceKey: string;\n readonly targetKey: string;\n}\n\nconst MIRROR_SELF_SAME_KEY_ERROR =\n \"mirrorSelf source and target keys must be different\";\n\nfunction wireSelfMirrors<TData extends StoreDataShape<TData>>(\n store: IStore<TData>,\n defs: readonly SelfMirrorDef[]\n): void {\n for (const def of defs) {\n if (def.sourceKey === def.targetKey) {\n throw new Error(MIRROR_SELF_SAME_KEY_ERROR);\n }\n\n mirrorKey(\n store,\n def.sourceKey as StoreKey<TData>,\n store,\n def.targetKey as StoreKey<TData>\n );\n }\n}\n\n// ---------------------------------------------------------------------------\n// Unconstrained builder (existing API)\n// ---------------------------------------------------------------------------\n\n/**\n * Intermediate builder step after .resource('key') — awaits .as<T>().\n */\ninterface AsStep<TAccum extends StoreConfig, TKey extends string> {\n /**\n * Assign the resource value type for the previously declared key.\n *\n * Returns the main fluent builder so you can define more resources, configure\n * mirrors, or call `.build()`.\n *\n * @example\n * ```ts\n * const CustomersStore = Store\n * .resource('CUSTOMERS').as<Customer[]>()\n * .build();\n * ```\n */\n as<T>(): StoreBuilder<TAccum & Record<TKey, ResourceDef<T>>>;\n}\n\n/**\n * Fluent builder for creating stores.\n * Accumulates resource definitions then produces an `InjectionToken` on `.build()`.\n */\ninterface StoreBuilder<TAccum extends StoreConfig> {\n /** Define a new resource slot. Chain `.as<T>()` to set its type. */\n resource<TKey extends string>(key: TKey): AsStep<TAccum, TKey>;\n\n /**\n * Mirror a slot from another store. When the source updates, the target is kept in sync.\n *\n * @param source - The source store's `InjectionToken`.\n * @param sourceKey - The key to watch on the source store.\n * @param targetKey - The key on this store to write to. Defaults to `sourceKey`.\n */\n mirror<TSourceData extends StoreDataShape<TSourceData>>(\n source: InjectionToken<IStore<TSourceData>>,\n sourceKey: StoreKey<TSourceData>,\n targetKey?: StoreKey<TAccum>\n ): StoreBuilder<TAccum>;\n\n /**\n * Mirror one slot to another **within the same store**.\n * Source and target keys must be different.\n *\n * @param sourceKey - The slot to read from.\n * @param targetKey - The slot to write to.\n */\n mirrorSelf(\n sourceKey: StoreKey<TAccum>,\n targetKey: StoreKey<TAccum>\n ): StoreBuilder<TAccum>;\n\n /**\n * Accumulate single-entity fetches from a source store into a `KeyedResourceData` slot.\n *\n * @param source - The source store's `InjectionToken`.\n * @param sourceKey - The single-entity key on the source store.\n * @param options - Must include `extractId` to derive the entity's key from its data.\n * @param targetKey - The keyed slot on this store. Defaults to `sourceKey`.\n */\n mirrorKeyed<TSourceData extends StoreDataShape<TSourceData>, TEntity>(\n source: InjectionToken<IStore<TSourceData>>,\n sourceKey: StoreKey<TSourceData>,\n options: {\n extractId: (data: TEntity | undefined) => KeyedResourceKey | undefined;\n },\n targetKey?: StoreKey<TAccum>\n ): StoreBuilder<TAccum>;\n\n /**\n * Finalize the builder and create an `InjectionToken` (`providedIn: 'root'`).\n * All mirrors are wired up automatically when Angular creates the store.\n */\n build(\n options?: StoreOptions<InferData<TAccum>>\n ): InjectionToken<BaseStore<InferEnum<TAccum>, InferData<TAccum>>>;\n}\n\nfunction createBuilder<TAccum extends StoreConfig>(\n accum: TAccum,\n mirrors: readonly MirrorDef[] = [],\n mirrorKeyedDefs: readonly MirrorKeyedDef[] = [],\n selfMirrors: readonly SelfMirrorDef[] = []\n): StoreBuilder<TAccum> {\n return {\n resource<TKey extends string>(key: TKey): AsStep<TAccum, TKey> {\n return {\n as<T>(): StoreBuilder<TAccum & Record<TKey, ResourceDef<T>>> {\n const nextAccum = {\n ...accum,\n [key]: resource<T>(),\n } as TAccum & Record<TKey, ResourceDef<T>>;\n return createBuilder(\n nextAccum,\n mirrors,\n mirrorKeyedDefs,\n selfMirrors\n );\n },\n };\n },\n mirror(source, sourceKey, targetKey?) {\n const def: MirrorDef = {\n sourceToken: source as InjectionToken<unknown>,\n sourceKey,\n targetKey: targetKey ?? sourceKey,\n };\n return createBuilder(\n accum,\n [...mirrors, def],\n mirrorKeyedDefs,\n selfMirrors\n );\n },\n mirrorSelf(sourceKey, targetKey) {\n const def: SelfMirrorDef = {\n sourceKey,\n targetKey,\n };\n return createBuilder(accum, mirrors, mirrorKeyedDefs, [\n ...selfMirrors,\n def,\n ]);\n },\n mirrorKeyed(source, sourceKey, options, targetKey?) {\n const def: MirrorKeyedDef = {\n sourceToken: source as InjectionToken<unknown>,\n sourceKey,\n targetKey: targetKey ?? sourceKey,\n extractId: options.extractId as (\n data: unknown\n ) => KeyedResourceKey | undefined,\n };\n return createBuilder(\n accum,\n mirrors,\n [...mirrorKeyedDefs, def],\n selfMirrors\n );\n },\n build(options?: StoreOptions<InferData<TAccum>>) {\n return new InjectionToken<\n BaseStore<InferEnum<TAccum>, InferData<TAccum>>\n >(\"FlurryxStore\", {\n providedIn: \"root\",\n factory: () => {\n const store = new DynamicStore(accum, options) as IStore<InferData<TAccum>>;\n wireMirrors(store, mirrors);\n wireMirrorKeyed(store, mirrorKeyedDefs);\n wireSelfMirrors(store, selfMirrors);\n return store as BaseStore<InferEnum<TAccum>, InferData<TAccum>>;\n },\n });\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Constrained builder (.for(enum) API)\n// ---------------------------------------------------------------------------\n\n/** Keys from the enum that have NOT yet been defined. */\ntype Remaining<\n TEnum extends Record<string, string>,\n TAccum extends StoreConfig\n> = Exclude<keyof TEnum & string, keyof TAccum>;\n\n/** Intermediate .as<T>() step for the constrained builder. */\ninterface ConstrainedAsStep<\n TEnum extends Record<string, string>,\n TAccum extends StoreConfig,\n TKey extends string\n> {\n /**\n * Assign the resource value type for the selected enum key.\n *\n * Returns the constrained builder for the remaining enum keys.\n */\n as<T>(): ConstrainedBuilder<TEnum, TAccum & Record<TKey, ResourceDef<T>>>;\n}\n\n/**\n * Constrained builder — only allows keys from the enum that haven't been\n * defined yet. `.build()` is only available when all keys are accounted for.\n */\ntype ConstrainedBuilder<\n TEnum extends Record<string, string>,\n TAccum extends StoreConfig\n> = [Remaining<TEnum, TAccum>] extends [never]\n ? {\n /**\n * Mirror a slot from another store. When the source updates, the target is kept in sync.\n *\n * @param source - The source store's `InjectionToken`.\n * @param sourceKey - The key to watch on the source store.\n * @param targetKey - The key on this store to write to. Defaults to `sourceKey`.\n */\n mirror<TSourceData extends StoreDataShape<TSourceData>>(\n source: InjectionToken<IStore<TSourceData>>,\n sourceKey: StoreKey<TSourceData>,\n targetKey?: StoreKey<TAccum>\n ): ConstrainedBuilder<TEnum, TAccum>;\n /**\n * Mirror one slot to another within the same store.\n * Source and target keys must be different.\n *\n * @param sourceKey - The slot to read from.\n * @param targetKey - The slot to write to.\n */\n mirrorSelf(\n sourceKey: StoreKey<TAccum>,\n targetKey: StoreKey<TAccum>\n ): ConstrainedBuilder<TEnum, TAccum>;\n /**\n * Accumulate single-entity fetches from a source store into a keyed slot.\n *\n * @param source - The source store's `InjectionToken`.\n * @param sourceKey - The single-entity key on the source store.\n * @param options - Must include `extractId` to derive the entity's key from its data.\n * @param targetKey - The keyed slot on this store. Defaults to `sourceKey`.\n */\n mirrorKeyed<TSourceData extends StoreDataShape<TSourceData>, TEntity>(\n source: InjectionToken<IStore<TSourceData>>,\n sourceKey: StoreKey<TSourceData>,\n options: {\n extractId: (\n data: TEntity | undefined\n ) => KeyedResourceKey | undefined;\n },\n targetKey?: StoreKey<TAccum>\n ): ConstrainedBuilder<TEnum, TAccum>;\n /**\n * Finalize the builder and create an `InjectionToken` (`providedIn: 'root'`).\n * Available only after all enum keys have been defined.\n */\n build(\n options?: StoreOptions<InferData<TAccum>>\n ): InjectionToken<BaseStore<InferEnum<TAccum>, InferData<TAccum>>>;\n }\n : {\n /** Define the next resource slot from the remaining enum keys. */\n resource<TKey extends Remaining<TEnum, TAccum>>(\n key: TKey\n ): ConstrainedAsStep<TEnum, TAccum, TKey>;\n };\n\nfunction createConstrainedBuilder<\n TEnum extends Record<string, string>,\n TAccum extends StoreConfig\n>(\n _enumObj: TEnum,\n accum: TAccum,\n mirrors: readonly MirrorDef[] = [],\n mirrorKeyedDefs: readonly MirrorKeyedDef[] = [],\n selfMirrors: readonly SelfMirrorDef[] = []\n): ConstrainedBuilder<TEnum, TAccum> {\n return {\n resource<TKey extends string>(\n key: TKey\n ): ConstrainedAsStep<TEnum, TAccum, TKey> {\n return {\n as<T>(): ConstrainedBuilder<\n TEnum,\n TAccum & Record<TKey, ResourceDef<T>>\n > {\n const nextAccum = {\n ...accum,\n [key]: resource<T>(),\n } as TAccum & Record<TKey, ResourceDef<T>>;\n return createConstrainedBuilder(\n _enumObj,\n nextAccum,\n mirrors,\n mirrorKeyedDefs,\n selfMirrors\n );\n },\n };\n },\n mirror(\n source: InjectionToken<IStore<AnyStoreData>>,\n sourceKey: string,\n targetKey?: string\n ) {\n const def: MirrorDef = {\n sourceToken: source,\n sourceKey,\n targetKey: targetKey ?? sourceKey,\n };\n return createConstrainedBuilder(\n _enumObj,\n accum,\n [...mirrors, def],\n mirrorKeyedDefs,\n selfMirrors\n );\n },\n mirrorSelf(sourceKey: string, targetKey: string) {\n const def: SelfMirrorDef = {\n sourceKey,\n targetKey,\n };\n return createConstrainedBuilder(\n _enumObj,\n accum,\n mirrors,\n mirrorKeyedDefs,\n [...selfMirrors, def]\n );\n },\n mirrorKeyed(\n source: InjectionToken<IStore<AnyStoreData>>,\n sourceKey: string,\n options: {\n extractId: (data: unknown) => KeyedResourceKey | undefined;\n },\n targetKey?: string\n ) {\n const def: MirrorKeyedDef = {\n sourceToken: source,\n sourceKey,\n targetKey: targetKey ?? sourceKey,\n extractId: options.extractId,\n };\n return createConstrainedBuilder(\n _enumObj,\n accum,\n mirrors,\n [...mirrorKeyedDefs, def],\n selfMirrors\n );\n },\n build(options?: StoreOptions<InferData<TAccum>>) {\n return new InjectionToken<\n BaseStore<InferEnum<TAccum>, InferData<TAccum>>\n >(\"FlurryxStore\", {\n providedIn: \"root\",\n factory: () => {\n const store = new DynamicStore(accum, options) as IStore<InferData<TAccum>>;\n wireMirrors(store, mirrors);\n wireMirrorKeyed(store, mirrorKeyedDefs);\n wireSelfMirrors(store, selfMirrors);\n return store as BaseStore<InferEnum<TAccum>, InferData<TAccum>>;\n },\n });\n },\n } as ConstrainedBuilder<TEnum, TAccum>;\n}\n\n// ---------------------------------------------------------------------------\n// Interface-based builder (Store.for<Config>() API)\n// ---------------------------------------------------------------------------\n\n/**\n * Interface-based builder for `Store.for<Config>()`.\n *\n * Uses a config interface for compile-time shape only, so no runtime enum is required.\n */\ninterface InterfaceBuilder<TConfig extends object> {\n /**\n * Mirror a slot from another store. When the source updates, the target is kept in sync.\n *\n * @param source - The source store's `InjectionToken`.\n * @param sourceKey - The key to watch on the source store.\n * @param targetKey - The key on this store to write to. Defaults to `sourceKey`.\n */\n mirror<TSourceData extends StoreDataShape<TSourceData>>(\n source: InjectionToken<IStore<TSourceData>>,\n sourceKey: StoreKey<TSourceData>,\n targetKey?: StoreKey<ConfigToData<TConfig>>\n ): InterfaceBuilder<TConfig>;\n /**\n * Mirror one slot to another within the same store.\n * Source and target keys must be different.\n *\n * @param sourceKey - The slot to read from.\n * @param targetKey - The slot to write to.\n */\n mirrorSelf(\n sourceKey: StoreKey<ConfigToData<TConfig>>,\n targetKey: StoreKey<ConfigToData<TConfig>>\n ): InterfaceBuilder<TConfig>;\n /**\n * Accumulate single-entity fetches from a source store into a keyed slot.\n *\n * @param source - The source store's `InjectionToken`.\n * @param sourceKey - The single-entity key on the source store.\n * @param options - Must include `extractId` to derive the entity's key from its data.\n * @param targetKey - The keyed slot on this store. Defaults to `sourceKey`.\n */\n mirrorKeyed<TSourceData extends StoreDataShape<TSourceData>, TEntity>(\n source: InjectionToken<IStore<TSourceData>>,\n sourceKey: StoreKey<TSourceData>,\n options: {\n extractId: (data: TEntity | undefined) => KeyedResourceKey | undefined;\n },\n targetKey?: StoreKey<ConfigToData<TConfig>>\n ): InterfaceBuilder<TConfig>;\n /**\n * Finalize the interface-based builder and create a store `InjectionToken`.\n *\n * The resulting token is registered with `providedIn: 'root'` and resolves to\n * a `LazyStore` implementing `IStore<ConfigToData<TConfig>>`.\n *\n * @returns An Angular `InjectionToken` for the configured store.\n *\n * @example\n * ```ts\n * interface ChatStoreConfig {\n * SESSIONS: ChatSession[];\n * MESSAGES: ChatMessage[];\n * }\n *\n * export const ChatStore = Store.for<ChatStoreConfig>().build();\n * ```\n */\n build(\n options?: StoreOptions<ConfigToData<TConfig>>\n ): InjectionToken<IStore<ConfigToData<TConfig>>>;\n}\n\nfunction createInterfaceBuilder<TConfig extends object>(\n mirrors: readonly MirrorDef[] = [],\n mirrorKeyedDefs: readonly MirrorKeyedDef[] = [],\n selfMirrors: readonly SelfMirrorDef[] = []\n): InterfaceBuilder<TConfig> {\n return {\n mirror(source, sourceKey, targetKey?) {\n const def: MirrorDef = {\n sourceToken: source as InjectionToken<unknown>,\n sourceKey,\n targetKey: targetKey ?? sourceKey,\n };\n return createInterfaceBuilder<TConfig>(\n [...mirrors, def],\n mirrorKeyedDefs,\n selfMirrors\n );\n },\n mirrorSelf(sourceKey, targetKey) {\n const def: SelfMirrorDef = {\n sourceKey,\n targetKey,\n };\n return createInterfaceBuilder<TConfig>(mirrors, mirrorKeyedDefs, [\n ...selfMirrors,\n def,\n ]);\n },\n mirrorKeyed(source, sourceKey, options, targetKey?) {\n const def: MirrorKeyedDef = {\n sourceToken: source as InjectionToken<unknown>,\n sourceKey,\n targetKey: targetKey ?? sourceKey,\n extractId: options.extractId as (\n data: unknown\n ) => KeyedResourceKey | undefined,\n };\n return createInterfaceBuilder<TConfig>(\n mirrors,\n [...mirrorKeyedDefs, def],\n selfMirrors\n );\n },\n build(options?: StoreOptions<ConfigToData<TConfig>>) {\n return new InjectionToken(\"FlurryxStore\", {\n providedIn: \"root\",\n factory: () => {\n const store = new LazyStore(options) as IStore<AnyStoreData>;\n wireMirrors(store, mirrors);\n wireMirrorKeyed(store, mirrorKeyedDefs);\n wireSelfMirrors(store, selfMirrors);\n return store as unknown as IStore<ConfigToData<TConfig>>;\n },\n });\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Public entry point\n// ---------------------------------------------------------------------------\n\ninterface StoreEntry {\n /**\n * Define a named resource slot.\n * Chain .as<T>() to assign its type, then continue with more .resource() calls\n * or call .build() when done.\n */\n resource<TKey extends string>(\n key: TKey\n ): {\n /**\n * Set the resource value type and continue the fluent builder chain.\n *\n * @example\n * ```ts\n * const UsersStore = Store\n * .resource('USERS').as<User[]>()\n * .build();\n * ```\n */\n as<T>(): StoreBuilder<Record<TKey, ResourceDef<T>>>;\n };\n\n /**\n * Interface-based builder: pass a config interface as a generic.\n * No runtime argument needed — keys and types are inferred from the interface.\n *\n * @example\n * interface ChatStoreConfig {\n * SESSIONS: ChatSession[];\n * MESSAGES: ChatMessage[];\n * }\n * const ChatStore = Store.for<ChatStoreConfig>().build();\n */\n for<TConfig extends object>(): InterfaceBuilder<TConfig>;\n\n /**\n * Bind the builder to an enum object for compile-time key validation.\n *\n * @example\n * const Enum = { A: 'A', B: 'B' } as const;\n * const MyStore = Store.for(Enum)\n * .resource('A').as<string>()\n * .resource('B').as<number>()\n * .build();\n */\n for<TEnum extends Record<string, string>>(\n enumObj: TEnum\n ): ConstrainedBuilder<TEnum, Record<never, never>>;\n}\n\n/**\n * Fluent store builder entry point.\n *\n * @example\n * // Unconstrained\n * export const CustomersStore = Store\n * .resource('customers').as<Customer[]>()\n * .resource('customerDetails').as<Customer>()\n * .build();\n *\n * @example\n * // Constrained with enum\n * const Enum = { SESSIONS: 'SESSIONS', MESSAGES: 'MESSAGES' } as const;\n * export const ChatStore = Store.for(Enum)\n * .resource('SESSIONS').as<Session[]>()\n * .resource('MESSAGES').as<Message[]>()\n * .build();\n */\nexport const Store: StoreEntry = {\n ...createBuilder({} as StoreConfig),\n for: createStoreFor,\n};\n\nfunction createStoreFor<TConfig extends object>(): InterfaceBuilder<TConfig>;\nfunction createStoreFor<TEnum extends Record<string, string>>(\n enumObj: TEnum\n): ConstrainedBuilder<TEnum, Record<never, never>>;\nfunction createStoreFor(enumObj?: Record<string, string>) {\n if (arguments.length === 0) {\n return createInterfaceBuilder();\n }\n\n return createConstrainedBuilder(enumObj!, {} as Record<never, never>);\n}\n","import { BaseStore } from './base-store';\nimport type { StoreConfig, InferEnum, InferData, StoreOptions } from './types';\n\n/**\n * Internal concrete subclass of BaseStore.\n * Auto-generates an identity enum from config keys.\n * NOT publicly exported — consumers interact via BaseStore interface.\n */\nexport class DynamicStore<\n TConfig extends StoreConfig,\n> extends BaseStore<InferEnum<TConfig>, InferData<TConfig>> {\n constructor(config: TConfig, options?: StoreOptions<InferData<TConfig>>) {\n const identityEnum = Object.keys(config).reduce(\n (acc, key) => ({ ...acc, [key]: key }),\n {} as InferEnum<TConfig>\n );\n super(identityEnum, options);\n }\n}\n","import type { IStore, StoreDataShape, StoreKey } from \"./types\";\n\n/**\n * Options for {@link mirrorKey}.\n */\nexport interface MirrorOptions {\n /**\n * Angular `DestroyRef` (or any object with an `onDestroy` method) for\n * automatic cleanup. When provided, the mirror stops when the ref is destroyed.\n */\n destroyRef?: { onDestroy: (fn: () => void) => void };\n}\n\n/**\n * Mirrors a resource key from a source store to a target store.\n * When the source key updates, the target key is updated with the same state.\n *\n * @param source - The store to mirror from\n * @param sourceKey - The key to watch on the source store\n * @param target - The store to mirror to\n * @param targetKeyOrOptions - Either the target key name or options (defaults source key)\n * @param options - Mirror options when a target key is provided\n * @returns Cleanup function to stop mirroring\n */\nexport function mirrorKey<\n TSource extends StoreDataShape<TSource>,\n TTarget extends StoreDataShape<TTarget>\n>(\n source: IStore<TSource>,\n sourceKey: StoreKey<TSource>,\n target: IStore<TTarget>,\n targetKeyOrOptions?: StoreKey<TTarget> | MirrorOptions,\n options?: MirrorOptions\n): () => void {\n const resolvedTargetKey = (\n typeof targetKeyOrOptions === \"string\" ? targetKeyOrOptions : sourceKey\n ) as StoreKey<TTarget>;\n\n const resolvedOptions =\n typeof targetKeyOrOptions === \"object\" ? targetKeyOrOptions : options;\n\n const cleanup = source.onUpdate(sourceKey, (state) => {\n target.update(\n resolvedTargetKey,\n state as unknown as Partial<TTarget[StoreKey<TTarget>]>\n );\n });\n\n if (resolvedOptions?.destroyRef) {\n resolvedOptions.destroyRef.onDestroy(cleanup);\n }\n\n return cleanup;\n}\n","import type {\n ResourceState,\n KeyedResourceKey,\n KeyedResourceData,\n} from \"@flurryx/core\";\nimport { createKeyedResourceData, isAnyKeyLoading } from \"@flurryx/core\";\nimport type { IStore, StoreDataShape, StoreKey } from \"./types\";\n\n/**\n * Options for {@link collectKeyed}.\n *\n * @template TEntity - The entity type emitted by the source store.\n */\nexport interface CollectKeyedOptions<TEntity> {\n /**\n * Extracts the entity identifier from the source data.\n * Return `undefined` to skip accumulation for that emission.\n */\n extractId: (data: TEntity | undefined) => KeyedResourceKey | undefined;\n /**\n * Angular `DestroyRef` (or any object with an `onDestroy` method) for\n * automatic cleanup. When provided, collection stops when the ref is destroyed.\n */\n destroyRef?: { onDestroy: (fn: () => void) => void };\n}\n\n/**\n * Accumulates single-entity resource fetches into a keyed cache on a target store.\n *\n * On each source update:\n * - If status is 'Success' and extractId returns a valid key, merges the entity\n * into the target's keyed resource data.\n * - If the source data is cleared and a previous entity existed, removes it from\n * the target's keyed data.\n *\n * @param source - The store containing the single-entity resource\n * @param sourceKey - The key to watch on the source store\n * @param target - The store to accumulate entities into\n * @param targetKeyOrOptions - Either the target key name or options (defaults source key)\n * @param options - Collect options when a target key is provided\n * @returns Cleanup function to stop collecting\n */\nexport function collectKeyed<\n TSource extends StoreDataShape<TSource>,\n TTarget extends StoreDataShape<TTarget>,\n TEntity = unknown\n>(\n source: IStore<TSource>,\n sourceKey: StoreKey<TSource>,\n target: IStore<TTarget>,\n targetKeyOrOptions?: StoreKey<TTarget> | CollectKeyedOptions<TEntity>,\n options?: CollectKeyedOptions<TEntity>\n): () => void {\n const resolvedTargetKey = (\n typeof targetKeyOrOptions === \"string\" ? targetKeyOrOptions : sourceKey\n ) as StoreKey<TTarget>;\n\n const resolvedOptions = (\n typeof targetKeyOrOptions === \"object\" ? targetKeyOrOptions : options\n ) as CollectKeyedOptions<TEntity>;\n\n // Initialize target with empty keyed resource data\n target.update(resolvedTargetKey, {\n data: createKeyedResourceData(),\n } as Partial<TTarget[StoreKey<TTarget>]>);\n\n let previousId: KeyedResourceKey | undefined;\n\n const cleanup = source.onUpdate(sourceKey, (state) => {\n const resourceState = state as ResourceState<TEntity>;\n const currentId = resolvedOptions.extractId(resourceState.data);\n const currentTarget = target.get(resolvedTargetKey)();\n const currentKeyed = (currentTarget as ResourceState<unknown>).data as\n | KeyedResourceData<KeyedResourceKey, TEntity>\n | undefined;\n\n if (!currentKeyed) {\n return;\n }\n\n if (resourceState.status === \"Success\" && currentId !== undefined) {\n const newEntities = {\n ...currentKeyed.entities,\n [currentId]: resourceState.data,\n };\n const newIsLoading = { ...currentKeyed.isLoading, [currentId]: false };\n const newStatus = {\n ...currentKeyed.status,\n [currentId]: resourceState.status,\n };\n const newErrors = { ...currentKeyed.errors };\n delete newErrors[currentId];\n\n const updatedKeyed: KeyedResourceData<KeyedResourceKey, TEntity> = {\n entities: newEntities,\n isLoading: newIsLoading,\n status: newStatus,\n errors: newErrors,\n };\n\n target.update(resolvedTargetKey, {\n data: updatedKeyed,\n isLoading: isAnyKeyLoading(newIsLoading),\n status: \"Success\",\n } as Partial<TTarget[StoreKey<TTarget>]>);\n\n previousId = currentId;\n } else if (resourceState.status === \"Error\" && currentId !== undefined) {\n const newIsLoading = { ...currentKeyed.isLoading, [currentId]: false };\n const newStatus = {\n ...currentKeyed.status,\n [currentId]: resourceState.status,\n };\n const newErrors = {\n ...currentKeyed.errors,\n [currentId]: resourceState.errors,\n };\n\n const updatedKeyed: KeyedResourceData<KeyedResourceKey, TEntity> = {\n entities: { ...currentKeyed.entities },\n isLoading: newIsLoading,\n status: newStatus,\n errors: newErrors,\n };\n\n target.update(resolvedTargetKey, {\n data: updatedKeyed,\n isLoading: isAnyKeyLoading(newIsLoading),\n } as Partial<TTarget[StoreKey<TTarget>]>);\n\n previousId = currentId;\n } else if (resourceState.data === undefined && previousId !== undefined) {\n // Source cleared — remove previous entity from cache\n const { [previousId]: _removed, ...remainingEntities } =\n currentKeyed.entities;\n const { [previousId]: _removedLoading, ...remainingLoading } =\n currentKeyed.isLoading;\n const { [previousId]: _removedStatus, ...remainingStatus } =\n currentKeyed.status;\n const { [previousId]: _removedErrors, ...remainingErrors } =\n currentKeyed.errors;\n\n const updatedKeyed: KeyedResourceData<KeyedResourceKey, TEntity> = {\n entities: remainingEntities,\n isLoading: remainingLoading,\n status: remainingStatus,\n errors: remainingErrors,\n };\n\n target.update(resolvedTargetKey, {\n data: updatedKeyed,\n isLoading: isAnyKeyLoading(remainingLoading),\n } as Partial<TTarget[StoreKey<TTarget>]>);\n\n previousId = undefined;\n } else if (resourceState.isLoading && currentId !== undefined) {\n const newIsLoading = { ...currentKeyed.isLoading, [currentId]: true };\n\n const updatedKeyed: KeyedResourceData<KeyedResourceKey, TEntity> = {\n entities: { ...currentKeyed.entities },\n isLoading: newIsLoading,\n status: { ...currentKeyed.status },\n errors: { ...currentKeyed.errors },\n };\n\n target.update(resolvedTargetKey, {\n data: updatedKeyed,\n isLoading: true,\n } as Partial<TTarget[StoreKey<TTarget>]>);\n\n previousId = currentId;\n }\n });\n\n if (resolvedOptions?.destroyRef) {\n resolvedOptions.destroyRef.onDestroy(cleanup);\n }\n\n return cleanup;\n}\n","import type { ResourceDef } from './types';\n\n/**\n * Creates a phantom-typed resource definition marker.\n * Zero runtime cost — returns an empty object that only carries type info.\n *\n * @example\n * const config = {\n * customers: resource<Customer[]>(),\n * customerDetails: resource<Customer>(),\n * };\n */\nexport function resource<T>(): ResourceDef<T> {\n return {} as ResourceDef<T>;\n}\n"],"mappings":"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","names":["signal","signal","signal","signal","createKeyedResourceData","isAnyKeyLoading"]}