cross-state 0.6.9 → 0.7.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.
Files changed (78) hide show
  1. package/dist/cjs/hash.cjs +0 -694
  2. package/dist/cjs/hash.cjs.map +1 -1
  3. package/dist/cjs/immer/index.cjs +6 -0
  4. package/dist/cjs/immer/index.cjs.map +1 -0
  5. package/dist/cjs/immer/register.cjs +6 -0
  6. package/dist/cjs/immer/register.cjs.map +1 -0
  7. package/dist/cjs/immerMethods.cjs +23 -0
  8. package/dist/cjs/immerMethods.cjs.map +1 -0
  9. package/dist/cjs/index.cjs +387 -278
  10. package/dist/cjs/index.cjs.map +1 -1
  11. package/dist/cjs/react/index.cjs +54 -0
  12. package/dist/cjs/react/index.cjs.map +1 -0
  13. package/dist/cjs/react/register.cjs +30 -0
  14. package/dist/cjs/react/register.cjs.map +1 -0
  15. package/dist/cjs/scope.cjs +399 -0
  16. package/dist/cjs/scope.cjs.map +1 -0
  17. package/dist/cjs/{react.cjs → scope2.cjs} +50 -37
  18. package/dist/cjs/scope2.cjs.map +1 -0
  19. package/dist/cjs/store.cjs +798 -0
  20. package/dist/cjs/store.cjs.map +1 -0
  21. package/dist/es/hash.mjs +1 -695
  22. package/dist/es/hash.mjs.map +1 -1
  23. package/dist/es/immer/index.mjs +6 -0
  24. package/dist/es/immer/index.mjs.map +1 -0
  25. package/dist/es/immer/register.mjs +5 -0
  26. package/dist/es/immer/register.mjs.map +1 -0
  27. package/dist/es/immerMethods.mjs +24 -0
  28. package/dist/es/immerMethods.mjs.map +1 -0
  29. package/dist/es/index.mjs +383 -273
  30. package/dist/es/index.mjs.map +1 -1
  31. package/dist/es/react/index.mjs +55 -0
  32. package/dist/es/react/index.mjs.map +1 -0
  33. package/dist/es/react/register.mjs +29 -0
  34. package/dist/es/react/register.mjs.map +1 -0
  35. package/dist/es/scope.mjs +400 -0
  36. package/dist/es/scope.mjs.map +1 -0
  37. package/dist/es/{react.mjs → scope2.mjs} +43 -29
  38. package/dist/es/scope2.mjs.map +1 -0
  39. package/dist/es/store.mjs +799 -0
  40. package/dist/es/store.mjs.map +1 -0
  41. package/dist/types/core/cache.d.ts +7 -2
  42. package/dist/types/core/commonTypes.d.ts +8 -0
  43. package/dist/types/core/index.d.ts +6 -6
  44. package/dist/types/core/resourceGroup.d.ts +2 -2
  45. package/dist/types/core/scope.d.ts +5 -0
  46. package/dist/types/core/store.d.ts +8 -10
  47. package/dist/types/core/subscriptionCache.d.ts +51 -0
  48. package/dist/types/core/urlStore.d.ts +26 -0
  49. package/dist/types/immer/immerMethods.d.ts +10 -0
  50. package/dist/types/immer/index.d.ts +1 -1
  51. package/dist/types/immer/register.d.ts +7 -0
  52. package/dist/types/index.d.ts +3 -1
  53. package/dist/types/lib/calcDuration.d.ts +1 -1
  54. package/dist/types/lib/calculationHelper.d.ts +15 -10
  55. package/dist/types/lib/equals.d.ts +3 -3
  56. package/dist/types/lib/path.d.ts +3 -3
  57. package/dist/types/lib/promiseWithState.d.ts +9 -0
  58. package/dist/types/lib/standardMethods.d.ts +2 -1
  59. package/dist/types/lib/trackingProxy.d.ts +2 -1
  60. package/dist/types/lib/typeHelpers.d.ts +3 -1
  61. package/dist/types/lib/updateHelpers.d.ts +1 -0
  62. package/dist/types/react/index.d.ts +3 -1
  63. package/dist/types/react/reactMethods.d.ts +9 -0
  64. package/dist/types/react/register.d.ts +29 -0
  65. package/dist/types/react/scope.d.ts +16 -0
  66. package/dist/types/react/useCache.d.ts +2 -1
  67. package/dist/types/react/useDecoupledState.d.ts +7 -0
  68. package/dist/types/react/useProp.d.ts +1 -2
  69. package/package.json +105 -27
  70. package/dist/cjs/immer.cjs +0 -10
  71. package/dist/cjs/immer.cjs.map +0 -1
  72. package/dist/cjs/react.cjs.map +0 -1
  73. package/dist/es/immer.mjs +0 -10
  74. package/dist/es/immer.mjs.map +0 -1
  75. package/dist/es/react.mjs.map +0 -1
  76. package/dist/types/core/storeScope.d.ts +0 -4
  77. package/dist/types/immer/immerActions.d.ts +0 -5
  78. package/dist/types/react/storeScope.d.ts +0 -12
