@legendapp/state 3.0.0-alpha.8 → 3.0.0-beta.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.
Files changed (86) hide show
  1. package/.DS_Store +0 -0
  2. package/config/configureLegendState.d.mts +13 -0
  3. package/config/configureLegendState.d.ts +13 -0
  4. package/config/configureLegendState.js +45 -0
  5. package/config/configureLegendState.mjs +43 -0
  6. package/config/enable$GetSet.js +2 -1
  7. package/config/enable$GetSet.mjs +2 -1
  8. package/config/enableReactTracking.js +2 -1
  9. package/config/enableReactTracking.mjs +2 -1
  10. package/config/enableReactUse.js +2 -1
  11. package/config/enableReactUse.mjs +2 -1
  12. package/config/enable_PeekAssign.js +2 -1
  13. package/config/enable_PeekAssign.mjs +2 -1
  14. package/helpers/trackHistory.js +2 -2
  15. package/helpers/trackHistory.mjs +2 -2
  16. package/index.d.mts +104 -80
  17. package/index.d.ts +104 -80
  18. package/index.js +328 -318
  19. package/index.mjs +325 -316
  20. package/package.json +36 -1
  21. package/persist-plugins/async-storage.d.mts +6 -3
  22. package/persist-plugins/async-storage.d.ts +6 -3
  23. package/persist-plugins/async-storage.js +8 -4
  24. package/persist-plugins/async-storage.mjs +8 -5
  25. package/persist-plugins/indexeddb.d.mts +6 -4
  26. package/persist-plugins/indexeddb.d.ts +6 -4
  27. package/persist-plugins/indexeddb.js +35 -15
  28. package/persist-plugins/indexeddb.mjs +35 -16
  29. package/persist-plugins/mmkv.d.mts +5 -1
  30. package/persist-plugins/mmkv.d.ts +5 -1
  31. package/persist-plugins/mmkv.js +10 -5
  32. package/persist-plugins/mmkv.mjs +10 -6
  33. package/react-reactive/enableReactComponents.d.mts +9 -0
  34. package/react-reactive/enableReactComponents.d.ts +9 -0
  35. package/react-reactive/enableReactComponents.js +19 -0
  36. package/react-reactive/enableReactComponents.mjs +17 -0
  37. package/react-reactive/enableReactNativeComponents.d.mts +22 -0
  38. package/react-reactive/enableReactNativeComponents.d.ts +22 -0
  39. package/react-reactive/enableReactNativeComponents.js +53 -0
  40. package/react-reactive/enableReactNativeComponents.mjs +51 -0
  41. package/react-reactive/enableReactive.d.mts +5 -0
  42. package/react-reactive/enableReactive.d.ts +5 -0
  43. package/react-reactive/enableReactive.js +24 -0
  44. package/react-reactive/enableReactive.mjs +22 -0
  45. package/react-reactive/enableReactive.native.d.mts +5 -0
  46. package/react-reactive/enableReactive.native.d.ts +5 -0
  47. package/react-reactive/enableReactive.native.js +58 -0
  48. package/react-reactive/enableReactive.native.mjs +56 -0
  49. package/react-reactive/enableReactive.web.d.mts +5 -0
  50. package/react-reactive/enableReactive.web.d.ts +5 -0
  51. package/react-reactive/enableReactive.web.js +58 -0
  52. package/react-reactive/enableReactive.web.mjs +56 -0
  53. package/react.d.mts +39 -34
  54. package/react.d.ts +39 -34
  55. package/react.js +39 -17
  56. package/react.mjs +39 -17
  57. package/sync-plugins/crud.d.mts +21 -24
  58. package/sync-plugins/crud.d.ts +21 -24
  59. package/sync-plugins/crud.js +241 -140
  60. package/sync-plugins/crud.mjs +243 -142
  61. package/sync-plugins/fetch.js +12 -8
  62. package/sync-plugins/fetch.mjs +13 -9
  63. package/sync-plugins/firebase.d.mts +27 -0
  64. package/sync-plugins/firebase.d.ts +27 -0
  65. package/sync-plugins/firebase.js +373 -0
  66. package/sync-plugins/firebase.mjs +368 -0
  67. package/sync-plugins/keel.d.mts +43 -26
  68. package/sync-plugins/keel.d.ts +43 -26
  69. package/sync-plugins/keel.js +145 -100
  70. package/sync-plugins/keel.mjs +147 -100
  71. package/sync-plugins/supabase.d.mts +19 -9
  72. package/sync-plugins/supabase.d.ts +19 -9
  73. package/sync-plugins/supabase.js +52 -22
  74. package/sync-plugins/supabase.mjs +53 -23
  75. package/sync-plugins/tanstack-query.d.mts +2 -2
  76. package/sync-plugins/tanstack-query.d.ts +2 -2
  77. package/sync-plugins/tanstack-query.js +22 -5
  78. package/sync-plugins/tanstack-query.mjs +22 -5
  79. package/sync-plugins/tanstack-react-query.d.mts +1 -1
  80. package/sync-plugins/tanstack-react-query.d.ts +1 -1
  81. package/sync-plugins/tanstack-react-query.js +8 -1
  82. package/sync-plugins/tanstack-react-query.mjs +8 -1
  83. package/sync.d.mts +74 -200
  84. package/sync.d.ts +74 -200
  85. package/sync.js +492 -293
  86. package/sync.mjs +498 -299
package/sync.js CHANGED
@@ -2,8 +2,6 @@
2
2
 
3
3
  var state = require('@legendapp/state');
4
4
 
5
- // sync.ts
6
-
7
5
  // src/sync/configureObservableSync.ts
8
6
  var observableSyncConfiguration = {};
9
7
  function configureObservableSync(options) {
@@ -139,34 +137,84 @@ function transformStringifyDates(...args) {
139
137
  }
140
138
  };
141
139
  }
