@flurryx/store 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/base-store.ts
2
- import { signal } from "@angular/core";
2
+ import { signal as signal2 } from "@angular/core";
3
3
 
4
4
  // src/store-clone.ts
5
5
  function cloneValue(value) {
@@ -82,10 +82,264 @@ function createSnapshotRestorePatch(currentState, snapshotState) {
82
82
  return patch;
83
83
  }
84
84
 
85
+ // src/store-replay.ts
86
+ import { signal, computed } from "@angular/core";
87
+
85
88
  // src/store-messages.ts
86
89
  var INVALID_HISTORY_INDEX_ERROR = "History index is out of range";
87
90
  var INVALID_HISTORY_MESSAGE_ID_ERROR = "History message id is out of range";
88
91
  var MESSAGE_NOT_ACKNOWLEDGED_ERROR = "Message was not acknowledged";
92
+ var INVALID_STORE_KEY_ERROR = "Invalid store key";
93
+
94
+ // src/store-message-consumer.ts
95
+ import {
96
+ isKeyedResourceData,
97
+ createKeyedResourceData,
98
+ isAnyKeyLoading
99
+ } from "@flurryx/core";
100
+ function createDefaultState() {
101
+ return {
102
+ data: void 0,
103
+ isLoading: false,
104
+ status: void 0,
105
+ errors: void 0
106
+ };
107
+ }
108
+ function createStoreMessageConsumer(signals, notifier) {
109
+ function applyUpdate(key, newState, notify = true) {
110
+ const sig = signals.getOrCreate(key);
111
+ const previousState = sig();
112
+ sig.update((state) => ({ ...state, ...newState }));
113
+ if (notify) {
114
+ const updatedState = sig();
115
+ notifier.notify(key, updatedState, previousState);
116
+ }
117
+ return true;
118
+ }
119
+ function applyClear(key) {
120
+ const sig = signals.getOrCreate(key);
121
+ const previousState = sig();
122
+ sig.set(createDefaultState());
123
+ const nextState = sig();
124
+ notifier.notify(key, nextState, previousState);
125
+ return true;
126
+ }
127
+ function applyClearAll() {
128
+ const keys = Array.from(signals.getAllKeys());
129
+ if (keys.length === 0) {
130
+ return false;
131
+ }
132
+ keys.forEach((key) => {
133
+ applyClear(key);
134
+ });
135
+ return true;
136
+ }
137
+ function applyStartLoading(key) {
138
+ const sig = signals.getOrCreate(key);
139
+ sig.update(
140
+ (state) => ({
141
+ ...state,
142
+ status: void 0,
143
+ isLoading: true,
144
+ errors: void 0
145
+ })
146
+ );
147
+ return true;
148
+ }
149
+ function applyStopLoading(key) {
150
+ const sig = signals.getOrCreate(key);
151
+ sig.update(
152
+ (state) => ({
153
+ ...state,
154
+ isLoading: false
155
+ })
156
+ );
157
+ return true;
158
+ }
159
+ function applyUpdateKeyedOne(key, resourceKey, entity) {
160
+ const sig = signals.getOrCreate(key);
161
+ const state = sig();
162
+ const data = isKeyedResourceData(state.data) ? state.data : createKeyedResourceData();
163
+ const nextErrors = { ...data.errors };
164
+ delete nextErrors[resourceKey];
165
+ const nextData = {
166
+ ...data,
167
+ entities: { ...data.entities, [resourceKey]: entity },
168
+ isLoading: { ...data.isLoading, [resourceKey]: false },
169
+ status: { ...data.status, [resourceKey]: "Success" },
170
+ errors: nextErrors
171
+ };
172
+ return applyUpdate(key, {
173
+ data: nextData,
174
+ isLoading: isAnyKeyLoading(nextData.isLoading),
175
+ status: void 0,
176
+ errors: void 0
177
+ });
178
+ }
179
+ function applyClearKeyedOne(key, resourceKey) {
180
+ const sig = signals.getOrCreate(key);
181
+ const previousState = sig();
182
+ const state = previousState;
183
+ if (!isKeyedResourceData(state.data)) {
184
+ return true;
185
+ }
186
+ const data = state.data;
187
+ const nextEntities = { ...data.entities };
188
+ delete nextEntities[resourceKey];
189
+ const nextIsLoading = { ...data.isLoading };
190
+ delete nextIsLoading[resourceKey];
191
+ const nextStatus = { ...data.status };
192
+ delete nextStatus[resourceKey];
193
+ const nextErrors = { ...data.errors };
194
+ delete nextErrors[resourceKey];
195
+ const nextData = {
196
+ ...data,
197
+ entities: nextEntities,
198
+ isLoading: nextIsLoading,
199
+ status: nextStatus,
200
+ errors: nextErrors
201
+ };
202
+ sig.update(
203
+ (prev) => ({
204
+ ...prev,
205
+ data: nextData,
206
+ status: void 0,
207
+ isLoading: isAnyKeyLoading(nextIsLoading),
208
+ errors: void 0
209
+ })
210
+ );
211
+ const updatedState = sig();
212
+ notifier.notify(key, updatedState, previousState);
213
+ return true;
214
+ }
215
+ function applyStartKeyedLoading(key, resourceKey) {
216
+ const sig = signals.getOrCreate(key);
217
+ const state = sig();
218
+ if (!isKeyedResourceData(state.data)) {
219
+ return applyStartLoading(key);
220
+ }
221
+ const previousState = state;
222
+ const data = state.data;
223
+ const nextIsLoading = {
224
+ ...data.isLoading,
225
+ [resourceKey]: true
226
+ };
227
+ const nextStatus = { ...data.status };
228
+ delete nextStatus[resourceKey];
229
+ const nextErrors = { ...data.errors };
230
+ delete nextErrors[resourceKey];
231
+ const nextData = {
232
+ ...data,
233
+ isLoading: nextIsLoading,
234
+ status: nextStatus,
235
+ errors: nextErrors
236
+ };
237
+ sig.update(
238
+ (previous) => ({
239
+ ...previous,
240
+ data: nextData,
241
+ status: void 0,
242
+ isLoading: isAnyKeyLoading(nextIsLoading),
243
+ errors: void 0
244
+ })
245
+ );
246
+ const updatedState = sig();
247
+ notifier.notify(key, updatedState, previousState);
248
+ return true;
249
+ }
250
+ function applyMessage(message) {
251
+ switch (message.type) {
252
+ case "update":
253
+ return applyUpdate(message.key, cloneValue(message.state));
254
+ case "clear":
255
+ return applyClear(message.key);
256
+ case "clearAll":
257
+ return applyClearAll();
258
+ case "startLoading":
259
+ return applyStartLoading(message.key);
260
+ case "stopLoading":
261
+ return applyStopLoading(message.key);
262
+ case "updateKeyedOne":
263
+ return applyUpdateKeyedOne(
264
+ message.key,
265
+ message.resourceKey,
266
+ cloneValue(message.entity)
267
+ );
268
+ case "clearKeyedOne":
269
+ return applyClearKeyedOne(message.key, message.resourceKey);
270
+ case "startKeyedLoading":
271
+ return applyStartKeyedLoading(message.key, message.resourceKey);
272
+ }
273
+ }
274
+ function applySnapshot(snapshot) {
275
+ const keys = /* @__PURE__ */ new Set([
276
+ ...Array.from(signals.getAllKeys()),
277
+ ...Object.keys(snapshot)
278
+ ]);
279
+ keys.forEach((rawKey) => {
280
+ const key = rawKey;
281
+ const sig = signals.getOrCreate(key);
282
+ const snapshotState = snapshot[key] ?? createDefaultState();
283
+ applyUpdate(key, createSnapshotRestorePatch(sig(), snapshotState), true);
284
+ });
285
+ }
286
+ function captureSnapshot() {
287
+ const entries = Array.from(signals.getAllKeys()).map((key) => [
288
+ key,
289
+ cloneValue(signals.getOrCreate(key)())
290
+ ]);
291
+ return Object.fromEntries(entries);
292
+ }
293
+ function applyKeyUpdate(key, snapshotState) {
294
+ const sig = signals.getOrCreate(key);
295
+ const currentState = sig();
296
+ const patch = createSnapshotRestorePatch(currentState, snapshotState);
297
+ applyUpdate(key, patch, true);
298
+ }
299
+ return {
300
+ applyMessage,
301
+ applySnapshot,
302
+ applyKeyUpdate,
303
+ createSnapshot: captureSnapshot
304
+ };
305
+ }
306
+ function createUpdateMessage(key, state) {
307
+ return { type: "update", key, state };
308
+ }
309
+ function createClearMessage(key) {
310
+ return { type: "clear", key };
311
+ }
312
+ function createClearAllMessage() {
313
+ return { type: "clearAll" };
314
+ }
315
+ function createStartLoadingMessage(key) {
316
+ return { type: "startLoading", key };
317
+ }
318
+ function createStopLoadingMessage(key) {
319
+ return { type: "stopLoading", key };
320
+ }
321
+ function createUpdateKeyedOneMessage(key, resourceKey, entity) {
322
+ return {
323
+ type: "updateKeyedOne",
324
+ key,
325
+ resourceKey,
326
+ entity
327
+ };
328
+ }
329
+ function createClearKeyedOneMessage(key, resourceKey) {
330
+ return {
331
+ type: "clearKeyedOne",
332
+ key,
333
+ resourceKey
334
+ };
335
+ }
336
+ function createStartKeyedLoadingMessage(key, resourceKey) {
337
+ return {
338
+ type: "startKeyedLoading",
339
+ key,
340
+ resourceKey
341
+ };
342
+ }
89
343
 
90
344
  // src/store-channels.ts
91
345
  function serializeStoreMessageChannelValue(value) {
@@ -388,31 +642,162 @@ function toDeadLetterEntry(record) {
388
642
  failedAt: record.lastAttemptedAt ?? record.createdAt
389
643
  };
390
644
  }
391
- function createStoreHistory(config) {
392
- const messageChannel = config.channel ?? createInMemoryStoreMessageChannel();
393
- const clock = config.clock ?? Date.now;
394
- let history = [
395
- {
396
- id: null,
397
- index: 0,
398
- message: null,
645
+ function areValuesEquivalent(left, right, seen = /* @__PURE__ */ new WeakMap()) {
646
+ if (Object.is(left, right)) {
647
+ return true;
648
+ }
649
+ if (typeof left !== typeof right || left === null || right === null) {
650
+ return false;
651
+ }
652
+ if (typeof left !== "object" || typeof right !== "object") {
653
+ return false;
654
+ }
655
+ let seenRights = seen.get(left);
656
+ if (seenRights?.has(right)) {
657
+ return true;
658
+ }
659
+ if (!seenRights) {
660
+ seenRights = /* @__PURE__ */ new WeakSet();
661
+ seen.set(left, seenRights);
662
+ }
663
+ seenRights.add(right);
664
+ if (left instanceof Date || right instanceof Date) {
665
+ return left instanceof Date && right instanceof Date && left.getTime() === right.getTime();
666
+ }
667
+ if (left instanceof Map || right instanceof Map) {
668
+ if (!(left instanceof Map) || !(right instanceof Map)) {
669
+ return false;
670
+ }
671
+ const leftEntries = Array.from(left.entries());
672
+ const rightEntries = Array.from(right.entries());
673
+ if (leftEntries.length !== rightEntries.length) {
674
+ return false;
675
+ }
676
+ return leftEntries.every(([leftKey, leftValue], index) => {
677
+ const rightEntry = rightEntries[index];
678
+ if (!rightEntry) {
679
+ return false;
680
+ }
681
+ return areValuesEquivalent(leftKey, rightEntry[0], seen) && areValuesEquivalent(leftValue, rightEntry[1], seen);
682
+ });
683
+ }
684
+ if (left instanceof Set || right instanceof Set) {
685
+ if (!(left instanceof Set) || !(right instanceof Set)) {
686
+ return false;
687
+ }
688
+ const leftValues = Array.from(left.values());
689
+ const rightValues = Array.from(right.values());
690
+ if (leftValues.length !== rightValues.length) {
691
+ return false;
692
+ }
693
+ return leftValues.every(
694
+ (leftValue, index) => areValuesEquivalent(leftValue, rightValues[index], seen)
695
+ );
696
+ }
697
+ if (Array.isArray(left) || Array.isArray(right)) {
698
+ if (!Array.isArray(left) || !Array.isArray(right)) {
699
+ return false;
700
+ }
701
+ if (left.length !== right.length) {
702
+ return false;
703
+ }
704
+ return left.every(
705
+ (leftValue, index) => areValuesEquivalent(leftValue, right[index], seen)
706
+ );
707
+ }
708
+ if (Object.getPrototypeOf(left) !== Object.getPrototypeOf(right)) {
709
+ return false;
710
+ }
711
+ const leftRecord = left;
712
+ const rightRecord = right;
713
+ const leftKeys = Reflect.ownKeys(leftRecord);
714
+ const rightKeys = Reflect.ownKeys(rightRecord);
715
+ if (leftKeys.length !== rightKeys.length) {
716
+ return false;
717
+ }
718
+ return leftKeys.every((key) => {
719
+ if (!Object.prototype.hasOwnProperty.call(rightRecord, key)) {
720
+ return false;
721
+ }
722
+ return areValuesEquivalent(leftRecord[key], rightRecord[key], seen);
723
+ });
724
+ }
725
+ function areStoreMessageRecordsEquivalent(sourceRecord, cachedRecord) {
726
+ return sourceRecord.id === cachedRecord.id && sourceRecord.status === cachedRecord.status && sourceRecord.attempts === cachedRecord.attempts && sourceRecord.createdAt === cachedRecord.createdAt && sourceRecord.lastAttemptedAt === cachedRecord.lastAttemptedAt && sourceRecord.acknowledgedAt === cachedRecord.acknowledgedAt && sourceRecord.error === cachedRecord.error && areValuesEquivalent(sourceRecord.message, cachedRecord.message);
727
+ }
728
+ function createStableReadonlyCollection(items) {
729
+ return Object.freeze([...items]);
730
+ }
731
+ function appendStableReadonlyCollectionItem(input) {
732
+ return createStableReadonlyCollection([...input.items, input.item]);
733
+ }
734
+ function upsertStableReadonlyCollectionItem(input) {
735
+ const existingIndex = input.items.findIndex(
736
+ (candidate) => candidate.id === input.item.id
737
+ );
738
+ if (existingIndex === -1) {
739
+ return appendStableReadonlyCollectionItem(input);
740
+ }
741
+ if (Object.is(input.items[existingIndex], input.item)) {
742
+ return input.items;
743
+ }
744
+ const nextItems = [...input.items];
745
+ nextItems[existingIndex] = input.item;
746
+ return createStableReadonlyCollection(nextItems);
747
+ }
748
+ function syncStableReadonlyCollectionById(input) {
749
+ const cachedItemsById = /* @__PURE__ */ new Map();
750
+ input.items.forEach((item) => {
751
+ cachedItemsById.set(item.id, item);
752
+ });
753
+ let didChange = input.items.length !== input.sourceItems.length;
754
+ const nextItems = input.sourceItems.map((sourceItem, index) => {
755
+ const cachedItem = cachedItemsById.get(input.getSourceId(sourceItem));
756
+ const nextItem = cachedItem && input.areEquivalent(sourceItem, cachedItem) ? cachedItem : input.createItem(sourceItem);
757
+ if (!didChange && input.items[index] !== nextItem) {
758
+ didChange = true;
759
+ }
760
+ return nextItem;
761
+ });
762
+ return didChange ? createStableReadonlyCollection(nextItems) : input.items;
763
+ }
764
+ function createStoreHistory(config) {
765
+ const messageChannel = config.channel ?? createInMemoryStoreMessageChannel();
766
+ const clock = config.clock ?? Date.now;
767
+ let history = [
768
+ {
769
+ id: null,
770
+ index: 0,
771
+ message: null,
399
772
  snapshot: config.captureSnapshot(),
400
773
  acknowledgedAt: null
401
774
  }
402
775
  ];
403
776
  let currentIndex = 0;
777
+ let historyCollection = createStableReadonlyCollection(
778
+ history.map((entry) => cloneValue(entry))
779
+ );
780
+ let messageCollection = createStableReadonlyCollection(
781
+ messageChannel.getMessages().map((record) => cloneValue(record))
782
+ );
783
+ const version = signal(0);
784
+ function notifyVersion() {
785
+ version.update((v) => v + 1);
786
+ }
404
787
  function recordSnapshot(record) {
405
788
  const nextIndex = history.length;
406
- history = [
407
- ...history,
408
- {
409
- id: record.id,
410
- index: nextIndex,
411
- message: cloneValue(record.message),
412
- snapshot: config.captureSnapshot(),
413
- acknowledgedAt: record.acknowledgedAt
414
- }
415
- ];
789
+ const nextHistoryEntry = {
790
+ id: record.id,
791
+ index: nextIndex,
792
+ message: cloneValue(record.message),
793
+ snapshot: config.captureSnapshot(),
794
+ acknowledgedAt: record.acknowledgedAt
795
+ };
796
+ history = [...history, nextHistoryEntry];
797
+ historyCollection = appendStableReadonlyCollectionItem({
798
+ items: historyCollection,
799
+ item: cloneValue(nextHistoryEntry)
800
+ });
416
801
  currentIndex = nextIndex;
417
802
  }
418
803
  function truncateFutureHistory() {
@@ -420,29 +805,45 @@ function createStoreHistory(config) {
420
805
  return;
421
806
  }
422
807
  history = history.slice(0, currentIndex + 1);
808
+ historyCollection = createStableReadonlyCollection(
809
+ historyCollection.slice(0, currentIndex + 1)
810
+ );
423
811
  }
424
812
  function ensureIndexInRange(index) {
425
813
  if (!Number.isInteger(index) || index < 0 || index >= history.length) {
426
814
  throw new Error(INVALID_HISTORY_INDEX_ERROR);
427
815
  }
428
816
  }
429
- function travelTo(index) {
817
+ function restoreStoreAt(index) {
430
818
  ensureIndexInRange(index);
431
819
  config.applySnapshot(history[index].snapshot);
432
820
  currentIndex = index;
821
+ notifyVersion();
822
+ }
823
+ function restoreResource(key, index) {
824
+ const targetIndex = index !== void 0 ? index : currentIndex;
825
+ ensureIndexInRange(targetIndex);
826
+ const allKeys = new Set(Array.from(config.getAllKeys()));
827
+ if (!allKeys.has(key)) {
828
+ throw new Error(INVALID_STORE_KEY_ERROR);
829
+ }
830
+ const snapshot = history[targetIndex].snapshot;
831
+ const snapshotState = snapshot[key];
832
+ config.applyKeyUpdate(key, snapshotState ?? createDefaultState());
833
+ notifyVersion();
433
834
  }
434
835
  function undo() {
435
836
  if (currentIndex === 0) {
436
837
  return false;
437
838
  }
438
- travelTo(currentIndex - 1);
839
+ restoreStoreAt(currentIndex - 1);
439
840
  return true;
440
841
  }
441
842
  function redo() {
442
843
  if (currentIndex >= history.length - 1) {
443
844
  return false;
444
845
  }
445
- travelTo(currentIndex + 1);
846
+ restoreStoreAt(currentIndex + 1);
446
847
  return true;
447
848
  }
448
849
  function getErrorMessage(error) {
@@ -462,6 +863,10 @@ function createStoreHistory(config) {
462
863
  error
463
864
  };
464
865
  messageChannel.saveMessage(nextRecord);
866
+ messageCollection = upsertStableReadonlyCollectionItem({
867
+ items: messageCollection,
868
+ item: cloneValue(nextRecord)
869
+ });
465
870
  return nextRecord;
466
871
  }
467
872
  function consumeRecord(record, options) {
@@ -485,6 +890,7 @@ function createStoreHistory(config) {
485
890
  truncateFutureHistory();
486
891
  recordSnapshot(acknowledgedRecord);
487
892
  }
893
+ notifyVersion();
488
894
  return true;
489
895
  } catch (error) {
490
896
  persistMessageAttempt(
@@ -496,6 +902,7 @@ function createStoreHistory(config) {
496
902
  getErrorMessage(error),
497
903
  attemptedAt
498
904
  );
905
+ notifyVersion();
499
906
  return false;
500
907
  }
501
908
  }
@@ -539,15 +946,42 @@ function createStoreHistory(config) {
539
946
  });
540
947
  return acknowledgedCount;
541
948
  }
949
+ const historySignal = computed(() => {
950
+ version();
951
+ return historyCollection;
952
+ });
953
+ const messagesSignal = computed(() => {
954
+ version();
955
+ messageCollection = syncStableReadonlyCollectionById({
956
+ items: messageCollection,
957
+ sourceItems: messageChannel.getMessages(),
958
+ getSourceId: (record) => record.id,
959
+ createItem: (record) => cloneValue(record),
960
+ areEquivalent: areStoreMessageRecordsEquivalent
961
+ });
962
+ return messageCollection;
963
+ });
964
+ const currentIndexSignal = computed(() => {
965
+ version();
966
+ return currentIndex;
967
+ });
542
968
  return {
969
+ historySignal,
970
+ messagesSignal,
971
+ currentIndexSignal,
543
972
  publish(message) {
544
973
  const record = messageChannel.publish(message);
974
+ messageCollection = appendStableReadonlyCollectionItem({
975
+ items: messageCollection,
976
+ item: cloneValue(record)
977
+ });
545
978
  return consumeRecord(record);
546
979
  },
547
980
  replay(input) {
548
981
  return replayByIds(input);
549
982
  },
550
- travelTo,
983
+ restoreStoreAt,
984
+ restoreResource,
551
985
  undo,
552
986
  redo,
553
987
  getHistory(key) {
@@ -590,249 +1024,6 @@ function clearAllStores() {
590
1024
  }
591
1025
  }
592
1026
 
593
- // src/store-message-consumer.ts
594
- import {
595
- isKeyedResourceData,
596
- createKeyedResourceData,
597
- isAnyKeyLoading
598
- } from "@flurryx/core";
599
- function createDefaultState() {
600
- return {
601
- data: void 0,
602
- isLoading: false,
603
- status: void 0,
604
- errors: void 0
605
- };
606
- }
607
- function createStoreMessageConsumer(signals, notifier) {
608
- function applyUpdate(key, newState, notify = true) {
609
- const sig = signals.getOrCreate(key);
610
- const previousState = sig();
611
- sig.update((state) => ({ ...state, ...newState }));
612
- if (notify) {
613
- const updatedState = sig();
614
- notifier.notify(key, updatedState, previousState);
615
- }
616
- return true;
617
- }
618
- function applyClear(key) {
619
- const sig = signals.getOrCreate(key);
620
- const previousState = sig();
621
- sig.set(createDefaultState());
622
- const nextState = sig();
623
- notifier.notify(key, nextState, previousState);
624
- return true;
625
- }
626
- function applyClearAll() {
627
- const keys = Array.from(signals.getAllKeys());
628
- if (keys.length === 0) {
629
- return false;
630
- }
631
- keys.forEach((key) => {
632
- applyClear(key);
633
- });
634
- return true;
635
- }
636
- function applyStartLoading(key) {
637
- const sig = signals.getOrCreate(key);
638
- sig.update(
639
- (state) => ({
640
- ...state,
641
- status: void 0,
642
- isLoading: true,
643
- errors: void 0
644
- })
645
- );
646
- return true;
647
- }
648
- function applyStopLoading(key) {
649
- const sig = signals.getOrCreate(key);
650
- sig.update(
651
- (state) => ({
652
- ...state,
653
- isLoading: false
654
- })
655
- );
656
- return true;
657
- }
658
- function applyUpdateKeyedOne(key, resourceKey, entity) {
659
- const sig = signals.getOrCreate(key);
660
- const state = sig();
661
- const data = isKeyedResourceData(state.data) ? state.data : createKeyedResourceData();
662
- const nextErrors = { ...data.errors };
663
- delete nextErrors[resourceKey];
664
- const nextData = {
665
- ...data,
666
- entities: { ...data.entities, [resourceKey]: entity },
667
- isLoading: { ...data.isLoading, [resourceKey]: false },
668
- status: { ...data.status, [resourceKey]: "Success" },
669
- errors: nextErrors
670
- };
671
- return applyUpdate(key, {
672
- data: nextData,
673
- isLoading: isAnyKeyLoading(nextData.isLoading),
674
- status: void 0,
675
- errors: void 0
676
- });
677
- }
678
- function applyClearKeyedOne(key, resourceKey) {
679
- const sig = signals.getOrCreate(key);
680
- const previousState = sig();
681
- const state = previousState;
682
- if (!isKeyedResourceData(state.data)) {
683
- return true;
684
- }
685
- const data = state.data;
686
- const nextEntities = { ...data.entities };
687
- delete nextEntities[resourceKey];
688
- const nextIsLoading = { ...data.isLoading };
689
- delete nextIsLoading[resourceKey];
690
- const nextStatus = { ...data.status };
691
- delete nextStatus[resourceKey];
692
- const nextErrors = { ...data.errors };
693
- delete nextErrors[resourceKey];
694
- const nextData = {
695
- ...data,
696
- entities: nextEntities,
697
- isLoading: nextIsLoading,
698
- status: nextStatus,
699
- errors: nextErrors
700
- };
701
- sig.update(
702
- (prev) => ({
703
- ...prev,
704
- data: nextData,
705
- status: void 0,
706
- isLoading: isAnyKeyLoading(nextIsLoading),
707
- errors: void 0
708
- })
709
- );
710
- const updatedState = sig();
711
- notifier.notify(key, updatedState, previousState);
712
- return true;
713
- }
714
- function applyStartKeyedLoading(key, resourceKey) {
715
- const sig = signals.getOrCreate(key);
716
- const state = sig();
717
- if (!isKeyedResourceData(state.data)) {
718
- return applyStartLoading(key);
719
- }
720
- const previousState = state;
721
- const data = state.data;
722
- const nextIsLoading = {
723
- ...data.isLoading,
724
- [resourceKey]: true
725
- };
726
- const nextStatus = { ...data.status };
727
- delete nextStatus[resourceKey];
728
- const nextErrors = { ...data.errors };
729
- delete nextErrors[resourceKey];
730
- const nextData = {
731
- ...data,
732
- isLoading: nextIsLoading,
733
- status: nextStatus,
734
- errors: nextErrors
735
- };
736
- sig.update(
737
- (previous) => ({
738
- ...previous,
739
- data: nextData,
740
- status: void 0,
741
- isLoading: isAnyKeyLoading(nextIsLoading),
742
- errors: void 0
743
- })
744
- );
745
- const updatedState = sig();
746
- notifier.notify(key, updatedState, previousState);
747
- return true;
748
- }
749
- function applyMessage(message) {
750
- switch (message.type) {
751
- case "update":
752
- return applyUpdate(message.key, cloneValue(message.state));
753
- case "clear":
754
- return applyClear(message.key);
755
- case "clearAll":
756
- return applyClearAll();
757
- case "startLoading":
758
- return applyStartLoading(message.key);
759
- case "stopLoading":
760
- return applyStopLoading(message.key);
761
- case "updateKeyedOne":
762
- return applyUpdateKeyedOne(
763
- message.key,
764
- message.resourceKey,
765
- cloneValue(message.entity)
766
- );
767
- case "clearKeyedOne":
768
- return applyClearKeyedOne(message.key, message.resourceKey);
769
- case "startKeyedLoading":
770
- return applyStartKeyedLoading(message.key, message.resourceKey);
771
- }
772
- }
773
- function applySnapshot(snapshot) {
774
- const keys = /* @__PURE__ */ new Set([
775
- ...Array.from(signals.getAllKeys()),
776
- ...Object.keys(snapshot)
777
- ]);
778
- keys.forEach((rawKey) => {
779
- const key = rawKey;
780
- const sig = signals.getOrCreate(key);
781
- const snapshotState = snapshot[key] ?? createDefaultState();
782
- applyUpdate(key, createSnapshotRestorePatch(sig(), snapshotState), true);
783
- });
784
- }
785
- function captureSnapshot() {
786
- const entries = Array.from(signals.getAllKeys()).map((key) => [
787
- key,
788
- cloneValue(signals.getOrCreate(key)())
789
- ]);
790
- return Object.fromEntries(entries);
791
- }
792
- return {
793
- applyMessage,
794
- applySnapshot,
795
- createSnapshot: captureSnapshot
796
- };
797
- }
798
- function createUpdateMessage(key, state) {
799
- return { type: "update", key, state };
800
- }
801
- function createClearMessage(key) {
802
- return { type: "clear", key };
803
- }
804
- function createClearAllMessage() {
805
- return { type: "clearAll" };
806
- }
807
- function createStartLoadingMessage(key) {
808
- return { type: "startLoading", key };
809
- }
810
- function createStopLoadingMessage(key) {
811
- return { type: "stopLoading", key };
812
- }
813
- function createUpdateKeyedOneMessage(key, resourceKey, entity) {
814
- return {
815
- type: "updateKeyedOne",
816
- key,
817
- resourceKey,
818
- entity
819
- };
820
- }
821
- function createClearKeyedOneMessage(key, resourceKey) {
822
- return {
823
- type: "clearKeyedOne",
824
- key,
825
- resourceKey
826
- };
827
- }
828
- function createStartKeyedLoadingMessage(key, resourceKey) {
829
- return {
830
- type: "startKeyedLoading",
831
- key,
832
- resourceKey
833
- };
834
- }
835
-
836
1027
  // src/base-store.ts
837
1028
  var updateHooksMap = /* @__PURE__ */ new WeakMap();
838
1029
  var BaseStore = class {
@@ -850,48 +1041,64 @@ var BaseStore = class {
850
1041
  notify: (key, next, prev) => this.notifyUpdateHooks(key, next, prev)
851
1042
  }
852
1043
  );
853
- this.history = createStoreHistory({
1044
+ this.historyDriver = createStoreHistory({
854
1045
  captureSnapshot: () => consumer.createSnapshot(),
855
1046
  applySnapshot: (snapshot) => consumer.applySnapshot(snapshot),
1047
+ applyKeyUpdate: (key, snapshotState) => consumer.applyKeyUpdate(key, snapshotState),
1048
+ getAllKeys: () => this.storeKeys,
856
1049
  applyMessage: (message) => consumer.applyMessage(message),
857
1050
  channel: options?.channel
858
1051
  });
1052
+ this.history = this.historyDriver.historySignal;
1053
+ this.messages = this.historyDriver.messagesSignal;
1054
+ this.currentIndex = this.historyDriver.currentIndexSignal;
1055
+ this.keys = signal2([...this.storeKeys]).asReadonly();
859
1056
  trackStore(this);
860
1057
  }
861
1058
  signalsState = /* @__PURE__ */ new Map();
862
1059
  storeKeys;
863
- history;
1060
+ historyDriver;
1061
+ /** @inheritDoc */
1062
+ restoreStoreAt = (index) => this.historyDriver.restoreStoreAt(index);
1063
+ /** @inheritDoc */
1064
+ restoreResource = (key, index) => this.historyDriver.restoreResource(key, index);
1065
+ /** @inheritDoc */
1066
+ undo = () => this.historyDriver.undo();
864
1067
  /** @inheritDoc */
865
- travelTo = (index) => this.history.travelTo(index);
1068
+ redo = () => this.historyDriver.redo();
866
1069
  /** @inheritDoc */
867
- undo = () => this.history.undo();
1070
+ getDeadLetters = () => this.historyDriver.getDeadLetters();
868
1071
  /** @inheritDoc */
869
- redo = () => this.history.redo();
1072
+ replayDeadLetter = (id) => this.historyDriver.replayDeadLetter(id);
870
1073
  /** @inheritDoc */
871
- getDeadLetters = () => this.history.getDeadLetters();
1074
+ replayDeadLetters = () => this.historyDriver.replayDeadLetters();
872
1075
  /** @inheritDoc */
873
- replayDeadLetter = (id) => this.history.replayDeadLetter(id);
1076
+ getCurrentIndex = () => this.historyDriver.getCurrentIndex();
874
1077
  /** @inheritDoc */
875
- replayDeadLetters = () => this.history.replayDeadLetters();
1078
+ history;
1079
+ /** @inheritDoc */
1080
+ messages;
1081
+ /** @inheritDoc */
1082
+ currentIndex;
876
1083
  /** @inheritDoc */
877
- getCurrentIndex = () => this.history.getCurrentIndex();
1084
+ keys;
878
1085
  replay(idOrIds) {
879
1086
  if (Array.isArray(idOrIds)) {
880
- return this.history.replay(idOrIds);
1087
+ return this.historyDriver.replay(idOrIds);
881
1088
  }
882
- return this.history.replay(idOrIds);
1089
+ return this.historyDriver.replay(idOrIds);
883
1090
  }
884
1091
  getHistory(key) {
885
1092
  if (key === void 0) {
886
- return this.history.getHistory();
1093
+ return this.historyDriver.getHistory();
887
1094
  }
888
- return this.history.getHistory(key);
1095
+ return this.historyDriver.getHistory(key);
889
1096
  }
890
1097
  getMessages(key) {
891
1098
  if (key === void 0) {
892
- return this.history.getMessages();
1099
+ return this.historyDriver.getMessages();
893
1100
  }
894
- return this.history.getMessages(key);
1101
+ return this.historyDriver.getMessages(key);
895
1102
  }
896
1103
  /**
897
1104
  * Returns a **read-only** `Signal` for the given store slot.
@@ -937,13 +1144,13 @@ var BaseStore = class {
937
1144
  * @param newState - Partial state to merge (e.g. `{ data: newData, status: 'Success' }`).
938
1145
  */
939
1146
  update(key, newState) {
940
- this.history.publish(
1147
+ this.historyDriver.publish(
941
1148
  createUpdateMessage(key, cloneValue(newState))
942
1149
  );
943
1150
  }
944
1151
  /** Resets every slot in this store to its initial idle state. */
945
1152
  clearAll() {
946
- this.history.publish(createClearAllMessage());
1153
+ this.historyDriver.publish(createClearAllMessage());
947
1154
  }
948
1155
  /**
949
1156
  * Resets a single slot to `{ data: undefined, isLoading: false, status: undefined, errors: undefined }`.
@@ -951,7 +1158,7 @@ var BaseStore = class {
951
1158
  * @param key - The slot to clear.
952
1159
  */
953
1160
  clear(key) {
954
- this.history.publish(createClearMessage(key));
1161
+ this.historyDriver.publish(createClearMessage(key));
955
1162
  }
956
1163
  /**
957
1164
  * Marks a slot as loading: sets `isLoading: true` and clears `status` and `errors`.
@@ -959,7 +1166,7 @@ var BaseStore = class {
959
1166
  * @param key - The slot to mark as loading.
960
1167
  */
961
1168
  startLoading(key) {
962
- this.history.publish(createStartLoadingMessage(key));
1169
+ this.historyDriver.publish(createStartLoadingMessage(key));
963
1170
  }
964
1171
  /**
965
1172
  * Marks a slot as no longer loading: sets `isLoading: false`.
@@ -968,7 +1175,7 @@ var BaseStore = class {
968
1175
  * @param key - The slot to stop loading.
969
1176
  */
970
1177
  stopLoading(key) {
971
- this.history.publish(createStopLoadingMessage(key));
1178
+ this.historyDriver.publish(createStopLoadingMessage(key));
972
1179
  }
973
1180
  /**
974
1181
  * Merges a single entity into a {@link KeyedResourceData} slot.
@@ -980,7 +1187,7 @@ var BaseStore = class {
980
1187
  * @param entity - The entity value to store.
981
1188
  */
982
1189
  updateKeyedOne(key, resourceKey, entity) {
983
- this.history.publish(
1190
+ this.historyDriver.publish(
984
1191
  createUpdateKeyedOneMessage(
985
1192
  key,
986
1193
  resourceKey,
@@ -997,7 +1204,7 @@ var BaseStore = class {
997
1204
  * @param resourceKey - The entity identifier to remove.
998
1205
  */
999
1206
  clearKeyedOne(key, resourceKey) {
1000
- this.history.publish(
1207
+ this.historyDriver.publish(
1001
1208
  createClearKeyedOneMessage(key, resourceKey)
1002
1209
  );
1003
1210
  }
@@ -1010,7 +1217,7 @@ var BaseStore = class {
1010
1217
  * @param resourceKey - The entity identifier to mark as loading.
1011
1218
  */
1012
1219
  startKeyedLoading(key, resourceKey) {
1013
- this.history.publish(
1220
+ this.historyDriver.publish(
1014
1221
  createStartKeyedLoadingMessage(key, resourceKey)
1015
1222
  );
1016
1223
  }
@@ -1047,49 +1254,59 @@ var BaseStore = class {
1047
1254
  this.storeKeys.forEach((key) => {
1048
1255
  this.signalsState.set(
1049
1256
  key,
1050
- signal(createDefaultState())
1257
+ signal2(createDefaultState())
1051
1258
  );
1052
1259
  });
1053
1260
  }
1054
1261
  };
1055
1262
 
1056
1263
  // src/lazy-store.ts
1057
- import { signal as signal2 } from "@angular/core";
1264
+ import { signal as signal3 } from "@angular/core";
1058
1265
  var LazyStore = class {
1059
1266
  signals = /* @__PURE__ */ new Map();
1060
1267
  hooks = /* @__PURE__ */ new Map();
1061
- history;
1268
+ historyDriver;
1062
1269
  /** @inheritDoc */
1063
- travelTo = (index) => this.history.travelTo(index);
1270
+ restoreStoreAt = (index) => this.historyDriver.restoreStoreAt(index);
1064
1271
  /** @inheritDoc */
1065
- undo = () => this.history.undo();
1272
+ restoreResource = (key, index) => this.historyDriver.restoreResource(key, index);
1066
1273
  /** @inheritDoc */
1067
- redo = () => this.history.redo();
1274
+ undo = () => this.historyDriver.undo();
1275
+ /** @inheritDoc */
1276
+ redo = () => this.historyDriver.redo();
1068
1277
  getMessages(key) {
1069
1278
  if (key === void 0) {
1070
- return this.history.getMessages();
1279
+ return this.historyDriver.getMessages();
1071
1280
  }
1072
- return this.history.getMessages(key);
1281
+ return this.historyDriver.getMessages(key);
1073
1282
  }
1283
+ getDeadLetters = () => this.historyDriver.getDeadLetters();
1284
+ /** @inheritDoc */
1285
+ replayDeadLetter = (id) => this.historyDriver.replayDeadLetter(id);
1286
+ /** @inheritDoc */
1287
+ replayDeadLetters = () => this.historyDriver.replayDeadLetters();
1074
1288
  /** @inheritDoc */
1075
- getDeadLetters = () => this.history.getDeadLetters();
1289
+ getCurrentIndex = () => this.historyDriver.getCurrentIndex();
1290
+ /** @inheritDoc */
1291
+ history;
1076
1292
  /** @inheritDoc */
1077
- replayDeadLetter = (id) => this.history.replayDeadLetter(id);
1293
+ messages;
1078
1294
  /** @inheritDoc */
1079
- replayDeadLetters = () => this.history.replayDeadLetters();
1295
+ currentIndex;
1080
1296
  /** @inheritDoc */
1081
- getCurrentIndex = () => this.history.getCurrentIndex();
1297
+ keys;
1298
+ keysSignal = signal3([]);
1082
1299
  replay(idOrIds) {
1083
1300
  if (Array.isArray(idOrIds)) {
1084
- return this.history.replay(idOrIds);
1301
+ return this.historyDriver.replay(idOrIds);
1085
1302
  }
1086
- return this.history.replay(idOrIds);
1303
+ return this.historyDriver.replay(idOrIds);
1087
1304
  }
1088
1305
  getHistory(key) {
1089
1306
  if (key === void 0) {
1090
- return this.history.getHistory();
1307
+ return this.historyDriver.getHistory();
1091
1308
  }
1092
- return this.history.getHistory(key);
1309
+ return this.historyDriver.getHistory(key);
1093
1310
  }
1094
1311
  constructor(options) {
1095
1312
  const consumer = createStoreMessageConsumer(
@@ -1101,19 +1318,26 @@ var LazyStore = class {
1101
1318
  notify: (key, next, prev) => this.notifyHooks(key, next, prev)
1102
1319
  }
1103
1320
  );
1104
- this.history = createStoreHistory({
1321
+ this.historyDriver = createStoreHistory({
1105
1322
  captureSnapshot: () => consumer.createSnapshot(),
1106
1323
  applySnapshot: (snapshot) => consumer.applySnapshot(snapshot),
1324
+ applyKeyUpdate: (key, snapshotState) => consumer.applyKeyUpdate(key, snapshotState),
1325
+ getAllKeys: () => this.signals.keys(),
1107
1326
  applyMessage: (message) => consumer.applyMessage(message),
1108
1327
  channel: options?.channel
1109
1328
  });
1329
+ this.history = this.historyDriver.historySignal;
1330
+ this.messages = this.historyDriver.messagesSignal;
1331
+ this.currentIndex = this.historyDriver.currentIndexSignal;
1332
+ this.keys = this.keysSignal.asReadonly();
1110
1333
  trackStore(this);
1111
1334
  }
1112
1335
  getOrCreate(key) {
1113
1336
  let sig = this.signals.get(key);
1114
1337
  if (!sig) {
1115
- sig = signal2(createDefaultState());
1338
+ sig = signal3(createDefaultState());
1116
1339
  this.signals.set(key, sig);
1340
+ this.keysSignal.update((prev) => [...prev, key]);
1117
1341
  }
1118
1342
  return sig;
1119
1343
  }
@@ -1123,29 +1347,29 @@ var LazyStore = class {
1123
1347
  }
1124
1348
  /** @inheritDoc */
1125
1349
  update(key, newState) {
1126
- this.history.publish(
1350
+ this.historyDriver.publish(
1127
1351
  createUpdateMessage(key, cloneValue(newState))
1128
1352
  );
1129
1353
  }
1130
1354
  /** @inheritDoc */
1131
1355
  clear(key) {
1132
- this.history.publish(createClearMessage(key));
1356
+ this.historyDriver.publish(createClearMessage(key));
1133
1357
  }
1134
1358
  /** @inheritDoc */
1135
1359
  clearAll() {
1136
- this.history.publish(createClearAllMessage());
1360
+ this.historyDriver.publish(createClearAllMessage());
1137
1361
  }
1138
1362
  /** @inheritDoc */
1139
1363
  startLoading(key) {
1140
- this.history.publish(createStartLoadingMessage(key));
1364
+ this.historyDriver.publish(createStartLoadingMessage(key));
1141
1365
  }
1142
1366
  /** @inheritDoc */
1143
1367
  stopLoading(key) {
1144
- this.history.publish(createStopLoadingMessage(key));
1368
+ this.historyDriver.publish(createStopLoadingMessage(key));
1145
1369
  }
1146
1370
  /** @inheritDoc */
1147
1371
  updateKeyedOne(key, resourceKey, entity) {
1148
- this.history.publish(
1372
+ this.historyDriver.publish(
1149
1373
  createUpdateKeyedOneMessage(
1150
1374
  key,
1151
1375
  resourceKey,
@@ -1155,13 +1379,13 @@ var LazyStore = class {
1155
1379
  }
1156
1380
  /** @inheritDoc */
1157
1381
  clearKeyedOne(key, resourceKey) {
1158
- this.history.publish(
1382
+ this.historyDriver.publish(
1159
1383
  createClearKeyedOneMessage(key, resourceKey)
1160
1384
  );
1161
1385
  }
1162
1386
  /** @inheritDoc */
1163
1387
  startKeyedLoading(key, resourceKey) {
1164
- this.history.publish(
1388
+ this.historyDriver.publish(
1165
1389
  createStartKeyedLoadingMessage(key, resourceKey)
1166
1390
  );
1167
1391
  }
@@ -1594,6 +1818,7 @@ function createStoreFor(enumObj) {
1594
1818
  }
1595
1819
  export {
1596
1820
  BaseStore,
1821
+ INVALID_STORE_KEY_ERROR,
1597
1822
  LazyStore,
1598
1823
  Store,
1599
1824
  clearAllStores,