package/dist/es/index.mjs CHANGED
@@ -1,280 +1,67 @@
1
- import { h as hash, S as Store, c as createStore, a as calcDuration, m as makeSelector } from "./hash.mjs";
2
- import { b, d, r, s } from "./hash.mjs";
3
- class ResourceGroup {
4
- constructor(name) {
5
- this.name = name;
6
- this.refMap = /* @__PURE__ */ new WeakMap();
7
- this.refSet = /* @__PURE__ */ new Set();
8
- this.add = this.add.bind(this);
9
- this.delete = this.delete.bind(this);
10
- this.invalidateAll = this.invalidateAll.bind(this);
11
- this.clearAll = this.clearAll.bind(this);
12
- }
13
- add(resource) {
14
- const ref = new WeakRef(resource);
15
- this.refMap.set(resource, ref);
16
- this.refSet.add(ref);
17
- }
18
- delete(resource) {
19
- const ref = this.refMap.get(resource);
20
- if (ref) {
21
- this.refMap.delete(resource);
22
- this.refSet.delete(ref);
23
- }
24
- }
25
- invalidateAll() {
26
- for (const ref of this.refSet) {
27
- const resource = ref.deref();
28
- if (resource) {
29
- resource.invalidate();
30
- } else {
31
- this.refSet.delete(ref);
32
- }
33
- }
34
- }
35
- clearAll() {
36
- for (const ref of this.refSet) {
37
- const resource = ref.deref();
38
- if (resource) {
39
- resource.clear();
40
- } else {
41
- this.refSet.delete(ref);
42
- }
43
- }
44
- }
45
- }
46
- const allResources = /* @__PURE__ */ new ResourceGroup();
47
- function createResourceGroup(name) {
48
- return new ResourceGroup(name);
49
- }
50
- class InstanceCache {
51
- constructor(factory, cacheTime) {
52
- this.factory = factory;
53
- this.cacheTime = cacheTime;
54
- this.cache = /* @__PURE__ */ new Map();
55
- this.interval = this.cacheTime ? setInterval(() => this.cleanup(), Math.max(this.cacheTime / 10, 1)) : void 0;
56
- }
57
- cleanup() {
58
- var _a;
59
- const cutoff = this.now() - (this.cacheTime ?? 0);
60
- for (const [key, entry] of this.cache.entries()) {
61
- if (entry.ref && entry.t <= cutoff) {
62
- delete entry.ref;
63
- }
64
- if (!entry.ref && !((_a = entry.weakRef) == null ? void 0 : _a.deref())) {
65
- this.cache.delete(key);
66
- }
67
- }
68
- }
69
- get(...args) {
70
- var _a;
71
- const key = hash(args);
72
- let entry = this.cache.get(key);
73
- let value = (entry == null ? void 0 : entry.ref) ?? ((_a = entry == null ? void 0 : entry.weakRef) == null ? void 0 : _a.deref());
74
- if (!entry || !value) {
75
- value = this.factory(...args);
76
- entry = {
77
- t: this.now(),
78
- ref: value,
79
- weakRef: new WeakRef(value)
80
- };
81
- this.cache.set(key, entry);
82
- } else {
83
- entry.t = this.now();
84
- entry.ref ?? (entry.ref = value);
85
- }
86
- return value;
87
- }
88
- values() {
89
- return [...this.cache.values()].map((entry) => {
90
- var _a;
91
- return entry.ref ?? ((_a = entry.weakRef) == null ? void 0 : _a.deref());
92
- }).filter((value) => !!value);
93
- }
94
- stop() {
95
- if (this.interval) {
96
- clearInterval(this.interval);
97
- }
98
- }
99
- stats() {
100
- return {
101
- count: this.cache.size,
102
- withRef: [...this.cache.values()].filter((x) => !!x.ref).length,
103
- withWeakRef: [...this.cache.values()].filter((x) => {
104
- var _a;
105
- return !!((_a = x.weakRef) == null ? void 0 : _a.deref());
106
- }).length
107
- };
108
- }
109
- now() {
110
- return performance.now();
111
- }
112
- }
113
- class Cache extends Store {
114
- constructor(getter, options = {}, derivedFromCache, _call) {
115
- super(getter, options, void 0, _call);
1
+ import { S as Store, c as createStore, a as calcDuration, q as queue, b as castArrayPath, s as shallowEqual, g as get, d as set } from "./store.mjs";
2
+ import { e, m, r, f } from "./store.mjs";
3
+ import { I as InstanceCache, a as allResources } from "./scope.mjs";
4
+ import { C, R, S, c, b, d } from "./scope.mjs";
5
+ import "./hash.mjs";
6
+ class SubstriptionCache extends Store {
7
+ constructor(connectFunction, options = {}, derivedFromSubscriptionCache, _call) {
8
+ super(void 0, options, void 0, _call);
9
+ this.connectFunction = connectFunction;
116
10
  this.options = options;
117
- this.derivedFromCache = derivedFromCache;
11
+ this.derivedFromSubscriptionCache = derivedFromSubscriptionCache;
118
12
  this.state = createStore({
119
- status: "pending",
120
- isStale: true,
121
- isUpdating: false
13
+ connectionState: "closed",
14
+ error: void 0
122
15
  });
123
- this.invalidate = this.invalidate.bind(this);
124
- this.clear = this.clear.bind(this);
125
- this.mapValue = this.mapValue.bind(this);
126
- this.watchPromise();
127
- this.watchFocus();
128
- }
129
- get({ update = "whenStale", backgroundUpdate = false } = {}) {
130
- var _a;
131
- const promise = (_a = this._value) == null ? void 0 : _a.v;
132
- const stalePromise = this.stalePromise;
133
- if (update === "whenMissing" && !promise && !stalePromise || update === "whenStale" && !promise || update === "force") {
134
- this.calculationHelper.execute();
135
- if (!promise && !stalePromise || !backgroundUpdate) {
136
- return super.get();
16
+ this.calculationHelper.options = {
17
+ ...this.calculationHelper.options,
18
+ calculate: (helpers) => {
19
+ let result = connectFunction.apply(helpers);
20
+ if (result instanceof Function && result.length > 0) {
21
+ result = result(helpers);
22
+ }
23
+ return result;
24
+ },
25
+ onValue: (value) => {
26
+ this.set(value);
27
+ },
28
+ onError: (error) => {
29
+ this.state.set("error", error);
30
+ },
31
+ onConnectionState: (state) => {
32
+ this.state.set("connectionState", state);
33
+ },
34
+ onInvalidate: () => {
35
+ this.invalidate();
137
36
  }
138
- }
139
- if (!promise || stalePromise && backgroundUpdate) {
140
- return stalePromise;
141
- }
142
- return promise;
37
+ };
143
38
  }
144
39
  invalidate({ invalidateDependencies = true } = {}) {
145
- var _a;
146
- const { clearOnInvalidate: clearOnInvalidation = defaultOptions.clearOnInvalidate } = this.options;
147
- if (clearOnInvalidation) {
40
+ const { clearOnInvalidate = defaultOptions.clearOnInvalidate } = this.options;
41
+ if (clearOnInvalidate) {
148
42
  return this.clear({ invalidateDependencies });
149
43
  }
150
44
  if (invalidateDependencies) {
151
45
  this.calculationHelper.invalidateDependencies();
152
46
  }
153
- const { status, isStale, isUpdating } = this.state.get();
154
- if (status !== "pending" && !isStale && !isUpdating) {
155
- this.stalePromise = (_a = this._value) == null ? void 0 : _a.v;
47
+ this.calculationHelper.stop();
48
+ if (this.isActive()) {
49
+ this.calculationHelper.execute();
156
50
  }
157
- this.state.set((state) => ({
158
- ...state,
159
- isStale: true,
160
- isUpdating: false
161
- }));
162
- super.reset();
163
51
  }
164
52
  clear({ invalidateDependencies = true } = {}) {
165
53
  if (invalidateDependencies) {
166
54
  this.calculationHelper.invalidateDependencies();
167
55
  }
168
- this.state.set({
169
- status: "pending",
170
- isStale: true,
171
- isUpdating: false
172
- });
173
- delete this.stalePromise;
174
- super.reset();
175
- }
176
- mapValue(_selector) {
177
- const selector = makeSelector(_selector);
178
- const derivedFromCache = {
179
- cache: this.derivedFromCache ? this.derivedFromCache.cache : this,
180
- selectors: this.derivedFromCache ? [...this.derivedFromCache.selectors, _selector] : [_selector]
181
- };
182
- const that = this;
183
- return new Cache(
184
- async function() {
185
- const value = await this.use(that);
186
- return selector(value);
187
- },
188
- {},
189
- derivedFromCache
190
- );
191
- }
192
- watchPromise() {
193
- this.sub(
194
- async (promise) => {
195
- var _a, _b;
196
- this.state.set((state) => ({
197
- ...state,
198
- isUpdating: true
199
- }));
200
- this.setTimers();
201
- try {
202
- const value = await promise;
203
- if (promise !== ((_a = this._value) == null ? void 0 : _a.v)) {
204
- return;
205
- }
206
- this.state.set({
207
- status: "value",
208
- value,
209
- isStale: false,
210
- isUpdating: false
211
- });
212
- delete this.stalePromise;
213
- this.setTimers();
214
- } catch (error) {
215
- if (promise !== ((_b = this._value) == null ? void 0 : _b.v)) {
216
- return;
217
- }
218
- this.state.set({
219
- status: "error",
220
- error,
221
- isStale: false,
222
- isUpdating: false
223
- });
224
- delete this.stalePromise;
225
- this.setTimers();
226
- }
227
- },
228
- { passive: true }
229
- );
230
- }
231
- setTimers() {
232
- if (this.invalidationTimer) {
233
- clearTimeout(this.invalidationTimer);
234
- }
235
- this.invalidationTimer = void 0;
236
- const state = this.state.get();
237
- let { invalidateAfter = defaultOptions.invalidateAfter } = this.options;
238
- const ref = new WeakRef(this);
239
- if (state.status === "pending") {
240
- return;
241
- }
242
- if (invalidateAfter instanceof Function) {
243
- invalidateAfter = invalidateAfter(state);
244
- }
245
- if (invalidateAfter !== null && invalidateAfter !== void 0) {
246
- this.invalidationTimer = setTimeout(
247
- () => {
248
- var _a;
249
- return (_a = ref == null ? void 0 : ref.deref()) == null ? void 0 : _a.invalidate();
250
- },
251
- calcDuration(invalidateAfter)
252
- );
253
- }
254
- }
255
- watchFocus() {
256
- const { invalidateOnWindowFocus = defaultOptions.invalidateOnWindowFocus } = this.options;
257
- if (!invalidateOnWindowFocus || typeof document === "undefined" || typeof document.addEventListener === "undefined") {
258
- return;
56
+ this.calculationHelper.stop();
57
+ if (this.isActive()) {
58
+ this.calculationHelper.execute();
259
59
  }
260
- const ref = new WeakRef(this);
261
- const onFocus = () => {
262
- const that = ref == null ? void 0 : ref.deref();
263
- if (!that) {
264
- document.removeEventListener("visibilitychange", onFocus);
265
- return;
266
- }
267
- if (!document.hidden) {
268
- that.invalidate();
269
- }
270
- };
271
- document.addEventListener("visibilitychange", onFocus);
272
60
  }
273
61
  }
274
62
  const defaultOptions = {
275
- invalidateOnWindowFocus: true,
276
- invalidateOnActivation: true,
277
- clearUnusedAfter: { days: 1 }
63
+ clearUnusedAfter: { days: 1 },
64
+ retain: { seconds: 1 }
278
65
  };
279
66
  function create(cacheFunction, options) {
280
67
  const { clearUnusedAfter = defaultOptions.clearUnusedAfter, resourceGroup } = options ?? {};
@@ -284,13 +71,13 @@ function create(cacheFunction, options) {
284
71
  if (args.length === 0 && baseInstance) {
285
72
  return baseInstance;
286
73
  }
287
- return new Cache(function() {
74
+ return new SubstriptionCache(function() {
288
75
  return cacheFunction.apply(this, args);
289
76
  }, options);
290
77
  },
291
78
  clearUnusedAfter ? calcDuration(clearUnusedAfter) : void 0
292
79
  );
293
- const get = (...args) => {
80
+ const get2 = (...args) => {
294
81
  return instanceCache.get(...args);
295
82
  };
296
83
  const invalidateAll = () => {
@@ -303,43 +90,366 @@ function create(cacheFunction, options) {
303
90
  instance.clear();
304
91
  }
305
92
  };
306
- const groups = Array.isArray(resourceGroup) ? resourceGroup : resourceGroup ? [resourceGroup] : [];
307
- for (const group of groups.concat(allResources)) {
308
- group.add({ invalidate: invalidateAll, clear: clearAll });
309
- }
310
93
  baseInstance = Object.assign(
311
- new Cache(
94
+ new SubstriptionCache(
312
95
  function() {
313
96
  return cacheFunction.apply(this);
314
97
  },
315
98
  options,
316
99
  void 0,
317
- get
100
+ get2
318
101
  ),
319
102
  {
320
103
  invalidateAll,
321
104
  clearAll
322
105
  }
323
106
  );
324
- get(...[]);
107
+ const groups = Array.isArray(resourceGroup) ? resourceGroup : resourceGroup ? [resourceGroup] : [];
108
+ for (const group of groups.concat(allResources)) {
109
+ group.add(baseInstance);
110
+ }
111
+ get2(...[]);
325
112
  return baseInstance;
326
113
  }
327
- const createCache = /* @__PURE__ */ Object.assign(create, {
114
+ const createSubscriptionCache = /* @__PURE__ */ Object.assign(create, {
328
115
  defaultOptions
329
116
  });
117
+ class UrlStore extends Store {
118
+ constructor(options) {
119
+ super(() => {
120
+ const url = new URL(window.location.href);
121
+ const parameters = new URLSearchParams(url[options.type].slice(1));
122
+ const urlValue = parameters.get(options.key);
123
+ const deserialize = options.deserialize ?? defaultDeserializer;
124
+ return urlValue !== null ? deserialize(urlValue) : options.defaultValue;
125
+ });
126
+ this.options = options;
127
+ this.serializedDefaultValue = this.options.serialize(this.options.defaultValue);
128
+ this.addEffect(() => this.watchUrl());
129
+ }
130
+ set(...args) {
131
+ super.set.apply(this, args);
132
+ this.updateUrl(super.get());
133
+ }
134
+ watchUrl() {
135
+ const originalPushState = window.history.pushState;
136
+ const originalReplaceState = window.history.replaceState;
137
+ window.history.pushState = (...args) => {
138
+ originalPushState.apply(window.history, args);
139
+ this.reset();
140
+ };
141
+ window.history.replaceState = (...args) => {
142
+ originalReplaceState.apply(window.history, args);
143
+ this.reset();
144
+ };
145
+ return () => {
146
+ window.history.pushState = originalPushState;
147
+ window.history.replaceState = originalReplaceState;
148
+ };
149
+ }
150
+ updateUrl(value) {
151
+ var _a, _b;
152
+ const url = new URL(window.location.href);
153
+ const parameters = new URLSearchParams(url[this.options.type].slice(1));
154
+ const serializedValue = value !== void 0 ? this.options.serialize(value) : void 0;
155
+ if (serializedValue === void 0 || serializedValue === this.serializedDefaultValue) {
156
+ parameters.delete(this.options.key);
157
+ } else {
158
+ parameters.set(this.options.key, serializedValue);
159
+ }
160
+ url[this.options.type] = parameters.toString();
161
+ window.history.replaceState(null, "", url.toString());
162
+ (_b = (_a = this.options).onCommit) == null ? void 0 : _b.call(_a, value);
163
+ }
164
+ }
165
+ function defaultDeserializer(value) {
166
+ if (value === void 0) {
167
+ return void 0;
168
+ }
169
+ try {
170
+ return JSON.parse(value, (_k, v) => {
171
+ if (typeof v === "object" && v !== null && "__set" in v) {
172
+ return new Set(v.__set);
173
+ }
174
+ if (typeof v === "object" && v !== null && "__map" in v) {
175
+ return new Map(v.__map);
176
+ }
177
+ return v;
178
+ });
179
+ } catch {
180
+ return void 0;
181
+ }
182
+ }
183
+ function defaultSerializer(value) {
184
+ return JSON.stringify(value, (_k, v) => {
185
+ if (v instanceof Set) {
186
+ return { __set: Array.from(v) };
187
+ }
188
+ if (v instanceof Map) {
189
+ return { __map: Array.from(v) };
190
+ }
191
+ return v;
192
+ });
193
+ }
194
+ function createUrlStore(options) {
195
+ return new UrlStore({
196
+ ...options,
197
+ type: options.type ?? "search",
198
+ serialize: options.serialize ?? defaultSerializer,
199
+ deserialize: options.deserialize ?? defaultDeserializer,
200
+ defaultValue: options.defaultValue ?? void 0
201
+ });
202
+ }
203
+ function findOrDefault(array, predicate, defaultValue) {
204
+ const index = array.findIndex(predicate);
205
+ if (index >= 0) {
206
+ return array[index];
207
+ }
208
+ const value = defaultValue instanceof Function ? defaultValue() : defaultValue;
209
+ array.push(value);
210
+ return value;
211
+ }
212
+ const isAncestor = (ancestor, path) => {
213
+ return ancestor.length <= path.length && ancestor.every((v, i) => v === "*" || path[i] === "*" || v === path[i]);
214
+ };
215
+ function maybeAsync(value, action) {
216
+ if (value instanceof Promise) {
217
+ return value.then(action);
218
+ }
219
+ return action(value);
220
+ }
221
+ function maybeAsyncArray(values) {
222
+ const run = (remainingValues, results) => {
223
+ const [first, ...rest] = remainingValues;
224
+ if (!first) {
225
+ return results;
226
+ }
227
+ return maybeAsync(first(), (result) => run(rest, results.concat(result)));
228
+ };
229
+ return run(values, []);
230
+ }
231
+ function normalizeStorage(storage) {
232
+ return {
233
+ getItem: storage.getItem.bind(storage),
234
+ setItem: storage.setItem.bind(storage),
235
+ removeItem: storage.removeItem.bind(storage),
236
+ keys() {
237
+ if ("keys" in storage) {
238
+ return storage.keys();
239
+ }
240
+ return maybeAsync(
241
+ storage.length instanceof Function ? storage.length() : storage.length,
242
+ (length) => {
243
+ const keyPromises = maybeAsyncArray(
244
+ Array.from({ length }, (_, index) => () => storage.key(index))
245
+ );
246
+ return maybeAsync(
247
+ keyPromises,
248
+ (keys) => keys.filter((key) => typeof key === "string")
249
+ );
250
+ }
251
+ );
252
+ }
253
+ };
254
+ }
255
+ function diff(a, b2) {
256
+ const result = [..._diff(a, b2)];
257
+ const patches = result.map(([patch]) => patch);
258
+ const reversePatches = result.map(([, reversePatch]) => reversePatch);
259
+ return [patches, reversePatches];
260
+ }
261
+ function* _diff(a, b2, prefix = []) {
262
+ if (a === b2) {
263
+ return;
264
+ }
265
+ if (a instanceof Map && b2 instanceof Map) {
266
+ return yield* mapDiff(a, b2, prefix);
267
+ }
268
+ if (a instanceof Set && b2 instanceof Set) {
269
+ a = [...a];
270
+ b2 = [...b2];
271
+ }
272
+ if (a instanceof Object && b2 instanceof Object && Array.isArray(a) === Array.isArray(b2)) {
273
+ return yield* objectDiff(a, b2, prefix);
274
+ }
275
+ yield [
276
+ { op: "replace", path: prefix, value: b2 },
277
+ { op: "replace", path: prefix, value: a }
278
+ ];
279
+ }
280
+ function* mapDiff(a, b2, prefix) {
281
+ for (const [key, value] of a) {
282
+ if (!b2.has(key)) {
283
+ yield [
284
+ { op: "remove", path: [...prefix, key] },
285
+ { op: "add", path: [...prefix, key], value }
286
+ ];
287
+ } else {
288
+ yield* _diff(value, b2.get(key), [...prefix, key]);
289
+ }
290
+ }
291
+ for (const [key, value] of b2) {
292
+ if (!a.has(key)) {
293
+ yield [
294
+ { op: "add", path: [...prefix, key], value },
295
+ { op: "remove", path: [...prefix, key] }
296
+ ];
297
+ }
298
+ }
299
+ }
300
+ function* objectDiff(a, b2, prefix) {
301
+ const castKey = (key) => Array.isArray(a) ? Number(key) : key;
302
+ for (const [key, value] of Object.entries(a)) {
303
+ if (!(key in b2)) {
304
+ yield [
305
+ { op: "remove", path: [...prefix, castKey(key)] },
306
+ { op: "add", path: [...prefix, castKey(key)], value }
307
+ ];
308
+ } else {
309
+ yield* _diff(value, b2[key], [...prefix, castKey(key)]);
310
+ }
311
+ }
312
+ for (const [key, value] of Object.entries(b2)) {
313
+ if (!(key in a)) {
314
+ yield [
315
+ { op: "add", path: [...prefix, castKey(key)], value },
316
+ { op: "remove", path: [...prefix, castKey(key)] }
317
+ ];
318
+ }
319
+ }
320
+ }
321
+ class Persist {
322
+ constructor(store, options) {
323
+ this.store = store;
324
+ this.options = options;
325
+ this.queue = queue();
326
+ this.handles = /* @__PURE__ */ new Set();
327
+ this.stopped = false;
328
+ this.storage = normalizeStorage(options.storage);
329
+ this.channel = new BroadcastChannel(`cross-state-persist_${options.id}`);
330
+ this.paths = (options.paths ?? []).map(
331
+ (p) => typeof p === "string" || Array.isArray(p) ? {
332
+ path: castArrayPath(p)
333
+ } : {
334
+ path: castArrayPath(p.path),
335
+ throttleMs: p.throttleMs
336
+ }
337
+ ).sort((a, b2) => b2.path.length - a.path.length);
338
+ if (this.paths.length === 0) {
339
+ this.paths.push({ path: ["*"] });
340
+ }
341
+ this.watchStore();
342
+ this.watchStorage();
343
+ }
344
+ watchStore() {
345
+ let committed = this.store.get();
346
+ const cancel = this.store.subscribe(
347
+ (value) => {
348
+ const [patches] = diff(committed, value);
349
+ committed = value;
350
+ for (const patch of patches) {
351
+ if (this.updateInProgress && shallowEqual(this.updateInProgress[0], patch.path) && this.updateInProgress[1] === (patch.op === "remove" ? void 0 : patch.value)) {
352
+ continue;
353
+ }
354
+ const ancestor = this.paths.find((p) => isAncestor(p.path, patch.path));
355
+ if (!ancestor) {
356
+ continue;
357
+ }
358
+ const pathToSave = patch.path.slice(0, ancestor.path.length);
359
+ this.queue(() => this.save(pathToSave), pathToSave);
360
+ }
361
+ },
362
+ { runNow: false }
363
+ );
364
+ this.handles.add(cancel);
365
+ }
366
+ async watchStorage() {
367
+ let keys = this.storage.keys();
368
+ if (keys instanceof Promise) {
369
+ keys = await keys;
370
+ }
371
+ if (this.stopped) {
372
+ return;
373
+ }
374
+ for (const key of keys) {
375
+ const path = JSON.parse(key);
376
+ this.queue(() => this.load(path));
377
+ }
378
+ const listener = (event) => {
379
+ this.queue(() => this.load(event.data));
380
+ };
381
+ this.channel.addEventListener("message", listener);
382
+ this.handles.add(() => this.channel.removeEventListener("message", listener));
383
+ }
384
+ load(path) {
385
+ const matchingPath = this.paths.find(
386
+ (p) => p.path.length === path.length && isAncestor(p.path, path)
387
+ );
388
+ if (!matchingPath) {
389
+ return;
390
+ }
391
+ const key = JSON.stringify(path);
392
+ return maybeAsync(this.storage.getItem(key), (value) => {
393
+ if (this.stopped || !value) {
394
+ return;
395
+ }
396
+ const inSaveQueue = this.queue.getRefs().find((ref) => isAncestor(ref, path) || isAncestor(path, ref));
397
+ if (inSaveQueue) {
398
+ return;
399
+ }
400
+ const parsedValue = value === "undefined" ? void 0 : JSON.parse(value);
401
+ this.updateInProgress = [path, parsedValue];
402
+ this.store.set((state) => set(state, path, parsedValue));
403
+ this.updateInProgress = void 0;
404
+ });
405
+ }
406
+ save(path) {
407
+ const key = JSON.stringify(path);
408
+ const value = get(this.store.get(), path);
409
+ const serializedValue = value === void 0 ? "undefined" : JSON.stringify(value);
410
+ return maybeAsync(this.storage.setItem(key, serializedValue), () => {
411
+ this.channel.postMessage(path);
412
+ return maybeAsync(this.storage.keys(), (keys) => {
413
+ const toRemove = keys.filter((k) => {
414
+ const parsedKey = JSON.parse(k);
415
+ return parsedKey.length > path.length && isAncestor(path, parsedKey);
416
+ });
417
+ return maybeAsyncArray(toRemove.map((k) => () => this.storage.removeItem(k)));
418
+ });
419
+ });
420
+ }
421
+ async stop() {
422
+ this.stopped = true;
423
+ for (const handle of this.handles) {
424
+ handle();
425
+ }
426
+ await this.queue.whenDone();
427
+ this.channel.close();
428
+ }
429
+ }
430
+ function persist(store, options) {
431
+ return new Persist(store, options);
432
+ }
330
433
  export {
331
- Cache,
434
+ C as Cache,
332
435
  InstanceCache,
333
- ResourceGroup,
436
+ R as ResourceGroup,
437
+ S as Scope,
334
438
  Store,
439
+ SubstriptionCache,
335
440
  allResources,
336
- b as arrayMethods,
441
+ e as arrayMethods,
337
442
  calcDuration,
338
- createCache,
339
- createResourceGroup,
443
+ c as createCache,
444
+ b as createResourceGroup,
445
+ d as createScope,
340
446
  createStore,
341
- d as mapMethods,
447
+ createSubscriptionCache,
448
+ createUrlStore,
449
+ findOrDefault,
450
+ m as mapMethods,
451
+ persist,
342
452
  r as recordMethods,
343
- s as setMethods
453
+ f as setMethods
344
454
  };
345
455
  //# sourceMappingURL=index.mjs.map