@flurryx/store 0.8.2 → 0.8.4
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.cjs +79 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +158 -1
- package/dist/index.d.ts +158 -1
- package/dist/index.js +79 -10
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -54,9 +54,22 @@ var BaseStore = class {
|
|
|
54
54
|
trackStore(this);
|
|
55
55
|
}
|
|
56
56
|
signalsState = /* @__PURE__ */ new Map();
|
|
57
|
+
/**
|
|
58
|
+
* Returns a **read-only** `Signal` for the given store slot.
|
|
59
|
+
*
|
|
60
|
+
* @param key - The slot name to read.
|
|
61
|
+
* @returns A `Signal` wrapping the slot's current {@link ResourceState}.
|
|
62
|
+
*/
|
|
57
63
|
get(key) {
|
|
58
64
|
return this.signalsState.get(key.toString());
|
|
59
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Registers a callback fired after every `update` or `clear` on the given slot.
|
|
68
|
+
*
|
|
69
|
+
* @param key - The slot to watch.
|
|
70
|
+
* @param callback - Receives the new state and the previous state.
|
|
71
|
+
* @returns A cleanup function that removes the listener when called.
|
|
72
|
+
*/
|
|
60
73
|
onUpdate(key, callback) {
|
|
61
74
|
const hooks = updateHooksMap.get(this);
|
|
62
75
|
if (!hooks.has(key)) {
|
|
@@ -78,6 +91,12 @@ var BaseStore = class {
|
|
|
78
91
|
}
|
|
79
92
|
};
|
|
80
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* Partially updates a slot by merging `newState` into the current value (immutable spread).
|
|
96
|
+
*
|
|
97
|
+
* @param key - The slot to update.
|
|
98
|
+
* @param newState - Partial state to merge (e.g. `{ data: newData, status: 'Success' }`).
|
|
99
|
+
*/
|
|
81
100
|
update(key, newState) {
|
|
82
101
|
const currentState = this.signalsState.get(key.toString());
|
|
83
102
|
if (!currentState) {
|
|
@@ -91,11 +110,17 @@ var BaseStore = class {
|
|
|
91
110
|
const updatedState = currentState();
|
|
92
111
|
this.notifyUpdateHooks(key, updatedState, previousState);
|
|
93
112
|
}
|
|
113
|
+
/** Resets every slot in this store to its initial idle state. */
|
|
94
114
|
clearAll() {
|
|
95
115
|
Object.keys(this.storeEnum).forEach((key) => {
|
|
96
116
|
this.clear(key);
|
|
97
117
|
});
|
|
98
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* Resets a single slot to `{ data: undefined, isLoading: false, status: undefined, errors: undefined }`.
|
|
121
|
+
*
|
|
122
|
+
* @param key - The slot to clear.
|
|
123
|
+
*/
|
|
99
124
|
clear(key) {
|
|
100
125
|
const currentState = this.signalsState.get(key.toString());
|
|
101
126
|
if (!currentState) {
|
|
@@ -112,6 +137,11 @@ var BaseStore = class {
|
|
|
112
137
|
const nextState = currentState();
|
|
113
138
|
this.notifyUpdateHooks(key, nextState, previousState);
|
|
114
139
|
}
|
|
140
|
+
/**
|
|
141
|
+
* Marks a slot as loading: sets `isLoading: true` and clears `status` and `errors`.
|
|
142
|
+
*
|
|
143
|
+
* @param key - The slot to mark as loading.
|
|
144
|
+
*/
|
|
115
145
|
startLoading(key) {
|
|
116
146
|
const currentState = this.signalsState.get(key.toString());
|
|
117
147
|
if (!currentState) {
|
|
@@ -127,6 +157,12 @@ var BaseStore = class {
|
|
|
127
157
|
})
|
|
128
158
|
);
|
|
129
159
|
}
|
|
160
|
+
/**
|
|
161
|
+
* Marks a slot as no longer loading: sets `isLoading: false`.
|
|
162
|
+
* Does **not** clear `status` or `errors`.
|
|
163
|
+
*
|
|
164
|
+
* @param key - The slot to stop loading.
|
|
165
|
+
*/
|
|
130
166
|
stopLoading(key) {
|
|
131
167
|
const currentState = this.signalsState.get(key.toString());
|
|
132
168
|
if (!currentState) {
|
|
@@ -136,12 +172,19 @@ var BaseStore = class {
|
|
|
136
172
|
currentState.update(
|
|
137
173
|
(state) => ({
|
|
138
174
|
...state,
|
|
139
|
-
isLoading: false
|
|
140
|
-
status: void 0,
|
|
141
|
-
errors: void 0
|
|
175
|
+
isLoading: false
|
|
142
176
|
})
|
|
143
177
|
);
|
|
144
178
|
}
|
|
179
|
+
/**
|
|
180
|
+
* Merges a single entity into a {@link KeyedResourceData} slot.
|
|
181
|
+
* Sets its status to `'Success'` and clears per-key errors.
|
|
182
|
+
* The top-level `isLoading` is recalculated based on remaining loading keys.
|
|
183
|
+
*
|
|
184
|
+
* @param key - The keyed slot name.
|
|
185
|
+
* @param resourceKey - The entity identifier (e.g. `'inv-123'`).
|
|
186
|
+
* @param entity - The entity value to store.
|
|
187
|
+
*/
|
|
145
188
|
updateKeyedOne(key, resourceKey, entity) {
|
|
146
189
|
const currentState = this.signalsState.get(key.toString());
|
|
147
190
|
if (!currentState) {
|
|
@@ -174,6 +217,14 @@ var BaseStore = class {
|
|
|
174
217
|
errors: void 0
|
|
175
218
|
});
|
|
176
219
|
}
|
|
220
|
+
/**
|
|
221
|
+
* Removes a single entity from a {@link KeyedResourceData} slot,
|
|
222
|
+
* including its loading flag, status, and errors.
|
|
223
|
+
* Recalculates the top-level `isLoading` from the remaining keys.
|
|
224
|
+
*
|
|
225
|
+
* @param key - The keyed slot name.
|
|
226
|
+
* @param resourceKey - The entity identifier to remove.
|
|
227
|
+
*/
|
|
177
228
|
clearKeyedOne(key, resourceKey) {
|
|
178
229
|
const currentState = this.signalsState.get(key.toString());
|
|
179
230
|
if (!currentState) {
|
|
@@ -213,6 +264,14 @@ var BaseStore = class {
|
|
|
213
264
|
const updatedState = currentState();
|
|
214
265
|
this.notifyUpdateHooks(key, updatedState, previousState);
|
|
215
266
|
}
|
|
267
|
+
/**
|
|
268
|
+
* Marks a single entity within a keyed slot as loading.
|
|
269
|
+
* Clears its status and errors. If the slot data is not yet a {@link KeyedResourceData},
|
|
270
|
+
* falls back to `startLoading(key)`.
|
|
271
|
+
*
|
|
272
|
+
* @param key - The keyed slot name.
|
|
273
|
+
* @param resourceKey - The entity identifier to mark as loading.
|
|
274
|
+
*/
|
|
216
275
|
startKeyedLoading(key, resourceKey) {
|
|
217
276
|
const currentState = this.signalsState.get(key.toString());
|
|
218
277
|
if (!currentState) {
|
|
@@ -349,9 +408,7 @@ var LazyStore = class {
|
|
|
349
408
|
sig.update(
|
|
350
409
|
(state) => ({
|
|
351
410
|
...state,
|
|
352
|
-
isLoading: false
|
|
353
|
-
status: void 0,
|
|
354
|
-
errors: void 0
|
|
411
|
+
isLoading: false
|
|
355
412
|
})
|
|
356
413
|
);
|
|
357
414
|
}
|
|
@@ -524,9 +581,15 @@ function collectKeyed(source, sourceKey, target, targetKeyOrOptions, options) {
|
|
|
524
581
|
return;
|
|
525
582
|
}
|
|
526
583
|
if (resourceState.status === "Success" && currentId !== void 0) {
|
|
527
|
-
const newEntities = {
|
|
584
|
+
const newEntities = {
|
|
585
|
+
...currentKeyed.entities,
|
|
586
|
+
[currentId]: resourceState.data
|
|
587
|
+
};
|
|
528
588
|
const newIsLoading = { ...currentKeyed.isLoading, [currentId]: false };
|
|
529
|
-
const newStatus = {
|
|
589
|
+
const newStatus = {
|
|
590
|
+
...currentKeyed.status,
|
|
591
|
+
[currentId]: resourceState.status
|
|
592
|
+
};
|
|
530
593
|
const newErrors = { ...currentKeyed.errors };
|
|
531
594
|
delete newErrors[currentId];
|
|
532
595
|
const updatedKeyed = {
|
|
@@ -543,8 +606,14 @@ function collectKeyed(source, sourceKey, target, targetKeyOrOptions, options) {
|
|
|
543
606
|
previousId = currentId;
|
|
544
607
|
} else if (resourceState.status === "Error" && currentId !== void 0) {
|
|
545
608
|
const newIsLoading = { ...currentKeyed.isLoading, [currentId]: false };
|
|
546
|
-
const newStatus = {
|
|
547
|
-
|
|
609
|
+
const newStatus = {
|
|
610
|
+
...currentKeyed.status,
|
|
611
|
+
[currentId]: resourceState.status
|
|
612
|
+
};
|
|
613
|
+
const newErrors = {
|
|
614
|
+
...currentKeyed.errors,
|
|
615
|
+
[currentId]: resourceState.errors
|
|
616
|
+
};
|
|
548
617
|
const updatedKeyed = {
|
|
549
618
|
entities: { ...currentKeyed.entities },
|
|
550
619
|
isLoading: newIsLoading,
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/base-store.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":["export { BaseStore } from \"./base-store\";\nexport { LazyStore } from \"./lazy-store\";\nexport { Store } from \"./store-builder\";\nexport { clearAllStores } from \"./store-registry\";\nexport { mirrorKey } from \"./mirror-key\";\nexport { collectKeyed } from \"./collect-keyed\";\nexport type { MirrorOptions } from \"./mirror-key\";\nexport type { CollectKeyedOptions } from \"./collect-keyed\";\nexport type { IStore, ConfigToData } from \"./types\";\n","import { signal, type Signal, WritableSignal } from \"@angular/core\";\nimport {\n ResourceState,\n isAnyKeyLoading,\n isKeyedResourceData,\n createKeyedResourceData,\n type KeyedResourceKey,\n} from \"@flurryx/core\";\nimport type { IStore } from \"./types\";\nimport { trackStore } from \"./store-registry\";\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\nexport abstract class BaseStore<\n TEnum extends Record<string, string | number>,\n TData extends { [K in keyof TEnum]: ResourceState<unknown> }\n> implements IStore<TData>\n{\n private readonly signalsState = new Map<\n keyof TEnum,\n WritableSignal<TData[keyof TEnum]>\n >();\n\n protected constructor(protected readonly storeEnum: TEnum) {\n this.initializeState();\n updateHooksMap.set(this, new Map());\n trackStore(this);\n }\n\n get<K extends keyof TData>(key: K): Signal<TData[K]> {\n return this.signalsState.get(key.toString()) as unknown as Signal<TData[K]>;\n }\n\n onUpdate<K extends keyof 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 update<K extends keyof TData>(key: K, newState: Partial<TData[K]>): void {\n const currentState = this.signalsState.get(key.toString());\n if (!currentState) {\n return;\n }\n\n const previousState = currentState() as TData[K];\n currentState.update((state) => ({\n ...state,\n ...newState,\n }));\n\n const updatedState = currentState() as TData[K];\n this.notifyUpdateHooks(key, updatedState, previousState);\n }\n\n clearAll(): void {\n Object.keys(this.storeEnum).forEach((key) => {\n this.clear(key as keyof TData);\n });\n }\n\n clear<K extends keyof TData>(key: K): void {\n const currentState = this.signalsState.get(key.toString());\n if (!currentState) {\n return;\n }\n\n const previousState = currentState() as TData[K];\n const _typedKey = key as keyof TEnum;\n currentState.set({\n data: undefined,\n isLoading: false,\n status: undefined,\n errors: undefined,\n } as TData[typeof _typedKey]);\n\n const nextState = currentState() as TData[K];\n this.notifyUpdateHooks(key, nextState, previousState);\n }\n\n startLoading<K extends keyof TData>(key: K): void {\n const currentState = this.signalsState.get(key.toString());\n if (!currentState) {\n return;\n }\n\n const _typedKey = key as keyof TEnum;\n currentState.update(\n (state) =>\n ({\n ...state,\n status: undefined,\n isLoading: true,\n errors: undefined,\n } as TData[typeof _typedKey])\n );\n }\n\n stopLoading<K extends keyof TData>(key: K): void {\n const currentState = this.signalsState.get(key.toString());\n if (!currentState) {\n return;\n }\n\n const _typedKey = key as keyof TEnum;\n currentState.update(\n (state) =>\n ({\n ...state,\n isLoading: false,\n status: undefined,\n errors: undefined,\n } as TData[typeof _typedKey])\n );\n }\n\n updateKeyedOne<K extends keyof TData>(\n key: K,\n resourceKey: KeyedResourceKey,\n entity: unknown\n ): void {\n const currentState = this.signalsState.get(key.toString());\n if (!currentState) {\n return;\n }\n\n const state = currentState();\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: {\n ...data.entities,\n [resourceKey]: entity,\n },\n isLoading: {\n ...data.isLoading,\n [resourceKey]: false,\n },\n status: {\n ...data.status,\n [resourceKey]: \"Success\" as const,\n },\n errors: nextErrors,\n };\n\n this.update(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 clearKeyedOne<K extends keyof TData>(\n key: K,\n resourceKey: KeyedResourceKey\n ): void {\n const currentState = this.signalsState.get(key.toString());\n if (!currentState) {\n return;\n }\n\n const previousState = currentState() as TData[K];\n const state = previousState as ResourceState<unknown>;\n if (!isKeyedResourceData(state.data)) {\n return;\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 const _typedKey = key as keyof TEnum;\n currentState.update(\n (prev) =>\n ({\n ...prev,\n data: nextData as unknown,\n status: undefined,\n isLoading: isAnyKeyLoading(nextIsLoading),\n errors: undefined,\n } as TData[typeof _typedKey])\n );\n\n const updatedState = currentState() as TData[K];\n this.notifyUpdateHooks(key, updatedState, previousState);\n }\n\n startKeyedLoading<K extends keyof TData>(\n key: K,\n resourceKey: KeyedResourceKey\n ): void {\n const currentState = this.signalsState.get(key.toString());\n if (!currentState) {\n return;\n }\n\n const _typedKey = key as keyof TEnum;\n const state = currentState();\n if (!isKeyedResourceData(state.data)) {\n this.startLoading(key);\n return;\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 = {\n ...data.status,\n };\n delete nextStatus[resourceKey];\n\n const nextErrors: typeof data.errors = {\n ...data.errors,\n };\n delete nextErrors[resourceKey];\n\n const nextData = {\n ...data,\n isLoading: nextIsLoading,\n status: nextStatus,\n errors: nextErrors,\n };\n\n currentState.update(\n (previous) =>\n ({\n ...previous,\n data: nextData,\n status: undefined,\n isLoading: isAnyKeyLoading(nextIsLoading),\n errors: undefined,\n } as TData[typeof _typedKey])\n );\n\n const updatedState = currentState() as TData[K];\n this.notifyUpdateHooks(key, updatedState, previousState);\n }\n\n private notifyUpdateHooks<K extends keyof 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 keyHooks.forEach((hook) =>\n hook(\n nextState as ResourceState<unknown>,\n previousState as ResourceState<unknown>\n )\n );\n }\n\n private initializeState(): void {\n Object.keys(this.storeEnum).forEach((key) => {\n const _typedKey = key as keyof TEnum;\n const initialState: ResourceState<unknown> = {\n data: undefined,\n isLoading: false,\n status: undefined,\n errors: undefined,\n };\n this.signalsState.set(\n _typedKey,\n signal<TData[typeof _typedKey]>(initialState as TData[typeof _typedKey])\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\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 {\n isAnyKeyLoading,\n isKeyedResourceData,\n createKeyedResourceData,\n type ResourceState,\n type KeyedResourceKey,\n} from \"@flurryx/core\";\nimport type { IStore, StoreDataShape, StoreKey } from \"./types\";\nimport { trackStore } from \"./store-registry\";\n\ntype UpdateCallback = (\n nextState: ResourceState<unknown>,\n previousState: ResourceState<unknown>\n) => void;\n\nfunction createDefaultState<T>(): ResourceState<T> {\n return {\n data: undefined,\n isLoading: false,\n status: undefined,\n errors: undefined,\n };\n}\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\n constructor() {\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 }\n return sig as WritableSignal<TData[K]>;\n }\n\n get<K extends StoreKey<TData>>(key: K): Signal<TData[K]> {\n return this.getOrCreate(key);\n }\n\n update<K extends StoreKey<TData>>(key: K, newState: Partial<TData[K]>): void {\n const sig = this.getOrCreate(key);\n const previousState = sig();\n sig.update((state) => ({ ...state, ...newState }));\n const nextState = sig();\n this.notifyHooks(key, nextState, previousState);\n }\n\n clear<K extends StoreKey<TData>>(key: K): void {\n const sig = this.getOrCreate(key);\n const previousState = sig();\n sig.set(createDefaultState() as TData[K]);\n const nextState = sig();\n this.notifyHooks(key, nextState, previousState);\n }\n\n clearAll(): void {\n for (const key of this.signals.keys()) {\n this.clear(key as StoreKey<TData>);\n }\n }\n\n startLoading<K extends StoreKey<TData>>(key: K): void {\n const sig = this.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 }\n\n stopLoading<K extends StoreKey<TData>>(key: K): void {\n const sig = this.getOrCreate(key);\n sig.update(\n (state) =>\n ({\n ...state,\n isLoading: false,\n status: undefined,\n errors: undefined,\n } as TData[K])\n );\n }\n\n updateKeyedOne<K extends StoreKey<TData>>(\n key: K,\n resourceKey: KeyedResourceKey,\n entity: unknown\n ): void {\n const sig = this.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 this.update(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 clearKeyedOne<K extends StoreKey<TData>>(\n key: K,\n resourceKey: KeyedResourceKey\n ): void {\n const sig = this.getOrCreate(key);\n const state = sig();\n if (!isKeyedResourceData(state.data)) {\n return;\n }\n\n const data = state.data;\n const previousState = state;\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 this.notifyHooks(key, updatedState, previousState);\n }\n\n startKeyedLoading<K extends StoreKey<TData>>(\n key: K,\n resourceKey: KeyedResourceKey\n ): void {\n const sig = this.getOrCreate(key);\n const state = sig();\n if (!isKeyedResourceData(state.data)) {\n this.startLoading(key);\n return;\n }\n\n const previousState = state;\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 this.notifyHooks(key, updatedState, previousState);\n }\n\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 keyHooks.forEach((hook) =>\n hook(\n nextState as ResourceState<unknown>,\n previousState as ResourceState<unknown>\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 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<IStore<AnyStoreData>>;\n readonly sourceKey: string;\n readonly targetKey: string;\n}\n\nfunction wireMirrors<\n TData extends StoreDataShape<TData>,\n TStore extends IStore<TData>\n>(store: TStore, mirrors: readonly MirrorDef[]): TStore {\n for (const def of mirrors) {\n const sourceStore = inject(def.sourceToken);\n mirrorKey(\n sourceStore,\n def.sourceKey,\n store,\n def.targetKey as StoreKey<TData>\n );\n }\n return store;\n}\n\n// ---------------------------------------------------------------------------\n// MirrorKeyed definition — accumulated by builders, wired up in build()\n// ---------------------------------------------------------------------------\n\ninterface MirrorKeyedDef {\n readonly sourceToken: InjectionToken<IStore<AnyStoreData>>;\n readonly sourceKey: string;\n readonly targetKey: string;\n readonly extractId: (data: unknown) => KeyedResourceKey | undefined;\n}\n\nfunction wireMirrorKeyed<\n TData extends StoreDataShape<TData>,\n TStore extends IStore<TData>\n>(store: TStore, defs: readonly MirrorKeyedDef[]): TStore {\n for (const def of defs) {\n const sourceStore = inject(def.sourceToken);\n collectKeyed(\n sourceStore,\n def.sourceKey,\n store,\n def.targetKey as StoreKey<TData>,\n {\n extractId: def.extractId,\n }\n );\n }\n return store;\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<\n TData extends StoreDataShape<TData>,\n TStore extends IStore<TData>\n>(store: TStore, defs: readonly SelfMirrorDef[]): TStore {\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 return store;\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 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 resource<TKey extends string>(key: TKey): AsStep<TAccum, TKey>;\n mirror<TSourceData extends StoreDataShape<TSourceData>>(\n source: InjectionToken<IStore<TSourceData>>,\n sourceKey: StoreKey<TSourceData>,\n targetKey?: StoreKey<TAccum>\n ): StoreBuilder<TAccum>;\n mirrorSelf(\n sourceKey: StoreKey<TAccum>,\n targetKey: StoreKey<TAccum>\n ): StoreBuilder<TAccum>;\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 build(): 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<IStore<AnyStoreData>>,\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<IStore<AnyStoreData>>,\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() {\n return new InjectionToken<\n BaseStore<InferEnum<TAccum>, InferData<TAccum>>\n >(\"FlurryxStore\", {\n providedIn: \"root\",\n factory: () => {\n const store = new DynamicStore(accum) 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 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 mirror<TSourceData extends StoreDataShape<TSourceData>>(\n source: InjectionToken<IStore<TSourceData>>,\n sourceKey: StoreKey<TSourceData>,\n targetKey?: StoreKey<TAccum>\n ): ConstrainedBuilder<TEnum, TAccum>;\n mirrorSelf(\n sourceKey: StoreKey<TAccum>,\n targetKey: StoreKey<TAccum>\n ): ConstrainedBuilder<TEnum, TAccum>;\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 build(): InjectionToken<BaseStore<InferEnum<TAccum>, InferData<TAccum>>>;\n }\n : {\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() {\n return new InjectionToken<\n BaseStore<InferEnum<TAccum>, InferData<TAccum>>\n >(\"FlurryxStore\", {\n providedIn: \"root\",\n factory: () => {\n const store = new DynamicStore(accum) 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\ninterface InterfaceBuilder<TConfig extends object> {\n mirror<TSourceData extends StoreDataShape<TSourceData>>(\n source: InjectionToken<IStore<TSourceData>>,\n sourceKey: StoreKey<TSourceData>,\n targetKey?: StoreKey<ConfigToData<TConfig>>\n ): InterfaceBuilder<TConfig>;\n mirrorSelf(\n sourceKey: StoreKey<ConfigToData<TConfig>>,\n targetKey: StoreKey<ConfigToData<TConfig>>\n ): InterfaceBuilder<TConfig>;\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 build(): 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<IStore<AnyStoreData>>,\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<IStore<AnyStoreData>>,\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() {\n return new InjectionToken(\"FlurryxStore\", {\n providedIn: \"root\",\n factory: () => {\n const store = new LazyStore() 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 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 } 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) {\n const identityEnum = Object.keys(config).reduce(\n (acc, key) => ({ ...acc, [key]: key }),\n {} as InferEnum<TConfig>\n );\n super(identityEnum);\n }\n}\n","import type { IStore, StoreDataShape, StoreKey } from \"./types\";\n\nexport interface MirrorOptions {\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\nexport interface CollectKeyedOptions<TEntity> {\n extractId: (data: TEntity | undefined) => KeyedResourceKey | undefined;\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'\n ? targetKeyOrOptions\n : 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> | undefined;\n\n if (!currentKeyed) {\n return;\n }\n\n if (resourceState.status === 'Success' && currentId !== undefined) {\n const newEntities = { ...currentKeyed.entities, [currentId]: resourceState.data };\n const newIsLoading = { ...currentKeyed.isLoading, [currentId]: false };\n const newStatus = { ...currentKeyed.status, [currentId]: resourceState.status };\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 = { ...currentKeyed.status, [currentId]: resourceState.status };\n const newErrors = { ...currentKeyed.errors, [currentId]: resourceState.errors };\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 } = currentKeyed.entities;\n const { [previousId]: _removedLoading, ...remainingLoading } = currentKeyed.isLoading;\n const { [previousId]: _removedStatus, ...remainingStatus } = currentKeyed.status;\n const { [previousId]: _removedErrors, ...remainingErrors } = 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":["import_core","import_core","import_core","import_core"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/base-store.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":["export { BaseStore } from \"./base-store\";\nexport { LazyStore } from \"./lazy-store\";\nexport { Store } from \"./store-builder\";\nexport { clearAllStores } from \"./store-registry\";\nexport { mirrorKey } from \"./mirror-key\";\nexport { collectKeyed } from \"./collect-keyed\";\nexport type { MirrorOptions } from \"./mirror-key\";\nexport type { CollectKeyedOptions } from \"./collect-keyed\";\nexport type { IStore, ConfigToData } from \"./types\";\n","import { signal, type Signal, WritableSignal } from \"@angular/core\";\nimport {\n ResourceState,\n isAnyKeyLoading,\n isKeyedResourceData,\n createKeyedResourceData,\n type KeyedResourceKey,\n} from \"@flurryx/core\";\nimport type { IStore } from \"./types\";\nimport { trackStore } from \"./store-registry\";\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 { [K in keyof TEnum]: ResourceState<unknown> }\n> implements IStore<TData>\n{\n private readonly signalsState = new Map<\n keyof TEnum,\n WritableSignal<TData[keyof TEnum]>\n >();\n\n protected constructor(protected readonly storeEnum: TEnum) {\n this.initializeState();\n updateHooksMap.set(this, new Map());\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 keyof 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 keyof 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 keyof TData>(key: K, newState: Partial<TData[K]>): void {\n const currentState = this.signalsState.get(key.toString());\n if (!currentState) {\n return;\n }\n\n const previousState = currentState() as TData[K];\n currentState.update((state) => ({\n ...state,\n ...newState,\n }));\n\n const updatedState = currentState() as TData[K];\n this.notifyUpdateHooks(key, updatedState, previousState);\n }\n\n /** Resets every slot in this store to its initial idle state. */\n clearAll(): void {\n Object.keys(this.storeEnum).forEach((key) => {\n this.clear(key as keyof TData);\n });\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 keyof TData>(key: K): void {\n const currentState = this.signalsState.get(key.toString());\n if (!currentState) {\n return;\n }\n\n const previousState = currentState() as TData[K];\n const _typedKey = key as keyof TEnum;\n currentState.set({\n data: undefined,\n isLoading: false,\n status: undefined,\n errors: undefined,\n } as TData[typeof _typedKey]);\n\n const nextState = currentState() as TData[K];\n this.notifyUpdateHooks(key, nextState, previousState);\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 keyof TData>(key: K): void {\n const currentState = this.signalsState.get(key.toString());\n if (!currentState) {\n return;\n }\n\n const _typedKey = key as keyof TEnum;\n currentState.update(\n (state) =>\n ({\n ...state,\n status: undefined,\n isLoading: true,\n errors: undefined,\n } as TData[typeof _typedKey])\n );\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 keyof TData>(key: K): void {\n const currentState = this.signalsState.get(key.toString());\n if (!currentState) {\n return;\n }\n\n const _typedKey = key as keyof TEnum;\n currentState.update(\n (state) =>\n ({\n ...state,\n isLoading: false,\n } as TData[typeof _typedKey])\n );\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 keyof TData>(\n key: K,\n resourceKey: KeyedResourceKey,\n entity: unknown\n ): void {\n const currentState = this.signalsState.get(key.toString());\n if (!currentState) {\n return;\n }\n\n const state = currentState();\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: {\n ...data.entities,\n [resourceKey]: entity,\n },\n isLoading: {\n ...data.isLoading,\n [resourceKey]: false,\n },\n status: {\n ...data.status,\n [resourceKey]: \"Success\" as const,\n },\n errors: nextErrors,\n };\n\n this.update(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 /**\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 keyof TData>(\n key: K,\n resourceKey: KeyedResourceKey\n ): void {\n const currentState = this.signalsState.get(key.toString());\n if (!currentState) {\n return;\n }\n\n const previousState = currentState() as TData[K];\n const state = previousState as ResourceState<unknown>;\n if (!isKeyedResourceData(state.data)) {\n return;\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 const _typedKey = key as keyof TEnum;\n currentState.update(\n (prev) =>\n ({\n ...prev,\n data: nextData as unknown,\n status: undefined,\n isLoading: isAnyKeyLoading(nextIsLoading),\n errors: undefined,\n } as TData[typeof _typedKey])\n );\n\n const updatedState = currentState() as TData[K];\n this.notifyUpdateHooks(key, updatedState, previousState);\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 keyof TData>(\n key: K,\n resourceKey: KeyedResourceKey\n ): void {\n const currentState = this.signalsState.get(key.toString());\n if (!currentState) {\n return;\n }\n\n const _typedKey = key as keyof TEnum;\n const state = currentState();\n if (!isKeyedResourceData(state.data)) {\n this.startLoading(key);\n return;\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 = {\n ...data.status,\n };\n delete nextStatus[resourceKey];\n\n const nextErrors: typeof data.errors = {\n ...data.errors,\n };\n delete nextErrors[resourceKey];\n\n const nextData = {\n ...data,\n isLoading: nextIsLoading,\n status: nextStatus,\n errors: nextErrors,\n };\n\n currentState.update(\n (previous) =>\n ({\n ...previous,\n data: nextData,\n status: undefined,\n isLoading: isAnyKeyLoading(nextIsLoading),\n errors: undefined,\n } as TData[typeof _typedKey])\n );\n\n const updatedState = currentState() as TData[K];\n this.notifyUpdateHooks(key, updatedState, previousState);\n }\n\n private notifyUpdateHooks<K extends keyof 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 keyHooks.forEach((hook) =>\n hook(\n nextState as ResourceState<unknown>,\n previousState as ResourceState<unknown>\n )\n );\n }\n\n private initializeState(): void {\n Object.keys(this.storeEnum).forEach((key) => {\n const _typedKey = key as keyof TEnum;\n const initialState: ResourceState<unknown> = {\n data: undefined,\n isLoading: false,\n status: undefined,\n errors: undefined,\n };\n this.signalsState.set(\n _typedKey,\n signal<TData[typeof _typedKey]>(initialState as TData[typeof _typedKey])\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';\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 {\n isAnyKeyLoading,\n isKeyedResourceData,\n createKeyedResourceData,\n type ResourceState,\n type KeyedResourceKey,\n} from \"@flurryx/core\";\nimport type { IStore, StoreDataShape, StoreKey } from \"./types\";\nimport { trackStore } from \"./store-registry\";\n\ntype UpdateCallback = (\n nextState: ResourceState<unknown>,\n previousState: ResourceState<unknown>\n) => void;\n\nfunction createDefaultState<T>(): ResourceState<T> {\n return {\n data: undefined,\n isLoading: false,\n status: undefined,\n errors: undefined,\n };\n}\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\n constructor() {\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 }\n return sig as WritableSignal<TData[K]>;\n }\n\n get<K extends StoreKey<TData>>(key: K): Signal<TData[K]> {\n return this.getOrCreate(key);\n }\n\n update<K extends StoreKey<TData>>(key: K, newState: Partial<TData[K]>): void {\n const sig = this.getOrCreate(key);\n const previousState = sig();\n sig.update((state) => ({ ...state, ...newState }));\n const nextState = sig();\n this.notifyHooks(key, nextState, previousState);\n }\n\n clear<K extends StoreKey<TData>>(key: K): void {\n const sig = this.getOrCreate(key);\n const previousState = sig();\n sig.set(createDefaultState() as TData[K]);\n const nextState = sig();\n this.notifyHooks(key, nextState, previousState);\n }\n\n clearAll(): void {\n for (const key of this.signals.keys()) {\n this.clear(key as StoreKey<TData>);\n }\n }\n\n startLoading<K extends StoreKey<TData>>(key: K): void {\n const sig = this.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 }\n\n stopLoading<K extends StoreKey<TData>>(key: K): void {\n const sig = this.getOrCreate(key);\n sig.update(\n (state) =>\n ({\n ...state,\n isLoading: false,\n } as TData[K])\n );\n }\n\n updateKeyedOne<K extends StoreKey<TData>>(\n key: K,\n resourceKey: KeyedResourceKey,\n entity: unknown\n ): void {\n const sig = this.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 this.update(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 clearKeyedOne<K extends StoreKey<TData>>(\n key: K,\n resourceKey: KeyedResourceKey\n ): void {\n const sig = this.getOrCreate(key);\n const state = sig();\n if (!isKeyedResourceData(state.data)) {\n return;\n }\n\n const data = state.data;\n const previousState = state;\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 this.notifyHooks(key, updatedState, previousState);\n }\n\n startKeyedLoading<K extends StoreKey<TData>>(\n key: K,\n resourceKey: KeyedResourceKey\n ): void {\n const sig = this.getOrCreate(key);\n const state = sig();\n if (!isKeyedResourceData(state.data)) {\n this.startLoading(key);\n return;\n }\n\n const previousState = state;\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 this.notifyHooks(key, updatedState, previousState);\n }\n\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 keyHooks.forEach((hook) =>\n hook(\n nextState as ResourceState<unknown>,\n previousState as ResourceState<unknown>\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 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<IStore<AnyStoreData>>;\n readonly sourceKey: string;\n readonly targetKey: string;\n}\n\nfunction wireMirrors<\n TData extends StoreDataShape<TData>,\n TStore extends IStore<TData>\n>(store: TStore, mirrors: readonly MirrorDef[]): TStore {\n for (const def of mirrors) {\n const sourceStore = inject(def.sourceToken);\n mirrorKey(\n sourceStore,\n def.sourceKey,\n store,\n def.targetKey as StoreKey<TData>\n );\n }\n return store;\n}\n\n// ---------------------------------------------------------------------------\n// MirrorKeyed definition — accumulated by builders, wired up in build()\n// ---------------------------------------------------------------------------\n\ninterface MirrorKeyedDef {\n readonly sourceToken: InjectionToken<IStore<AnyStoreData>>;\n readonly sourceKey: string;\n readonly targetKey: string;\n readonly extractId: (data: unknown) => KeyedResourceKey | undefined;\n}\n\nfunction wireMirrorKeyed<\n TData extends StoreDataShape<TData>,\n TStore extends IStore<TData>\n>(store: TStore, defs: readonly MirrorKeyedDef[]): TStore {\n for (const def of defs) {\n const sourceStore = inject(def.sourceToken);\n collectKeyed(\n sourceStore,\n def.sourceKey,\n store,\n def.targetKey as StoreKey<TData>,\n {\n extractId: def.extractId,\n }\n );\n }\n return store;\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<\n TData extends StoreDataShape<TData>,\n TStore extends IStore<TData>\n>(store: TStore, defs: readonly SelfMirrorDef[]): TStore {\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 return store;\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 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(): 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<IStore<AnyStoreData>>,\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<IStore<AnyStoreData>>,\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() {\n return new InjectionToken<\n BaseStore<InferEnum<TAccum>, InferData<TAccum>>\n >(\"FlurryxStore\", {\n providedIn: \"root\",\n factory: () => {\n const store = new DynamicStore(accum) 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 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 mirror<TSourceData extends StoreDataShape<TSourceData>>(\n source: InjectionToken<IStore<TSourceData>>,\n sourceKey: StoreKey<TSourceData>,\n targetKey?: StoreKey<TAccum>\n ): ConstrainedBuilder<TEnum, TAccum>;\n mirrorSelf(\n sourceKey: StoreKey<TAccum>,\n targetKey: StoreKey<TAccum>\n ): ConstrainedBuilder<TEnum, TAccum>;\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 build(): InjectionToken<BaseStore<InferEnum<TAccum>, InferData<TAccum>>>;\n }\n : {\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() {\n return new InjectionToken<\n BaseStore<InferEnum<TAccum>, InferData<TAccum>>\n >(\"FlurryxStore\", {\n providedIn: \"root\",\n factory: () => {\n const store = new DynamicStore(accum) 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\ninterface InterfaceBuilder<TConfig extends object> {\n mirror<TSourceData extends StoreDataShape<TSourceData>>(\n source: InjectionToken<IStore<TSourceData>>,\n sourceKey: StoreKey<TSourceData>,\n targetKey?: StoreKey<ConfigToData<TConfig>>\n ): InterfaceBuilder<TConfig>;\n mirrorSelf(\n sourceKey: StoreKey<ConfigToData<TConfig>>,\n targetKey: StoreKey<ConfigToData<TConfig>>\n ): InterfaceBuilder<TConfig>;\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 build(): 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<IStore<AnyStoreData>>,\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<IStore<AnyStoreData>>,\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() {\n return new InjectionToken(\"FlurryxStore\", {\n providedIn: \"root\",\n factory: () => {\n const store = new LazyStore() 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 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 } 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) {\n const identityEnum = Object.keys(config).reduce(\n (acc, key) => ({ ...acc, [key]: key }),\n {} as InferEnum<TConfig>\n );\n super(identityEnum);\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":["import_core","import_core","import_core","import_core"]}
|