142
- function syncObservableAdapter({ get, set }) {
143
- const ret = {};
144
- if (get) {
145
- ret.get = async (params) => {
146
- try {
147
- let value = get(params);
148
- if (state.isPromise(value)) {
149
- value = await value;
150
- }
151
- params.onChange({
152
- value,
153
- lastSync: params.lastSync,
154
- mode: params.mode
155
- });
156
- params.onGet();
157
- } catch (e) {
140
+
141
+ // src/is.ts
142
+ function isPromise(obj) {
143
+ return obj instanceof Promise;
144
+ }
145
+
146
+ // src/sync/retry.ts
147
+ function calculateRetryDelay(retryOptions, retryNum) {
148
+ const { backoff, delay = 1e3, infinite, times = 3, maxDelay = 3e4 } = retryOptions;
149
+ if (infinite || retryNum < times) {
150
+ const delayTime = Math.min(delay * (backoff === "constant" ? 1 : 2 ** retryNum), maxDelay);
151
+ return delayTime;
152
+ }
153
+ return null;
154
+ }
155
+ function createRetryTimeout(retryOptions, retryNum, fn) {
156
+ const delayTime = calculateRetryDelay(retryOptions, retryNum);
157
+ if (delayTime) {
158
+ return setTimeout(fn, delayTime);
159
+ } else {
160
+ return false;
161
+ }
162
+ }
163
+ var mapRetryTimeouts = /* @__PURE__ */ new Map();
164
+ function runWithRetry(state, retryOptions, fn, onError) {
165
+ try {
166
+ let value = fn(state);
167
+ if (isPromise(value) && retryOptions) {
168
+ let timeoutRetry;
169
+ if (mapRetryTimeouts.has(state.node)) {
170
+ clearTimeout(mapRetryTimeouts.get(state.node));
158
171
  }
159
- };
172
+ return new Promise((resolve, reject) => {
173
+ const run = () => {
174
+ value.then((val) => {
175
+ resolve(val);
176
+ }).catch((error) => {
177
+ state.retryNum++;
178
+ if (timeoutRetry) {
179
+ clearTimeout(timeoutRetry);
180
+ }
181
+ if (onError) {
182
+ onError(error, state);
183
+ }
184
+ if (!state.cancelRetry) {
185
+ const timeout = createRetryTimeout(retryOptions, state.retryNum, () => {
186
+ value = fn(state);
187
+ run();
188
+ });
189
+ if (timeout === false) {
190
+ state.cancelRetry = true;
191
+ reject(error);
192
+ } else {
193
+ mapRetryTimeouts.set(state.node, timeout);
194
+ timeoutRetry = timeout;
195
+ }
196
+ }
197
+ });
198
+ };
199
+ run();
200
+ });
201
+ }
202
+ return value;
203
+ } catch (error) {
204
+ return Promise.reject(error);
160
205
  }
161
- if (set) {
162
- ret.set = set;
206
+ }
207
+ async function waitForSet(waitForSet2, changes, value, params = {}) {
208
+ const waitFn = state.isFunction(waitForSet2) ? waitForSet2({ changes, value, ...params }) : waitForSet2;
209
+ if (waitFn) {
210
+ await state.when(waitFn);
163
211
  }
164
- return ret;
165
212
  }
166
213
 
167
214
  // src/sync/syncObservable.ts
168
- var { createPreviousHandler, clone, getValueAtPath, globalState, symbolLinked, getNode, getNodeValue } = state.internal;
215
+ var { clone, deepMerge, getNode, getNodeValue, getValueAtPath, globalState, symbolLinked, createPreviousHandler } = state.internal;
169
216
  var mapSyncPlugins = /* @__PURE__ */ new WeakMap();
217
+ var allSyncStates = /* @__PURE__ */ new Map();
170
218
  var metadatas = /* @__PURE__ */ new WeakMap();
171
219
  var promisesLocalSaves = /* @__PURE__ */ new Set();
172
220
  function parseLocalConfig(config) {
@@ -183,13 +231,19 @@ function onChangeRemote(cb) {
183
231
  globalState.isLoadingRemote = false;
184
232
  state.endBatch(true);
185
233
  }
186
- function transformSaveData(value, path, pathTypes, { transform }) {
234
+ async function transformSaveData(value, path, pathTypes, { transform }) {
187
235
  if (transform == null ? void 0 : transform.save) {
188
236
  const constructed = state.constructObjectWithPath(path, pathTypes, value);
189
- const saved = transform.save(constructed);
190
- value = state.deconstructObjectWithPath(path, pathTypes, saved);
237
+ const saved = await transform.save(constructed);
238
+ value = saved;
239
+ const outPath = [];
240
+ for (let i = 0; i < path.length; i++) {
241
+ outPath[i] = Object.keys(value)[0];
242
+ value = value[outPath[i]];
243
+ }
244
+ path = outPath;
191
245
  }
192
- return value;
246
+ return { value, path };
193
247
  }
194
248
  function transformLoadData(value, { transform }, doUserTransform, method) {
195
249
  if (doUserTransform && (transform == null ? void 0 : transform.load)) {
@@ -197,13 +251,13 @@ function transformLoadData(value, { transform }, doUserTransform, method) {
197
251
  }
198
252
  return value;
199
253
  }
200
- async function updateMetadataImmediate(value$, localState, syncState, syncOptions, newMetadata) {
254
+ async function updateMetadataImmediate(value$, localState, syncState2, syncOptions, newMetadata) {
201
255
  const saves = Array.from(promisesLocalSaves);
202
256
  if (saves.length > 0) {
203
257
  await Promise.all(saves);
204
258
  }
205
259
  const { pluginPersist } = localState;
206
- const { table, config } = parseLocalConfig(syncOptions == null ? void 0 : syncOptions.persist);
260
+ const { table, config } = parseLocalConfig(syncOptions.persist);
207
261
  const oldMetadata = metadatas.get(value$);
208
262
  const { lastSync } = newMetadata;
209
263
  const metadata = Object.assign({}, oldMetadata, newMetadata);
@@ -212,17 +266,17 @@ async function updateMetadataImmediate(value$, localState, syncState, syncOption
212
266
  await pluginPersist.setMetadata(table, metadata, config);
213
267
  }
214
268
  if (lastSync) {
215
- syncState.assign({
269
+ syncState2.assign({
216
270
  lastSync
217
271
  });
218
272
  }
219
273
  }
220
- function updateMetadata(value$, localState, syncState, syncOptions, newMetadata) {
274
+ function updateMetadata(value$, localState, syncState2, syncOptions, newMetadata) {
221
275
  if (localState.timeoutSaveMetadata) {
222
276
  clearTimeout(localState.timeoutSaveMetadata);
223
277
  }
224
278
  localState.timeoutSaveMetadata = setTimeout(
225
- () => updateMetadataImmediate(value$, localState, syncState, syncOptions, newMetadata),
279
+ () => updateMetadataImmediate(value$, localState, syncState2, syncOptions, newMetadata),
226
280
  0
227
281
  );
228
282
  }
@@ -250,26 +304,21 @@ function mergeChanges(changes) {
250
304
  return changesOut;
251
305
  }
252
306
  function mergeQueuedChanges(allChanges) {
253
- const changesByObsRemote = /* @__PURE__ */ new Map();
254
- const changesByObsLocal = /* @__PURE__ */ new Map();
255
- const previousByObs = /* @__PURE__ */ new Map();
307
+ const changesByOptionsRemote = /* @__PURE__ */ new Map();
308
+ const changesByOptionsLocal = /* @__PURE__ */ new Map();
256
309
  const outRemote = /* @__PURE__ */ new Map();
257
310
  const outLocal = /* @__PURE__ */ new Map();
258
311
  for (let i = 0; i < allChanges.length; i++) {
259
312
  const value = allChanges[i];
260
- const { value$: obs, changes, inRemoteChange, getPrevious } = value;
313
+ const { changes, inRemoteChange, syncOptions } = value;
261
314
  const targetMap = inRemoteChange ? outRemote : outLocal;
262
- const changesMap = inRemoteChange ? changesByObsRemote : changesByObsLocal;
263
- const existing = changesMap.get(obs);
315
+ const changesMap = inRemoteChange ? changesByOptionsRemote : changesByOptionsLocal;
316
+ const existing = changesMap.get(syncOptions);
264
317
  const newChanges = existing ? [...existing, ...changes] : changes;
265
318
  const merged = mergeChanges(newChanges);
266
- changesMap.set(obs, merged);
319
+ changesMap.set(syncOptions, merged);
267
320
  value.changes = merged;
268
- if (!previousByObs.has(obs)) {
269
- previousByObs.set(obs, getPrevious());
270
- }
271
- value.valuePrevious = previousByObs.get(obs);
272
- targetMap.set(obs, value);
321
+ targetMap.set(syncOptions, value);
273
322
  }
274
323
  return Array.from(outRemote.values()).concat(Array.from(outLocal.values()));
275
324
  }
@@ -315,15 +364,13 @@ async function processQueuedRemoteChanges(syncOptions) {
315
364
  }
316
365
  }
317
366
  async function prepChangeLocal(queuedChange) {
318
- const { syncState, changes, localState, syncOptions, inRemoteChange, isApplyingPending } = queuedChange;
367
+ const { syncState: syncState2, changes, syncOptions, inRemoteChange, isApplyingPending } = queuedChange;
319
368
  const persist = syncOptions.persist;
320
- const { pluginSync } = localState;
321
369
  const { config: configLocal } = parseLocalConfig(persist);
322
- const configRemote = syncOptions;
323
- const saveLocal = (persist == null ? void 0 : persist.name) && !configLocal.readonly && !isApplyingPending && syncState.isPersistEnabled.peek();
324
- const saveRemote = !!(!inRemoteChange && (pluginSync == null ? void 0 : pluginSync.set) && (configRemote == null ? void 0 : configRemote.enableSync) !== false && syncState.isSyncEnabled.peek());
370
+ const saveLocal = (persist == null ? void 0 : persist.name) && !configLocal.readonly && !isApplyingPending && syncState2.isPersistEnabled.peek();
371
+ const saveRemote = !!(!inRemoteChange && (syncOptions == null ? void 0 : syncOptions.set) && syncState2.isSyncEnabled.peek());
325
372
  if (saveLocal || saveRemote) {
326
- if (saveLocal && !syncState.isPersistLoaded.peek()) {
373
+ if (saveLocal && !syncState2.isPersistLoaded.peek()) {
327
374
  console.error(
328
375
  "[legend-state] WARNING: An observable was changed before being loaded from persist",
329
376
  persist
@@ -356,13 +403,13 @@ async function prepChangeLocal(queuedChange) {
356
403
  configLocal
357
404
  );
358
405
  promisesTransform.push(
359
- doInOrder(promiseTransformLocal, (valueTransformed) => {
406
+ doInOrder(promiseTransformLocal, ({ value: valueTransformed, path: pathTransformed }) => {
360
407
  changesLocal.push({
361
- path,
408
+ path: pathTransformed,
362
409
  pathTypes,
363
410
  prevAtPath,
364
411
  valueAtPath: valueTransformed,
365
- pathStr
412
+ pathStr: path === pathTransformed ? pathStr : pathTransformed.join("/")
366
413
  });
367
414
  })
368
415
  );
@@ -378,22 +425,19 @@ async function prepChangeLocal(queuedChange) {
378
425
  }
379
426
  async function prepChangeRemote(queuedChange) {
380
427
  const {
381
- syncState,
428
+ syncState: syncState2,
382
429
  changes,
383
430
  localState,
384
431
  syncOptions,
385
432
  inRemoteChange,
386
- isApplyingPending,
387
- valuePrevious
433
+ isApplyingPending
388
434
  } = queuedChange;
389
435
  const persist = syncOptions.persist;
390
- const { pluginSync } = localState;
391
436
  const { config: configLocal } = parseLocalConfig(persist);
392
- const configRemote = syncOptions;
393
- const saveLocal = persist && !configLocal.readonly && !isApplyingPending && syncState.isPersistEnabled.peek();
394
- const saveRemote = !inRemoteChange && (pluginSync == null ? void 0 : pluginSync.set) && (configRemote == null ? void 0 : configRemote.enableSync) !== false && syncState.isSyncEnabled.peek();
437
+ const saveLocal = persist && !configLocal.readonly && !isApplyingPending && syncState2.isPersistEnabled.peek();
438
+ const saveRemote = !inRemoteChange && (syncOptions == null ? void 0 : syncOptions.set) && syncState2.isSyncEnabled.peek();
395
439
  if (saveLocal || saveRemote) {
396
- if (saveLocal && !syncState.isPersistLoaded.peek()) {
440
+ if (saveLocal && !syncState2.isPersistLoaded.peek()) {
397
441
  console.error(
398
442
  "[legend-state] WARNING: An observable was changed before being loaded from persist",
399
443
  persist
@@ -423,20 +467,20 @@ async function prepChangeRemote(queuedChange) {
423
467
  valueAtPath,
424
468
  path,
425
469
  pathTypes,
426
- configRemote || {}
470
+ syncOptions || {}
427
471
  );
428
472
  promisesTransform.push(
429
- doInOrder(promiseTransformRemote, (valueTransformed) => {
473
+ doInOrder(promiseTransformRemote, ({ value: valueTransformed, path: pathTransformed }) => {
430
474
  var _a;
431
475
  if (!localState.pendingChanges) {
432
476
  localState.pendingChanges = {};
433
477
  }
434
478
  let found2 = false;
435
- for (let i2 = 0; !found2 && i2 < path.length - 1; i2++) {
436
- const pathParent = path.slice(0, i2 + 1).join("/");
479
+ for (let i2 = 0; !found2 && i2 < pathTransformed.length - 1; i2++) {
480
+ const pathParent = pathTransformed.slice(0, i2 + 1).join("/");
437
481
  if ((_a = localState.pendingChanges[pathParent]) == null ? void 0 : _a.v) {
438
482
  found2 = true;
439
- const pathChild = path.slice(i2 + 1);
483
+ const pathChild = pathTransformed.slice(i2 + 1);
440
484
  const pathTypesChild = pathTypes.slice(i2 + 1);
441
485
  state.setAtPath(
442
486
  localState.pendingChanges[pathParent].v,
@@ -458,12 +502,11 @@ async function prepChangeRemote(queuedChange) {
458
502
  localState.pendingChanges[pathStr].v = valueAtPath;
459
503
  }
460
504
  changesRemote.push({
461
- path,
505
+ path: pathTransformed,
462
506
  pathTypes,
463
507
  prevAtPath,
464
508
  valueAtPath: valueTransformed,
465
- pathStr,
466
- valuePrevious
509
+ pathStr
467
510
  });
468
511
  })
469
512
  );
@@ -481,7 +524,7 @@ async function doChangeLocal(changeInfo) {
481
524
  if (!changeInfo)
482
525
  return;
483
526
  const { queuedChange, changesLocal, saveRemote } = changeInfo;
484
- const { value$: obs, syncState, localState, syncOptions } = queuedChange;
527
+ const { value$: obs, syncState: syncState2, localState, syncOptions } = queuedChange;
485
528
  const { pluginPersist } = localState;
486
529
  const persist = syncOptions.persist;
487
530
  const saveLocal = !!(persist == null ? void 0 : persist.name);
@@ -489,7 +532,7 @@ async function doChangeLocal(changeInfo) {
489
532
  const { table, config: configLocal } = parseLocalConfig(persist);
490
533
  const shouldSaveMetadata = persist == null ? void 0 : persist.retrySync;
491
534
  if (saveRemote && shouldSaveMetadata) {
492
- await updateMetadataImmediate(obs, localState, syncState, syncOptions, {
535
+ await updateMetadataImmediate(obs, localState, syncState2, syncOptions, {
493
536
  pending: localState.pendingChanges
494
537
  });
495
538
  }
@@ -510,103 +553,148 @@ async function doChangeRemote(changeInfo) {
510
553
  if (!changeInfo)
511
554
  return;
512
555
  const { queuedChange, changesRemote } = changeInfo;
513
- const { value$: obs, syncState, localState, syncOptions, valuePrevious: previous } = queuedChange;
514
- const { pluginPersist, pluginSync } = localState;
556
+ const { value$: obs$, syncState: syncState2, localState, syncOptions } = queuedChange;
557
+ const { pluginPersist } = localState;
558
+ const node = getNode(obs$);
559
+ const state$ = node.state;
515
560
  const persist = syncOptions.persist;
516
561
  const { table, config: configLocal } = parseLocalConfig(persist);
517
- const { allowSetIfGetError, onBeforeSet, onSetError, waitForSet, onAfterSet } = syncOptions || {};
562
+ const { onBeforeSet, waitForSet: waitForSetParam, onAfterSet } = syncOptions || {};
518
563
  const shouldSaveMetadata = persist == null ? void 0 : persist.retrySync;
519
564
  const saveLocal = !!(persist == null ? void 0 : persist.name);
520
565
  if (changesRemote.length > 0) {
521
- await state.when(() => syncState.isLoaded.get() || allowSetIfGetError && syncState.error.get());
522
- if (waitForSet) {
523
- const waitFor = state.isFunction(waitForSet) ? waitForSet({ changes: changesRemote, value: obs.peek() }) : waitForSet;
524
- if (waitFor) {
525
- await state.when(waitFor);
566
+ if (!syncState2.isLoaded.peek()) {
567
+ await state.when(syncState2.isLoaded);
568
+ const pending = localState.pendingChanges;
569
+ if (pending) {
570
+ changesRemote.forEach((change) => {
571
+ const key = change.pathStr;
572
+ const pendingAtPath = pending[key];
573
+ if (!state.isNullOrUndefined(pendingAtPath)) {
574
+ const { p } = pendingAtPath;
575
+ change.prevAtPath = p;
576
+ }
577
+ });
526
578
  }
527
579
  }
528
- let value = obs.peek();
580
+ if (waitForSetParam) {
581
+ await waitForSet(waitForSetParam, changesRemote, obs$.peek());
582
+ }
583
+ let value = clone(obs$.peek());
529
584
  const transformSave = (_a = syncOptions == null ? void 0 : syncOptions.transform) == null ? void 0 : _a.save;
530
585
  if (transformSave) {
531
- value = transformSave(clone(value));
532
- }
533
- onBeforeSet == null ? void 0 : onBeforeSet();
534
- localState.numSavesOutstanding = (localState.numSavesOutstanding || 0) + 1;
535
- let savedPromise = pluginSync.set({
536
- value$: obs,
537
- syncState,
538
- options: syncOptions,
539
- changes: changesRemote,
540
- value,
541
- valuePrevious: previous
542
- });
543
- if (state.isPromise(savedPromise)) {
544
- savedPromise = savedPromise.catch((err) => onSetError == null ? void 0 : onSetError(err));
586
+ value = transformSave(value);
545
587
  }
546
- const saved = await savedPromise;
547
- localState.numSavesOutstanding--;
548
- if (saved !== void 0) {
549
- const pathStrs = Array.from(new Set(changesRemote.map((change) => change.pathStr)));
550
- const { changes, lastSync } = saved;
551
- if (pathStrs.length > 0) {
552
- let transformedChanges = void 0;
553
- const metadata = {};
554
- if (saveLocal) {
555
- const pendingMetadata = (_b = pluginPersist.getMetadata(table, configLocal)) == null ? void 0 : _b.pending;
556
- const pending = localState.pendingChanges;
557
- for (let i = 0; i < pathStrs.length; i++) {
558
- const pathStr = pathStrs[i];
559
- if (pendingMetadata == null ? void 0 : pendingMetadata[pathStr]) {
560
- delete pendingMetadata[pathStr];
561
- metadata.pending = pendingMetadata;
588
+ state$.numPendingSets.set((v) => (v || 0) + 1);
589
+ state$.isSetting.set(true);
590
+ const beforeSetParams = {
591
+ cancel: false
592
+ };
593
+ onBeforeSet == null ? void 0 : onBeforeSet(beforeSetParams);
594
+ if (!beforeSetParams.cancel) {
595
+ let updateResult = void 0;
596
+ let errorHandled = false;
597
+ const onError = (error, retryParams) => {
598
+ var _a2;
599
+ state$.error.set(error);
600
+ if (!errorHandled) {
601
+ (_a2 = syncOptions.onError) == null ? void 0 : _a2.call(syncOptions, error, {
602
+ setParams,
603
+ source: "set",
604
+ value$: obs$,
605
+ retryParams
606
+ });
607
+ }
608
+ errorHandled = true;
609
+ };
610
+ const setParams = {
611
+ node,
612
+ value$: obs$,
613
+ changes: changesRemote,
614
+ value,
615
+ onError,
616
+ update: (params) => {
617
+ if (updateResult) {
618
+ const { value: value2, lastSync, mode } = params;
619
+ updateResult = {
620
+ lastSync: Math.max(updateResult.lastSync || 0, lastSync || 0),
621
+ value: deepMerge(updateResult.value, value2),
622
+ mode
623
+ };
624
+ } else {
625
+ updateResult = params;
626
+ }
627
+ },
628
+ refresh: syncState2.sync,
629
+ retryNum: 0,
630
+ cancelRetry: false
631
+ };
632
+ const savedPromise = runWithRetry(
633
+ setParams,
634
+ syncOptions.retry,
635
+ async () => {
636
+ return syncOptions.set(setParams);
637
+ },
638
+ onError
639
+ );
640
+ let didError = false;
641
+ if (state.isPromise(savedPromise)) {
642
+ await savedPromise.catch(() => {
643
+ didError = true;
644
+ });
645
+ }
646
+ if (!didError) {
647
+ const pathStrs = Array.from(new Set(changesRemote.map((change) => change.pathStr)));
648
+ const { value: changes, lastSync } = updateResult || {};
649
+ if (pathStrs.length > 0) {
650
+ let transformedChanges = void 0;
651
+ const metadata = {};
652
+ if (saveLocal) {
653
+ const pendingMetadata = (_b = pluginPersist.getMetadata(table, configLocal)) == null ? void 0 : _b.pending;
654
+ const pending = localState.pendingChanges;
655
+ for (let i = 0; i < pathStrs.length; i++) {
656
+ const pathStr = pathStrs[i];
657
+ if (pendingMetadata == null ? void 0 : pendingMetadata[pathStr]) {
658
+ delete pendingMetadata[pathStr];
659
+ metadata.pending = pendingMetadata;
660
+ }
661
+ if (pending == null ? void 0 : pending[pathStr]) {
662
+ delete pending[pathStr];
663
+ }
562
664
  }
563
- if (pending == null ? void 0 : pending[pathStr]) {
564
- delete pending[pathStr];
665
+ if (lastSync) {
666
+ metadata.lastSync = lastSync;
565
667
  }
566
668
  }
567
- if (lastSync) {
568
- metadata.lastSync = lastSync;
569
- }
570
- }
571
- if (changes && !state.isEmpty(changes)) {
572
- transformedChanges = transformLoadData(changes, syncOptions, false, "set");
573
- }
574
- if (localState.numSavesOutstanding > 0) {
575
- if (transformedChanges) {
576
- if (!localState.pendingSaveResults) {
577
- localState.pendingSaveResults = [];
578
- }
579
- localState.pendingSaveResults.push(transformedChanges);
669
+ if (changes && !state.isEmpty(changes)) {
670
+ transformedChanges = transformLoadData(changes, syncOptions, false, "set");
580
671
  }
581
- } else {
582
- let allChanges = [...localState.pendingSaveResults || [], transformedChanges].filter(
583
- (v) => v !== void 0
584
- );
585
- if (allChanges.length > 0) {
586
- if (allChanges.some((change) => state.isPromise(change))) {
587
- allChanges = await Promise.all(allChanges);
672
+ if (transformedChanges !== void 0) {
673
+ if (state.isPromise(transformedChanges)) {
674
+ transformedChanges = await transformedChanges;
588
675
  }
589
- onChangeRemote(() => state.mergeIntoObservable(obs, ...allChanges));
676
+ onChangeRemote(() => state.mergeIntoObservable(obs$, transformedChanges));
590
677
  }
591
678
  if (saveLocal) {
592
679
  if (shouldSaveMetadata && !state.isEmpty(metadata)) {
593
- updateMetadata(obs, localState, syncState, syncOptions, metadata);
680
+ updateMetadata(obs$, localState, syncState2, syncOptions, metadata);
594
681
  }
595
682
  }
596
- localState.pendingSaveResults = [];
597
683
  }
684
+ state$.numPendingSets.set((v) => v - 1);
685
+ state$.isSetting.set(state$.numPendingSets.peek() > 0);
598
686
  onAfterSet == null ? void 0 : onAfterSet();
599
687
  }
600
688
  }
601
689
  }
602
690
  }
603
- function onObsChange(value$, syncState, localState, syncOptions, { changes, loading, remote, getPrevious }) {
604
- if (!loading) {
605
- const inRemoteChange = remote;
691
+ function onObsChange(value$, syncState2, localState, syncOptions, { changes, isFromPersist, isFromSync, getPrevious }) {
692
+ if (!isFromPersist) {
693
+ const inRemoteChange = isFromSync;
606
694
  const isApplyingPending = localState.isApplyingPending;
607
695
  _queuedChanges.push({
608
696
  value$,
609
- syncState,
697
+ syncState: syncState2,
610
698
  localState,
611
699
  syncOptions,
612
700
  changes,
@@ -619,19 +707,22 @@ function onObsChange(value$, syncState, localState, syncOptions, { changes, load
619
707
  }
620
708
  }
621
709
  }
622
- async function loadLocal(value$, syncOptions, syncState, localState) {
710
+ async function loadLocal(value$, syncOptions, syncState$, localState) {
623
711
  var _a, _b, _c;
624
712
  const { persist } = syncOptions;
625
713
  const node = getNode(value$);
626
714
  const nodeValue = getNodeValue(getNode(node.state));
715
+ const syncStateValue = syncState$.peek();
716
+ const prevResetPersistence = nodeValue.resetPersistence;
627
717
  if (persist == null ? void 0 : persist.name) {
628
718
  const PersistPlugin = persist.plugin || ((_a = observableSyncConfiguration.persist) == null ? void 0 : _a.plugin);
629
719
  const { table, config } = parseLocalConfig(persist);
720
+ syncStateValue.numPendingLocalLoads = (syncStateValue.numPendingLocalLoads || 0) + 1;
630
721
  if (!PersistPlugin) {
631
722
  throw new Error("Local persist is not configured");
632
723
  }
633
724
  if (!mapSyncPlugins.has(PersistPlugin)) {
634
- const persistPlugin2 = new PersistPlugin();
725
+ const persistPlugin2 = state.isFunction(PersistPlugin) ? new PersistPlugin() : PersistPlugin;
635
726
  const mapValue = { plugin: persistPlugin2, initialized: state.observable(false) };
636
727
  mapSyncPlugins.set(PersistPlugin, mapValue);
637
728
  if (persistPlugin2.initialize) {
@@ -660,7 +751,7 @@ async function loadLocal(value$, syncOptions, syncState, localState) {
660
751
  if (metadata) {
661
752
  metadatas.set(value$, metadata);
662
753
  localState.pendingChanges = metadata.pending;
663
- syncState.assign({
754
+ syncState$.assign({
664
755
  lastSync: metadata.lastSync
665
756
  });
666
757
  }
@@ -678,15 +769,19 @@ async function loadLocal(value$, syncOptions, syncState, localState) {
678
769
  }
679
770
  state.internal.globalState.isLoadingLocal = false;
680
771
  }
681
- nodeValue.clearPersist = () => Promise.all([
682
- persistPlugin.deleteTable(table, config),
683
- persistPlugin.deleteMetadata(table, config)
684
- ]);
772
+ syncStateValue.numPendingLocalLoads--;
773
+ nodeValue.resetPersistence = () => Promise.all(
774
+ [
775
+ prevResetPersistence,
776
+ persistPlugin.deleteTable(table, config),
777
+ persistPlugin.deleteMetadata(table, config)
778
+ ].filter(Boolean)
779
+ );
685
780
  } else {
686
- nodeValue.clearPersist = () => {
687
- };
781
+ nodeValue.resetPersistence = () => prevResetPersistence == null ? void 0 : prevResetPersistence();
688
782
  }
689
- syncState.isPersistLoaded.set(true);
783
+ nodeValue.clearPersist = nodeValue.resetPersistence;
784
+ syncState$.isPersistLoaded.set(!(syncStateValue.numPendingLocalLoads > 0));
690
785
  }
691
786
  function syncObservable(obs$, syncOptionsOrSynced) {
692
787
  let syncOptions = syncOptionsOrSynced;
@@ -697,7 +792,7 @@ function syncObservable(obs$, syncOptionsOrSynced) {
697
792
  if ((process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test") && (!obs$ || !node)) {
698
793
  throw new Error("[legend-state] syncObservable called with undefined observable");
699
794
  }
700
- syncOptions = state.mergeIntoObservable(
795
+ syncOptions = deepMerge(
701
796
  {
702
797
  syncMode: "auto"
703
798
  },
@@ -706,24 +801,54 @@ function syncObservable(obs$, syncOptionsOrSynced) {
706
801
  );
707
802
  const localState = {};
708
803
  let sync;
709
- const syncState = node.state = state.observable({
710
- isPersistLoaded: false,
711
- isLoaded: !syncOptions.get,
712
- isPersistEnabled: true,
713
- isSyncEnabled: true,
714
- clearPersist: void 0,
715
- sync: () => Promise.resolve(),
716
- getPendingChanges: () => localState.pendingChanges
717
- });
718
- loadLocal(obs$, syncOptions, syncState, localState);
719
- localState.pluginSync = syncObservableAdapter(syncOptions);
804
+ const syncState$ = state.syncState(obs$);
805
+ const syncStateValue = getNodeValue(getNode(syncState$));
806
+ allSyncStates.set(syncState$, node);
807
+ syncStateValue.getPendingChanges = () => localState.pendingChanges;
808
+ let errorHandled = false;
809
+ const onGetError = (error, params) => {
810
+ var _a;
811
+ syncState$.error.set(error);
812
+ if (!errorHandled) {
813
+ (_a = syncOptions.onError) == null ? void 0 : _a.call(syncOptions, error, { ...params, value$: obs$ });
814
+ }
815
+ errorHandled = true;
816
+ };
817
+ loadLocal(obs$, syncOptions, syncState$, localState);
818
+ let isWaitingForLoad = !!syncOptions.get;
819
+ if (isWaitingForLoad) {
820
+ syncStateValue.numPendingRemoteLoads = (syncStateValue.numPendingRemoteLoads || 0) + 1;
821
+ }
822
+ syncState$.isLoaded.set(!syncState$.numPendingRemoteLoads.peek());
823
+ let isSynced = false;
824
+ let isSubscribed = false;
825
+ let unsubscribe = void 0;
826
+ const applyPending = (pending) => {
827
+ if (pending && !state.isEmpty(pending)) {
828
+ localState.isApplyingPending = true;
829
+ const keys = Object.keys(pending);
830
+ const changes = [];
831
+ for (let i = 0; i < keys.length; i++) {
832
+ const key = keys[i];
833
+ const path = key.split("/").filter((p2) => p2 !== "");
834
+ const { p, v, t } = pending[key];
835
+ changes.push({ path, valueAtPath: v, prevAtPath: p, pathTypes: t });
836
+ }
837
+ const value = getNodeValue(node);
838
+ onObsChange(obs$, syncState$, localState, syncOptions, {
839
+ value,
840
+ isFromPersist: false,
841
+ isFromSync: false,
842
+ getPrevious: createPreviousHandler(value, changes),
843
+ changes
844
+ });
845
+ localState.isApplyingPending = false;
846
+ }
847
+ };
720
848
  if (syncOptions.get) {
721
- let isSynced = false;
722
- let isSubscribed = false;
723
- let unsubscribe = void 0;
724
849
  sync = async () => {
725
- var _a, _b;
726
- if (isSynced && state.shouldIgnoreUnobserved(node, sync)) {
850
+ var _a;
851
+ if (isSynced && (!getNodeValue(getNode(syncState$)).isSyncEnabled || state.shouldIgnoreUnobserved(node, sync))) {
727
852
  if (unsubscribe) {
728
853
  isSubscribed = false;
729
854
  unsubscribe();
@@ -733,9 +858,11 @@ function syncObservable(obs$, syncOptionsOrSynced) {
733
858
  }
734
859
  const lastSync = (_a = metadatas.get(obs$)) == null ? void 0 : _a.lastSync;
735
860
  const pending = localState.pendingChanges;
736
- const get = (_b = localState.pluginSync.get) == null ? void 0 : _b.bind(localState.pluginSync);
861
+ const get = syncOptions.get;
737
862
  if (get) {
863
+ const { waitFor } = syncOptions;
738
864
  const runGet = () => {
865
+ var _a2;
739
866
  const onChange = async ({ value, mode, lastSync: lastSync2 }) => {
740
867
  mode = mode || syncOptions.mode || "set";
741
868
  if (value !== void 0) {
@@ -748,9 +875,11 @@ function syncObservable(obs$, syncOptionsOrSynced) {
748
875
  if (pending2) {
749
876
  let didChangeMetadata = false;
750
877
  Object.keys(pending2).forEach((key) => {
751
- const p = key.split("/").filter((p2) => p2 !== "");
878
+ const p = key.split("/").filter((k) => k !== "");
752
879
  const { v, t } = pending2[key];
753
880
  if (t.length === 0 || !value) {
881
+ const oldValue = clone(value);
882
+ pending2[key].p = oldValue;
754
883
  if (state.isObject(value) && state.isObject(v)) {
755
884
  Object.assign(value, v);
756
885
  } else {
@@ -763,6 +892,8 @@ function syncObservable(obs$, syncOptionsOrSynced) {
763
892
  delete pending2[key];
764
893
  didChangeMetadata = true;
765
894
  } else {
895
+ const oldValue = clone(value);
896
+ pending2[key].p = getValueAtPath(oldValue, p);
766
897
  value = state.setAtPath(
767
898
  value,
768
899
  p,
@@ -782,18 +913,27 @@ function syncObservable(obs$, syncOptionsOrSynced) {
782
913
  }
783
914
  }
784
915
  });
785
- if (didChangeMetadata) {
786
- updateMetadata(obs$, localState, syncState, syncOptions, {
916
+ if (didChangeMetadata && syncOptions.persist) {
917
+ updateMetadata(obs$, localState, syncState$, syncOptions, {
787
918
  pending: pending2
788
919
  });
789
920
  }
790
921
  }
791
922
  onChangeRemote(() => {
792
- if (mode === "assign" && state.isObject(value)) {
923
+ if (state.isPlainObject(value)) {
924
+ value = state.ObservableHint.plain(value);
925
+ }
926
+ if (mode === "assign") {
793
927
  obs$.assign(value);
794
- } else if (mode === "append" && state.isArray(value)) {
928
+ } else if (mode === "append") {
929
+ if ((process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test") && !state.isArray(value)) {
930
+ console.error("[legend-state] mode:append expects the value to be an array");
931
+ }
795
932
  obs$.push(...value);
796
- } else if (mode === "prepend" && state.isArray(value)) {
933
+ } else if (mode === "prepend") {
934
+ if ((process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test") && !state.isArray(value)) {
935
+ console.error("[legend-state] mode:prepend expects the value to be an array");
936
+ }
797
937
  obs$.splice(0, 0, ...value);
798
938
  } else if (mode === "merge") {
799
939
  state.mergeIntoObservable(obs$, value);
@@ -803,78 +943,180 @@ function syncObservable(obs$, syncOptionsOrSynced) {
803
943
  });
804
944
  }
805
945
  if (lastSync2 && syncOptions.persist) {
806
- updateMetadata(obs$, localState, syncState, syncOptions, {
946
+ updateMetadata(obs$, localState, syncState$, syncOptions, {
807
947
  lastSync: lastSync2
808
948
  });
809
949
  }
810
950
  };
811
- get({
812
- state: syncState,
951
+ if (node.activationState) {
952
+ node.activationState.onChange = onChange;
953
+ }
954
+ if (!isSubscribed && syncOptions.subscribe) {
955
+ const subscribe = syncOptions.subscribe;
956
+ isSubscribed = true;
957
+ const doSubscribe = () => {
958
+ const subscribeParams = {
959
+ node,
960
+ value$: obs$,
961
+ lastSync,
962
+ update: (params) => {
963
+ state.when(syncState$.isLoaded, () => {
964
+ state.when(waitFor || true, () => {
965
+ params.mode || (params.mode = syncOptions.mode || "merge");
966
+ onChange(params);
967
+ });
968
+ });
969
+ },
970
+ refresh: () => state.when(syncState$.isLoaded, sync),
971
+ onError: (error) => onGetError(error, { source: "subscribe", subscribeParams })
972
+ };
973
+ unsubscribe = subscribe(subscribeParams);
974
+ };
975
+ if (waitFor) {
976
+ state.whenReady(waitFor, doSubscribe);
977
+ } else {
978
+ doSubscribe();
979
+ }
980
+ }
981
+ const existingValue = getNodeValue(node);
982
+ const onError = (error) => onGetError(error, { getParams, source: "get" });
983
+ const getParams = {
984
+ node,
813
985
  value$: obs$,
986
+ value: state.isFunction(existingValue) || (existingValue == null ? void 0 : existingValue[symbolLinked]) ? void 0 : existingValue,
987
+ mode: syncOptions.mode,
988
+ refresh: sync,
814
989
  options: syncOptions,
815
990
  lastSync,
816
- dateModified: lastSync,
817
- onError: (error) => {
818
- var _a2;
819
- (_a2 = syncOptions.onGetError) == null ? void 0 : _a2.call(syncOptions, error);
820
- },
821
- onGet: () => {
822
- node.state.assign({
823
- isLoaded: true,
824
- error: void 0
991
+ updateLastSync: (lastSync2) => getParams.lastSync = lastSync2,
992
+ onError,
993
+ retryNum: 0,
994
+ cancelRetry: false
995
+ };
996
+ let modeBeforeReset = void 0;
997
+ const beforeGetParams = {
998
+ value: getParams.value,
999
+ lastSync,
1000
+ pendingChanges: pending && !state.isEmpty(pending) ? pending : void 0,
1001
+ clearPendingChanges: async () => {
1002
+ localState.pendingChanges = {};
1003
+ await updateMetadataImmediate(obs$, localState, syncState$, syncOptions, {
1004
+ pending: localState.pendingChanges
825
1005
  });
826
1006
  },
827
- onChange
828
- });
829
- if (!isSubscribed && syncOptions.subscribe) {
830
- isSubscribed = true;
831
- unsubscribe = syncOptions.subscribe({
832
- node,
833
- value$: obs$,
834
- update: (params) => {
835
- state.when(node.state.isLoaded, () => {
836
- params.mode || (params.mode = syncOptions.mode || "merge");
837
- onChange(params);
838
- });
839
- },
840
- refresh: () => state.when(node.state.isLoaded, sync)
1007
+ resetCache: () => {
1008
+ var _a3;
1009
+ modeBeforeReset = getParams.mode;
1010
+ getParams.mode = "set";
1011
+ return (_a3 = syncStateValue.resetPersistence) == null ? void 0 : _a3.call(syncStateValue);
1012
+ },
1013
+ cancel: false
1014
+ };
1015
+ (_a2 = syncOptions.onBeforeGet) == null ? void 0 : _a2.call(syncOptions, beforeGetParams);
1016
+ if (!beforeGetParams.cancel) {
1017
+ syncState$.assign({
1018
+ numPendingGets: (syncStateValue.numPendingGets || 0) + 1,
1019
+ isGetting: true
841
1020
  });
1021
+ const got = runWithRetry(
1022
+ getParams,
1023
+ syncOptions.retry,
1024
+ (retryEvent) => {
1025
+ const params = getParams;
1026
+ params.cancelRetry = retryEvent.cancelRetry;
1027
+ params.retryNum = retryEvent.retryNum;
1028
+ return get(params);
1029
+ },
1030
+ onError
1031
+ );
1032
+ const numGets = node.numGets = (node.numGets || 0) + 1;
1033
+ const handle = (value) => {
1034
+ syncState$.numPendingGets.set((v) => v - 1);
1035
+ if (isWaitingForLoad) {
1036
+ isWaitingForLoad = false;
1037
+ syncStateValue.numPendingRemoteLoads--;
1038
+ }
1039
+ if (numGets >= (node.getNumResolved || 0)) {
1040
+ node.getNumResolved = node.numGets;
1041
+ onChange({
1042
+ value,
1043
+ lastSync: getParams.lastSync,
1044
+ mode: getParams.mode
1045
+ });
1046
+ }
1047
+ if (modeBeforeReset) {
1048
+ getParams.mode = modeBeforeReset;
1049
+ modeBeforeReset = void 0;
1050
+ }
1051
+ syncState$.assign({
1052
+ isLoaded: syncStateValue.numPendingRemoteLoads < 1,
1053
+ error: void 0,
1054
+ isGetting: syncStateValue.numPendingGets > 0
1055
+ });
1056
+ };
1057
+ if (state.isPromise(got)) {
1058
+ got.then(handle).catch(onError);
1059
+ } else {
1060
+ handle(got);
1061
+ }
842
1062
  }
843
1063
  };
844
- runGet();
1064
+ if (waitFor) {
1065
+ state.whenReady(waitFor, () => state.trackSelector(runGet, sync));
1066
+ } else {
1067
+ state.trackSelector(runGet, sync);
1068
+ }
845
1069
  } else {
846
- node.state.assign({
1070
+ syncState$.assign({
847
1071
  isLoaded: true,
848
1072
  error: void 0
849
1073
  });
850
1074
  }
851
1075
  if (!isSynced) {
852
1076
  isSynced = true;
853
- await state.when(() => syncState.isLoaded.get() || syncOptions.allowSetIfGetError && syncState.error.get());
854
- if (pending && !state.isEmpty(pending)) {
855
- localState.isApplyingPending = true;
856
- const keys = Object.keys(pending);
857
- const changes = [];
858
- for (let i = 0; i < keys.length; i++) {
859
- const key = keys[i];
860
- const path = key.split("/").filter((p2) => p2 !== "");
861
- const { p, v, t } = pending[key];
862
- changes.push({ path, valueAtPath: v, prevAtPath: p, pathTypes: t });
863
- }
864
- const value = getNodeValue(node);
865
- onObsChange(obs$, syncState, localState, syncOptions, {
866
- value,
867
- loading: false,
868
- remote: false,
869
- getPrevious: createPreviousHandler(value, changes),
870
- changes
871
- });
872
- localState.isApplyingPending = false;
873
- }
1077
+ await state.when(syncState$.isLoaded);
1078
+ applyPending(pending);
874
1079
  }
875
1080
  };
876
- syncState.assign({ sync });
1081
+ syncStateValue.sync = sync;
1082
+ } else {
1083
+ if (!isSynced) {
1084
+ applyPending(localState.pendingChanges);
1085
+ }
877
1086
  }
1087
+ syncStateValue.reset = async () => {
1088
+ const wasPersistEnabled = syncStateValue.isPersistEnabled;
1089
+ const wasSyncEnabled = syncStateValue.isSyncEnabled;
1090
+ const metadata = metadatas.get(obs$);
1091
+ if (metadata) {
1092
+ Object.assign(metadata, { lastSync: void 0, pending: void 0 });
1093
+ }
1094
+ Object.assign(syncStateValue, {
1095
+ isPersistEnabled: false,
1096
+ isSyncEnabled: false,
1097
+ lastSync: void 0,
1098
+ numPendingGets: 0,
1099
+ isLoaded: false,
1100
+ isGetting: false,
1101
+ isSetting: false,
1102
+ numPendingSets: 0,
1103
+ syncCount: 0
1104
+ });
1105
+ isSynced = false;
1106
+ isSubscribed = false;
1107
+ unsubscribe == null ? void 0 : unsubscribe();
1108
+ unsubscribe = void 0;
1109
+ const promise = syncStateValue.resetPersistence();
1110
+ onChangeRemote(() => {
1111
+ var _a;
1112
+ obs$.set((_a = syncOptions.initial) != null ? _a : void 0);
1113
+ });
1114
+ syncState$.isLoaded.set(false);
1115
+ syncStateValue.isPersistEnabled = wasPersistEnabled;
1116
+ syncStateValue.isSyncEnabled = wasSyncEnabled;
1117
+ node.dirtyFn = sync;
1118
+ await promise;
1119
+ };
878
1120
  const onAllPersistLoaded = () => {
879
1121
  var _a, _b;
880
1122
  let parentNode = node;
@@ -892,77 +1134,27 @@ function syncObservable(obs$, syncOptionsOrSynced) {
892
1134
  }
893
1135
  if ((syncOptions == null ? void 0 : syncOptions.set) || (syncOptions == null ? void 0 : syncOptions.persist)) {
894
1136
  obs$.onChange(
895
- onObsChange.bind(this, obs$, syncState, localState, syncOptions)
1137
+ onObsChange.bind(this, obs$, syncState$, localState, syncOptions)
896
1138
  );
897
1139
  }
898
1140
  });
899
- return syncState;
1141
+ return syncState$;
900
1142
  }
901
- var { getProxy, globalState: globalState2, runWithRetry, symbolLinked: symbolLinked2, setNodeValue, getNodeValue: getNodeValue2 } = state.internal;
1143
+ var { getProxy, globalState: globalState2, setNodeValue, getNodeValue: getNodeValue2 } = state.internal;
902
1144
  function enableActivateSyncedNode() {
903
1145
  globalState2.activateSyncedNode = function activateSyncedNode(node, newValue) {
904
1146
  const obs$ = getProxy(node);
905
1147
  if (node.activationState) {
906
- const { get, initial, set, retry } = node.activationState;
907
- let onChange = void 0;
908
- const pluginRemote = {};
1148
+ const {
1149
+ get: getOrig,
1150
+ initial,
1151
+ set,
1152
+ onChange
1153
+ } = node.activationState;
909
1154
  let promiseReturn = void 0;
910
- let syncState;
911
- const refresh = () => syncState == null ? void 0 : syncState.sync();
912
- if (get) {
913
- pluginRemote.get = (params) => {
914
- var _a;
915
- onChange = params.onChange;
916
- const updateLastSync = (lastSync) => params.lastSync = lastSync;
917
- const existingValue = getNodeValue2(node);
918
- const value = runWithRetry(node, { attemptNum: 0, retry: retry || ((_a = params.options) == null ? void 0 : _a.retry) }, () => {
919
- const paramsToGet = {
920
- value: state.isFunction(existingValue) || (existingValue == null ? void 0 : existingValue[symbolLinked2]) ? void 0 : existingValue,
921
- lastSync: params.lastSync,
922
- updateLastSync,
923
- mode: params.mode,
924
- refresh
925
- };
926
- const ret = get(paramsToGet);
927
- params.mode = paramsToGet.mode;
928
- return ret;
929
- });
930
- promiseReturn = value;
931
- return value;
932
- };
933
- }
934
- if (set) {
935
- pluginRemote.set = async (params) => {
936
- var _a, _b;
937
- if ((_a = node.state) == null ? void 0 : _a.isLoaded.get()) {
938
- const retryAttempts = { attemptNum: 0, retry: retry || ((_b = params.options) == null ? void 0 : _b.retry) };
939
- return runWithRetry(node, retryAttempts, async (retryEvent) => {
940
- let changes = {};
941
- let maxModified = 0;
942
- if (!node.state.isLoaded.peek()) {
943
- await state.whenReady(node.state.isLoaded);
944
- }
945
- const cancelRetry = () => {
946
- retryEvent.cancel = true;
947
- };
948
- await set({
949
- ...params,
950
- node,
951
- update: (params2) => {
952
- const { value, lastSync } = params2;
953
- maxModified = Math.max(lastSync || 0, maxModified);
954
- changes = state.mergeIntoObservable(changes, value);
955
- },
956
- retryNum: retryAttempts.attemptNum,
957
- cancelRetry,
958
- refresh,
959
- fromSubscribe: false
960
- });
961
- return { changes, lastSync: maxModified || void 0 };
962
- });
963
- }
964
- };
965
- }
1155
+ const get = getOrig ? (params) => {
1156
+ return promiseReturn = getOrig(params);
1157
+ } : void 0;
966
1158
  const nodeVal = getNodeValue2(node);
967
1159
  if (promiseReturn !== void 0) {
968
1160
  newValue = promiseReturn;
@@ -972,7 +1164,7 @@ function enableActivateSyncedNode() {
972
1164
  newValue = initial;
973
1165
  }
974
1166
  setNodeValue(node, promiseReturn ? void 0 : newValue);
975
- syncState = syncObservable(obs$, { ...node.activationState, ...pluginRemote });
1167
+ syncObservable(obs$, { ...node.activationState, get, set });
976
1168
  return { update: onChange, value: newValue };
977
1169
  } else {
978
1170
  let update = void 0;
@@ -1009,21 +1201,28 @@ function installPersistActivateNode() {
1009
1201
  didInstall = true;
1010
1202
  }
1011
1203
  }
1204
+ var { deepMerge: deepMerge2 } = state.internal;
1205
+ function configureSynced(fnOrOrigOptions, origOptions) {
1206
+ const fn = origOptions ? fnOrOrigOptions : synced;
1207
+ origOptions = origOptions != null ? origOptions : fnOrOrigOptions;
1208
+ return (options) => {
1209
+ const merged = deepMerge2(origOptions, options);
1210
+ return fn(merged);
1211
+ };
1212
+ }
1012
1213
 
1013
1214
  // sync.ts
1014
- function isInRemoteChange() {
1015
- return state.internal.globalState.isLoadingRemote;
1016
- }
1017
- var internal3 = {
1018
- observableSyncConfiguration
1215
+ var internal4 = {
1216
+ observableSyncConfiguration,
1217
+ waitForSet
1019
1218
  };
1020
1219
 
1021
1220
  exports.combineTransforms = combineTransforms;
1022
1221
  exports.configureObservableSync = configureObservableSync;
1222
+ exports.configureSynced = configureSynced;
1023
1223
  exports.deepEqual = deepEqual;
1024
1224
  exports.diffObjects = diffObjects;
1025
- exports.internal = internal3;
1026
- exports.isInRemoteChange = isInRemoteChange;
1225
+ exports.internal = internal4;
1027
1226
  exports.mapSyncPlugins = mapSyncPlugins;
1028
1227
  exports.onChangeRemote = onChangeRemote;
1029
1228
  exports.removeNullUndefined = removeNullUndefined;