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