@flurryx/store 0.8.3 → 1.0.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.cjs +1088 -297
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +715 -18
- package/dist/index.d.ts +715 -18
- package/dist/index.js +1072 -292
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,97 +1,641 @@
|
|
|
1
1
|
// src/base-store.ts
|
|
2
2
|
import { signal } from "@angular/core";
|
|
3
|
-
import {
|
|
4
|
-
isAnyKeyLoading,
|
|
5
|
-
isKeyedResourceData,
|
|
6
|
-
createKeyedResourceData
|
|
7
|
-
} from "@flurryx/core";
|
|
8
3
|
|
|
9
|
-
// src/store-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
4
|
+
// src/store-clone.ts
|
|
5
|
+
function cloneValue(value) {
|
|
6
|
+
if (value !== null && typeof value === "object") {
|
|
7
|
+
const existingClone = cloneReference(value, /* @__PURE__ */ new WeakMap());
|
|
8
|
+
return existingClone;
|
|
9
|
+
}
|
|
10
|
+
return value;
|
|
13
11
|
}
|
|
14
|
-
function
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
function cloneReference(value, seen) {
|
|
13
|
+
const seenClone = seen.get(value);
|
|
14
|
+
if (seenClone) {
|
|
15
|
+
return seenClone;
|
|
16
|
+
}
|
|
17
|
+
if (value instanceof Date) {
|
|
18
|
+
return new Date(value.getTime());
|
|
19
|
+
}
|
|
20
|
+
if (value instanceof Map) {
|
|
21
|
+
const clonedMap = /* @__PURE__ */ new Map();
|
|
22
|
+
seen.set(value, clonedMap);
|
|
23
|
+
value.forEach((entryValue, key) => {
|
|
24
|
+
clonedMap.set(
|
|
25
|
+
cloneValueWithSeen(key, seen),
|
|
26
|
+
cloneValueWithSeen(entryValue, seen)
|
|
27
|
+
);
|
|
28
|
+
});
|
|
29
|
+
return clonedMap;
|
|
17
30
|
}
|
|
31
|
+
if (value instanceof Set) {
|
|
32
|
+
const clonedSet = /* @__PURE__ */ new Set();
|
|
33
|
+
seen.set(value, clonedSet);
|
|
34
|
+
value.forEach((entryValue) => {
|
|
35
|
+
clonedSet.add(cloneValueWithSeen(entryValue, seen));
|
|
36
|
+
});
|
|
37
|
+
return clonedSet;
|
|
38
|
+
}
|
|
39
|
+
if (Array.isArray(value)) {
|
|
40
|
+
const clonedArray = [];
|
|
41
|
+
seen.set(value, clonedArray);
|
|
42
|
+
value.forEach((item, index) => {
|
|
43
|
+
clonedArray[index] = cloneValueWithSeen(item, seen);
|
|
44
|
+
});
|
|
45
|
+
return clonedArray;
|
|
46
|
+
}
|
|
47
|
+
const clonedObject = Object.create(Object.getPrototypeOf(value));
|
|
48
|
+
seen.set(value, clonedObject);
|
|
49
|
+
Reflect.ownKeys(value).forEach((key) => {
|
|
50
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
51
|
+
if (!descriptor) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if ("value" in descriptor) {
|
|
55
|
+
descriptor.value = cloneValueWithSeen(descriptor.value, seen);
|
|
56
|
+
}
|
|
57
|
+
Object.defineProperty(clonedObject, key, descriptor);
|
|
58
|
+
});
|
|
59
|
+
return clonedObject;
|
|
60
|
+
}
|
|
61
|
+
function cloneValueWithSeen(value, seen) {
|
|
62
|
+
if (value !== null && typeof value === "object") {
|
|
63
|
+
return cloneReference(value, seen);
|
|
64
|
+
}
|
|
65
|
+
return value;
|
|
66
|
+
}
|
|
67
|
+
function createSnapshotRestorePatch(currentState, snapshotState) {
|
|
68
|
+
const patch = {};
|
|
69
|
+
const keys = /* @__PURE__ */ new Set([
|
|
70
|
+
...Reflect.ownKeys(currentState),
|
|
71
|
+
...Reflect.ownKeys(snapshotState)
|
|
72
|
+
]);
|
|
73
|
+
keys.forEach((key) => {
|
|
74
|
+
if (Object.prototype.hasOwnProperty.call(snapshotState, key)) {
|
|
75
|
+
patch[key] = cloneValue(
|
|
76
|
+
snapshotState[key]
|
|
77
|
+
);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
patch[key] = void 0;
|
|
81
|
+
});
|
|
82
|
+
return patch;
|
|
18
83
|
}
|
|
19
84
|
|
|
20
|
-
// src/
|
|
21
|
-
var
|
|
22
|
-
var
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
85
|
+
// src/store-messages.ts
|
|
86
|
+
var INVALID_HISTORY_INDEX_ERROR = "History index is out of range";
|
|
87
|
+
var INVALID_HISTORY_MESSAGE_ID_ERROR = "History message id is out of range";
|
|
88
|
+
var MESSAGE_NOT_ACKNOWLEDGED_ERROR = "Message was not acknowledged";
|
|
89
|
+
|
|
90
|
+
// src/store-channels.ts
|
|
91
|
+
function serializeStoreMessageChannelValue(value) {
|
|
92
|
+
if (value === void 0) {
|
|
93
|
+
return { __flurryxType: "undefined" };
|
|
28
94
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
return this.signalsState.get(key.toString());
|
|
95
|
+
if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
96
|
+
return value;
|
|
32
97
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
98
|
+
if (value instanceof Date) {
|
|
99
|
+
return {
|
|
100
|
+
__flurryxType: "date",
|
|
101
|
+
value: value.toISOString()
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
if (value instanceof Map) {
|
|
105
|
+
return {
|
|
106
|
+
__flurryxType: "map",
|
|
107
|
+
entries: Array.from(value.entries(), ([key, entryValue]) => [
|
|
108
|
+
serializeStoreMessageChannelValue(key),
|
|
109
|
+
serializeStoreMessageChannelValue(entryValue)
|
|
110
|
+
])
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
if (value instanceof Set) {
|
|
114
|
+
return {
|
|
115
|
+
__flurryxType: "set",
|
|
116
|
+
values: Array.from(
|
|
117
|
+
value.values(),
|
|
118
|
+
(entryValue) => serializeStoreMessageChannelValue(entryValue)
|
|
119
|
+
)
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
if (Array.isArray(value)) {
|
|
123
|
+
return {
|
|
124
|
+
__flurryxType: "array",
|
|
125
|
+
values: value.map(
|
|
126
|
+
(entryValue) => serializeStoreMessageChannelValue(entryValue)
|
|
127
|
+
)
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
if (typeof value === "object") {
|
|
131
|
+
return {
|
|
132
|
+
__flurryxType: "object",
|
|
133
|
+
entries: Object.entries(value).map(
|
|
134
|
+
([key, entryValue]) => [
|
|
135
|
+
key,
|
|
136
|
+
serializeStoreMessageChannelValue(entryValue)
|
|
137
|
+
]
|
|
138
|
+
)
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
throw new Error("Store message channel cannot serialize this value");
|
|
142
|
+
}
|
|
143
|
+
function deserializeStoreMessageChannelValue(value) {
|
|
144
|
+
if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
145
|
+
return value;
|
|
146
|
+
}
|
|
147
|
+
switch (value.__flurryxType) {
|
|
148
|
+
case "undefined":
|
|
149
|
+
return void 0;
|
|
150
|
+
case "date":
|
|
151
|
+
return new Date(value.value);
|
|
152
|
+
case "array":
|
|
153
|
+
return value.values.map(
|
|
154
|
+
(entryValue) => deserializeStoreMessageChannelValue(entryValue)
|
|
155
|
+
);
|
|
156
|
+
case "set":
|
|
157
|
+
return new Set(
|
|
158
|
+
value.values.map(
|
|
159
|
+
(entryValue) => deserializeStoreMessageChannelValue(entryValue)
|
|
160
|
+
)
|
|
161
|
+
);
|
|
162
|
+
case "map":
|
|
163
|
+
return new Map(
|
|
164
|
+
value.entries.map(([key, entryValue]) => [
|
|
165
|
+
deserializeStoreMessageChannelValue(key),
|
|
166
|
+
deserializeStoreMessageChannelValue(entryValue)
|
|
167
|
+
])
|
|
168
|
+
);
|
|
169
|
+
case "object": {
|
|
170
|
+
const result = {};
|
|
171
|
+
value.entries.forEach(([key, entryValue]) => {
|
|
172
|
+
result[key] = deserializeStoreMessageChannelValue(entryValue);
|
|
173
|
+
});
|
|
174
|
+
return result;
|
|
37
175
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
function defaultSerializeStoreMessageChannelState(state) {
|
|
179
|
+
return JSON.stringify(serializeStoreMessageChannelValue(state));
|
|
180
|
+
}
|
|
181
|
+
function defaultDeserializeStoreMessageChannelState(value) {
|
|
182
|
+
return deserializeStoreMessageChannelValue(
|
|
183
|
+
JSON.parse(value)
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
function normalizeStoreMessageChannelState(state) {
|
|
187
|
+
const maxId = state.messages.reduce(
|
|
188
|
+
(currentMax, entry) => Math.max(currentMax, entry.id),
|
|
189
|
+
0
|
|
190
|
+
);
|
|
191
|
+
return {
|
|
192
|
+
nextId: Math.max(state.nextId, maxId + 1),
|
|
193
|
+
messages: state.messages.map((entry) => cloneValue(entry))
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
function createInitialStoreMessageRecord(id, message, clock = Date.now) {
|
|
197
|
+
return {
|
|
198
|
+
id,
|
|
199
|
+
message: cloneValue(message),
|
|
200
|
+
status: "pending",
|
|
201
|
+
attempts: 0,
|
|
202
|
+
createdAt: clock(),
|
|
203
|
+
lastAttemptedAt: null,
|
|
204
|
+
acknowledgedAt: null,
|
|
205
|
+
error: null
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
function isQuotaExceededError(error) {
|
|
209
|
+
return error instanceof DOMException && (error.code === 22 || error.code === 1014 || error.name === "QuotaExceededError" || error.name === "NS_ERROR_DOM_QUOTA_REACHED");
|
|
210
|
+
}
|
|
211
|
+
function resolveGlobalStorage(name) {
|
|
212
|
+
const storage = globalThis[name];
|
|
213
|
+
if (!storage) {
|
|
214
|
+
throw new Error(`${name} is not available in this environment`);
|
|
215
|
+
}
|
|
216
|
+
return storage;
|
|
217
|
+
}
|
|
218
|
+
function createInMemoryStoreMessageChannel() {
|
|
219
|
+
let messages = [];
|
|
220
|
+
let nextId = 1;
|
|
221
|
+
return {
|
|
222
|
+
publish(message) {
|
|
223
|
+
const record = createInitialStoreMessageRecord(nextId++, message);
|
|
224
|
+
messages = [...messages, record];
|
|
225
|
+
return cloneValue(record);
|
|
226
|
+
},
|
|
227
|
+
getMessage(id) {
|
|
228
|
+
const record = messages.find((entry) => entry.id === id);
|
|
229
|
+
return record ? cloneValue(record) : void 0;
|
|
230
|
+
},
|
|
231
|
+
getMessages() {
|
|
232
|
+
return messages.map((entry) => cloneValue(entry));
|
|
233
|
+
},
|
|
234
|
+
saveMessage(entry) {
|
|
235
|
+
const record = cloneValue(entry);
|
|
236
|
+
const existingIndex = messages.findIndex(
|
|
237
|
+
(candidate) => candidate.id === record.id
|
|
238
|
+
);
|
|
239
|
+
if (existingIndex === -1) {
|
|
240
|
+
messages = [...messages, record];
|
|
241
|
+
} else {
|
|
242
|
+
messages = messages.map((c, i) => i === existingIndex ? record : c);
|
|
243
|
+
}
|
|
244
|
+
nextId = Math.max(nextId, record.id + 1);
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
function createStorageStoreMessageChannel(options) {
|
|
249
|
+
const serialize = options.serialize ?? defaultSerializeStoreMessageChannelState;
|
|
250
|
+
const deserialize = options.deserialize ?? defaultDeserializeStoreMessageChannelState;
|
|
251
|
+
function readState() {
|
|
252
|
+
const rawState = options.storage.getItem(options.storageKey);
|
|
253
|
+
if (rawState === null) {
|
|
254
|
+
return { nextId: 1, messages: [] };
|
|
255
|
+
}
|
|
256
|
+
try {
|
|
257
|
+
return normalizeStoreMessageChannelState(deserialize(rawState));
|
|
258
|
+
} catch {
|
|
259
|
+
return { nextId: 1, messages: [] };
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
function writeState(state) {
|
|
263
|
+
const normalized = normalizeStoreMessageChannelState(state);
|
|
264
|
+
try {
|
|
265
|
+
options.storage.setItem(options.storageKey, serialize(normalized));
|
|
266
|
+
} catch (error) {
|
|
267
|
+
if (!isQuotaExceededError(error) || normalized.messages.length === 0) {
|
|
268
|
+
throw error;
|
|
269
|
+
}
|
|
270
|
+
let remaining = [...normalized.messages];
|
|
271
|
+
while (remaining.length > 0) {
|
|
272
|
+
remaining = remaining.slice(1);
|
|
273
|
+
try {
|
|
274
|
+
options.storage.setItem(
|
|
275
|
+
options.storageKey,
|
|
276
|
+
serialize({ nextId: normalized.nextId, messages: remaining })
|
|
277
|
+
);
|
|
278
|
+
return;
|
|
279
|
+
} catch (retryError) {
|
|
280
|
+
if (!isQuotaExceededError(retryError)) {
|
|
281
|
+
throw retryError;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
options.storage.setItem(
|
|
286
|
+
options.storageKey,
|
|
287
|
+
serialize({ nextId: normalized.nextId, messages: [] })
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
return {
|
|
292
|
+
publish(message) {
|
|
293
|
+
const state = readState();
|
|
294
|
+
const record = createInitialStoreMessageRecord(state.nextId, message);
|
|
295
|
+
writeState({
|
|
296
|
+
nextId: state.nextId + 1,
|
|
297
|
+
messages: [...state.messages, record]
|
|
298
|
+
});
|
|
299
|
+
return cloneValue(record);
|
|
300
|
+
},
|
|
301
|
+
getMessage(id) {
|
|
302
|
+
const record = readState().messages.find((entry) => entry.id === id);
|
|
303
|
+
return record ? cloneValue(record) : void 0;
|
|
304
|
+
},
|
|
305
|
+
getMessages() {
|
|
306
|
+
return readState().messages.map((entry) => cloneValue(entry));
|
|
307
|
+
},
|
|
308
|
+
saveMessage(entry) {
|
|
309
|
+
const state = readState();
|
|
310
|
+
const record = cloneValue(entry);
|
|
311
|
+
const existingIndex = state.messages.findIndex(
|
|
312
|
+
(candidate) => candidate.id === record.id
|
|
313
|
+
);
|
|
314
|
+
if (existingIndex === -1) {
|
|
315
|
+
writeState({
|
|
316
|
+
nextId: Math.max(state.nextId, record.id + 1),
|
|
317
|
+
messages: [...state.messages, record]
|
|
318
|
+
});
|
|
44
319
|
return;
|
|
45
320
|
}
|
|
46
|
-
const
|
|
47
|
-
|
|
321
|
+
const nextMessages = state.messages.map(
|
|
322
|
+
(c, i) => i === existingIndex ? record : c
|
|
48
323
|
);
|
|
49
|
-
|
|
50
|
-
|
|
324
|
+
writeState({
|
|
325
|
+
nextId: Math.max(state.nextId, record.id + 1),
|
|
326
|
+
messages: nextMessages
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
function createLocalStorageStoreMessageChannel(options) {
|
|
332
|
+
return createStorageStoreMessageChannel({
|
|
333
|
+
...options,
|
|
334
|
+
storage: options.storage ?? resolveGlobalStorage("localStorage")
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
function createSessionStorageStoreMessageChannel(options) {
|
|
338
|
+
return createStorageStoreMessageChannel({
|
|
339
|
+
...options,
|
|
340
|
+
storage: options.storage ?? resolveGlobalStorage("sessionStorage")
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
function createCompositeStoreMessageChannel(options) {
|
|
344
|
+
if (options.channels.length === 0) {
|
|
345
|
+
throw new Error(
|
|
346
|
+
"createCompositeStoreMessageChannel: 'channels' option must contain at least one channel"
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
const primaryChannel = options.channels[0];
|
|
350
|
+
const replicaChannels = options.channels.slice(1);
|
|
351
|
+
return {
|
|
352
|
+
publish(message) {
|
|
353
|
+
const record = primaryChannel.publish(message);
|
|
354
|
+
replicaChannels.forEach((channel) => {
|
|
355
|
+
channel.saveMessage(record);
|
|
356
|
+
});
|
|
357
|
+
return cloneValue(record);
|
|
358
|
+
},
|
|
359
|
+
getMessage(id) {
|
|
360
|
+
const record = primaryChannel.getMessage(id);
|
|
361
|
+
return record ? cloneValue(record) : void 0;
|
|
362
|
+
},
|
|
363
|
+
getMessages() {
|
|
364
|
+
return primaryChannel.getMessages().map((record) => cloneValue(record));
|
|
365
|
+
},
|
|
366
|
+
saveMessage(entry) {
|
|
367
|
+
primaryChannel.saveMessage(entry);
|
|
368
|
+
replicaChannels.forEach((channel) => {
|
|
369
|
+
channel.saveMessage(entry);
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// src/store-replay.ts
|
|
376
|
+
function messageAffectsKey(message, key) {
|
|
377
|
+
if (message.type === "clearAll") {
|
|
378
|
+
return true;
|
|
379
|
+
}
|
|
380
|
+
return "key" in message && message.key === key;
|
|
381
|
+
}
|
|
382
|
+
function toDeadLetterEntry(record) {
|
|
383
|
+
return {
|
|
384
|
+
id: record.id,
|
|
385
|
+
message: cloneValue(record.message),
|
|
386
|
+
attempts: record.attempts,
|
|
387
|
+
error: record.error ?? MESSAGE_NOT_ACKNOWLEDGED_ERROR,
|
|
388
|
+
failedAt: record.lastAttemptedAt ?? record.createdAt
|
|
389
|
+
};
|
|
390
|
+
}
|
|
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,
|
|
399
|
+
snapshot: config.captureSnapshot(),
|
|
400
|
+
acknowledgedAt: null
|
|
401
|
+
}
|
|
402
|
+
];
|
|
403
|
+
let currentIndex = 0;
|
|
404
|
+
function recordSnapshot(record) {
|
|
405
|
+
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
|
|
51
414
|
}
|
|
52
|
-
|
|
415
|
+
];
|
|
416
|
+
currentIndex = nextIndex;
|
|
53
417
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if (!currentState) {
|
|
418
|
+
function truncateFutureHistory() {
|
|
419
|
+
if (currentIndex === history.length - 1) {
|
|
57
420
|
return;
|
|
58
421
|
}
|
|
59
|
-
|
|
60
|
-
currentState.update((state) => ({
|
|
61
|
-
...state,
|
|
62
|
-
...newState
|
|
63
|
-
}));
|
|
64
|
-
const updatedState = currentState();
|
|
65
|
-
this.notifyUpdateHooks(key, updatedState, previousState);
|
|
422
|
+
history = history.slice(0, currentIndex + 1);
|
|
66
423
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
424
|
+
function ensureIndexInRange(index) {
|
|
425
|
+
if (!Number.isInteger(index) || index < 0 || index >= history.length) {
|
|
426
|
+
throw new Error(INVALID_HISTORY_INDEX_ERROR);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
function travelTo(index) {
|
|
430
|
+
ensureIndexInRange(index);
|
|
431
|
+
config.applySnapshot(history[index].snapshot);
|
|
432
|
+
currentIndex = index;
|
|
433
|
+
}
|
|
434
|
+
function undo() {
|
|
435
|
+
if (currentIndex === 0) {
|
|
436
|
+
return false;
|
|
437
|
+
}
|
|
438
|
+
travelTo(currentIndex - 1);
|
|
439
|
+
return true;
|
|
440
|
+
}
|
|
441
|
+
function redo() {
|
|
442
|
+
if (currentIndex >= history.length - 1) {
|
|
443
|
+
return false;
|
|
444
|
+
}
|
|
445
|
+
travelTo(currentIndex + 1);
|
|
446
|
+
return true;
|
|
447
|
+
}
|
|
448
|
+
function getErrorMessage(error) {
|
|
449
|
+
if (error instanceof Error && error.message) {
|
|
450
|
+
return error.message;
|
|
451
|
+
}
|
|
452
|
+
return MESSAGE_NOT_ACKNOWLEDGED_ERROR;
|
|
453
|
+
}
|
|
454
|
+
function persistMessageAttempt(record, status, error, attemptedAt) {
|
|
455
|
+
const nextRecord = {
|
|
456
|
+
...record,
|
|
457
|
+
message: cloneValue(record.message),
|
|
458
|
+
status,
|
|
459
|
+
attempts: record.attempts + 1,
|
|
460
|
+
lastAttemptedAt: attemptedAt,
|
|
461
|
+
acknowledgedAt: status === "acknowledged" ? attemptedAt : record.acknowledgedAt,
|
|
462
|
+
error
|
|
463
|
+
};
|
|
464
|
+
messageChannel.saveMessage(nextRecord);
|
|
465
|
+
return nextRecord;
|
|
466
|
+
}
|
|
467
|
+
function consumeRecord(record, options) {
|
|
468
|
+
const clonedMessage = cloneValue(record.message);
|
|
469
|
+
const attemptedAt = clock();
|
|
470
|
+
try {
|
|
471
|
+
const acknowledged = config.applyMessage(clonedMessage);
|
|
472
|
+
if (!acknowledged) {
|
|
473
|
+
throw new Error(MESSAGE_NOT_ACKNOWLEDGED_ERROR);
|
|
474
|
+
}
|
|
475
|
+
const acknowledgedRecord = persistMessageAttempt(
|
|
476
|
+
{
|
|
477
|
+
...record,
|
|
478
|
+
message: clonedMessage
|
|
479
|
+
},
|
|
480
|
+
"acknowledged",
|
|
481
|
+
null,
|
|
482
|
+
attemptedAt
|
|
483
|
+
);
|
|
484
|
+
if (options?.recordHistory !== false) {
|
|
485
|
+
truncateFutureHistory();
|
|
486
|
+
recordSnapshot(acknowledgedRecord);
|
|
487
|
+
}
|
|
488
|
+
return true;
|
|
489
|
+
} catch (error) {
|
|
490
|
+
persistMessageAttempt(
|
|
491
|
+
{
|
|
492
|
+
...record,
|
|
493
|
+
message: clonedMessage
|
|
494
|
+
},
|
|
495
|
+
"dead-letter",
|
|
496
|
+
getErrorMessage(error),
|
|
497
|
+
attemptedAt
|
|
498
|
+
);
|
|
499
|
+
return false;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
function resolveReplayRecords(ids) {
|
|
503
|
+
return ids.map((id) => {
|
|
504
|
+
if (!Number.isInteger(id) || id < 1) {
|
|
505
|
+
throw new Error(INVALID_HISTORY_MESSAGE_ID_ERROR);
|
|
506
|
+
}
|
|
507
|
+
const record = messageChannel.getMessage(id);
|
|
508
|
+
if (!record) {
|
|
509
|
+
throw new Error(INVALID_HISTORY_MESSAGE_ID_ERROR);
|
|
510
|
+
}
|
|
511
|
+
return cloneValue(record);
|
|
70
512
|
});
|
|
71
513
|
}
|
|
72
|
-
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
514
|
+
function replayByIds(input) {
|
|
515
|
+
const ids = Array.isArray(input) ? input : [input];
|
|
516
|
+
const records = resolveReplayRecords(ids);
|
|
517
|
+
let acknowledgedCount = 0;
|
|
518
|
+
records.forEach((record) => {
|
|
519
|
+
if (consumeRecord(record)) {
|
|
520
|
+
acknowledgedCount += 1;
|
|
521
|
+
}
|
|
522
|
+
});
|
|
523
|
+
return acknowledgedCount;
|
|
524
|
+
}
|
|
525
|
+
function replayDeadLetter(id) {
|
|
526
|
+
const record = messageChannel.getMessage(id);
|
|
527
|
+
if (!record || record.status !== "dead-letter") {
|
|
528
|
+
return false;
|
|
76
529
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
530
|
+
return consumeRecord(record);
|
|
531
|
+
}
|
|
532
|
+
function replayDeadLetters() {
|
|
533
|
+
const ids = messageChannel.getMessages().filter((record) => record.status === "dead-letter").map((record) => record.id);
|
|
534
|
+
let acknowledgedCount = 0;
|
|
535
|
+
ids.forEach((id) => {
|
|
536
|
+
if (replayDeadLetter(id)) {
|
|
537
|
+
acknowledgedCount += 1;
|
|
538
|
+
}
|
|
84
539
|
});
|
|
85
|
-
|
|
86
|
-
this.notifyUpdateHooks(key, nextState, previousState);
|
|
540
|
+
return acknowledgedCount;
|
|
87
541
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
return;
|
|
542
|
+
return {
|
|
543
|
+
publish(message) {
|
|
544
|
+
const record = messageChannel.publish(message);
|
|
545
|
+
return consumeRecord(record);
|
|
546
|
+
},
|
|
547
|
+
replay(input) {
|
|
548
|
+
return replayByIds(input);
|
|
549
|
+
},
|
|
550
|
+
travelTo,
|
|
551
|
+
undo,
|
|
552
|
+
redo,
|
|
553
|
+
getHistory(key) {
|
|
554
|
+
if (key === void 0) {
|
|
555
|
+
return history.map((entry) => cloneValue(entry));
|
|
556
|
+
}
|
|
557
|
+
return history.filter((entry) => {
|
|
558
|
+
if (entry.message === null) {
|
|
559
|
+
return true;
|
|
560
|
+
}
|
|
561
|
+
return messageAffectsKey(entry.message, key);
|
|
562
|
+
}).map((entry) => cloneValue(entry));
|
|
563
|
+
},
|
|
564
|
+
getMessages(key) {
|
|
565
|
+
const records = messageChannel.getMessages();
|
|
566
|
+
if (key === void 0) {
|
|
567
|
+
return records.map((record) => cloneValue(record));
|
|
568
|
+
}
|
|
569
|
+
return records.filter((record) => messageAffectsKey(record.message, key)).map((record) => cloneValue(record));
|
|
570
|
+
},
|
|
571
|
+
getDeadLetters() {
|
|
572
|
+
return messageChannel.getMessages().filter((record) => record.status === "dead-letter").map((record) => toDeadLetterEntry(record));
|
|
573
|
+
},
|
|
574
|
+
replayDeadLetter,
|
|
575
|
+
replayDeadLetters,
|
|
576
|
+
getCurrentIndex() {
|
|
577
|
+
return currentIndex;
|
|
578
|
+
}
|
|
579
|
+
};
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
// src/store-registry.ts
|
|
583
|
+
var trackedStores = /* @__PURE__ */ new Set();
|
|
584
|
+
function trackStore(store) {
|
|
585
|
+
trackedStores.add(store);
|
|
586
|
+
}
|
|
587
|
+
function clearAllStores() {
|
|
588
|
+
for (const store of [...trackedStores]) {
|
|
589
|
+
store.clearAll();
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
|
|
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);
|
|
92
615
|
}
|
|
93
|
-
|
|
94
|
-
|
|
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(
|
|
95
639
|
(state) => ({
|
|
96
640
|
...state,
|
|
97
641
|
status: void 0,
|
|
@@ -99,61 +643,44 @@ var BaseStore = class {
|
|
|
99
643
|
errors: void 0
|
|
100
644
|
})
|
|
101
645
|
);
|
|
646
|
+
return true;
|
|
102
647
|
}
|
|
103
|
-
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
const _typedKey = key;
|
|
109
|
-
currentState.update(
|
|
648
|
+
function applyStopLoading(key) {
|
|
649
|
+
const sig = signals.getOrCreate(key);
|
|
650
|
+
sig.update(
|
|
110
651
|
(state) => ({
|
|
111
652
|
...state,
|
|
112
653
|
isLoading: false
|
|
113
654
|
})
|
|
114
655
|
);
|
|
656
|
+
return true;
|
|
115
657
|
}
|
|
116
|
-
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
121
|
-
const state = currentState();
|
|
658
|
+
function applyUpdateKeyedOne(key, resourceKey, entity) {
|
|
659
|
+
const sig = signals.getOrCreate(key);
|
|
660
|
+
const state = sig();
|
|
122
661
|
const data = isKeyedResourceData(state.data) ? state.data : createKeyedResourceData();
|
|
123
662
|
const nextErrors = { ...data.errors };
|
|
124
663
|
delete nextErrors[resourceKey];
|
|
125
664
|
const nextData = {
|
|
126
665
|
...data,
|
|
127
|
-
entities: {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
},
|
|
131
|
-
isLoading: {
|
|
132
|
-
...data.isLoading,
|
|
133
|
-
[resourceKey]: false
|
|
134
|
-
},
|
|
135
|
-
status: {
|
|
136
|
-
...data.status,
|
|
137
|
-
[resourceKey]: "Success"
|
|
138
|
-
},
|
|
666
|
+
entities: { ...data.entities, [resourceKey]: entity },
|
|
667
|
+
isLoading: { ...data.isLoading, [resourceKey]: false },
|
|
668
|
+
status: { ...data.status, [resourceKey]: "Success" },
|
|
139
669
|
errors: nextErrors
|
|
140
670
|
};
|
|
141
|
-
|
|
671
|
+
return applyUpdate(key, {
|
|
142
672
|
data: nextData,
|
|
143
673
|
isLoading: isAnyKeyLoading(nextData.isLoading),
|
|
144
674
|
status: void 0,
|
|
145
675
|
errors: void 0
|
|
146
676
|
});
|
|
147
677
|
}
|
|
148
|
-
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
const previousState = currentState();
|
|
678
|
+
function applyClearKeyedOne(key, resourceKey) {
|
|
679
|
+
const sig = signals.getOrCreate(key);
|
|
680
|
+
const previousState = sig();
|
|
154
681
|
const state = previousState;
|
|
155
682
|
if (!isKeyedResourceData(state.data)) {
|
|
156
|
-
return;
|
|
683
|
+
return true;
|
|
157
684
|
}
|
|
158
685
|
const data = state.data;
|
|
159
686
|
const nextEntities = { ...data.entities };
|
|
@@ -171,8 +698,7 @@ var BaseStore = class {
|
|
|
171
698
|
status: nextStatus,
|
|
172
699
|
errors: nextErrors
|
|
173
700
|
};
|
|
174
|
-
|
|
175
|
-
currentState.update(
|
|
701
|
+
sig.update(
|
|
176
702
|
(prev) => ({
|
|
177
703
|
...prev,
|
|
178
704
|
data: nextData,
|
|
@@ -181,19 +707,15 @@ var BaseStore = class {
|
|
|
181
707
|
errors: void 0
|
|
182
708
|
})
|
|
183
709
|
);
|
|
184
|
-
const updatedState =
|
|
185
|
-
|
|
710
|
+
const updatedState = sig();
|
|
711
|
+
notifier.notify(key, updatedState, previousState);
|
|
712
|
+
return true;
|
|
186
713
|
}
|
|
187
|
-
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
const _typedKey = key;
|
|
193
|
-
const state = currentState();
|
|
714
|
+
function applyStartKeyedLoading(key, resourceKey) {
|
|
715
|
+
const sig = signals.getOrCreate(key);
|
|
716
|
+
const state = sig();
|
|
194
717
|
if (!isKeyedResourceData(state.data)) {
|
|
195
|
-
|
|
196
|
-
return;
|
|
718
|
+
return applyStartLoading(key);
|
|
197
719
|
}
|
|
198
720
|
const previousState = state;
|
|
199
721
|
const data = state.data;
|
|
@@ -201,13 +723,9 @@ var BaseStore = class {
|
|
|
201
723
|
...data.isLoading,
|
|
202
724
|
[resourceKey]: true
|
|
203
725
|
};
|
|
204
|
-
const nextStatus = {
|
|
205
|
-
...data.status
|
|
206
|
-
};
|
|
726
|
+
const nextStatus = { ...data.status };
|
|
207
727
|
delete nextStatus[resourceKey];
|
|
208
|
-
const nextErrors = {
|
|
209
|
-
...data.errors
|
|
210
|
-
};
|
|
728
|
+
const nextErrors = { ...data.errors };
|
|
211
729
|
delete nextErrors[resourceKey];
|
|
212
730
|
const nextData = {
|
|
213
731
|
...data,
|
|
@@ -215,7 +733,7 @@ var BaseStore = class {
|
|
|
215
733
|
status: nextStatus,
|
|
216
734
|
errors: nextErrors
|
|
217
735
|
};
|
|
218
|
-
|
|
736
|
+
sig.update(
|
|
219
737
|
(previous) => ({
|
|
220
738
|
...previous,
|
|
221
739
|
data: nextData,
|
|
@@ -224,8 +742,277 @@ var BaseStore = class {
|
|
|
224
742
|
errors: void 0
|
|
225
743
|
})
|
|
226
744
|
);
|
|
227
|
-
const updatedState =
|
|
228
|
-
|
|
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
|
+
// src/base-store.ts
|
|
837
|
+
var updateHooksMap = /* @__PURE__ */ new WeakMap();
|
|
838
|
+
var BaseStore = class {
|
|
839
|
+
constructor(storeEnum, options) {
|
|
840
|
+
this.storeEnum = storeEnum;
|
|
841
|
+
this.storeKeys = Object.keys(storeEnum);
|
|
842
|
+
this.initializeState();
|
|
843
|
+
updateHooksMap.set(this, /* @__PURE__ */ new Map());
|
|
844
|
+
const consumer = createStoreMessageConsumer(
|
|
845
|
+
{
|
|
846
|
+
getOrCreate: (key) => this.signalsState.get(key),
|
|
847
|
+
getAllKeys: () => this.storeKeys
|
|
848
|
+
},
|
|
849
|
+
{
|
|
850
|
+
notify: (key, next, prev) => this.notifyUpdateHooks(key, next, prev)
|
|
851
|
+
}
|
|
852
|
+
);
|
|
853
|
+
this.history = createStoreHistory({
|
|
854
|
+
captureSnapshot: () => consumer.createSnapshot(),
|
|
855
|
+
applySnapshot: (snapshot) => consumer.applySnapshot(snapshot),
|
|
856
|
+
applyMessage: (message) => consumer.applyMessage(message),
|
|
857
|
+
channel: options?.channel
|
|
858
|
+
});
|
|
859
|
+
trackStore(this);
|
|
860
|
+
}
|
|
861
|
+
signalsState = /* @__PURE__ */ new Map();
|
|
862
|
+
storeKeys;
|
|
863
|
+
history;
|
|
864
|
+
/** @inheritDoc */
|
|
865
|
+
travelTo = (index) => this.history.travelTo(index);
|
|
866
|
+
/** @inheritDoc */
|
|
867
|
+
undo = () => this.history.undo();
|
|
868
|
+
/** @inheritDoc */
|
|
869
|
+
redo = () => this.history.redo();
|
|
870
|
+
/** @inheritDoc */
|
|
871
|
+
getDeadLetters = () => this.history.getDeadLetters();
|
|
872
|
+
/** @inheritDoc */
|
|
873
|
+
replayDeadLetter = (id) => this.history.replayDeadLetter(id);
|
|
874
|
+
/** @inheritDoc */
|
|
875
|
+
replayDeadLetters = () => this.history.replayDeadLetters();
|
|
876
|
+
/** @inheritDoc */
|
|
877
|
+
getCurrentIndex = () => this.history.getCurrentIndex();
|
|
878
|
+
replay(idOrIds) {
|
|
879
|
+
if (Array.isArray(idOrIds)) {
|
|
880
|
+
return this.history.replay(idOrIds);
|
|
881
|
+
}
|
|
882
|
+
return this.history.replay(idOrIds);
|
|
883
|
+
}
|
|
884
|
+
getHistory(key) {
|
|
885
|
+
if (key === void 0) {
|
|
886
|
+
return this.history.getHistory();
|
|
887
|
+
}
|
|
888
|
+
return this.history.getHistory(key);
|
|
889
|
+
}
|
|
890
|
+
getMessages(key) {
|
|
891
|
+
if (key === void 0) {
|
|
892
|
+
return this.history.getMessages();
|
|
893
|
+
}
|
|
894
|
+
return this.history.getMessages(key);
|
|
895
|
+
}
|
|
896
|
+
/**
|
|
897
|
+
* Returns a **read-only** `Signal` for the given store slot.
|
|
898
|
+
*
|
|
899
|
+
* @param key - The slot name to read.
|
|
900
|
+
* @returns A `Signal` wrapping the slot's current {@link ResourceState}.
|
|
901
|
+
*/
|
|
902
|
+
get(key) {
|
|
903
|
+
return this.signalsState.get(key.toString());
|
|
904
|
+
}
|
|
905
|
+
/**
|
|
906
|
+
* Registers a callback fired after every `update` or `clear` on the given slot.
|
|
907
|
+
*
|
|
908
|
+
* @param key - The slot to watch.
|
|
909
|
+
* @param callback - Receives the new state and the previous state.
|
|
910
|
+
* @returns A cleanup function that removes the listener when called.
|
|
911
|
+
*/
|
|
912
|
+
onUpdate(key, callback) {
|
|
913
|
+
const hooks = updateHooksMap.get(this);
|
|
914
|
+
if (!hooks.has(key)) {
|
|
915
|
+
hooks.set(key, []);
|
|
916
|
+
}
|
|
917
|
+
hooks.get(key).push(
|
|
918
|
+
callback
|
|
919
|
+
);
|
|
920
|
+
return () => {
|
|
921
|
+
const hooksMap = hooks.get(key);
|
|
922
|
+
if (!hooksMap) {
|
|
923
|
+
return;
|
|
924
|
+
}
|
|
925
|
+
const index = hooksMap.indexOf(
|
|
926
|
+
callback
|
|
927
|
+
);
|
|
928
|
+
if (index > -1) {
|
|
929
|
+
hooksMap.splice(index, 1);
|
|
930
|
+
}
|
|
931
|
+
};
|
|
932
|
+
}
|
|
933
|
+
/**
|
|
934
|
+
* Partially updates a slot by merging `newState` into the current value (immutable spread).
|
|
935
|
+
*
|
|
936
|
+
* @param key - The slot to update.
|
|
937
|
+
* @param newState - Partial state to merge (e.g. `{ data: newData, status: 'Success' }`).
|
|
938
|
+
*/
|
|
939
|
+
update(key, newState) {
|
|
940
|
+
this.history.publish(
|
|
941
|
+
createUpdateMessage(key, cloneValue(newState))
|
|
942
|
+
);
|
|
943
|
+
}
|
|
944
|
+
/** Resets every slot in this store to its initial idle state. */
|
|
945
|
+
clearAll() {
|
|
946
|
+
this.history.publish(createClearAllMessage());
|
|
947
|
+
}
|
|
948
|
+
/**
|
|
949
|
+
* Resets a single slot to `{ data: undefined, isLoading: false, status: undefined, errors: undefined }`.
|
|
950
|
+
*
|
|
951
|
+
* @param key - The slot to clear.
|
|
952
|
+
*/
|
|
953
|
+
clear(key) {
|
|
954
|
+
this.history.publish(createClearMessage(key));
|
|
955
|
+
}
|
|
956
|
+
/**
|
|
957
|
+
* Marks a slot as loading: sets `isLoading: true` and clears `status` and `errors`.
|
|
958
|
+
*
|
|
959
|
+
* @param key - The slot to mark as loading.
|
|
960
|
+
*/
|
|
961
|
+
startLoading(key) {
|
|
962
|
+
this.history.publish(createStartLoadingMessage(key));
|
|
963
|
+
}
|
|
964
|
+
/**
|
|
965
|
+
* Marks a slot as no longer loading: sets `isLoading: false`.
|
|
966
|
+
* Does **not** clear `status` or `errors`.
|
|
967
|
+
*
|
|
968
|
+
* @param key - The slot to stop loading.
|
|
969
|
+
*/
|
|
970
|
+
stopLoading(key) {
|
|
971
|
+
this.history.publish(createStopLoadingMessage(key));
|
|
972
|
+
}
|
|
973
|
+
/**
|
|
974
|
+
* Merges a single entity into a {@link KeyedResourceData} slot.
|
|
975
|
+
* Sets its status to `'Success'` and clears per-key errors.
|
|
976
|
+
* The top-level `isLoading` is recalculated based on remaining loading keys.
|
|
977
|
+
*
|
|
978
|
+
* @param key - The keyed slot name.
|
|
979
|
+
* @param resourceKey - The entity identifier (e.g. `'inv-123'`).
|
|
980
|
+
* @param entity - The entity value to store.
|
|
981
|
+
*/
|
|
982
|
+
updateKeyedOne(key, resourceKey, entity) {
|
|
983
|
+
this.history.publish(
|
|
984
|
+
createUpdateKeyedOneMessage(
|
|
985
|
+
key,
|
|
986
|
+
resourceKey,
|
|
987
|
+
cloneValue(entity)
|
|
988
|
+
)
|
|
989
|
+
);
|
|
990
|
+
}
|
|
991
|
+
/**
|
|
992
|
+
* Removes a single entity from a {@link KeyedResourceData} slot,
|
|
993
|
+
* including its loading flag, status, and errors.
|
|
994
|
+
* Recalculates the top-level `isLoading` from the remaining keys.
|
|
995
|
+
*
|
|
996
|
+
* @param key - The keyed slot name.
|
|
997
|
+
* @param resourceKey - The entity identifier to remove.
|
|
998
|
+
*/
|
|
999
|
+
clearKeyedOne(key, resourceKey) {
|
|
1000
|
+
this.history.publish(
|
|
1001
|
+
createClearKeyedOneMessage(key, resourceKey)
|
|
1002
|
+
);
|
|
1003
|
+
}
|
|
1004
|
+
/**
|
|
1005
|
+
* Marks a single entity within a keyed slot as loading.
|
|
1006
|
+
* Clears its status and errors. If the slot data is not yet a {@link KeyedResourceData},
|
|
1007
|
+
* falls back to `startLoading(key)`.
|
|
1008
|
+
*
|
|
1009
|
+
* @param key - The keyed slot name.
|
|
1010
|
+
* @param resourceKey - The entity identifier to mark as loading.
|
|
1011
|
+
*/
|
|
1012
|
+
startKeyedLoading(key, resourceKey) {
|
|
1013
|
+
this.history.publish(
|
|
1014
|
+
createStartKeyedLoadingMessage(key, resourceKey)
|
|
1015
|
+
);
|
|
229
1016
|
}
|
|
230
1017
|
notifyUpdateHooks(key, nextState, previousState) {
|
|
231
1018
|
const hooks = updateHooksMap.get(this);
|
|
@@ -233,25 +1020,34 @@ var BaseStore = class {
|
|
|
233
1020
|
if (!keyHooks) {
|
|
234
1021
|
return;
|
|
235
1022
|
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
1023
|
+
const errors = [];
|
|
1024
|
+
keyHooks.forEach((hook) => {
|
|
1025
|
+
try {
|
|
1026
|
+
hook(
|
|
1027
|
+
nextState,
|
|
1028
|
+
previousState
|
|
1029
|
+
);
|
|
1030
|
+
} catch (error) {
|
|
1031
|
+
errors.push(error);
|
|
1032
|
+
}
|
|
1033
|
+
});
|
|
1034
|
+
if (errors.length > 0) {
|
|
1035
|
+
queueMicrotask(() => {
|
|
1036
|
+
if (errors.length === 1) {
|
|
1037
|
+
throw errors[0];
|
|
1038
|
+
}
|
|
1039
|
+
throw new AggregateError(
|
|
1040
|
+
errors,
|
|
1041
|
+
`${errors.length} onUpdate hooks threw for key "${String(key)}"`
|
|
1042
|
+
);
|
|
1043
|
+
});
|
|
1044
|
+
}
|
|
242
1045
|
}
|
|
243
1046
|
initializeState() {
|
|
244
|
-
|
|
245
|
-
const _typedKey = key;
|
|
246
|
-
const initialState = {
|
|
247
|
-
data: void 0,
|
|
248
|
-
isLoading: false,
|
|
249
|
-
status: void 0,
|
|
250
|
-
errors: void 0
|
|
251
|
-
};
|
|
1047
|
+
this.storeKeys.forEach((key) => {
|
|
252
1048
|
this.signalsState.set(
|
|
253
|
-
|
|
254
|
-
signal(
|
|
1049
|
+
key,
|
|
1050
|
+
signal(createDefaultState())
|
|
255
1051
|
);
|
|
256
1052
|
});
|
|
257
1053
|
}
|
|
@@ -259,23 +1055,58 @@ var BaseStore = class {
|
|
|
259
1055
|
|
|
260
1056
|
// src/lazy-store.ts
|
|
261
1057
|
import { signal as signal2 } from "@angular/core";
|
|
262
|
-
import {
|
|
263
|
-
isAnyKeyLoading as isAnyKeyLoading2,
|
|
264
|
-
isKeyedResourceData as isKeyedResourceData2,
|
|
265
|
-
createKeyedResourceData as createKeyedResourceData2
|
|
266
|
-
} from "@flurryx/core";
|
|
267
|
-
function createDefaultState() {
|
|
268
|
-
return {
|
|
269
|
-
data: void 0,
|
|
270
|
-
isLoading: false,
|
|
271
|
-
status: void 0,
|
|
272
|
-
errors: void 0
|
|
273
|
-
};
|
|
274
|
-
}
|
|
275
1058
|
var LazyStore = class {
|
|
276
1059
|
signals = /* @__PURE__ */ new Map();
|
|
277
1060
|
hooks = /* @__PURE__ */ new Map();
|
|
278
|
-
|
|
1061
|
+
history;
|
|
1062
|
+
/** @inheritDoc */
|
|
1063
|
+
travelTo = (index) => this.history.travelTo(index);
|
|
1064
|
+
/** @inheritDoc */
|
|
1065
|
+
undo = () => this.history.undo();
|
|
1066
|
+
/** @inheritDoc */
|
|
1067
|
+
redo = () => this.history.redo();
|
|
1068
|
+
getMessages(key) {
|
|
1069
|
+
if (key === void 0) {
|
|
1070
|
+
return this.history.getMessages();
|
|
1071
|
+
}
|
|
1072
|
+
return this.history.getMessages(key);
|
|
1073
|
+
}
|
|
1074
|
+
/** @inheritDoc */
|
|
1075
|
+
getDeadLetters = () => this.history.getDeadLetters();
|
|
1076
|
+
/** @inheritDoc */
|
|
1077
|
+
replayDeadLetter = (id) => this.history.replayDeadLetter(id);
|
|
1078
|
+
/** @inheritDoc */
|
|
1079
|
+
replayDeadLetters = () => this.history.replayDeadLetters();
|
|
1080
|
+
/** @inheritDoc */
|
|
1081
|
+
getCurrentIndex = () => this.history.getCurrentIndex();
|
|
1082
|
+
replay(idOrIds) {
|
|
1083
|
+
if (Array.isArray(idOrIds)) {
|
|
1084
|
+
return this.history.replay(idOrIds);
|
|
1085
|
+
}
|
|
1086
|
+
return this.history.replay(idOrIds);
|
|
1087
|
+
}
|
|
1088
|
+
getHistory(key) {
|
|
1089
|
+
if (key === void 0) {
|
|
1090
|
+
return this.history.getHistory();
|
|
1091
|
+
}
|
|
1092
|
+
return this.history.getHistory(key);
|
|
1093
|
+
}
|
|
1094
|
+
constructor(options) {
|
|
1095
|
+
const consumer = createStoreMessageConsumer(
|
|
1096
|
+
{
|
|
1097
|
+
getOrCreate: (key) => this.getOrCreate(key),
|
|
1098
|
+
getAllKeys: () => this.signals.keys()
|
|
1099
|
+
},
|
|
1100
|
+
{
|
|
1101
|
+
notify: (key, next, prev) => this.notifyHooks(key, next, prev)
|
|
1102
|
+
}
|
|
1103
|
+
);
|
|
1104
|
+
this.history = createStoreHistory({
|
|
1105
|
+
captureSnapshot: () => consumer.createSnapshot(),
|
|
1106
|
+
applySnapshot: (snapshot) => consumer.applySnapshot(snapshot),
|
|
1107
|
+
applyMessage: (message) => consumer.applyMessage(message),
|
|
1108
|
+
channel: options?.channel
|
|
1109
|
+
});
|
|
279
1110
|
trackStore(this);
|
|
280
1111
|
}
|
|
281
1112
|
getOrCreate(key) {
|
|
@@ -286,138 +1117,55 @@ var LazyStore = class {
|
|
|
286
1117
|
}
|
|
287
1118
|
return sig;
|
|
288
1119
|
}
|
|
1120
|
+
/** @inheritDoc */
|
|
289
1121
|
get(key) {
|
|
290
1122
|
return this.getOrCreate(key);
|
|
291
1123
|
}
|
|
1124
|
+
/** @inheritDoc */
|
|
292
1125
|
update(key, newState) {
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
const nextState = sig();
|
|
297
|
-
this.notifyHooks(key, nextState, previousState);
|
|
1126
|
+
this.history.publish(
|
|
1127
|
+
createUpdateMessage(key, cloneValue(newState))
|
|
1128
|
+
);
|
|
298
1129
|
}
|
|
1130
|
+
/** @inheritDoc */
|
|
299
1131
|
clear(key) {
|
|
300
|
-
|
|
301
|
-
const previousState = sig();
|
|
302
|
-
sig.set(createDefaultState());
|
|
303
|
-
const nextState = sig();
|
|
304
|
-
this.notifyHooks(key, nextState, previousState);
|
|
1132
|
+
this.history.publish(createClearMessage(key));
|
|
305
1133
|
}
|
|
1134
|
+
/** @inheritDoc */
|
|
306
1135
|
clearAll() {
|
|
307
|
-
|
|
308
|
-
this.clear(key);
|
|
309
|
-
}
|
|
1136
|
+
this.history.publish(createClearAllMessage());
|
|
310
1137
|
}
|
|
1138
|
+
/** @inheritDoc */
|
|
311
1139
|
startLoading(key) {
|
|
312
|
-
|
|
313
|
-
sig.update(
|
|
314
|
-
(state) => ({
|
|
315
|
-
...state,
|
|
316
|
-
status: void 0,
|
|
317
|
-
isLoading: true,
|
|
318
|
-
errors: void 0
|
|
319
|
-
})
|
|
320
|
-
);
|
|
1140
|
+
this.history.publish(createStartLoadingMessage(key));
|
|
321
1141
|
}
|
|
1142
|
+
/** @inheritDoc */
|
|
322
1143
|
stopLoading(key) {
|
|
323
|
-
|
|
324
|
-
sig.update(
|
|
325
|
-
(state) => ({
|
|
326
|
-
...state,
|
|
327
|
-
isLoading: false
|
|
328
|
-
})
|
|
329
|
-
);
|
|
1144
|
+
this.history.publish(createStopLoadingMessage(key));
|
|
330
1145
|
}
|
|
1146
|
+
/** @inheritDoc */
|
|
331
1147
|
updateKeyedOne(key, resourceKey, entity) {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
entities: { ...data.entities, [resourceKey]: entity },
|
|
340
|
-
isLoading: { ...data.isLoading, [resourceKey]: false },
|
|
341
|
-
status: { ...data.status, [resourceKey]: "Success" },
|
|
342
|
-
errors: nextErrors
|
|
343
|
-
};
|
|
344
|
-
this.update(key, {
|
|
345
|
-
data: nextData,
|
|
346
|
-
isLoading: isAnyKeyLoading2(nextData.isLoading),
|
|
347
|
-
status: void 0,
|
|
348
|
-
errors: void 0
|
|
349
|
-
});
|
|
1148
|
+
this.history.publish(
|
|
1149
|
+
createUpdateKeyedOneMessage(
|
|
1150
|
+
key,
|
|
1151
|
+
resourceKey,
|
|
1152
|
+
cloneValue(entity)
|
|
1153
|
+
)
|
|
1154
|
+
);
|
|
350
1155
|
}
|
|
1156
|
+
/** @inheritDoc */
|
|
351
1157
|
clearKeyedOne(key, resourceKey) {
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
if (!isKeyedResourceData2(state.data)) {
|
|
355
|
-
return;
|
|
356
|
-
}
|
|
357
|
-
const data = state.data;
|
|
358
|
-
const previousState = state;
|
|
359
|
-
const nextEntities = { ...data.entities };
|
|
360
|
-
delete nextEntities[resourceKey];
|
|
361
|
-
const nextIsLoading = { ...data.isLoading };
|
|
362
|
-
delete nextIsLoading[resourceKey];
|
|
363
|
-
const nextStatus = { ...data.status };
|
|
364
|
-
delete nextStatus[resourceKey];
|
|
365
|
-
const nextErrors = { ...data.errors };
|
|
366
|
-
delete nextErrors[resourceKey];
|
|
367
|
-
const nextData = {
|
|
368
|
-
...data,
|
|
369
|
-
entities: nextEntities,
|
|
370
|
-
isLoading: nextIsLoading,
|
|
371
|
-
status: nextStatus,
|
|
372
|
-
errors: nextErrors
|
|
373
|
-
};
|
|
374
|
-
sig.update(
|
|
375
|
-
(prev) => ({
|
|
376
|
-
...prev,
|
|
377
|
-
data: nextData,
|
|
378
|
-
status: void 0,
|
|
379
|
-
isLoading: isAnyKeyLoading2(nextIsLoading),
|
|
380
|
-
errors: void 0
|
|
381
|
-
})
|
|
1158
|
+
this.history.publish(
|
|
1159
|
+
createClearKeyedOneMessage(key, resourceKey)
|
|
382
1160
|
);
|
|
383
|
-
const updatedState = sig();
|
|
384
|
-
this.notifyHooks(key, updatedState, previousState);
|
|
385
1161
|
}
|
|
1162
|
+
/** @inheritDoc */
|
|
386
1163
|
startKeyedLoading(key, resourceKey) {
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
if (!isKeyedResourceData2(state.data)) {
|
|
390
|
-
this.startLoading(key);
|
|
391
|
-
return;
|
|
392
|
-
}
|
|
393
|
-
const previousState = state;
|
|
394
|
-
const data = state.data;
|
|
395
|
-
const nextIsLoading = {
|
|
396
|
-
...data.isLoading,
|
|
397
|
-
[resourceKey]: true
|
|
398
|
-
};
|
|
399
|
-
const nextStatus = { ...data.status };
|
|
400
|
-
delete nextStatus[resourceKey];
|
|
401
|
-
const nextErrors = { ...data.errors };
|
|
402
|
-
delete nextErrors[resourceKey];
|
|
403
|
-
const nextData = {
|
|
404
|
-
...data,
|
|
405
|
-
isLoading: nextIsLoading,
|
|
406
|
-
status: nextStatus,
|
|
407
|
-
errors: nextErrors
|
|
408
|
-
};
|
|
409
|
-
sig.update(
|
|
410
|
-
(previous) => ({
|
|
411
|
-
...previous,
|
|
412
|
-
data: nextData,
|
|
413
|
-
status: void 0,
|
|
414
|
-
isLoading: isAnyKeyLoading2(nextIsLoading),
|
|
415
|
-
errors: void 0
|
|
416
|
-
})
|
|
1164
|
+
this.history.publish(
|
|
1165
|
+
createStartKeyedLoadingMessage(key, resourceKey)
|
|
417
1166
|
);
|
|
418
|
-
const updatedState = sig();
|
|
419
|
-
this.notifyHooks(key, updatedState, previousState);
|
|
420
1167
|
}
|
|
1168
|
+
/** @inheritDoc */
|
|
421
1169
|
onUpdate(key, callback) {
|
|
422
1170
|
if (!this.hooks.has(key)) {
|
|
423
1171
|
this.hooks.set(key, []);
|
|
@@ -440,12 +1188,28 @@ var LazyStore = class {
|
|
|
440
1188
|
if (!keyHooks) {
|
|
441
1189
|
return;
|
|
442
1190
|
}
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
1191
|
+
const errors = [];
|
|
1192
|
+
keyHooks.forEach((hook) => {
|
|
1193
|
+
try {
|
|
1194
|
+
hook(
|
|
1195
|
+
nextState,
|
|
1196
|
+
previousState
|
|
1197
|
+
);
|
|
1198
|
+
} catch (error) {
|
|
1199
|
+
errors.push(error);
|
|
1200
|
+
}
|
|
1201
|
+
});
|
|
1202
|
+
if (errors.length > 0) {
|
|
1203
|
+
queueMicrotask(() => {
|
|
1204
|
+
if (errors.length === 1) {
|
|
1205
|
+
throw errors[0];
|
|
1206
|
+
}
|
|
1207
|
+
throw new AggregateError(
|
|
1208
|
+
errors,
|
|
1209
|
+
`${errors.length} onUpdate hooks threw for key "${String(key)}"`
|
|
1210
|
+
);
|
|
1211
|
+
});
|
|
1212
|
+
}
|
|
449
1213
|
}
|
|
450
1214
|
};
|
|
451
1215
|
|
|
@@ -454,12 +1218,12 @@ import { InjectionToken, inject } from "@angular/core";
|
|
|
454
1218
|
|
|
455
1219
|
// src/dynamic-store.ts
|
|
456
1220
|
var DynamicStore = class extends BaseStore {
|
|
457
|
-
constructor(config) {
|
|
1221
|
+
constructor(config, options) {
|
|
458
1222
|
const identityEnum = Object.keys(config).reduce(
|
|
459
1223
|
(acc, key) => ({ ...acc, [key]: key }),
|
|
460
1224
|
{}
|
|
461
1225
|
);
|
|
462
|
-
super(identityEnum);
|
|
1226
|
+
super(identityEnum, options);
|
|
463
1227
|
}
|
|
464
1228
|
};
|
|
465
1229
|
|
|
@@ -480,12 +1244,12 @@ function mirrorKey(source, sourceKey, target, targetKeyOrOptions, options) {
|
|
|
480
1244
|
}
|
|
481
1245
|
|
|
482
1246
|
// src/collect-keyed.ts
|
|
483
|
-
import { createKeyedResourceData as
|
|
1247
|
+
import { createKeyedResourceData as createKeyedResourceData2, isAnyKeyLoading as isAnyKeyLoading2 } from "@flurryx/core";
|
|
484
1248
|
function collectKeyed(source, sourceKey, target, targetKeyOrOptions, options) {
|
|
485
1249
|
const resolvedTargetKey = typeof targetKeyOrOptions === "string" ? targetKeyOrOptions : sourceKey;
|
|
486
1250
|
const resolvedOptions = typeof targetKeyOrOptions === "object" ? targetKeyOrOptions : options;
|
|
487
1251
|
target.update(resolvedTargetKey, {
|
|
488
|
-
data:
|
|
1252
|
+
data: createKeyedResourceData2()
|
|
489
1253
|
});
|
|
490
1254
|
let previousId;
|
|
491
1255
|
const cleanup = source.onUpdate(sourceKey, (state) => {
|
|
@@ -497,9 +1261,15 @@ function collectKeyed(source, sourceKey, target, targetKeyOrOptions, options) {
|
|
|
497
1261
|
return;
|
|
498
1262
|
}
|
|
499
1263
|
if (resourceState.status === "Success" && currentId !== void 0) {
|
|
500
|
-
const newEntities = {
|
|
1264
|
+
const newEntities = {
|
|
1265
|
+
...currentKeyed.entities,
|
|
1266
|
+
[currentId]: resourceState.data
|
|
1267
|
+
};
|
|
501
1268
|
const newIsLoading = { ...currentKeyed.isLoading, [currentId]: false };
|
|
502
|
-
const newStatus = {
|
|
1269
|
+
const newStatus = {
|
|
1270
|
+
...currentKeyed.status,
|
|
1271
|
+
[currentId]: resourceState.status
|
|
1272
|
+
};
|
|
503
1273
|
const newErrors = { ...currentKeyed.errors };
|
|
504
1274
|
delete newErrors[currentId];
|
|
505
1275
|
const updatedKeyed = {
|
|
@@ -510,14 +1280,20 @@ function collectKeyed(source, sourceKey, target, targetKeyOrOptions, options) {
|
|
|
510
1280
|
};
|
|
511
1281
|
target.update(resolvedTargetKey, {
|
|
512
1282
|
data: updatedKeyed,
|
|
513
|
-
isLoading:
|
|
1283
|
+
isLoading: isAnyKeyLoading2(newIsLoading),
|
|
514
1284
|
status: "Success"
|
|
515
1285
|
});
|
|
516
1286
|
previousId = currentId;
|
|
517
1287
|
} else if (resourceState.status === "Error" && currentId !== void 0) {
|
|
518
1288
|
const newIsLoading = { ...currentKeyed.isLoading, [currentId]: false };
|
|
519
|
-
const newStatus = {
|
|
520
|
-
|
|
1289
|
+
const newStatus = {
|
|
1290
|
+
...currentKeyed.status,
|
|
1291
|
+
[currentId]: resourceState.status
|
|
1292
|
+
};
|
|
1293
|
+
const newErrors = {
|
|
1294
|
+
...currentKeyed.errors,
|
|
1295
|
+
[currentId]: resourceState.errors
|
|
1296
|
+
};
|
|
521
1297
|
const updatedKeyed = {
|
|
522
1298
|
entities: { ...currentKeyed.entities },
|
|
523
1299
|
isLoading: newIsLoading,
|
|
@@ -526,7 +1302,7 @@ function collectKeyed(source, sourceKey, target, targetKeyOrOptions, options) {
|
|
|
526
1302
|
};
|
|
527
1303
|
target.update(resolvedTargetKey, {
|
|
528
1304
|
data: updatedKeyed,
|
|
529
|
-
isLoading:
|
|
1305
|
+
isLoading: isAnyKeyLoading2(newIsLoading)
|
|
530
1306
|
});
|
|
531
1307
|
previousId = currentId;
|
|
532
1308
|
} else if (resourceState.data === void 0 && previousId !== void 0) {
|
|
@@ -542,7 +1318,7 @@ function collectKeyed(source, sourceKey, target, targetKeyOrOptions, options) {
|
|
|
542
1318
|
};
|
|
543
1319
|
target.update(resolvedTargetKey, {
|
|
544
1320
|
data: updatedKeyed,
|
|
545
|
-
isLoading:
|
|
1321
|
+
isLoading: isAnyKeyLoading2(remainingLoading)
|
|
546
1322
|
});
|
|
547
1323
|
previousId = void 0;
|
|
548
1324
|
} else if (resourceState.isLoading && currentId !== void 0) {
|
|
@@ -582,7 +1358,6 @@ function wireMirrors(store, mirrors) {
|
|
|
582
1358
|
def.targetKey
|
|
583
1359
|
);
|
|
584
1360
|
}
|
|
585
|
-
return store;
|
|
586
1361
|
}
|
|
587
1362
|
function wireMirrorKeyed(store, defs) {
|
|
588
1363
|
for (const def of defs) {
|
|
@@ -597,7 +1372,6 @@ function wireMirrorKeyed(store, defs) {
|
|
|
597
1372
|
}
|
|
598
1373
|
);
|
|
599
1374
|
}
|
|
600
|
-
return store;
|
|
601
1375
|
}
|
|
602
1376
|
var MIRROR_SELF_SAME_KEY_ERROR = "mirrorSelf source and target keys must be different";
|
|
603
1377
|
function wireSelfMirrors(store, defs) {
|
|
@@ -612,7 +1386,6 @@ function wireSelfMirrors(store, defs) {
|
|
|
612
1386
|
def.targetKey
|
|
613
1387
|
);
|
|
614
1388
|
}
|
|
615
|
-
return store;
|
|
616
1389
|
}
|
|
617
1390
|
function createBuilder(accum, mirrors = [], mirrorKeyedDefs = [], selfMirrors = []) {
|
|
618
1391
|
return {
|
|
@@ -669,11 +1442,11 @@ function createBuilder(accum, mirrors = [], mirrorKeyedDefs = [], selfMirrors =
|
|
|
669
1442
|
selfMirrors
|
|
670
1443
|
);
|
|
671
1444
|
},
|
|
672
|
-
build() {
|
|
1445
|
+
build(options) {
|
|
673
1446
|
return new InjectionToken("FlurryxStore", {
|
|
674
1447
|
providedIn: "root",
|
|
675
1448
|
factory: () => {
|
|
676
|
-
const store = new DynamicStore(accum);
|
|
1449
|
+
const store = new DynamicStore(accum, options);
|
|
677
1450
|
wireMirrors(store, mirrors);
|
|
678
1451
|
wireMirrorKeyed(store, mirrorKeyedDefs);
|
|
679
1452
|
wireSelfMirrors(store, selfMirrors);
|
|
@@ -744,11 +1517,11 @@ function createConstrainedBuilder(_enumObj, accum, mirrors = [], mirrorKeyedDefs
|
|
|
744
1517
|
selfMirrors
|
|
745
1518
|
);
|
|
746
1519
|
},
|
|
747
|
-
build() {
|
|
1520
|
+
build(options) {
|
|
748
1521
|
return new InjectionToken("FlurryxStore", {
|
|
749
1522
|
providedIn: "root",
|
|
750
1523
|
factory: () => {
|
|
751
|
-
const store = new DynamicStore(accum);
|
|
1524
|
+
const store = new DynamicStore(accum, options);
|
|
752
1525
|
wireMirrors(store, mirrors);
|
|
753
1526
|
wireMirrorKeyed(store, mirrorKeyedDefs);
|
|
754
1527
|
wireSelfMirrors(store, selfMirrors);
|
|
@@ -795,11 +1568,11 @@ function createInterfaceBuilder(mirrors = [], mirrorKeyedDefs = [], selfMirrors
|
|
|
795
1568
|
selfMirrors
|
|
796
1569
|
);
|
|
797
1570
|
},
|
|
798
|
-
build() {
|
|
1571
|
+
build(options) {
|
|
799
1572
|
return new InjectionToken("FlurryxStore", {
|
|
800
1573
|
providedIn: "root",
|
|
801
1574
|
factory: () => {
|
|
802
|
-
const store = new LazyStore();
|
|
1575
|
+
const store = new LazyStore(options);
|
|
803
1576
|
wireMirrors(store, mirrors);
|
|
804
1577
|
wireMirrorKeyed(store, mirrorKeyedDefs);
|
|
805
1578
|
wireSelfMirrors(store, selfMirrors);
|
|
@@ -824,7 +1597,14 @@ export {
|
|
|
824
1597
|
LazyStore,
|
|
825
1598
|
Store,
|
|
826
1599
|
clearAllStores,
|
|
1600
|
+
cloneValue,
|
|
827
1601
|
collectKeyed,
|
|
1602
|
+
createCompositeStoreMessageChannel,
|
|
1603
|
+
createInMemoryStoreMessageChannel,
|
|
1604
|
+
createLocalStorageStoreMessageChannel,
|
|
1605
|
+
createSessionStorageStoreMessageChannel,
|
|
1606
|
+
createSnapshotRestorePatch,
|
|
1607
|
+
createStorageStoreMessageChannel,
|
|
828
1608
|
mirrorKey
|
|
829
1609
|
};
|
|
830
1610
|
//# sourceMappingURL=index.js.map
|