@flurryx/store 0.8.4 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1233 -320
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +588 -18
- package/dist/index.d.ts +588 -18
- package/dist/index.js +1236 -334
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -24,36 +24,1091 @@ __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
|
|
40
|
+
var import_core3 = require("@angular/core");
|
|
41
|
+
|
|
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;
|
|
49
|
+
}
|
|
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);
|
|
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;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// src/store-replay.ts
|
|
33
124
|
var import_core = require("@angular/core");
|
|
34
|
-
|
|
125
|
+
|
|
126
|
+
// src/store-messages.ts
|
|
127
|
+
var INVALID_HISTORY_INDEX_ERROR = "History index is out of range";
|
|
128
|
+
var INVALID_HISTORY_MESSAGE_ID_ERROR = "History message id is out of range";
|
|
129
|
+
var MESSAGE_NOT_ACKNOWLEDGED_ERROR = "Message was not acknowledged";
|
|
130
|
+
|
|
131
|
+
// src/store-channels.ts
|
|
132
|
+
function serializeStoreMessageChannelValue(value) {
|
|
133
|
+
if (value === void 0) {
|
|
134
|
+
return { __flurryxType: "undefined" };
|
|
135
|
+
}
|
|
136
|
+
if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
137
|
+
return value;
|
|
138
|
+
}
|
|
139
|
+
if (value instanceof Date) {
|
|
140
|
+
return {
|
|
141
|
+
__flurryxType: "date",
|
|
142
|
+
value: value.toISOString()
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
if (value instanceof Map) {
|
|
146
|
+
return {
|
|
147
|
+
__flurryxType: "map",
|
|
148
|
+
entries: Array.from(value.entries(), ([key, entryValue]) => [
|
|
149
|
+
serializeStoreMessageChannelValue(key),
|
|
150
|
+
serializeStoreMessageChannelValue(entryValue)
|
|
151
|
+
])
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
if (value instanceof Set) {
|
|
155
|
+
return {
|
|
156
|
+
__flurryxType: "set",
|
|
157
|
+
values: Array.from(
|
|
158
|
+
value.values(),
|
|
159
|
+
(entryValue) => serializeStoreMessageChannelValue(entryValue)
|
|
160
|
+
)
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
if (Array.isArray(value)) {
|
|
164
|
+
return {
|
|
165
|
+
__flurryxType: "array",
|
|
166
|
+
values: value.map(
|
|
167
|
+
(entryValue) => serializeStoreMessageChannelValue(entryValue)
|
|
168
|
+
)
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
if (typeof value === "object") {
|
|
172
|
+
return {
|
|
173
|
+
__flurryxType: "object",
|
|
174
|
+
entries: Object.entries(value).map(
|
|
175
|
+
([key, entryValue]) => [
|
|
176
|
+
key,
|
|
177
|
+
serializeStoreMessageChannelValue(entryValue)
|
|
178
|
+
]
|
|
179
|
+
)
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
throw new Error("Store message channel cannot serialize this value");
|
|
183
|
+
}
|
|
184
|
+
function deserializeStoreMessageChannelValue(value) {
|
|
185
|
+
if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
186
|
+
return value;
|
|
187
|
+
}
|
|
188
|
+
switch (value.__flurryxType) {
|
|
189
|
+
case "undefined":
|
|
190
|
+
return void 0;
|
|
191
|
+
case "date":
|
|
192
|
+
return new Date(value.value);
|
|
193
|
+
case "array":
|
|
194
|
+
return value.values.map(
|
|
195
|
+
(entryValue) => deserializeStoreMessageChannelValue(entryValue)
|
|
196
|
+
);
|
|
197
|
+
case "set":
|
|
198
|
+
return new Set(
|
|
199
|
+
value.values.map(
|
|
200
|
+
(entryValue) => deserializeStoreMessageChannelValue(entryValue)
|
|
201
|
+
)
|
|
202
|
+
);
|
|
203
|
+
case "map":
|
|
204
|
+
return new Map(
|
|
205
|
+
value.entries.map(([key, entryValue]) => [
|
|
206
|
+
deserializeStoreMessageChannelValue(key),
|
|
207
|
+
deserializeStoreMessageChannelValue(entryValue)
|
|
208
|
+
])
|
|
209
|
+
);
|
|
210
|
+
case "object": {
|
|
211
|
+
const result = {};
|
|
212
|
+
value.entries.forEach(([key, entryValue]) => {
|
|
213
|
+
result[key] = deserializeStoreMessageChannelValue(entryValue);
|
|
214
|
+
});
|
|
215
|
+
return result;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
function defaultSerializeStoreMessageChannelState(state) {
|
|
220
|
+
return JSON.stringify(serializeStoreMessageChannelValue(state));
|
|
221
|
+
}
|
|
222
|
+
function defaultDeserializeStoreMessageChannelState(value) {
|
|
223
|
+
return deserializeStoreMessageChannelValue(
|
|
224
|
+
JSON.parse(value)
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
function normalizeStoreMessageChannelState(state) {
|
|
228
|
+
const maxId = state.messages.reduce(
|
|
229
|
+
(currentMax, entry) => Math.max(currentMax, entry.id),
|
|
230
|
+
0
|
|
231
|
+
);
|
|
232
|
+
return {
|
|
233
|
+
nextId: Math.max(state.nextId, maxId + 1),
|
|
234
|
+
messages: state.messages.map((entry) => cloneValue(entry))
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
function createInitialStoreMessageRecord(id, message, clock = Date.now) {
|
|
238
|
+
return {
|
|
239
|
+
id,
|
|
240
|
+
message: cloneValue(message),
|
|
241
|
+
status: "pending",
|
|
242
|
+
attempts: 0,
|
|
243
|
+
createdAt: clock(),
|
|
244
|
+
lastAttemptedAt: null,
|
|
245
|
+
acknowledgedAt: null,
|
|
246
|
+
error: null
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
function isQuotaExceededError(error) {
|
|
250
|
+
return error instanceof DOMException && (error.code === 22 || error.code === 1014 || error.name === "QuotaExceededError" || error.name === "NS_ERROR_DOM_QUOTA_REACHED");
|
|
251
|
+
}
|
|
252
|
+
function resolveGlobalStorage(name) {
|
|
253
|
+
const storage = globalThis[name];
|
|
254
|
+
if (!storage) {
|
|
255
|
+
throw new Error(`${name} is not available in this environment`);
|
|
256
|
+
}
|
|
257
|
+
return storage;
|
|
258
|
+
}
|
|
259
|
+
function createInMemoryStoreMessageChannel() {
|
|
260
|
+
let messages = [];
|
|
261
|
+
let nextId = 1;
|
|
262
|
+
return {
|
|
263
|
+
publish(message) {
|
|
264
|
+
const record = createInitialStoreMessageRecord(nextId++, message);
|
|
265
|
+
messages = [...messages, record];
|
|
266
|
+
return cloneValue(record);
|
|
267
|
+
},
|
|
268
|
+
getMessage(id) {
|
|
269
|
+
const record = messages.find((entry) => entry.id === id);
|
|
270
|
+
return record ? cloneValue(record) : void 0;
|
|
271
|
+
},
|
|
272
|
+
getMessages() {
|
|
273
|
+
return messages.map((entry) => cloneValue(entry));
|
|
274
|
+
},
|
|
275
|
+
saveMessage(entry) {
|
|
276
|
+
const record = cloneValue(entry);
|
|
277
|
+
const existingIndex = messages.findIndex(
|
|
278
|
+
(candidate) => candidate.id === record.id
|
|
279
|
+
);
|
|
280
|
+
if (existingIndex === -1) {
|
|
281
|
+
messages = [...messages, record];
|
|
282
|
+
} else {
|
|
283
|
+
messages = messages.map((c, i) => i === existingIndex ? record : c);
|
|
284
|
+
}
|
|
285
|
+
nextId = Math.max(nextId, record.id + 1);
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
function createStorageStoreMessageChannel(options) {
|
|
290
|
+
const serialize = options.serialize ?? defaultSerializeStoreMessageChannelState;
|
|
291
|
+
const deserialize = options.deserialize ?? defaultDeserializeStoreMessageChannelState;
|
|
292
|
+
function readState() {
|
|
293
|
+
const rawState = options.storage.getItem(options.storageKey);
|
|
294
|
+
if (rawState === null) {
|
|
295
|
+
return { nextId: 1, messages: [] };
|
|
296
|
+
}
|
|
297
|
+
try {
|
|
298
|
+
return normalizeStoreMessageChannelState(deserialize(rawState));
|
|
299
|
+
} catch {
|
|
300
|
+
return { nextId: 1, messages: [] };
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
function writeState(state) {
|
|
304
|
+
const normalized = normalizeStoreMessageChannelState(state);
|
|
305
|
+
try {
|
|
306
|
+
options.storage.setItem(options.storageKey, serialize(normalized));
|
|
307
|
+
} catch (error) {
|
|
308
|
+
if (!isQuotaExceededError(error) || normalized.messages.length === 0) {
|
|
309
|
+
throw error;
|
|
310
|
+
}
|
|
311
|
+
let remaining = [...normalized.messages];
|
|
312
|
+
while (remaining.length > 0) {
|
|
313
|
+
remaining = remaining.slice(1);
|
|
314
|
+
try {
|
|
315
|
+
options.storage.setItem(
|
|
316
|
+
options.storageKey,
|
|
317
|
+
serialize({ nextId: normalized.nextId, messages: remaining })
|
|
318
|
+
);
|
|
319
|
+
return;
|
|
320
|
+
} catch (retryError) {
|
|
321
|
+
if (!isQuotaExceededError(retryError)) {
|
|
322
|
+
throw retryError;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
options.storage.setItem(
|
|
327
|
+
options.storageKey,
|
|
328
|
+
serialize({ nextId: normalized.nextId, messages: [] })
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return {
|
|
333
|
+
publish(message) {
|
|
334
|
+
const state = readState();
|
|
335
|
+
const record = createInitialStoreMessageRecord(state.nextId, message);
|
|
336
|
+
writeState({
|
|
337
|
+
nextId: state.nextId + 1,
|
|
338
|
+
messages: [...state.messages, record]
|
|
339
|
+
});
|
|
340
|
+
return cloneValue(record);
|
|
341
|
+
},
|
|
342
|
+
getMessage(id) {
|
|
343
|
+
const record = readState().messages.find((entry) => entry.id === id);
|
|
344
|
+
return record ? cloneValue(record) : void 0;
|
|
345
|
+
},
|
|
346
|
+
getMessages() {
|
|
347
|
+
return readState().messages.map((entry) => cloneValue(entry));
|
|
348
|
+
},
|
|
349
|
+
saveMessage(entry) {
|
|
350
|
+
const state = readState();
|
|
351
|
+
const record = cloneValue(entry);
|
|
352
|
+
const existingIndex = state.messages.findIndex(
|
|
353
|
+
(candidate) => candidate.id === record.id
|
|
354
|
+
);
|
|
355
|
+
if (existingIndex === -1) {
|
|
356
|
+
writeState({
|
|
357
|
+
nextId: Math.max(state.nextId, record.id + 1),
|
|
358
|
+
messages: [...state.messages, record]
|
|
359
|
+
});
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
const nextMessages = state.messages.map(
|
|
363
|
+
(c, i) => i === existingIndex ? record : c
|
|
364
|
+
);
|
|
365
|
+
writeState({
|
|
366
|
+
nextId: Math.max(state.nextId, record.id + 1),
|
|
367
|
+
messages: nextMessages
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
function createLocalStorageStoreMessageChannel(options) {
|
|
373
|
+
return createStorageStoreMessageChannel({
|
|
374
|
+
...options,
|
|
375
|
+
storage: options.storage ?? resolveGlobalStorage("localStorage")
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
function createSessionStorageStoreMessageChannel(options) {
|
|
379
|
+
return createStorageStoreMessageChannel({
|
|
380
|
+
...options,
|
|
381
|
+
storage: options.storage ?? resolveGlobalStorage("sessionStorage")
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
function createCompositeStoreMessageChannel(options) {
|
|
385
|
+
if (options.channels.length === 0) {
|
|
386
|
+
throw new Error(
|
|
387
|
+
"createCompositeStoreMessageChannel: 'channels' option must contain at least one channel"
|
|
388
|
+
);
|
|
389
|
+
}
|
|
390
|
+
const primaryChannel = options.channels[0];
|
|
391
|
+
const replicaChannels = options.channels.slice(1);
|
|
392
|
+
return {
|
|
393
|
+
publish(message) {
|
|
394
|
+
const record = primaryChannel.publish(message);
|
|
395
|
+
replicaChannels.forEach((channel) => {
|
|
396
|
+
channel.saveMessage(record);
|
|
397
|
+
});
|
|
398
|
+
return cloneValue(record);
|
|
399
|
+
},
|
|
400
|
+
getMessage(id) {
|
|
401
|
+
const record = primaryChannel.getMessage(id);
|
|
402
|
+
return record ? cloneValue(record) : void 0;
|
|
403
|
+
},
|
|
404
|
+
getMessages() {
|
|
405
|
+
return primaryChannel.getMessages().map((record) => cloneValue(record));
|
|
406
|
+
},
|
|
407
|
+
saveMessage(entry) {
|
|
408
|
+
primaryChannel.saveMessage(entry);
|
|
409
|
+
replicaChannels.forEach((channel) => {
|
|
410
|
+
channel.saveMessage(entry);
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// src/store-replay.ts
|
|
417
|
+
function messageAffectsKey(message, key) {
|
|
418
|
+
if (message.type === "clearAll") {
|
|
419
|
+
return true;
|
|
420
|
+
}
|
|
421
|
+
return "key" in message && message.key === key;
|
|
422
|
+
}
|
|
423
|
+
function toDeadLetterEntry(record) {
|
|
424
|
+
return {
|
|
425
|
+
id: record.id,
|
|
426
|
+
message: cloneValue(record.message),
|
|
427
|
+
attempts: record.attempts,
|
|
428
|
+
error: record.error ?? MESSAGE_NOT_ACKNOWLEDGED_ERROR,
|
|
429
|
+
failedAt: record.lastAttemptedAt ?? record.createdAt
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
function areValuesEquivalent(left, right, seen = /* @__PURE__ */ new WeakMap()) {
|
|
433
|
+
if (Object.is(left, right)) {
|
|
434
|
+
return true;
|
|
435
|
+
}
|
|
436
|
+
if (typeof left !== typeof right || left === null || right === null) {
|
|
437
|
+
return false;
|
|
438
|
+
}
|
|
439
|
+
if (typeof left !== "object" || typeof right !== "object") {
|
|
440
|
+
return false;
|
|
441
|
+
}
|
|
442
|
+
let seenRights = seen.get(left);
|
|
443
|
+
if (seenRights?.has(right)) {
|
|
444
|
+
return true;
|
|
445
|
+
}
|
|
446
|
+
if (!seenRights) {
|
|
447
|
+
seenRights = /* @__PURE__ */ new WeakSet();
|
|
448
|
+
seen.set(left, seenRights);
|
|
449
|
+
}
|
|
450
|
+
seenRights.add(right);
|
|
451
|
+
if (left instanceof Date || right instanceof Date) {
|
|
452
|
+
return left instanceof Date && right instanceof Date && left.getTime() === right.getTime();
|
|
453
|
+
}
|
|
454
|
+
if (left instanceof Map || right instanceof Map) {
|
|
455
|
+
if (!(left instanceof Map) || !(right instanceof Map)) {
|
|
456
|
+
return false;
|
|
457
|
+
}
|
|
458
|
+
const leftEntries = Array.from(left.entries());
|
|
459
|
+
const rightEntries = Array.from(right.entries());
|
|
460
|
+
if (leftEntries.length !== rightEntries.length) {
|
|
461
|
+
return false;
|
|
462
|
+
}
|
|
463
|
+
return leftEntries.every(([leftKey, leftValue], index) => {
|
|
464
|
+
const rightEntry = rightEntries[index];
|
|
465
|
+
if (!rightEntry) {
|
|
466
|
+
return false;
|
|
467
|
+
}
|
|
468
|
+
return areValuesEquivalent(leftKey, rightEntry[0], seen) && areValuesEquivalent(leftValue, rightEntry[1], seen);
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
if (left instanceof Set || right instanceof Set) {
|
|
472
|
+
if (!(left instanceof Set) || !(right instanceof Set)) {
|
|
473
|
+
return false;
|
|
474
|
+
}
|
|
475
|
+
const leftValues = Array.from(left.values());
|
|
476
|
+
const rightValues = Array.from(right.values());
|
|
477
|
+
if (leftValues.length !== rightValues.length) {
|
|
478
|
+
return false;
|
|
479
|
+
}
|
|
480
|
+
return leftValues.every(
|
|
481
|
+
(leftValue, index) => areValuesEquivalent(leftValue, rightValues[index], seen)
|
|
482
|
+
);
|
|
483
|
+
}
|
|
484
|
+
if (Array.isArray(left) || Array.isArray(right)) {
|
|
485
|
+
if (!Array.isArray(left) || !Array.isArray(right)) {
|
|
486
|
+
return false;
|
|
487
|
+
}
|
|
488
|
+
if (left.length !== right.length) {
|
|
489
|
+
return false;
|
|
490
|
+
}
|
|
491
|
+
return left.every(
|
|
492
|
+
(leftValue, index) => areValuesEquivalent(leftValue, right[index], seen)
|
|
493
|
+
);
|
|
494
|
+
}
|
|
495
|
+
if (Object.getPrototypeOf(left) !== Object.getPrototypeOf(right)) {
|
|
496
|
+
return false;
|
|
497
|
+
}
|
|
498
|
+
const leftRecord = left;
|
|
499
|
+
const rightRecord = right;
|
|
500
|
+
const leftKeys = Reflect.ownKeys(leftRecord);
|
|
501
|
+
const rightKeys = Reflect.ownKeys(rightRecord);
|
|
502
|
+
if (leftKeys.length !== rightKeys.length) {
|
|
503
|
+
return false;
|
|
504
|
+
}
|
|
505
|
+
return leftKeys.every((key) => {
|
|
506
|
+
if (!Object.prototype.hasOwnProperty.call(rightRecord, key)) {
|
|
507
|
+
return false;
|
|
508
|
+
}
|
|
509
|
+
return areValuesEquivalent(leftRecord[key], rightRecord[key], seen);
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
function areStoreMessageRecordsEquivalent(sourceRecord, cachedRecord) {
|
|
513
|
+
return sourceRecord.id === cachedRecord.id && sourceRecord.status === cachedRecord.status && sourceRecord.attempts === cachedRecord.attempts && sourceRecord.createdAt === cachedRecord.createdAt && sourceRecord.lastAttemptedAt === cachedRecord.lastAttemptedAt && sourceRecord.acknowledgedAt === cachedRecord.acknowledgedAt && sourceRecord.error === cachedRecord.error && areValuesEquivalent(sourceRecord.message, cachedRecord.message);
|
|
514
|
+
}
|
|
515
|
+
function createStableReadonlyCollection(items) {
|
|
516
|
+
return Object.freeze([...items]);
|
|
517
|
+
}
|
|
518
|
+
function appendStableReadonlyCollectionItem(input) {
|
|
519
|
+
return createStableReadonlyCollection([...input.items, input.item]);
|
|
520
|
+
}
|
|
521
|
+
function upsertStableReadonlyCollectionItem(input) {
|
|
522
|
+
const existingIndex = input.items.findIndex(
|
|
523
|
+
(candidate) => candidate.id === input.item.id
|
|
524
|
+
);
|
|
525
|
+
if (existingIndex === -1) {
|
|
526
|
+
return appendStableReadonlyCollectionItem(input);
|
|
527
|
+
}
|
|
528
|
+
if (Object.is(input.items[existingIndex], input.item)) {
|
|
529
|
+
return input.items;
|
|
530
|
+
}
|
|
531
|
+
const nextItems = [...input.items];
|
|
532
|
+
nextItems[existingIndex] = input.item;
|
|
533
|
+
return createStableReadonlyCollection(nextItems);
|
|
534
|
+
}
|
|
535
|
+
function syncStableReadonlyCollectionById(input) {
|
|
536
|
+
const cachedItemsById = /* @__PURE__ */ new Map();
|
|
537
|
+
input.items.forEach((item) => {
|
|
538
|
+
cachedItemsById.set(item.id, item);
|
|
539
|
+
});
|
|
540
|
+
let didChange = input.items.length !== input.sourceItems.length;
|
|
541
|
+
const nextItems = input.sourceItems.map((sourceItem, index) => {
|
|
542
|
+
const cachedItem = cachedItemsById.get(input.getSourceId(sourceItem));
|
|
543
|
+
const nextItem = cachedItem && input.areEquivalent(sourceItem, cachedItem) ? cachedItem : input.createItem(sourceItem);
|
|
544
|
+
if (!didChange && input.items[index] !== nextItem) {
|
|
545
|
+
didChange = true;
|
|
546
|
+
}
|
|
547
|
+
return nextItem;
|
|
548
|
+
});
|
|
549
|
+
return didChange ? createStableReadonlyCollection(nextItems) : input.items;
|
|
550
|
+
}
|
|
551
|
+
function createStoreHistory(config) {
|
|
552
|
+
const messageChannel = config.channel ?? createInMemoryStoreMessageChannel();
|
|
553
|
+
const clock = config.clock ?? Date.now;
|
|
554
|
+
let history = [
|
|
555
|
+
{
|
|
556
|
+
id: null,
|
|
557
|
+
index: 0,
|
|
558
|
+
message: null,
|
|
559
|
+
snapshot: config.captureSnapshot(),
|
|
560
|
+
acknowledgedAt: null
|
|
561
|
+
}
|
|
562
|
+
];
|
|
563
|
+
let currentIndex = 0;
|
|
564
|
+
let historyCollection = createStableReadonlyCollection(
|
|
565
|
+
history.map((entry) => cloneValue(entry))
|
|
566
|
+
);
|
|
567
|
+
let messageCollection = createStableReadonlyCollection(
|
|
568
|
+
messageChannel.getMessages().map((record) => cloneValue(record))
|
|
569
|
+
);
|
|
570
|
+
const version = (0, import_core.signal)(0);
|
|
571
|
+
function notifyVersion() {
|
|
572
|
+
version.update((v) => v + 1);
|
|
573
|
+
}
|
|
574
|
+
function recordSnapshot(record) {
|
|
575
|
+
const nextIndex = history.length;
|
|
576
|
+
const nextHistoryEntry = {
|
|
577
|
+
id: record.id,
|
|
578
|
+
index: nextIndex,
|
|
579
|
+
message: cloneValue(record.message),
|
|
580
|
+
snapshot: config.captureSnapshot(),
|
|
581
|
+
acknowledgedAt: record.acknowledgedAt
|
|
582
|
+
};
|
|
583
|
+
history = [...history, nextHistoryEntry];
|
|
584
|
+
historyCollection = appendStableReadonlyCollectionItem({
|
|
585
|
+
items: historyCollection,
|
|
586
|
+
item: cloneValue(nextHistoryEntry)
|
|
587
|
+
});
|
|
588
|
+
currentIndex = nextIndex;
|
|
589
|
+
}
|
|
590
|
+
function truncateFutureHistory() {
|
|
591
|
+
if (currentIndex === history.length - 1) {
|
|
592
|
+
return;
|
|
593
|
+
}
|
|
594
|
+
history = history.slice(0, currentIndex + 1);
|
|
595
|
+
historyCollection = createStableReadonlyCollection(
|
|
596
|
+
historyCollection.slice(0, currentIndex + 1)
|
|
597
|
+
);
|
|
598
|
+
}
|
|
599
|
+
function ensureIndexInRange(index) {
|
|
600
|
+
if (!Number.isInteger(index) || index < 0 || index >= history.length) {
|
|
601
|
+
throw new Error(INVALID_HISTORY_INDEX_ERROR);
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
function travelTo(index) {
|
|
605
|
+
ensureIndexInRange(index);
|
|
606
|
+
config.applySnapshot(history[index].snapshot);
|
|
607
|
+
currentIndex = index;
|
|
608
|
+
notifyVersion();
|
|
609
|
+
}
|
|
610
|
+
function undo() {
|
|
611
|
+
if (currentIndex === 0) {
|
|
612
|
+
return false;
|
|
613
|
+
}
|
|
614
|
+
travelTo(currentIndex - 1);
|
|
615
|
+
return true;
|
|
616
|
+
}
|
|
617
|
+
function redo() {
|
|
618
|
+
if (currentIndex >= history.length - 1) {
|
|
619
|
+
return false;
|
|
620
|
+
}
|
|
621
|
+
travelTo(currentIndex + 1);
|
|
622
|
+
return true;
|
|
623
|
+
}
|
|
624
|
+
function getErrorMessage(error) {
|
|
625
|
+
if (error instanceof Error && error.message) {
|
|
626
|
+
return error.message;
|
|
627
|
+
}
|
|
628
|
+
return MESSAGE_NOT_ACKNOWLEDGED_ERROR;
|
|
629
|
+
}
|
|
630
|
+
function persistMessageAttempt(record, status, error, attemptedAt) {
|
|
631
|
+
const nextRecord = {
|
|
632
|
+
...record,
|
|
633
|
+
message: cloneValue(record.message),
|
|
634
|
+
status,
|
|
635
|
+
attempts: record.attempts + 1,
|
|
636
|
+
lastAttemptedAt: attemptedAt,
|
|
637
|
+
acknowledgedAt: status === "acknowledged" ? attemptedAt : record.acknowledgedAt,
|
|
638
|
+
error
|
|
639
|
+
};
|
|
640
|
+
messageChannel.saveMessage(nextRecord);
|
|
641
|
+
messageCollection = upsertStableReadonlyCollectionItem({
|
|
642
|
+
items: messageCollection,
|
|
643
|
+
item: cloneValue(nextRecord)
|
|
644
|
+
});
|
|
645
|
+
return nextRecord;
|
|
646
|
+
}
|
|
647
|
+
function consumeRecord(record, options) {
|
|
648
|
+
const clonedMessage = cloneValue(record.message);
|
|
649
|
+
const attemptedAt = clock();
|
|
650
|
+
try {
|
|
651
|
+
const acknowledged = config.applyMessage(clonedMessage);
|
|
652
|
+
if (!acknowledged) {
|
|
653
|
+
throw new Error(MESSAGE_NOT_ACKNOWLEDGED_ERROR);
|
|
654
|
+
}
|
|
655
|
+
const acknowledgedRecord = persistMessageAttempt(
|
|
656
|
+
{
|
|
657
|
+
...record,
|
|
658
|
+
message: clonedMessage
|
|
659
|
+
},
|
|
660
|
+
"acknowledged",
|
|
661
|
+
null,
|
|
662
|
+
attemptedAt
|
|
663
|
+
);
|
|
664
|
+
if (options?.recordHistory !== false) {
|
|
665
|
+
truncateFutureHistory();
|
|
666
|
+
recordSnapshot(acknowledgedRecord);
|
|
667
|
+
}
|
|
668
|
+
notifyVersion();
|
|
669
|
+
return true;
|
|
670
|
+
} catch (error) {
|
|
671
|
+
persistMessageAttempt(
|
|
672
|
+
{
|
|
673
|
+
...record,
|
|
674
|
+
message: clonedMessage
|
|
675
|
+
},
|
|
676
|
+
"dead-letter",
|
|
677
|
+
getErrorMessage(error),
|
|
678
|
+
attemptedAt
|
|
679
|
+
);
|
|
680
|
+
notifyVersion();
|
|
681
|
+
return false;
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
function resolveReplayRecords(ids) {
|
|
685
|
+
return ids.map((id) => {
|
|
686
|
+
if (!Number.isInteger(id) || id < 1) {
|
|
687
|
+
throw new Error(INVALID_HISTORY_MESSAGE_ID_ERROR);
|
|
688
|
+
}
|
|
689
|
+
const record = messageChannel.getMessage(id);
|
|
690
|
+
if (!record) {
|
|
691
|
+
throw new Error(INVALID_HISTORY_MESSAGE_ID_ERROR);
|
|
692
|
+
}
|
|
693
|
+
return cloneValue(record);
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
function replayByIds(input) {
|
|
697
|
+
const ids = Array.isArray(input) ? input : [input];
|
|
698
|
+
const records = resolveReplayRecords(ids);
|
|
699
|
+
let acknowledgedCount = 0;
|
|
700
|
+
records.forEach((record) => {
|
|
701
|
+
if (consumeRecord(record)) {
|
|
702
|
+
acknowledgedCount += 1;
|
|
703
|
+
}
|
|
704
|
+
});
|
|
705
|
+
return acknowledgedCount;
|
|
706
|
+
}
|
|
707
|
+
function replayDeadLetter(id) {
|
|
708
|
+
const record = messageChannel.getMessage(id);
|
|
709
|
+
if (!record || record.status !== "dead-letter") {
|
|
710
|
+
return false;
|
|
711
|
+
}
|
|
712
|
+
return consumeRecord(record);
|
|
713
|
+
}
|
|
714
|
+
function replayDeadLetters() {
|
|
715
|
+
const ids = messageChannel.getMessages().filter((record) => record.status === "dead-letter").map((record) => record.id);
|
|
716
|
+
let acknowledgedCount = 0;
|
|
717
|
+
ids.forEach((id) => {
|
|
718
|
+
if (replayDeadLetter(id)) {
|
|
719
|
+
acknowledgedCount += 1;
|
|
720
|
+
}
|
|
721
|
+
});
|
|
722
|
+
return acknowledgedCount;
|
|
723
|
+
}
|
|
724
|
+
const historySignal = (0, import_core.computed)(() => {
|
|
725
|
+
version();
|
|
726
|
+
return historyCollection;
|
|
727
|
+
});
|
|
728
|
+
const messagesSignal = (0, import_core.computed)(() => {
|
|
729
|
+
version();
|
|
730
|
+
messageCollection = syncStableReadonlyCollectionById({
|
|
731
|
+
items: messageCollection,
|
|
732
|
+
sourceItems: messageChannel.getMessages(),
|
|
733
|
+
getSourceId: (record) => record.id,
|
|
734
|
+
createItem: (record) => cloneValue(record),
|
|
735
|
+
areEquivalent: areStoreMessageRecordsEquivalent
|
|
736
|
+
});
|
|
737
|
+
return messageCollection;
|
|
738
|
+
});
|
|
739
|
+
const currentIndexSignal = (0, import_core.computed)(() => {
|
|
740
|
+
version();
|
|
741
|
+
return currentIndex;
|
|
742
|
+
});
|
|
743
|
+
return {
|
|
744
|
+
historySignal,
|
|
745
|
+
messagesSignal,
|
|
746
|
+
currentIndexSignal,
|
|
747
|
+
publish(message) {
|
|
748
|
+
const record = messageChannel.publish(message);
|
|
749
|
+
messageCollection = appendStableReadonlyCollectionItem({
|
|
750
|
+
items: messageCollection,
|
|
751
|
+
item: cloneValue(record)
|
|
752
|
+
});
|
|
753
|
+
return consumeRecord(record);
|
|
754
|
+
},
|
|
755
|
+
replay(input) {
|
|
756
|
+
return replayByIds(input);
|
|
757
|
+
},
|
|
758
|
+
travelTo,
|
|
759
|
+
undo,
|
|
760
|
+
redo,
|
|
761
|
+
getHistory(key) {
|
|
762
|
+
if (key === void 0) {
|
|
763
|
+
return history.map((entry) => cloneValue(entry));
|
|
764
|
+
}
|
|
765
|
+
return history.filter((entry) => {
|
|
766
|
+
if (entry.message === null) {
|
|
767
|
+
return true;
|
|
768
|
+
}
|
|
769
|
+
return messageAffectsKey(entry.message, key);
|
|
770
|
+
}).map((entry) => cloneValue(entry));
|
|
771
|
+
},
|
|
772
|
+
getMessages(key) {
|
|
773
|
+
const records = messageChannel.getMessages();
|
|
774
|
+
if (key === void 0) {
|
|
775
|
+
return records.map((record) => cloneValue(record));
|
|
776
|
+
}
|
|
777
|
+
return records.filter((record) => messageAffectsKey(record.message, key)).map((record) => cloneValue(record));
|
|
778
|
+
},
|
|
779
|
+
getDeadLetters() {
|
|
780
|
+
return messageChannel.getMessages().filter((record) => record.status === "dead-letter").map((record) => toDeadLetterEntry(record));
|
|
781
|
+
},
|
|
782
|
+
replayDeadLetter,
|
|
783
|
+
replayDeadLetters,
|
|
784
|
+
getCurrentIndex() {
|
|
785
|
+
return currentIndex;
|
|
786
|
+
}
|
|
787
|
+
};
|
|
788
|
+
}
|
|
35
789
|
|
|
36
790
|
// src/store-registry.ts
|
|
37
791
|
var trackedStores = /* @__PURE__ */ new Set();
|
|
38
792
|
function trackStore(store) {
|
|
39
793
|
trackedStores.add(store);
|
|
40
794
|
}
|
|
41
|
-
function clearAllStores() {
|
|
42
|
-
for (const store of [...trackedStores]) {
|
|
43
|
-
store.clearAll();
|
|
44
|
-
}
|
|
795
|
+
function clearAllStores() {
|
|
796
|
+
for (const store of [...trackedStores]) {
|
|
797
|
+
store.clearAll();
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
// src/store-message-consumer.ts
|
|
802
|
+
var import_core2 = require("@flurryx/core");
|
|
803
|
+
function createDefaultState() {
|
|
804
|
+
return {
|
|
805
|
+
data: void 0,
|
|
806
|
+
isLoading: false,
|
|
807
|
+
status: void 0,
|
|
808
|
+
errors: void 0
|
|
809
|
+
};
|
|
810
|
+
}
|
|
811
|
+
function createStoreMessageConsumer(signals, notifier) {
|
|
812
|
+
function applyUpdate(key, newState, notify = true) {
|
|
813
|
+
const sig = signals.getOrCreate(key);
|
|
814
|
+
const previousState = sig();
|
|
815
|
+
sig.update((state) => ({ ...state, ...newState }));
|
|
816
|
+
if (notify) {
|
|
817
|
+
const updatedState = sig();
|
|
818
|
+
notifier.notify(key, updatedState, previousState);
|
|
819
|
+
}
|
|
820
|
+
return true;
|
|
821
|
+
}
|
|
822
|
+
function applyClear(key) {
|
|
823
|
+
const sig = signals.getOrCreate(key);
|
|
824
|
+
const previousState = sig();
|
|
825
|
+
sig.set(createDefaultState());
|
|
826
|
+
const nextState = sig();
|
|
827
|
+
notifier.notify(key, nextState, previousState);
|
|
828
|
+
return true;
|
|
829
|
+
}
|
|
830
|
+
function applyClearAll() {
|
|
831
|
+
const keys = Array.from(signals.getAllKeys());
|
|
832
|
+
if (keys.length === 0) {
|
|
833
|
+
return false;
|
|
834
|
+
}
|
|
835
|
+
keys.forEach((key) => {
|
|
836
|
+
applyClear(key);
|
|
837
|
+
});
|
|
838
|
+
return true;
|
|
839
|
+
}
|
|
840
|
+
function applyStartLoading(key) {
|
|
841
|
+
const sig = signals.getOrCreate(key);
|
|
842
|
+
sig.update(
|
|
843
|
+
(state) => ({
|
|
844
|
+
...state,
|
|
845
|
+
status: void 0,
|
|
846
|
+
isLoading: true,
|
|
847
|
+
errors: void 0
|
|
848
|
+
})
|
|
849
|
+
);
|
|
850
|
+
return true;
|
|
851
|
+
}
|
|
852
|
+
function applyStopLoading(key) {
|
|
853
|
+
const sig = signals.getOrCreate(key);
|
|
854
|
+
sig.update(
|
|
855
|
+
(state) => ({
|
|
856
|
+
...state,
|
|
857
|
+
isLoading: false
|
|
858
|
+
})
|
|
859
|
+
);
|
|
860
|
+
return true;
|
|
861
|
+
}
|
|
862
|
+
function applyUpdateKeyedOne(key, resourceKey, entity) {
|
|
863
|
+
const sig = signals.getOrCreate(key);
|
|
864
|
+
const state = sig();
|
|
865
|
+
const data = (0, import_core2.isKeyedResourceData)(state.data) ? state.data : (0, import_core2.createKeyedResourceData)();
|
|
866
|
+
const nextErrors = { ...data.errors };
|
|
867
|
+
delete nextErrors[resourceKey];
|
|
868
|
+
const nextData = {
|
|
869
|
+
...data,
|
|
870
|
+
entities: { ...data.entities, [resourceKey]: entity },
|
|
871
|
+
isLoading: { ...data.isLoading, [resourceKey]: false },
|
|
872
|
+
status: { ...data.status, [resourceKey]: "Success" },
|
|
873
|
+
errors: nextErrors
|
|
874
|
+
};
|
|
875
|
+
return applyUpdate(key, {
|
|
876
|
+
data: nextData,
|
|
877
|
+
isLoading: (0, import_core2.isAnyKeyLoading)(nextData.isLoading),
|
|
878
|
+
status: void 0,
|
|
879
|
+
errors: void 0
|
|
880
|
+
});
|
|
881
|
+
}
|
|
882
|
+
function applyClearKeyedOne(key, resourceKey) {
|
|
883
|
+
const sig = signals.getOrCreate(key);
|
|
884
|
+
const previousState = sig();
|
|
885
|
+
const state = previousState;
|
|
886
|
+
if (!(0, import_core2.isKeyedResourceData)(state.data)) {
|
|
887
|
+
return true;
|
|
888
|
+
}
|
|
889
|
+
const data = state.data;
|
|
890
|
+
const nextEntities = { ...data.entities };
|
|
891
|
+
delete nextEntities[resourceKey];
|
|
892
|
+
const nextIsLoading = { ...data.isLoading };
|
|
893
|
+
delete nextIsLoading[resourceKey];
|
|
894
|
+
const nextStatus = { ...data.status };
|
|
895
|
+
delete nextStatus[resourceKey];
|
|
896
|
+
const nextErrors = { ...data.errors };
|
|
897
|
+
delete nextErrors[resourceKey];
|
|
898
|
+
const nextData = {
|
|
899
|
+
...data,
|
|
900
|
+
entities: nextEntities,
|
|
901
|
+
isLoading: nextIsLoading,
|
|
902
|
+
status: nextStatus,
|
|
903
|
+
errors: nextErrors
|
|
904
|
+
};
|
|
905
|
+
sig.update(
|
|
906
|
+
(prev) => ({
|
|
907
|
+
...prev,
|
|
908
|
+
data: nextData,
|
|
909
|
+
status: void 0,
|
|
910
|
+
isLoading: (0, import_core2.isAnyKeyLoading)(nextIsLoading),
|
|
911
|
+
errors: void 0
|
|
912
|
+
})
|
|
913
|
+
);
|
|
914
|
+
const updatedState = sig();
|
|
915
|
+
notifier.notify(key, updatedState, previousState);
|
|
916
|
+
return true;
|
|
917
|
+
}
|
|
918
|
+
function applyStartKeyedLoading(key, resourceKey) {
|
|
919
|
+
const sig = signals.getOrCreate(key);
|
|
920
|
+
const state = sig();
|
|
921
|
+
if (!(0, import_core2.isKeyedResourceData)(state.data)) {
|
|
922
|
+
return applyStartLoading(key);
|
|
923
|
+
}
|
|
924
|
+
const previousState = state;
|
|
925
|
+
const data = state.data;
|
|
926
|
+
const nextIsLoading = {
|
|
927
|
+
...data.isLoading,
|
|
928
|
+
[resourceKey]: true
|
|
929
|
+
};
|
|
930
|
+
const nextStatus = { ...data.status };
|
|
931
|
+
delete nextStatus[resourceKey];
|
|
932
|
+
const nextErrors = { ...data.errors };
|
|
933
|
+
delete nextErrors[resourceKey];
|
|
934
|
+
const nextData = {
|
|
935
|
+
...data,
|
|
936
|
+
isLoading: nextIsLoading,
|
|
937
|
+
status: nextStatus,
|
|
938
|
+
errors: nextErrors
|
|
939
|
+
};
|
|
940
|
+
sig.update(
|
|
941
|
+
(previous) => ({
|
|
942
|
+
...previous,
|
|
943
|
+
data: nextData,
|
|
944
|
+
status: void 0,
|
|
945
|
+
isLoading: (0, import_core2.isAnyKeyLoading)(nextIsLoading),
|
|
946
|
+
errors: void 0
|
|
947
|
+
})
|
|
948
|
+
);
|
|
949
|
+
const updatedState = sig();
|
|
950
|
+
notifier.notify(key, updatedState, previousState);
|
|
951
|
+
return true;
|
|
952
|
+
}
|
|
953
|
+
function applyMessage(message) {
|
|
954
|
+
switch (message.type) {
|
|
955
|
+
case "update":
|
|
956
|
+
return applyUpdate(message.key, cloneValue(message.state));
|
|
957
|
+
case "clear":
|
|
958
|
+
return applyClear(message.key);
|
|
959
|
+
case "clearAll":
|
|
960
|
+
return applyClearAll();
|
|
961
|
+
case "startLoading":
|
|
962
|
+
return applyStartLoading(message.key);
|
|
963
|
+
case "stopLoading":
|
|
964
|
+
return applyStopLoading(message.key);
|
|
965
|
+
case "updateKeyedOne":
|
|
966
|
+
return applyUpdateKeyedOne(
|
|
967
|
+
message.key,
|
|
968
|
+
message.resourceKey,
|
|
969
|
+
cloneValue(message.entity)
|
|
970
|
+
);
|
|
971
|
+
case "clearKeyedOne":
|
|
972
|
+
return applyClearKeyedOne(message.key, message.resourceKey);
|
|
973
|
+
case "startKeyedLoading":
|
|
974
|
+
return applyStartKeyedLoading(message.key, message.resourceKey);
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
function applySnapshot(snapshot) {
|
|
978
|
+
const keys = /* @__PURE__ */ new Set([
|
|
979
|
+
...Array.from(signals.getAllKeys()),
|
|
980
|
+
...Object.keys(snapshot)
|
|
981
|
+
]);
|
|
982
|
+
keys.forEach((rawKey) => {
|
|
983
|
+
const key = rawKey;
|
|
984
|
+
const sig = signals.getOrCreate(key);
|
|
985
|
+
const snapshotState = snapshot[key] ?? createDefaultState();
|
|
986
|
+
applyUpdate(key, createSnapshotRestorePatch(sig(), snapshotState), true);
|
|
987
|
+
});
|
|
988
|
+
}
|
|
989
|
+
function captureSnapshot() {
|
|
990
|
+
const entries = Array.from(signals.getAllKeys()).map((key) => [
|
|
991
|
+
key,
|
|
992
|
+
cloneValue(signals.getOrCreate(key)())
|
|
993
|
+
]);
|
|
994
|
+
return Object.fromEntries(entries);
|
|
995
|
+
}
|
|
996
|
+
return {
|
|
997
|
+
applyMessage,
|
|
998
|
+
applySnapshot,
|
|
999
|
+
createSnapshot: captureSnapshot
|
|
1000
|
+
};
|
|
1001
|
+
}
|
|
1002
|
+
function createUpdateMessage(key, state) {
|
|
1003
|
+
return { type: "update", key, state };
|
|
1004
|
+
}
|
|
1005
|
+
function createClearMessage(key) {
|
|
1006
|
+
return { type: "clear", key };
|
|
1007
|
+
}
|
|
1008
|
+
function createClearAllMessage() {
|
|
1009
|
+
return { type: "clearAll" };
|
|
1010
|
+
}
|
|
1011
|
+
function createStartLoadingMessage(key) {
|
|
1012
|
+
return { type: "startLoading", key };
|
|
1013
|
+
}
|
|
1014
|
+
function createStopLoadingMessage(key) {
|
|
1015
|
+
return { type: "stopLoading", key };
|
|
1016
|
+
}
|
|
1017
|
+
function createUpdateKeyedOneMessage(key, resourceKey, entity) {
|
|
1018
|
+
return {
|
|
1019
|
+
type: "updateKeyedOne",
|
|
1020
|
+
key,
|
|
1021
|
+
resourceKey,
|
|
1022
|
+
entity
|
|
1023
|
+
};
|
|
1024
|
+
}
|
|
1025
|
+
function createClearKeyedOneMessage(key, resourceKey) {
|
|
1026
|
+
return {
|
|
1027
|
+
type: "clearKeyedOne",
|
|
1028
|
+
key,
|
|
1029
|
+
resourceKey
|
|
1030
|
+
};
|
|
1031
|
+
}
|
|
1032
|
+
function createStartKeyedLoadingMessage(key, resourceKey) {
|
|
1033
|
+
return {
|
|
1034
|
+
type: "startKeyedLoading",
|
|
1035
|
+
key,
|
|
1036
|
+
resourceKey
|
|
1037
|
+
};
|
|
45
1038
|
}
|
|
46
1039
|
|
|
47
1040
|
// src/base-store.ts
|
|
48
1041
|
var updateHooksMap = /* @__PURE__ */ new WeakMap();
|
|
49
1042
|
var BaseStore = class {
|
|
50
|
-
constructor(storeEnum) {
|
|
1043
|
+
constructor(storeEnum, options) {
|
|
51
1044
|
this.storeEnum = storeEnum;
|
|
1045
|
+
this.storeKeys = Object.keys(storeEnum);
|
|
52
1046
|
this.initializeState();
|
|
53
1047
|
updateHooksMap.set(this, /* @__PURE__ */ new Map());
|
|
1048
|
+
const consumer = createStoreMessageConsumer(
|
|
1049
|
+
{
|
|
1050
|
+
getOrCreate: (key) => this.signalsState.get(key),
|
|
1051
|
+
getAllKeys: () => this.storeKeys
|
|
1052
|
+
},
|
|
1053
|
+
{
|
|
1054
|
+
notify: (key, next, prev) => this.notifyUpdateHooks(key, next, prev)
|
|
1055
|
+
}
|
|
1056
|
+
);
|
|
1057
|
+
this.historyDriver = createStoreHistory({
|
|
1058
|
+
captureSnapshot: () => consumer.createSnapshot(),
|
|
1059
|
+
applySnapshot: (snapshot) => consumer.applySnapshot(snapshot),
|
|
1060
|
+
applyMessage: (message) => consumer.applyMessage(message),
|
|
1061
|
+
channel: options?.channel
|
|
1062
|
+
});
|
|
1063
|
+
this.history = this.historyDriver.historySignal;
|
|
1064
|
+
this.messages = this.historyDriver.messagesSignal;
|
|
1065
|
+
this.currentIndex = this.historyDriver.currentIndexSignal;
|
|
1066
|
+
this.keys = (0, import_core3.signal)([...this.storeKeys]).asReadonly();
|
|
54
1067
|
trackStore(this);
|
|
55
1068
|
}
|
|
56
1069
|
signalsState = /* @__PURE__ */ new Map();
|
|
1070
|
+
storeKeys;
|
|
1071
|
+
historyDriver;
|
|
1072
|
+
/** @inheritDoc */
|
|
1073
|
+
travelTo = (index) => this.historyDriver.travelTo(index);
|
|
1074
|
+
/** @inheritDoc */
|
|
1075
|
+
undo = () => this.historyDriver.undo();
|
|
1076
|
+
/** @inheritDoc */
|
|
1077
|
+
redo = () => this.historyDriver.redo();
|
|
1078
|
+
/** @inheritDoc */
|
|
1079
|
+
getDeadLetters = () => this.historyDriver.getDeadLetters();
|
|
1080
|
+
/** @inheritDoc */
|
|
1081
|
+
replayDeadLetter = (id) => this.historyDriver.replayDeadLetter(id);
|
|
1082
|
+
/** @inheritDoc */
|
|
1083
|
+
replayDeadLetters = () => this.historyDriver.replayDeadLetters();
|
|
1084
|
+
/** @inheritDoc */
|
|
1085
|
+
getCurrentIndex = () => this.historyDriver.getCurrentIndex();
|
|
1086
|
+
/** @inheritDoc */
|
|
1087
|
+
history;
|
|
1088
|
+
/** @inheritDoc */
|
|
1089
|
+
messages;
|
|
1090
|
+
/** @inheritDoc */
|
|
1091
|
+
currentIndex;
|
|
1092
|
+
/** @inheritDoc */
|
|
1093
|
+
keys;
|
|
1094
|
+
replay(idOrIds) {
|
|
1095
|
+
if (Array.isArray(idOrIds)) {
|
|
1096
|
+
return this.historyDriver.replay(idOrIds);
|
|
1097
|
+
}
|
|
1098
|
+
return this.historyDriver.replay(idOrIds);
|
|
1099
|
+
}
|
|
1100
|
+
getHistory(key) {
|
|
1101
|
+
if (key === void 0) {
|
|
1102
|
+
return this.historyDriver.getHistory();
|
|
1103
|
+
}
|
|
1104
|
+
return this.historyDriver.getHistory(key);
|
|
1105
|
+
}
|
|
1106
|
+
getMessages(key) {
|
|
1107
|
+
if (key === void 0) {
|
|
1108
|
+
return this.historyDriver.getMessages();
|
|
1109
|
+
}
|
|
1110
|
+
return this.historyDriver.getMessages(key);
|
|
1111
|
+
}
|
|
57
1112
|
/**
|
|
58
1113
|
* Returns a **read-only** `Signal` for the given store slot.
|
|
59
1114
|
*
|
|
@@ -98,23 +1153,13 @@ var BaseStore = class {
|
|
|
98
1153
|
* @param newState - Partial state to merge (e.g. `{ data: newData, status: 'Success' }`).
|
|
99
1154
|
*/
|
|
100
1155
|
update(key, newState) {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
const previousState = currentState();
|
|
106
|
-
currentState.update((state) => ({
|
|
107
|
-
...state,
|
|
108
|
-
...newState
|
|
109
|
-
}));
|
|
110
|
-
const updatedState = currentState();
|
|
111
|
-
this.notifyUpdateHooks(key, updatedState, previousState);
|
|
1156
|
+
this.historyDriver.publish(
|
|
1157
|
+
createUpdateMessage(key, cloneValue(newState))
|
|
1158
|
+
);
|
|
112
1159
|
}
|
|
113
1160
|
/** Resets every slot in this store to its initial idle state. */
|
|
114
1161
|
clearAll() {
|
|
115
|
-
|
|
116
|
-
this.clear(key);
|
|
117
|
-
});
|
|
1162
|
+
this.historyDriver.publish(createClearAllMessage());
|
|
118
1163
|
}
|
|
119
1164
|
/**
|
|
120
1165
|
* Resets a single slot to `{ data: undefined, isLoading: false, status: undefined, errors: undefined }`.
|
|
@@ -122,20 +1167,7 @@ var BaseStore = class {
|
|
|
122
1167
|
* @param key - The slot to clear.
|
|
123
1168
|
*/
|
|
124
1169
|
clear(key) {
|
|
125
|
-
|
|
126
|
-
if (!currentState) {
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
const previousState = currentState();
|
|
130
|
-
const _typedKey = key;
|
|
131
|
-
currentState.set({
|
|
132
|
-
data: void 0,
|
|
133
|
-
isLoading: false,
|
|
134
|
-
status: void 0,
|
|
135
|
-
errors: void 0
|
|
136
|
-
});
|
|
137
|
-
const nextState = currentState();
|
|
138
|
-
this.notifyUpdateHooks(key, nextState, previousState);
|
|
1170
|
+
this.historyDriver.publish(createClearMessage(key));
|
|
139
1171
|
}
|
|
140
1172
|
/**
|
|
141
1173
|
* Marks a slot as loading: sets `isLoading: true` and clears `status` and `errors`.
|
|
@@ -143,19 +1175,7 @@ var BaseStore = class {
|
|
|
143
1175
|
* @param key - The slot to mark as loading.
|
|
144
1176
|
*/
|
|
145
1177
|
startLoading(key) {
|
|
146
|
-
|
|
147
|
-
if (!currentState) {
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
const _typedKey = key;
|
|
151
|
-
currentState.update(
|
|
152
|
-
(state) => ({
|
|
153
|
-
...state,
|
|
154
|
-
status: void 0,
|
|
155
|
-
isLoading: true,
|
|
156
|
-
errors: void 0
|
|
157
|
-
})
|
|
158
|
-
);
|
|
1178
|
+
this.historyDriver.publish(createStartLoadingMessage(key));
|
|
159
1179
|
}
|
|
160
1180
|
/**
|
|
161
1181
|
* Marks a slot as no longer loading: sets `isLoading: false`.
|
|
@@ -164,17 +1184,7 @@ var BaseStore = class {
|
|
|
164
1184
|
* @param key - The slot to stop loading.
|
|
165
1185
|
*/
|
|
166
1186
|
stopLoading(key) {
|
|
167
|
-
|
|
168
|
-
if (!currentState) {
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
|
-
const _typedKey = key;
|
|
172
|
-
currentState.update(
|
|
173
|
-
(state) => ({
|
|
174
|
-
...state,
|
|
175
|
-
isLoading: false
|
|
176
|
-
})
|
|
177
|
-
);
|
|
1187
|
+
this.historyDriver.publish(createStopLoadingMessage(key));
|
|
178
1188
|
}
|
|
179
1189
|
/**
|
|
180
1190
|
* Merges a single entity into a {@link KeyedResourceData} slot.
|
|
@@ -186,36 +1196,13 @@ var BaseStore = class {
|
|
|
186
1196
|
* @param entity - The entity value to store.
|
|
187
1197
|
*/
|
|
188
1198
|
updateKeyedOne(key, resourceKey, entity) {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
delete nextErrors[resourceKey];
|
|
197
|
-
const nextData = {
|
|
198
|
-
...data,
|
|
199
|
-
entities: {
|
|
200
|
-
...data.entities,
|
|
201
|
-
[resourceKey]: entity
|
|
202
|
-
},
|
|
203
|
-
isLoading: {
|
|
204
|
-
...data.isLoading,
|
|
205
|
-
[resourceKey]: false
|
|
206
|
-
},
|
|
207
|
-
status: {
|
|
208
|
-
...data.status,
|
|
209
|
-
[resourceKey]: "Success"
|
|
210
|
-
},
|
|
211
|
-
errors: nextErrors
|
|
212
|
-
};
|
|
213
|
-
this.update(key, {
|
|
214
|
-
data: nextData,
|
|
215
|
-
isLoading: (0, import_core2.isAnyKeyLoading)(nextData.isLoading),
|
|
216
|
-
status: void 0,
|
|
217
|
-
errors: void 0
|
|
218
|
-
});
|
|
1199
|
+
this.historyDriver.publish(
|
|
1200
|
+
createUpdateKeyedOneMessage(
|
|
1201
|
+
key,
|
|
1202
|
+
resourceKey,
|
|
1203
|
+
cloneValue(entity)
|
|
1204
|
+
)
|
|
1205
|
+
);
|
|
219
1206
|
}
|
|
220
1207
|
/**
|
|
221
1208
|
* Removes a single entity from a {@link KeyedResourceData} slot,
|
|
@@ -226,43 +1213,9 @@ var BaseStore = class {
|
|
|
226
1213
|
* @param resourceKey - The entity identifier to remove.
|
|
227
1214
|
*/
|
|
228
1215
|
clearKeyedOne(key, resourceKey) {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
|
-
const previousState = currentState();
|
|
234
|
-
const state = previousState;
|
|
235
|
-
if (!(0, import_core2.isKeyedResourceData)(state.data)) {
|
|
236
|
-
return;
|
|
237
|
-
}
|
|
238
|
-
const data = state.data;
|
|
239
|
-
const nextEntities = { ...data.entities };
|
|
240
|
-
delete nextEntities[resourceKey];
|
|
241
|
-
const nextIsLoading = { ...data.isLoading };
|
|
242
|
-
delete nextIsLoading[resourceKey];
|
|
243
|
-
const nextStatus = { ...data.status };
|
|
244
|
-
delete nextStatus[resourceKey];
|
|
245
|
-
const nextErrors = { ...data.errors };
|
|
246
|
-
delete nextErrors[resourceKey];
|
|
247
|
-
const nextData = {
|
|
248
|
-
...data,
|
|
249
|
-
entities: nextEntities,
|
|
250
|
-
isLoading: nextIsLoading,
|
|
251
|
-
status: nextStatus,
|
|
252
|
-
errors: nextErrors
|
|
253
|
-
};
|
|
254
|
-
const _typedKey = key;
|
|
255
|
-
currentState.update(
|
|
256
|
-
(prev) => ({
|
|
257
|
-
...prev,
|
|
258
|
-
data: nextData,
|
|
259
|
-
status: void 0,
|
|
260
|
-
isLoading: (0, import_core2.isAnyKeyLoading)(nextIsLoading),
|
|
261
|
-
errors: void 0
|
|
262
|
-
})
|
|
1216
|
+
this.historyDriver.publish(
|
|
1217
|
+
createClearKeyedOneMessage(key, resourceKey)
|
|
263
1218
|
);
|
|
264
|
-
const updatedState = currentState();
|
|
265
|
-
this.notifyUpdateHooks(key, updatedState, previousState);
|
|
266
1219
|
}
|
|
267
1220
|
/**
|
|
268
1221
|
* Marks a single entity within a keyed slot as loading.
|
|
@@ -273,47 +1226,9 @@ var BaseStore = class {
|
|
|
273
1226
|
* @param resourceKey - The entity identifier to mark as loading.
|
|
274
1227
|
*/
|
|
275
1228
|
startKeyedLoading(key, resourceKey) {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
return;
|
|
279
|
-
}
|
|
280
|
-
const _typedKey = key;
|
|
281
|
-
const state = currentState();
|
|
282
|
-
if (!(0, import_core2.isKeyedResourceData)(state.data)) {
|
|
283
|
-
this.startLoading(key);
|
|
284
|
-
return;
|
|
285
|
-
}
|
|
286
|
-
const previousState = state;
|
|
287
|
-
const data = state.data;
|
|
288
|
-
const nextIsLoading = {
|
|
289
|
-
...data.isLoading,
|
|
290
|
-
[resourceKey]: true
|
|
291
|
-
};
|
|
292
|
-
const nextStatus = {
|
|
293
|
-
...data.status
|
|
294
|
-
};
|
|
295
|
-
delete nextStatus[resourceKey];
|
|
296
|
-
const nextErrors = {
|
|
297
|
-
...data.errors
|
|
298
|
-
};
|
|
299
|
-
delete nextErrors[resourceKey];
|
|
300
|
-
const nextData = {
|
|
301
|
-
...data,
|
|
302
|
-
isLoading: nextIsLoading,
|
|
303
|
-
status: nextStatus,
|
|
304
|
-
errors: nextErrors
|
|
305
|
-
};
|
|
306
|
-
currentState.update(
|
|
307
|
-
(previous) => ({
|
|
308
|
-
...previous,
|
|
309
|
-
data: nextData,
|
|
310
|
-
status: void 0,
|
|
311
|
-
isLoading: (0, import_core2.isAnyKeyLoading)(nextIsLoading),
|
|
312
|
-
errors: void 0
|
|
313
|
-
})
|
|
1229
|
+
this.historyDriver.publish(
|
|
1230
|
+
createStartKeyedLoadingMessage(key, resourceKey)
|
|
314
1231
|
);
|
|
315
|
-
const updatedState = currentState();
|
|
316
|
-
this.notifyUpdateHooks(key, updatedState, previousState);
|
|
317
1232
|
}
|
|
318
1233
|
notifyUpdateHooks(key, nextState, previousState) {
|
|
319
1234
|
const hooks = updateHooksMap.get(this);
|
|
@@ -321,187 +1236,165 @@ var BaseStore = class {
|
|
|
321
1236
|
if (!keyHooks) {
|
|
322
1237
|
return;
|
|
323
1238
|
}
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
1239
|
+
const errors = [];
|
|
1240
|
+
keyHooks.forEach((hook) => {
|
|
1241
|
+
try {
|
|
1242
|
+
hook(
|
|
1243
|
+
nextState,
|
|
1244
|
+
previousState
|
|
1245
|
+
);
|
|
1246
|
+
} catch (error) {
|
|
1247
|
+
errors.push(error);
|
|
1248
|
+
}
|
|
1249
|
+
});
|
|
1250
|
+
if (errors.length > 0) {
|
|
1251
|
+
queueMicrotask(() => {
|
|
1252
|
+
if (errors.length === 1) {
|
|
1253
|
+
throw errors[0];
|
|
1254
|
+
}
|
|
1255
|
+
throw new AggregateError(
|
|
1256
|
+
errors,
|
|
1257
|
+
`${errors.length} onUpdate hooks threw for key "${String(key)}"`
|
|
1258
|
+
);
|
|
1259
|
+
});
|
|
1260
|
+
}
|
|
330
1261
|
}
|
|
331
1262
|
initializeState() {
|
|
332
|
-
|
|
333
|
-
const _typedKey = key;
|
|
334
|
-
const initialState = {
|
|
335
|
-
data: void 0,
|
|
336
|
-
isLoading: false,
|
|
337
|
-
status: void 0,
|
|
338
|
-
errors: void 0
|
|
339
|
-
};
|
|
1263
|
+
this.storeKeys.forEach((key) => {
|
|
340
1264
|
this.signalsState.set(
|
|
341
|
-
|
|
342
|
-
(0,
|
|
1265
|
+
key,
|
|
1266
|
+
(0, import_core3.signal)(createDefaultState())
|
|
343
1267
|
);
|
|
344
1268
|
});
|
|
345
1269
|
}
|
|
346
1270
|
};
|
|
347
1271
|
|
|
348
1272
|
// src/lazy-store.ts
|
|
349
|
-
var
|
|
350
|
-
var import_core4 = require("@flurryx/core");
|
|
351
|
-
function createDefaultState() {
|
|
352
|
-
return {
|
|
353
|
-
data: void 0,
|
|
354
|
-
isLoading: false,
|
|
355
|
-
status: void 0,
|
|
356
|
-
errors: void 0
|
|
357
|
-
};
|
|
358
|
-
}
|
|
1273
|
+
var import_core4 = require("@angular/core");
|
|
359
1274
|
var LazyStore = class {
|
|
360
1275
|
signals = /* @__PURE__ */ new Map();
|
|
361
1276
|
hooks = /* @__PURE__ */ new Map();
|
|
362
|
-
|
|
1277
|
+
historyDriver;
|
|
1278
|
+
/** @inheritDoc */
|
|
1279
|
+
travelTo = (index) => this.historyDriver.travelTo(index);
|
|
1280
|
+
/** @inheritDoc */
|
|
1281
|
+
undo = () => this.historyDriver.undo();
|
|
1282
|
+
/** @inheritDoc */
|
|
1283
|
+
redo = () => this.historyDriver.redo();
|
|
1284
|
+
getMessages(key) {
|
|
1285
|
+
if (key === void 0) {
|
|
1286
|
+
return this.historyDriver.getMessages();
|
|
1287
|
+
}
|
|
1288
|
+
return this.historyDriver.getMessages(key);
|
|
1289
|
+
}
|
|
1290
|
+
getDeadLetters = () => this.historyDriver.getDeadLetters();
|
|
1291
|
+
/** @inheritDoc */
|
|
1292
|
+
replayDeadLetter = (id) => this.historyDriver.replayDeadLetter(id);
|
|
1293
|
+
/** @inheritDoc */
|
|
1294
|
+
replayDeadLetters = () => this.historyDriver.replayDeadLetters();
|
|
1295
|
+
/** @inheritDoc */
|
|
1296
|
+
getCurrentIndex = () => this.historyDriver.getCurrentIndex();
|
|
1297
|
+
/** @inheritDoc */
|
|
1298
|
+
history;
|
|
1299
|
+
/** @inheritDoc */
|
|
1300
|
+
messages;
|
|
1301
|
+
/** @inheritDoc */
|
|
1302
|
+
currentIndex;
|
|
1303
|
+
/** @inheritDoc */
|
|
1304
|
+
keys;
|
|
1305
|
+
keysSignal = (0, import_core4.signal)([]);
|
|
1306
|
+
replay(idOrIds) {
|
|
1307
|
+
if (Array.isArray(idOrIds)) {
|
|
1308
|
+
return this.historyDriver.replay(idOrIds);
|
|
1309
|
+
}
|
|
1310
|
+
return this.historyDriver.replay(idOrIds);
|
|
1311
|
+
}
|
|
1312
|
+
getHistory(key) {
|
|
1313
|
+
if (key === void 0) {
|
|
1314
|
+
return this.historyDriver.getHistory();
|
|
1315
|
+
}
|
|
1316
|
+
return this.historyDriver.getHistory(key);
|
|
1317
|
+
}
|
|
1318
|
+
constructor(options) {
|
|
1319
|
+
const consumer = createStoreMessageConsumer(
|
|
1320
|
+
{
|
|
1321
|
+
getOrCreate: (key) => this.getOrCreate(key),
|
|
1322
|
+
getAllKeys: () => this.signals.keys()
|
|
1323
|
+
},
|
|
1324
|
+
{
|
|
1325
|
+
notify: (key, next, prev) => this.notifyHooks(key, next, prev)
|
|
1326
|
+
}
|
|
1327
|
+
);
|
|
1328
|
+
this.historyDriver = createStoreHistory({
|
|
1329
|
+
captureSnapshot: () => consumer.createSnapshot(),
|
|
1330
|
+
applySnapshot: (snapshot) => consumer.applySnapshot(snapshot),
|
|
1331
|
+
applyMessage: (message) => consumer.applyMessage(message),
|
|
1332
|
+
channel: options?.channel
|
|
1333
|
+
});
|
|
1334
|
+
this.history = this.historyDriver.historySignal;
|
|
1335
|
+
this.messages = this.historyDriver.messagesSignal;
|
|
1336
|
+
this.currentIndex = this.historyDriver.currentIndexSignal;
|
|
1337
|
+
this.keys = this.keysSignal.asReadonly();
|
|
363
1338
|
trackStore(this);
|
|
364
1339
|
}
|
|
365
1340
|
getOrCreate(key) {
|
|
366
1341
|
let sig = this.signals.get(key);
|
|
367
1342
|
if (!sig) {
|
|
368
|
-
sig = (0,
|
|
1343
|
+
sig = (0, import_core4.signal)(createDefaultState());
|
|
369
1344
|
this.signals.set(key, sig);
|
|
1345
|
+
this.keysSignal.update((prev) => [...prev, key]);
|
|
370
1346
|
}
|
|
371
1347
|
return sig;
|
|
372
1348
|
}
|
|
1349
|
+
/** @inheritDoc */
|
|
373
1350
|
get(key) {
|
|
374
1351
|
return this.getOrCreate(key);
|
|
375
1352
|
}
|
|
1353
|
+
/** @inheritDoc */
|
|
376
1354
|
update(key, newState) {
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
const nextState = sig();
|
|
381
|
-
this.notifyHooks(key, nextState, previousState);
|
|
1355
|
+
this.historyDriver.publish(
|
|
1356
|
+
createUpdateMessage(key, cloneValue(newState))
|
|
1357
|
+
);
|
|
382
1358
|
}
|
|
1359
|
+
/** @inheritDoc */
|
|
383
1360
|
clear(key) {
|
|
384
|
-
|
|
385
|
-
const previousState = sig();
|
|
386
|
-
sig.set(createDefaultState());
|
|
387
|
-
const nextState = sig();
|
|
388
|
-
this.notifyHooks(key, nextState, previousState);
|
|
1361
|
+
this.historyDriver.publish(createClearMessage(key));
|
|
389
1362
|
}
|
|
1363
|
+
/** @inheritDoc */
|
|
390
1364
|
clearAll() {
|
|
391
|
-
|
|
392
|
-
this.clear(key);
|
|
393
|
-
}
|
|
1365
|
+
this.historyDriver.publish(createClearAllMessage());
|
|
394
1366
|
}
|
|
1367
|
+
/** @inheritDoc */
|
|
395
1368
|
startLoading(key) {
|
|
396
|
-
|
|
397
|
-
sig.update(
|
|
398
|
-
(state) => ({
|
|
399
|
-
...state,
|
|
400
|
-
status: void 0,
|
|
401
|
-
isLoading: true,
|
|
402
|
-
errors: void 0
|
|
403
|
-
})
|
|
404
|
-
);
|
|
1369
|
+
this.historyDriver.publish(createStartLoadingMessage(key));
|
|
405
1370
|
}
|
|
1371
|
+
/** @inheritDoc */
|
|
406
1372
|
stopLoading(key) {
|
|
407
|
-
|
|
408
|
-
sig.update(
|
|
409
|
-
(state) => ({
|
|
410
|
-
...state,
|
|
411
|
-
isLoading: false
|
|
412
|
-
})
|
|
413
|
-
);
|
|
1373
|
+
this.historyDriver.publish(createStopLoadingMessage(key));
|
|
414
1374
|
}
|
|
1375
|
+
/** @inheritDoc */
|
|
415
1376
|
updateKeyedOne(key, resourceKey, entity) {
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
entities: { ...data.entities, [resourceKey]: entity },
|
|
424
|
-
isLoading: { ...data.isLoading, [resourceKey]: false },
|
|
425
|
-
status: { ...data.status, [resourceKey]: "Success" },
|
|
426
|
-
errors: nextErrors
|
|
427
|
-
};
|
|
428
|
-
this.update(key, {
|
|
429
|
-
data: nextData,
|
|
430
|
-
isLoading: (0, import_core4.isAnyKeyLoading)(nextData.isLoading),
|
|
431
|
-
status: void 0,
|
|
432
|
-
errors: void 0
|
|
433
|
-
});
|
|
1377
|
+
this.historyDriver.publish(
|
|
1378
|
+
createUpdateKeyedOneMessage(
|
|
1379
|
+
key,
|
|
1380
|
+
resourceKey,
|
|
1381
|
+
cloneValue(entity)
|
|
1382
|
+
)
|
|
1383
|
+
);
|
|
434
1384
|
}
|
|
1385
|
+
/** @inheritDoc */
|
|
435
1386
|
clearKeyedOne(key, resourceKey) {
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
if (!(0, import_core4.isKeyedResourceData)(state.data)) {
|
|
439
|
-
return;
|
|
440
|
-
}
|
|
441
|
-
const data = state.data;
|
|
442
|
-
const previousState = state;
|
|
443
|
-
const nextEntities = { ...data.entities };
|
|
444
|
-
delete nextEntities[resourceKey];
|
|
445
|
-
const nextIsLoading = { ...data.isLoading };
|
|
446
|
-
delete nextIsLoading[resourceKey];
|
|
447
|
-
const nextStatus = { ...data.status };
|
|
448
|
-
delete nextStatus[resourceKey];
|
|
449
|
-
const nextErrors = { ...data.errors };
|
|
450
|
-
delete nextErrors[resourceKey];
|
|
451
|
-
const nextData = {
|
|
452
|
-
...data,
|
|
453
|
-
entities: nextEntities,
|
|
454
|
-
isLoading: nextIsLoading,
|
|
455
|
-
status: nextStatus,
|
|
456
|
-
errors: nextErrors
|
|
457
|
-
};
|
|
458
|
-
sig.update(
|
|
459
|
-
(prev) => ({
|
|
460
|
-
...prev,
|
|
461
|
-
data: nextData,
|
|
462
|
-
status: void 0,
|
|
463
|
-
isLoading: (0, import_core4.isAnyKeyLoading)(nextIsLoading),
|
|
464
|
-
errors: void 0
|
|
465
|
-
})
|
|
1387
|
+
this.historyDriver.publish(
|
|
1388
|
+
createClearKeyedOneMessage(key, resourceKey)
|
|
466
1389
|
);
|
|
467
|
-
const updatedState = sig();
|
|
468
|
-
this.notifyHooks(key, updatedState, previousState);
|
|
469
1390
|
}
|
|
1391
|
+
/** @inheritDoc */
|
|
470
1392
|
startKeyedLoading(key, resourceKey) {
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
if (!(0, import_core4.isKeyedResourceData)(state.data)) {
|
|
474
|
-
this.startLoading(key);
|
|
475
|
-
return;
|
|
476
|
-
}
|
|
477
|
-
const previousState = state;
|
|
478
|
-
const data = state.data;
|
|
479
|
-
const nextIsLoading = {
|
|
480
|
-
...data.isLoading,
|
|
481
|
-
[resourceKey]: true
|
|
482
|
-
};
|
|
483
|
-
const nextStatus = { ...data.status };
|
|
484
|
-
delete nextStatus[resourceKey];
|
|
485
|
-
const nextErrors = { ...data.errors };
|
|
486
|
-
delete nextErrors[resourceKey];
|
|
487
|
-
const nextData = {
|
|
488
|
-
...data,
|
|
489
|
-
isLoading: nextIsLoading,
|
|
490
|
-
status: nextStatus,
|
|
491
|
-
errors: nextErrors
|
|
492
|
-
};
|
|
493
|
-
sig.update(
|
|
494
|
-
(previous) => ({
|
|
495
|
-
...previous,
|
|
496
|
-
data: nextData,
|
|
497
|
-
status: void 0,
|
|
498
|
-
isLoading: (0, import_core4.isAnyKeyLoading)(nextIsLoading),
|
|
499
|
-
errors: void 0
|
|
500
|
-
})
|
|
1393
|
+
this.historyDriver.publish(
|
|
1394
|
+
createStartKeyedLoadingMessage(key, resourceKey)
|
|
501
1395
|
);
|
|
502
|
-
const updatedState = sig();
|
|
503
|
-
this.notifyHooks(key, updatedState, previousState);
|
|
504
1396
|
}
|
|
1397
|
+
/** @inheritDoc */
|
|
505
1398
|
onUpdate(key, callback) {
|
|
506
1399
|
if (!this.hooks.has(key)) {
|
|
507
1400
|
this.hooks.set(key, []);
|
|
@@ -524,12 +1417,28 @@ var LazyStore = class {
|
|
|
524
1417
|
if (!keyHooks) {
|
|
525
1418
|
return;
|
|
526
1419
|
}
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
1420
|
+
const errors = [];
|
|
1421
|
+
keyHooks.forEach((hook) => {
|
|
1422
|
+
try {
|
|
1423
|
+
hook(
|
|
1424
|
+
nextState,
|
|
1425
|
+
previousState
|
|
1426
|
+
);
|
|
1427
|
+
} catch (error) {
|
|
1428
|
+
errors.push(error);
|
|
1429
|
+
}
|
|
1430
|
+
});
|
|
1431
|
+
if (errors.length > 0) {
|
|
1432
|
+
queueMicrotask(() => {
|
|
1433
|
+
if (errors.length === 1) {
|
|
1434
|
+
throw errors[0];
|
|
1435
|
+
}
|
|
1436
|
+
throw new AggregateError(
|
|
1437
|
+
errors,
|
|
1438
|
+
`${errors.length} onUpdate hooks threw for key "${String(key)}"`
|
|
1439
|
+
);
|
|
1440
|
+
});
|
|
1441
|
+
}
|
|
533
1442
|
}
|
|
534
1443
|
};
|
|
535
1444
|
|
|
@@ -538,12 +1447,12 @@ var import_core6 = require("@angular/core");
|
|
|
538
1447
|
|
|
539
1448
|
// src/dynamic-store.ts
|
|
540
1449
|
var DynamicStore = class extends BaseStore {
|
|
541
|
-
constructor(config) {
|
|
1450
|
+
constructor(config, options) {
|
|
542
1451
|
const identityEnum = Object.keys(config).reduce(
|
|
543
1452
|
(acc, key) => ({ ...acc, [key]: key }),
|
|
544
1453
|
{}
|
|
545
1454
|
);
|
|
546
|
-
super(identityEnum);
|
|
1455
|
+
super(identityEnum, options);
|
|
547
1456
|
}
|
|
548
1457
|
};
|
|
549
1458
|
|
|
@@ -678,7 +1587,6 @@ function wireMirrors(store, mirrors) {
|
|
|
678
1587
|
def.targetKey
|
|
679
1588
|
);
|
|
680
1589
|
}
|
|
681
|
-
return store;
|
|
682
1590
|
}
|
|
683
1591
|
function wireMirrorKeyed(store, defs) {
|
|
684
1592
|
for (const def of defs) {
|
|
@@ -693,7 +1601,6 @@ function wireMirrorKeyed(store, defs) {
|
|
|
693
1601
|
}
|
|
694
1602
|
);
|
|
695
1603
|
}
|
|
696
|
-
return store;
|
|
697
1604
|
}
|
|
698
1605
|
var MIRROR_SELF_SAME_KEY_ERROR = "mirrorSelf source and target keys must be different";
|
|
699
1606
|
function wireSelfMirrors(store, defs) {
|
|
@@ -708,7 +1615,6 @@ function wireSelfMirrors(store, defs) {
|
|
|
708
1615
|
def.targetKey
|
|
709
1616
|
);
|
|
710
1617
|
}
|
|
711
|
-
return store;
|
|
712
1618
|
}
|
|
713
1619
|
function createBuilder(accum, mirrors = [], mirrorKeyedDefs = [], selfMirrors = []) {
|
|
714
1620
|
return {
|
|
@@ -765,11 +1671,11 @@ function createBuilder(accum, mirrors = [], mirrorKeyedDefs = [], selfMirrors =
|
|
|
765
1671
|
selfMirrors
|
|
766
1672
|
);
|
|
767
1673
|
},
|
|
768
|
-
build() {
|
|
1674
|
+
build(options) {
|
|
769
1675
|
return new import_core6.InjectionToken("FlurryxStore", {
|
|
770
1676
|
providedIn: "root",
|
|
771
1677
|
factory: () => {
|
|
772
|
-
const store = new DynamicStore(accum);
|
|
1678
|
+
const store = new DynamicStore(accum, options);
|
|
773
1679
|
wireMirrors(store, mirrors);
|
|
774
1680
|
wireMirrorKeyed(store, mirrorKeyedDefs);
|
|
775
1681
|
wireSelfMirrors(store, selfMirrors);
|
|
@@ -840,11 +1746,11 @@ function createConstrainedBuilder(_enumObj, accum, mirrors = [], mirrorKeyedDefs
|
|
|
840
1746
|
selfMirrors
|
|
841
1747
|
);
|
|
842
1748
|
},
|
|
843
|
-
build() {
|
|
1749
|
+
build(options) {
|
|
844
1750
|
return new import_core6.InjectionToken("FlurryxStore", {
|
|
845
1751
|
providedIn: "root",
|
|
846
1752
|
factory: () => {
|
|
847
|
-
const store = new DynamicStore(accum);
|
|
1753
|
+
const store = new DynamicStore(accum, options);
|
|
848
1754
|
wireMirrors(store, mirrors);
|
|
849
1755
|
wireMirrorKeyed(store, mirrorKeyedDefs);
|
|
850
1756
|
wireSelfMirrors(store, selfMirrors);
|
|
@@ -891,11 +1797,11 @@ function createInterfaceBuilder(mirrors = [], mirrorKeyedDefs = [], selfMirrors
|
|
|
891
1797
|
selfMirrors
|
|
892
1798
|
);
|
|
893
1799
|
},
|
|
894
|
-
build() {
|
|
1800
|
+
build(options) {
|
|
895
1801
|
return new import_core6.InjectionToken("FlurryxStore", {
|
|
896
1802
|
providedIn: "root",
|
|
897
1803
|
factory: () => {
|
|
898
|
-
const store = new LazyStore();
|
|
1804
|
+
const store = new LazyStore(options);
|
|
899
1805
|
wireMirrors(store, mirrors);
|
|
900
1806
|
wireMirrorKeyed(store, mirrorKeyedDefs);
|
|
901
1807
|
wireSelfMirrors(store, selfMirrors);
|
|
@@ -921,7 +1827,14 @@ function createStoreFor(enumObj) {
|
|
|
921
1827
|
LazyStore,
|
|
922
1828
|
Store,
|
|
923
1829
|
clearAllStores,
|
|
1830
|
+
cloneValue,
|
|
924
1831
|
collectKeyed,
|
|
1832
|
+
createCompositeStoreMessageChannel,
|
|
1833
|
+
createInMemoryStoreMessageChannel,
|
|
1834
|
+
createLocalStorageStoreMessageChannel,
|
|
1835
|
+
createSessionStorageStoreMessageChannel,
|
|
1836
|
+
createSnapshotRestorePatch,
|
|
1837
|
+
createStorageStoreMessageChannel,
|
|
925
1838
|
mirrorKey
|
|
926
1839
|
});
|
|
927
1840
|
//# sourceMappingURL=index.cjs.map
|