@asaidimu/utils-store 10.2.17 → 11.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/index.d.cts +11 -0
- package/index.d.ts +11 -0
- package/index.js +36 -14
- package/index.mjs +36 -14
- package/package.json +5 -5
package/index.d.cts
CHANGED
|
@@ -527,6 +527,10 @@ interface DataStore<T extends object> {
|
|
|
527
527
|
* Releases all resources held by the store and renders it unusable
|
|
528
528
|
*/
|
|
529
529
|
dispose(): Promise<void>;
|
|
530
|
+
/**
|
|
531
|
+
* Checks whether the store has been disposed
|
|
532
|
+
*/
|
|
533
|
+
disposed(): boolean;
|
|
530
534
|
}
|
|
531
535
|
/** Payload for the 'persistence:queued' event. */
|
|
532
536
|
interface PersistenceQueuedPayload {
|
|
@@ -1336,6 +1340,13 @@ declare class SelectorManager<T extends object> {
|
|
|
1336
1340
|
private pathBasedCache;
|
|
1337
1341
|
/** Reverse lookup: Path -> Set of Selector IDs for O(1) update dispatch. */
|
|
1338
1342
|
private dependencyMap;
|
|
1343
|
+
/**
|
|
1344
|
+
* WeakMap from selector function reference to its buildPaths result.
|
|
1345
|
+
* Avoids re-running the proxy analysis on every re-render when the same
|
|
1346
|
+
* function reference is reused (module-level selectors, useCallback, etc).
|
|
1347
|
+
* Entries are GC'd automatically when the function is collected.
|
|
1348
|
+
*/
|
|
1349
|
+
private buildPathsCache;
|
|
1339
1350
|
private getState;
|
|
1340
1351
|
private eventBus;
|
|
1341
1352
|
private unsubscribeFromStore;
|
package/index.d.ts
CHANGED
|
@@ -404,6 +404,10 @@ interface DataStore<T extends object> {
|
|
|
404
404
|
* Releases all resources held by the store and renders it unusable
|
|
405
405
|
*/
|
|
406
406
|
dispose(): Promise<void>;
|
|
407
|
+
/**
|
|
408
|
+
* Checks whether the store has been disposed
|
|
409
|
+
*/
|
|
410
|
+
disposed(): boolean;
|
|
407
411
|
}
|
|
408
412
|
/** Payload for the 'persistence:queued' event. */
|
|
409
413
|
interface PersistenceQueuedPayload {
|
|
@@ -1132,6 +1136,13 @@ declare class SelectorManager<T extends object> {
|
|
|
1132
1136
|
private pathBasedCache;
|
|
1133
1137
|
/** Reverse lookup: Path -> Set of Selector IDs for O(1) update dispatch. */
|
|
1134
1138
|
private dependencyMap;
|
|
1139
|
+
/**
|
|
1140
|
+
* WeakMap from selector function reference to its buildPaths result.
|
|
1141
|
+
* Avoids re-running the proxy analysis on every re-render when the same
|
|
1142
|
+
* function reference is reused (module-level selectors, useCallback, etc).
|
|
1143
|
+
* Entries are GC'd automatically when the function is collected.
|
|
1144
|
+
*/
|
|
1145
|
+
private buildPathsCache;
|
|
1135
1146
|
private getState;
|
|
1136
1147
|
private eventBus;
|
|
1137
1148
|
private unsubscribeFromStore;
|
package/index.js
CHANGED
|
@@ -176,6 +176,13 @@ var SelectorManager = class {
|
|
|
176
176
|
pathBasedCache = /* @__PURE__ */ new Map();
|
|
177
177
|
/** Reverse lookup: Path -> Set of Selector IDs for O(1) update dispatch. */
|
|
178
178
|
dependencyMap = /* @__PURE__ */ new Map();
|
|
179
|
+
/**
|
|
180
|
+
* WeakMap from selector function reference to its buildPaths result.
|
|
181
|
+
* Avoids re-running the proxy analysis on every re-render when the same
|
|
182
|
+
* function reference is reused (module-level selectors, useCallback, etc).
|
|
183
|
+
* Entries are GC'd automatically when the function is collected.
|
|
184
|
+
*/
|
|
185
|
+
buildPathsCache = /* @__PURE__ */ new WeakMap();
|
|
179
186
|
getState;
|
|
180
187
|
eventBus;
|
|
181
188
|
unsubscribeFromStore;
|
|
@@ -187,7 +194,7 @@ var SelectorManager = class {
|
|
|
187
194
|
handleStoreUpdate = (payload) => {
|
|
188
195
|
const selectorsToEvaluate = /* @__PURE__ */ new Set();
|
|
189
196
|
const divider = ".";
|
|
190
|
-
for (const delta of payload.deltas) {
|
|
197
|
+
for (const delta of payload.deltas ?? []) {
|
|
191
198
|
const changedPath = delta.path;
|
|
192
199
|
for (const [registeredPath, dependents] of this.dependencyMap) if (registeredPath === changedPath || registeredPath.startsWith(changedPath + divider) || changedPath.startsWith(registeredPath + divider)) for (const id of dependents) selectorsToEvaluate.add(id);
|
|
193
200
|
}
|
|
@@ -217,8 +224,16 @@ var SelectorManager = class {
|
|
|
217
224
|
}
|
|
218
225
|
}
|
|
219
226
|
createReactiveSelector(selector) {
|
|
220
|
-
|
|
221
|
-
|
|
227
|
+
let cached = this.buildPathsCache.get(selector);
|
|
228
|
+
if (!cached) {
|
|
229
|
+
const paths = buildPaths(selector);
|
|
230
|
+
cached = {
|
|
231
|
+
paths,
|
|
232
|
+
key: [...paths].sort().join("|")
|
|
233
|
+
};
|
|
234
|
+
this.buildPathsCache.set(selector, cached);
|
|
235
|
+
}
|
|
236
|
+
const { key: pathCacheKey, paths: accessedPaths } = cached;
|
|
222
237
|
const cachedEntry = this.pathBasedCache.get(pathCacheKey);
|
|
223
238
|
if (cachedEntry) {
|
|
224
239
|
if (cachedEntry.cleanupTimer !== void 0) {
|
|
@@ -324,6 +339,7 @@ var SelectorManager = class {
|
|
|
324
339
|
this.reactiveSelectors.clear();
|
|
325
340
|
this.dependencyMap.clear();
|
|
326
341
|
this.pathBasedCache.clear();
|
|
342
|
+
this.buildPathsCache = /* @__PURE__ */ new WeakMap();
|
|
327
343
|
}
|
|
328
344
|
};
|
|
329
345
|
/**
|
|
@@ -403,7 +419,7 @@ function isEqual(a, b) {
|
|
|
403
419
|
if (length !== bKeys.length) return false;
|
|
404
420
|
for (i = length; i-- > 0;) {
|
|
405
421
|
const key = aKeys[i];
|
|
406
|
-
if (!Object.
|
|
422
|
+
if (!Object.hasOwn(b, key) || !isEqual(a[key], b[key])) return false;
|
|
407
423
|
}
|
|
408
424
|
return true;
|
|
409
425
|
}
|
|
@@ -834,6 +850,11 @@ var PersistenceHandler = class {
|
|
|
834
850
|
* picking up a retried task before its delay has passed.
|
|
835
851
|
*/
|
|
836
852
|
pendingRetries = /* @__PURE__ */ new Set();
|
|
853
|
+
/**
|
|
854
|
+
* Guards against the feedback loop where applying external state triggers
|
|
855
|
+
* persistence writes that trigger more external state applications.
|
|
856
|
+
*/
|
|
857
|
+
isSyncing = false;
|
|
837
858
|
logger;
|
|
838
859
|
constructor(eventBus, coreState, instanceID, options) {
|
|
839
860
|
this.eventBus = eventBus;
|
|
@@ -1018,15 +1039,13 @@ var PersistenceHandler = class {
|
|
|
1018
1039
|
this.setPersistenceReady();
|
|
1019
1040
|
}
|
|
1020
1041
|
this.persistence.subscribe(this.instanceID, async (state) => {
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
}
|
|
1029
|
-
});
|
|
1042
|
+
if (this.isSyncing) return;
|
|
1043
|
+
this.isSyncing = true;
|
|
1044
|
+
try {
|
|
1045
|
+
this.coreState.applyChanges(state);
|
|
1046
|
+
} finally {
|
|
1047
|
+
this.isSyncing = false;
|
|
1048
|
+
}
|
|
1030
1049
|
});
|
|
1031
1050
|
}
|
|
1032
1051
|
/**
|
|
@@ -2100,7 +2119,10 @@ var StoreObserver = class {
|
|
|
2100
2119
|
const event = {
|
|
2101
2120
|
type,
|
|
2102
2121
|
timestamp: Date.now(),
|
|
2103
|
-
data:
|
|
2122
|
+
data: type === "update:complete" ? {
|
|
2123
|
+
...data,
|
|
2124
|
+
newState: void 0
|
|
2125
|
+
} : structuredClone(data)
|
|
2104
2126
|
};
|
|
2105
2127
|
this.eventHistory.unshift(event);
|
|
2106
2128
|
if (this.eventHistory.length > this.maxEvents) this.eventHistory.pop();
|
package/index.mjs
CHANGED
|
@@ -175,6 +175,13 @@ var SelectorManager = class {
|
|
|
175
175
|
pathBasedCache = /* @__PURE__ */ new Map();
|
|
176
176
|
/** Reverse lookup: Path -> Set of Selector IDs for O(1) update dispatch. */
|
|
177
177
|
dependencyMap = /* @__PURE__ */ new Map();
|
|
178
|
+
/**
|
|
179
|
+
* WeakMap from selector function reference to its buildPaths result.
|
|
180
|
+
* Avoids re-running the proxy analysis on every re-render when the same
|
|
181
|
+
* function reference is reused (module-level selectors, useCallback, etc).
|
|
182
|
+
* Entries are GC'd automatically when the function is collected.
|
|
183
|
+
*/
|
|
184
|
+
buildPathsCache = /* @__PURE__ */ new WeakMap();
|
|
178
185
|
getState;
|
|
179
186
|
eventBus;
|
|
180
187
|
unsubscribeFromStore;
|
|
@@ -186,7 +193,7 @@ var SelectorManager = class {
|
|
|
186
193
|
handleStoreUpdate = (payload) => {
|
|
187
194
|
const selectorsToEvaluate = /* @__PURE__ */ new Set();
|
|
188
195
|
const divider = ".";
|
|
189
|
-
for (const delta of payload.deltas) {
|
|
196
|
+
for (const delta of payload.deltas ?? []) {
|
|
190
197
|
const changedPath = delta.path;
|
|
191
198
|
for (const [registeredPath, dependents] of this.dependencyMap) if (registeredPath === changedPath || registeredPath.startsWith(changedPath + divider) || changedPath.startsWith(registeredPath + divider)) for (const id of dependents) selectorsToEvaluate.add(id);
|
|
192
199
|
}
|
|
@@ -216,8 +223,16 @@ var SelectorManager = class {
|
|
|
216
223
|
}
|
|
217
224
|
}
|
|
218
225
|
createReactiveSelector(selector) {
|
|
219
|
-
|
|
220
|
-
|
|
226
|
+
let cached = this.buildPathsCache.get(selector);
|
|
227
|
+
if (!cached) {
|
|
228
|
+
const paths = buildPaths(selector);
|
|
229
|
+
cached = {
|
|
230
|
+
paths,
|
|
231
|
+
key: [...paths].sort().join("|")
|
|
232
|
+
};
|
|
233
|
+
this.buildPathsCache.set(selector, cached);
|
|
234
|
+
}
|
|
235
|
+
const { key: pathCacheKey, paths: accessedPaths } = cached;
|
|
221
236
|
const cachedEntry = this.pathBasedCache.get(pathCacheKey);
|
|
222
237
|
if (cachedEntry) {
|
|
223
238
|
if (cachedEntry.cleanupTimer !== void 0) {
|
|
@@ -323,6 +338,7 @@ var SelectorManager = class {
|
|
|
323
338
|
this.reactiveSelectors.clear();
|
|
324
339
|
this.dependencyMap.clear();
|
|
325
340
|
this.pathBasedCache.clear();
|
|
341
|
+
this.buildPathsCache = /* @__PURE__ */ new WeakMap();
|
|
326
342
|
}
|
|
327
343
|
};
|
|
328
344
|
/**
|
|
@@ -402,7 +418,7 @@ function isEqual(a, b) {
|
|
|
402
418
|
if (length !== bKeys.length) return false;
|
|
403
419
|
for (i = length; i-- > 0;) {
|
|
404
420
|
const key = aKeys[i];
|
|
405
|
-
if (!Object.
|
|
421
|
+
if (!Object.hasOwn(b, key) || !isEqual(a[key], b[key])) return false;
|
|
406
422
|
}
|
|
407
423
|
return true;
|
|
408
424
|
}
|
|
@@ -828,6 +844,11 @@ var PersistenceHandler = class {
|
|
|
828
844
|
* picking up a retried task before its delay has passed.
|
|
829
845
|
*/
|
|
830
846
|
pendingRetries = /* @__PURE__ */ new Set();
|
|
847
|
+
/**
|
|
848
|
+
* Guards against the feedback loop where applying external state triggers
|
|
849
|
+
* persistence writes that trigger more external state applications.
|
|
850
|
+
*/
|
|
851
|
+
isSyncing = false;
|
|
831
852
|
logger;
|
|
832
853
|
constructor(eventBus, coreState, instanceID, options) {
|
|
833
854
|
this.eventBus = eventBus;
|
|
@@ -1012,15 +1033,13 @@ var PersistenceHandler = class {
|
|
|
1012
1033
|
this.setPersistenceReady();
|
|
1013
1034
|
}
|
|
1014
1035
|
this.persistence.subscribe(this.instanceID, async (state) => {
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
}
|
|
1023
|
-
});
|
|
1036
|
+
if (this.isSyncing) return;
|
|
1037
|
+
this.isSyncing = true;
|
|
1038
|
+
try {
|
|
1039
|
+
this.coreState.applyChanges(state);
|
|
1040
|
+
} finally {
|
|
1041
|
+
this.isSyncing = false;
|
|
1042
|
+
}
|
|
1024
1043
|
});
|
|
1025
1044
|
}
|
|
1026
1045
|
/**
|
|
@@ -2089,7 +2108,10 @@ var StoreObserver = class {
|
|
|
2089
2108
|
const event = {
|
|
2090
2109
|
type,
|
|
2091
2110
|
timestamp: Date.now(),
|
|
2092
|
-
data:
|
|
2111
|
+
data: type === "update:complete" ? {
|
|
2112
|
+
...data,
|
|
2113
|
+
newState: void 0
|
|
2114
|
+
} : structuredClone(data)
|
|
2093
2115
|
};
|
|
2094
2116
|
this.eventHistory.unshift(event);
|
|
2095
2117
|
if (this.eventHistory.length > this.maxEvents) this.eventHistory.pop();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@asaidimu/utils-store",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "11.0.0",
|
|
4
4
|
"description": "A reactive data store",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"module": "index.mjs",
|
|
@@ -29,11 +29,11 @@
|
|
|
29
29
|
"access": "public"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@asaidimu/utils-events": "^1.2.
|
|
33
|
-
"@asaidimu/utils-logger": "^1.0.
|
|
32
|
+
"@asaidimu/utils-events": "^1.2.11",
|
|
33
|
+
"@asaidimu/utils-logger": "^1.0.14",
|
|
34
34
|
"uuid": "^14.0.0",
|
|
35
|
-
"@asaidimu/utils-sync": "^2.3.
|
|
36
|
-
"@asaidimu/utils-persistence": "^6.1.
|
|
35
|
+
"@asaidimu/utils-sync": "^2.3.10",
|
|
36
|
+
"@asaidimu/utils-persistence": "^6.1.22"
|
|
37
37
|
},
|
|
38
38
|
"exports": {
|
|
39
39
|
".": {
|