@legendapp/state 3.0.0-alpha.9 → 3.0.0-beta.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 (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 +103 -79
  17. package/index.d.ts +103 -79
  18. package/index.js +326 -316
  19. package/index.mjs +323 -314
  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 -23
  58. package/sync-plugins/crud.d.ts +21 -23
  59. package/sync-plugins/crud.js +224 -112
  60. package/sync-plugins/crud.mjs +226 -114
  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 -99
  70. package/sync-plugins/keel.mjs +147 -99
  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 -21
  74. package/sync-plugins/supabase.mjs +53 -22
  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 +498 -281
  86. package/sync.mjs +503 -286
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,88 +553,151 @@ 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 = clone(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
586
  value = transformSave(value);
532
587
  }
533
- onBeforeSet == null ? void 0 : onBeforeSet();
534
- let savedPromise = pluginSync.set({
535
- value$: obs,
536
- syncState,
537
- options: syncOptions,
538
- changes: changesRemote,
539
- value,
540
- valuePrevious: previous
541
- });
542
- if (state.isPromise(savedPromise)) {
543
- savedPromise = savedPromise.catch((err) => onSetError == null ? void 0 : onSetError(err));
544
- }
545
- const saved = await savedPromise;
546
- if (saved !== void 0) {
547
- const pathStrs = Array.from(new Set(changesRemote.map((change) => change.pathStr)));
548
- const { changes, lastSync } = saved;
549
- if (pathStrs.length > 0) {
550
- let transformedChanges = void 0;
551
- const metadata = {};
552
- if (saveLocal) {
553
- const pendingMetadata = (_b = pluginPersist.getMetadata(table, configLocal)) == null ? void 0 : _b.pending;
554
- const pending = localState.pendingChanges;
555
- for (let i = 0; i < pathStrs.length; i++) {
556
- const pathStr = pathStrs[i];
557
- if (pendingMetadata == null ? void 0 : pendingMetadata[pathStr]) {
558
- delete pendingMetadata[pathStr];
559
- 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((error) => {
643
+ didError = true;
644
+ if (!syncOptions.retry) {
645
+ onError(error);
646
+ }
647
+ });
648
+ }
649
+ if (!didError) {
650
+ const pathStrs = Array.from(new Set(changesRemote.map((change) => change.pathStr)));
651
+ const { value: changes, lastSync } = updateResult || {};
652
+ if (pathStrs.length > 0) {
653
+ let transformedChanges = void 0;
654
+ const metadata = {};
655
+ if (saveLocal) {
656
+ const pendingMetadata = (_b = pluginPersist.getMetadata(table, configLocal)) == null ? void 0 : _b.pending;
657
+ const pending = localState.pendingChanges;
658
+ for (let i = 0; i < pathStrs.length; i++) {
659
+ const pathStr = pathStrs[i];
660
+ if (pendingMetadata == null ? void 0 : pendingMetadata[pathStr]) {
661
+ delete pendingMetadata[pathStr];
662
+ metadata.pending = pendingMetadata;
663
+ }
664
+ if (pending == null ? void 0 : pending[pathStr]) {
665
+ delete pending[pathStr];
666
+ }
560
667
  }
561
- if (pending == null ? void 0 : pending[pathStr]) {
562
- delete pending[pathStr];
668
+ if (lastSync) {
669
+ metadata.lastSync = lastSync;
563
670
  }
564
671
  }
565
- if (lastSync) {
566
- metadata.lastSync = lastSync;
672
+ if (changes && !state.isEmpty(changes)) {
673
+ transformedChanges = transformLoadData(changes, syncOptions, false, "set");
567
674
  }
568
- }
569
- if (changes && !state.isEmpty(changes)) {
570
- transformedChanges = transformLoadData(changes, syncOptions, false, "set");
571
- }
572
- if (transformedChanges !== void 0) {
573
- if (state.isPromise(transformedChanges)) {
574
- transformedChanges = await transformedChanges;
675
+ if (transformedChanges !== void 0) {
676
+ if (state.isPromise(transformedChanges)) {
677
+ transformedChanges = await transformedChanges;
678
+ }
679
+ onChangeRemote(() => state.mergeIntoObservable(obs$, transformedChanges));
575
680
  }
576
- onChangeRemote(() => state.mergeIntoObservable(obs, transformedChanges));
577
- }
578
- if (saveLocal) {
579
- if (shouldSaveMetadata && !state.isEmpty(metadata)) {
580
- updateMetadata(obs, localState, syncState, syncOptions, metadata);
681
+ if (saveLocal) {
682
+ if (shouldSaveMetadata && !state.isEmpty(metadata)) {
683
+ updateMetadata(obs$, localState, syncState2, syncOptions, metadata);
684
+ }
581
685
  }
582
686
  }
687
+ state$.numPendingSets.set((v) => v - 1);
688
+ state$.isSetting.set(state$.numPendingSets.peek() > 0);
583
689
  onAfterSet == null ? void 0 : onAfterSet();
584
690
  }
585
691
  }
586
692
  }
587
693
  }
588
- function onObsChange(value$, syncState, localState, syncOptions, { changes, loading, remote, getPrevious }) {
589
- if (!loading) {
590
- const inRemoteChange = remote;
694
+ function onObsChange(value$, syncState2, localState, syncOptions, { changes, isFromPersist, isFromSync, getPrevious }) {
695
+ if (!isFromPersist) {
696
+ const inRemoteChange = isFromSync;
591
697
  const isApplyingPending = localState.isApplyingPending;
592
698
  _queuedChanges.push({
593
699
  value$,
594
- syncState,
700
+ syncState: syncState2,
595
701
  localState,
596
702
  syncOptions,
597
703
  changes,
@@ -604,19 +710,22 @@ function onObsChange(value$, syncState, localState, syncOptions, { changes, load
604
710
  }
605
711
  }
606
712
  }
607
- async function loadLocal(value$, syncOptions, syncState, localState) {
713
+ async function loadLocal(value$, syncOptions, syncState$, localState) {
608
714
  var _a, _b, _c;
609
715
  const { persist } = syncOptions;
610
716
  const node = getNode(value$);
611
717
  const nodeValue = getNodeValue(getNode(node.state));
718
+ const syncStateValue = syncState$.peek();
719
+ const prevResetPersistence = nodeValue.resetPersistence;
612
720
  if (persist == null ? void 0 : persist.name) {
613
721
  const PersistPlugin = persist.plugin || ((_a = observableSyncConfiguration.persist) == null ? void 0 : _a.plugin);
614
722
  const { table, config } = parseLocalConfig(persist);
723
+ syncStateValue.numPendingLocalLoads = (syncStateValue.numPendingLocalLoads || 0) + 1;
615
724
  if (!PersistPlugin) {
616
725
  throw new Error("Local persist is not configured");
617
726
  }
618
727
  if (!mapSyncPlugins.has(PersistPlugin)) {
619
- const persistPlugin2 = new PersistPlugin();
728
+ const persistPlugin2 = state.isFunction(PersistPlugin) ? new PersistPlugin() : PersistPlugin;
620
729
  const mapValue = { plugin: persistPlugin2, initialized: state.observable(false) };
621
730
  mapSyncPlugins.set(PersistPlugin, mapValue);
622
731
  if (persistPlugin2.initialize) {
@@ -645,7 +754,7 @@ async function loadLocal(value$, syncOptions, syncState, localState) {
645
754
  if (metadata) {
646
755
  metadatas.set(value$, metadata);
647
756
  localState.pendingChanges = metadata.pending;
648
- syncState.assign({
757
+ syncState$.assign({
649
758
  lastSync: metadata.lastSync
650
759
  });
651
760
  }
@@ -663,15 +772,19 @@ async function loadLocal(value$, syncOptions, syncState, localState) {
663
772
  }
664
773
  state.internal.globalState.isLoadingLocal = false;
665
774
  }
666
- nodeValue.clearPersist = () => Promise.all([
667
- persistPlugin.deleteTable(table, config),
668
- persistPlugin.deleteMetadata(table, config)
669
- ]);
775
+ syncStateValue.numPendingLocalLoads--;
776
+ nodeValue.resetPersistence = () => Promise.all(
777
+ [
778
+ prevResetPersistence,
779
+ persistPlugin.deleteTable(table, config),
780
+ persistPlugin.deleteMetadata(table, config)
781
+ ].filter(Boolean)
782
+ );
670
783
  } else {
671
- nodeValue.clearPersist = () => {
672
- };
784
+ nodeValue.resetPersistence = () => prevResetPersistence == null ? void 0 : prevResetPersistence();
673
785
  }
674
- syncState.isPersistLoaded.set(true);
786
+ nodeValue.clearPersist = nodeValue.resetPersistence;
787
+ syncState$.isPersistLoaded.set(!(syncStateValue.numPendingLocalLoads > 0));
675
788
  }
676
789
  function syncObservable(obs$, syncOptionsOrSynced) {
677
790
  let syncOptions = syncOptionsOrSynced;
@@ -682,7 +795,7 @@ function syncObservable(obs$, syncOptionsOrSynced) {
682
795
  if ((process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test") && (!obs$ || !node)) {
683
796
  throw new Error("[legend-state] syncObservable called with undefined observable");
684
797
  }
685
- syncOptions = state.mergeIntoObservable(
798
+ syncOptions = deepMerge(
686
799
  {
687
800
  syncMode: "auto"
688
801
  },
@@ -691,24 +804,54 @@ function syncObservable(obs$, syncOptionsOrSynced) {
691
804
  );
692
805
  const localState = {};
693
806
  let sync;
694
- const syncState = node.state = state.observable({
695
- isPersistLoaded: false,
696
- isLoaded: !syncOptions.get,
697
- isPersistEnabled: true,
698
- isSyncEnabled: true,
699
- clearPersist: void 0,
700
- sync: () => Promise.resolve(),
701
- getPendingChanges: () => localState.pendingChanges
702
- });
703
- loadLocal(obs$, syncOptions, syncState, localState);
704
- localState.pluginSync = syncObservableAdapter(syncOptions);
807
+ const syncState$ = state.syncState(obs$);
808
+ const syncStateValue = getNodeValue(getNode(syncState$));
809
+ allSyncStates.set(syncState$, node);
810
+ syncStateValue.getPendingChanges = () => localState.pendingChanges;
811
+ let errorHandled = false;
812
+ const onGetError = (error, params) => {
813
+ var _a;
814
+ syncState$.error.set(error);
815
+ if (!errorHandled) {
816
+ (_a = syncOptions.onError) == null ? void 0 : _a.call(syncOptions, error, { ...params, value$: obs$ });
817
+ }
818
+ errorHandled = true;
819
+ };
820
+ loadLocal(obs$, syncOptions, syncState$, localState);
821
+ let isWaitingForLoad = !!syncOptions.get;
822
+ if (isWaitingForLoad) {
823
+ syncStateValue.numPendingRemoteLoads = (syncStateValue.numPendingRemoteLoads || 0) + 1;
824
+ }
825
+ syncState$.isLoaded.set(!syncState$.numPendingRemoteLoads.peek());
826
+ let isSynced = false;
827
+ let isSubscribed = false;
828
+ let unsubscribe = void 0;
829
+ const applyPending = (pending) => {
830
+ if (pending && !state.isEmpty(pending)) {
831
+ localState.isApplyingPending = true;
832
+ const keys = Object.keys(pending);
833
+ const changes = [];
834
+ for (let i = 0; i < keys.length; i++) {
835
+ const key = keys[i];
836
+ const path = key.split("/").filter((p2) => p2 !== "");
837
+ const { p, v, t } = pending[key];
838
+ changes.push({ path, valueAtPath: v, prevAtPath: p, pathTypes: t });
839
+ }
840
+ const value = getNodeValue(node);
841
+ onObsChange(obs$, syncState$, localState, syncOptions, {
842
+ value,
843
+ isFromPersist: false,
844
+ isFromSync: false,
845
+ getPrevious: createPreviousHandler(value, changes),
846
+ changes
847
+ });
848
+ localState.isApplyingPending = false;
849
+ }
850
+ };
705
851
  if (syncOptions.get) {
706
- let isSynced = false;
707
- let isSubscribed = false;
708
- let unsubscribe = void 0;
709
852
  sync = async () => {
710
- var _a, _b;
711
- if (isSynced && state.shouldIgnoreUnobserved(node, sync)) {
853
+ var _a;
854
+ if (isSynced && (!getNodeValue(getNode(syncState$)).isSyncEnabled || state.shouldIgnoreUnobserved(node, sync))) {
712
855
  if (unsubscribe) {
713
856
  isSubscribed = false;
714
857
  unsubscribe();
@@ -718,9 +861,11 @@ function syncObservable(obs$, syncOptionsOrSynced) {
718
861
  }
719
862
  const lastSync = (_a = metadatas.get(obs$)) == null ? void 0 : _a.lastSync;
720
863
  const pending = localState.pendingChanges;
721
- const get = (_b = localState.pluginSync.get) == null ? void 0 : _b.bind(localState.pluginSync);
864
+ const get = syncOptions.get;
722
865
  if (get) {
866
+ const { waitFor } = syncOptions;
723
867
  const runGet = () => {
868
+ var _a2;
724
869
  const onChange = async ({ value, mode, lastSync: lastSync2 }) => {
725
870
  mode = mode || syncOptions.mode || "set";
726
871
  if (value !== void 0) {
@@ -733,9 +878,11 @@ function syncObservable(obs$, syncOptionsOrSynced) {
733
878
  if (pending2) {
734
879
  let didChangeMetadata = false;
735
880
  Object.keys(pending2).forEach((key) => {
736
- const p = key.split("/").filter((p2) => p2 !== "");
881
+ const p = key.split("/").filter((k) => k !== "");
737
882
  const { v, t } = pending2[key];
738
883
  if (t.length === 0 || !value) {
884
+ const oldValue = clone(value);
885
+ pending2[key].p = oldValue;
739
886
  if (state.isObject(value) && state.isObject(v)) {
740
887
  Object.assign(value, v);
741
888
  } else {
@@ -748,6 +895,8 @@ function syncObservable(obs$, syncOptionsOrSynced) {
748
895
  delete pending2[key];
749
896
  didChangeMetadata = true;
750
897
  } else {
898
+ const oldValue = clone(value);
899
+ pending2[key].p = getValueAtPath(oldValue, p);
751
900
  value = state.setAtPath(
752
901
  value,
753
902
  p,
@@ -767,18 +916,27 @@ function syncObservable(obs$, syncOptionsOrSynced) {
767
916
  }
768
917
  }
769
918
  });
770
- if (didChangeMetadata) {
771
- updateMetadata(obs$, localState, syncState, syncOptions, {
919
+ if (didChangeMetadata && syncOptions.persist) {
920
+ updateMetadata(obs$, localState, syncState$, syncOptions, {
772
921
  pending: pending2
773
922
  });
774
923
  }
775
924
  }
776
925
  onChangeRemote(() => {
777
- if (mode === "assign" && state.isObject(value)) {
926
+ if (state.isPlainObject(value)) {
927
+ value = state.ObservableHint.plain(value);
928
+ }
929
+ if (mode === "assign") {
778
930
  obs$.assign(value);
779
- } else if (mode === "append" && state.isArray(value)) {
931
+ } else if (mode === "append") {
932
+ if ((process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test") && !state.isArray(value)) {
933
+ console.error("[legend-state] mode:append expects the value to be an array");
934
+ }
780
935
  obs$.push(...value);
781
- } else if (mode === "prepend" && state.isArray(value)) {
936
+ } else if (mode === "prepend") {
937
+ if ((process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test") && !state.isArray(value)) {
938
+ console.error("[legend-state] mode:prepend expects the value to be an array");
939
+ }
782
940
  obs$.splice(0, 0, ...value);
783
941
  } else if (mode === "merge") {
784
942
  state.mergeIntoObservable(obs$, value);
@@ -788,78 +946,180 @@ function syncObservable(obs$, syncOptionsOrSynced) {
788
946
  });
789
947
  }
790
948
  if (lastSync2 && syncOptions.persist) {
791
- updateMetadata(obs$, localState, syncState, syncOptions, {
949
+ updateMetadata(obs$, localState, syncState$, syncOptions, {
792
950
  lastSync: lastSync2
793
951
  });
794
952
  }
795
953
  };
796
- get({
797
- state: syncState,
954
+ if (node.activationState) {
955
+ node.activationState.onChange = onChange;
956
+ }
957
+ if (!isSubscribed && syncOptions.subscribe) {
958
+ const subscribe = syncOptions.subscribe;
959
+ isSubscribed = true;
960
+ const doSubscribe = () => {
961
+ const subscribeParams = {
962
+ node,
963
+ value$: obs$,
964
+ lastSync,
965
+ update: (params) => {
966
+ state.when(syncState$.isLoaded, () => {
967
+ state.when(waitFor || true, () => {
968
+ params.mode || (params.mode = syncOptions.mode || "merge");
969
+ onChange(params);
970
+ });
971
+ });
972
+ },
973
+ refresh: () => state.when(syncState$.isLoaded, sync),
974
+ onError: (error) => onGetError(error, { source: "subscribe", subscribeParams })
975
+ };
976
+ unsubscribe = subscribe(subscribeParams);
977
+ };
978
+ if (waitFor) {
979
+ state.whenReady(waitFor, doSubscribe);
980
+ } else {
981
+ doSubscribe();
982
+ }
983
+ }
984
+ const existingValue = getNodeValue(node);
985
+ const onError = (error) => onGetError(error, { getParams, source: "get" });
986
+ const getParams = {
987
+ node,
798
988
  value$: obs$,
989
+ value: state.isFunction(existingValue) || (existingValue == null ? void 0 : existingValue[symbolLinked]) ? void 0 : existingValue,
990
+ mode: syncOptions.mode,
991
+ refresh: sync,
799
992
  options: syncOptions,
800
993
  lastSync,
801
- dateModified: lastSync,
802
- onError: (error) => {
803
- var _a2;
804
- (_a2 = syncOptions.onGetError) == null ? void 0 : _a2.call(syncOptions, error);
805
- },
806
- onGet: () => {
807
- node.state.assign({
808
- isLoaded: true,
809
- error: void 0
994
+ updateLastSync: (lastSync2) => getParams.lastSync = lastSync2,
995
+ onError,
996
+ retryNum: 0,
997
+ cancelRetry: false
998
+ };
999
+ let modeBeforeReset = void 0;
1000
+ const beforeGetParams = {
1001
+ value: getParams.value,
1002
+ lastSync,
1003
+ pendingChanges: pending && !state.isEmpty(pending) ? pending : void 0,
1004
+ clearPendingChanges: async () => {
1005
+ localState.pendingChanges = {};
1006
+ await updateMetadataImmediate(obs$, localState, syncState$, syncOptions, {
1007
+ pending: localState.pendingChanges
810
1008
  });
811
1009
  },
812
- onChange
813
- });
814
- if (!isSubscribed && syncOptions.subscribe) {
815
- isSubscribed = true;
816
- unsubscribe = syncOptions.subscribe({
817
- node,
818
- value$: obs$,
819
- update: (params) => {
820
- state.when(node.state.isLoaded, () => {
821
- params.mode || (params.mode = syncOptions.mode || "merge");
822
- onChange(params);
823
- });
824
- },
825
- refresh: () => state.when(node.state.isLoaded, sync)
1010
+ resetCache: () => {
1011
+ var _a3;
1012
+ modeBeforeReset = getParams.mode;
1013
+ getParams.mode = "set";
1014
+ return (_a3 = syncStateValue.resetPersistence) == null ? void 0 : _a3.call(syncStateValue);
1015
+ },
1016
+ cancel: false
1017
+ };
1018
+ (_a2 = syncOptions.onBeforeGet) == null ? void 0 : _a2.call(syncOptions, beforeGetParams);
1019
+ if (!beforeGetParams.cancel) {
1020
+ syncState$.assign({
1021
+ numPendingGets: (syncStateValue.numPendingGets || 0) + 1,
1022
+ isGetting: true
826
1023
  });
1024
+ const got = runWithRetry(
1025
+ getParams,
1026
+ syncOptions.retry,
1027
+ (retryEvent) => {
1028
+ const params = getParams;
1029
+ params.cancelRetry = retryEvent.cancelRetry;
1030
+ params.retryNum = retryEvent.retryNum;
1031
+ return get(params);
1032
+ },
1033
+ onError
1034
+ );
1035
+ const numGets = node.numGets = (node.numGets || 0) + 1;
1036
+ const handle = (value) => {
1037
+ syncState$.numPendingGets.set((v) => v - 1);
1038
+ if (isWaitingForLoad) {
1039
+ isWaitingForLoad = false;
1040
+ syncStateValue.numPendingRemoteLoads--;
1041
+ }
1042
+ if (numGets >= (node.getNumResolved || 0)) {
1043
+ node.getNumResolved = node.numGets;
1044
+ onChange({
1045
+ value,
1046
+ lastSync: getParams.lastSync,
1047
+ mode: getParams.mode
1048
+ });
1049
+ }
1050
+ if (modeBeforeReset) {
1051
+ getParams.mode = modeBeforeReset;
1052
+ modeBeforeReset = void 0;
1053
+ }
1054
+ syncState$.assign({
1055
+ isLoaded: syncStateValue.numPendingRemoteLoads < 1,
1056
+ error: void 0,
1057
+ isGetting: syncStateValue.numPendingGets > 0
1058
+ });
1059
+ };
1060
+ if (state.isPromise(got)) {
1061
+ got.then(handle).catch(onError);
1062
+ } else {
1063
+ handle(got);
1064
+ }
827
1065
  }
828
1066
  };
829
- runGet();
1067
+ if (waitFor) {
1068
+ state.whenReady(waitFor, () => state.trackSelector(runGet, sync));
1069
+ } else {
1070
+ state.trackSelector(runGet, sync);
1071
+ }
830
1072
  } else {
831
- node.state.assign({
1073
+ syncState$.assign({
832
1074
  isLoaded: true,
833
1075
  error: void 0
834
1076
  });
835
1077
  }
836
1078
  if (!isSynced) {
837
1079
  isSynced = true;
838
- await state.when(() => syncState.isLoaded.get() || syncOptions.allowSetIfGetError && syncState.error.get());
839
- if (pending && !state.isEmpty(pending)) {
840
- localState.isApplyingPending = true;
841
- const keys = Object.keys(pending);
842
- const changes = [];
843
- for (let i = 0; i < keys.length; i++) {
844
- const key = keys[i];
845
- const path = key.split("/").filter((p2) => p2 !== "");
846
- const { p, v, t } = pending[key];
847
- changes.push({ path, valueAtPath: v, prevAtPath: p, pathTypes: t });
848
- }
849
- const value = getNodeValue(node);
850
- onObsChange(obs$, syncState, localState, syncOptions, {
851
- value,
852
- loading: false,
853
- remote: false,
854
- getPrevious: createPreviousHandler(value, changes),
855
- changes
856
- });
857
- localState.isApplyingPending = false;
858
- }
1080
+ await state.when(syncState$.isLoaded);
1081
+ applyPending(pending);
859
1082
  }
860
1083
  };
861
- syncState.assign({ sync });
1084
+ syncStateValue.sync = sync;
1085
+ } else {
1086
+ if (!isSynced) {
1087
+ applyPending(localState.pendingChanges);
1088
+ }
862
1089
  }
1090
+ syncStateValue.reset = async () => {
1091
+ const wasPersistEnabled = syncStateValue.isPersistEnabled;
1092
+ const wasSyncEnabled = syncStateValue.isSyncEnabled;
1093
+ const metadata = metadatas.get(obs$);
1094
+ if (metadata) {
1095
+ Object.assign(metadata, { lastSync: void 0, pending: void 0 });
1096
+ }
1097
+ Object.assign(syncStateValue, {
1098
+ isPersistEnabled: false,
1099
+ isSyncEnabled: false,
1100
+ lastSync: void 0,
1101
+ numPendingGets: 0,
1102
+ isLoaded: false,
1103
+ isGetting: false,
1104
+ isSetting: false,
1105
+ numPendingSets: 0,
1106
+ syncCount: 0
1107
+ });
1108
+ isSynced = false;
1109
+ isSubscribed = false;
1110
+ unsubscribe == null ? void 0 : unsubscribe();
1111
+ unsubscribe = void 0;
1112
+ const promise = syncStateValue.resetPersistence();
1113
+ onChangeRemote(() => {
1114
+ var _a;
1115
+ obs$.set((_a = syncOptions.initial) != null ? _a : void 0);
1116
+ });
1117
+ syncState$.isLoaded.set(false);
1118
+ syncStateValue.isPersistEnabled = wasPersistEnabled;
1119
+ syncStateValue.isSyncEnabled = wasSyncEnabled;
1120
+ node.dirtyFn = sync;
1121
+ await promise;
1122
+ };
863
1123
  const onAllPersistLoaded = () => {
864
1124
  var _a, _b;
865
1125
  let parentNode = node;
@@ -877,77 +1137,27 @@ function syncObservable(obs$, syncOptionsOrSynced) {
877
1137
  }
878
1138
  if ((syncOptions == null ? void 0 : syncOptions.set) || (syncOptions == null ? void 0 : syncOptions.persist)) {
879
1139
  obs$.onChange(
880
- onObsChange.bind(this, obs$, syncState, localState, syncOptions)
1140
+ onObsChange.bind(this, obs$, syncState$, localState, syncOptions)
881
1141
  );
882
1142
  }
883
1143
  });
884
- return syncState;
1144
+ return syncState$;
885
1145
  }
886
- var { getProxy, globalState: globalState2, runWithRetry, symbolLinked: symbolLinked2, setNodeValue, getNodeValue: getNodeValue2 } = state.internal;
1146
+ var { getProxy, globalState: globalState2, setNodeValue, getNodeValue: getNodeValue2 } = state.internal;
887
1147
  function enableActivateSyncedNode() {
888
1148
  globalState2.activateSyncedNode = function activateSyncedNode(node, newValue) {
889
1149
  const obs$ = getProxy(node);
890
1150
  if (node.activationState) {
891
- const { get, initial, set, retry } = node.activationState;
892
- let onChange = void 0;
893
- const pluginRemote = {};
1151
+ const {
1152
+ get: getOrig,
1153
+ initial,
1154
+ set,
1155
+ onChange
1156
+ } = node.activationState;
894
1157
  let promiseReturn = void 0;
895
- let syncState;
896
- const refresh = () => syncState == null ? void 0 : syncState.sync();
897
- if (get) {
898
- pluginRemote.get = (params) => {
899
- var _a;
900
- onChange = params.onChange;
901
- const updateLastSync = (lastSync) => params.lastSync = lastSync;
902
- const existingValue = getNodeValue2(node);
903
- const value = runWithRetry(node, { attemptNum: 0, retry: retry || ((_a = params.options) == null ? void 0 : _a.retry) }, () => {
904
- const paramsToGet = {
905
- value: state.isFunction(existingValue) || (existingValue == null ? void 0 : existingValue[symbolLinked2]) ? void 0 : existingValue,
906
- lastSync: params.lastSync,
907
- updateLastSync,
908
- mode: params.mode,
909
- refresh
910
- };
911
- const ret = get(paramsToGet);
912
- params.mode = paramsToGet.mode;
913
- return ret;
914
- });
915
- promiseReturn = value;
916
- return value;
917
- };
918
- }
919
- if (set) {
920
- pluginRemote.set = async (params) => {
921
- var _a, _b;
922
- if ((_a = node.state) == null ? void 0 : _a.isLoaded.get()) {
923
- const retryAttempts = { attemptNum: 0, retry: retry || ((_b = params.options) == null ? void 0 : _b.retry) };
924
- return runWithRetry(node, retryAttempts, async (retryEvent) => {
925
- let changes = {};
926
- let maxModified = 0;
927
- if (!node.state.isLoaded.peek()) {
928
- await state.whenReady(node.state.isLoaded);
929
- }
930
- const cancelRetry = () => {
931
- retryEvent.cancel = true;
932
- };
933
- await set({
934
- ...params,
935
- node,
936
- update: (params2) => {
937
- const { value, lastSync } = params2;
938
- maxModified = Math.max(lastSync || 0, maxModified);
939
- changes = state.mergeIntoObservable(changes, value);
940
- },
941
- retryNum: retryAttempts.attemptNum,
942
- cancelRetry,
943
- refresh,
944
- fromSubscribe: false
945
- });
946
- return { changes, lastSync: maxModified || void 0 };
947
- });
948
- }
949
- };
950
- }
1158
+ const get = getOrig ? (params) => {
1159
+ return promiseReturn = getOrig(params);
1160
+ } : void 0;
951
1161
  const nodeVal = getNodeValue2(node);
952
1162
  if (promiseReturn !== void 0) {
953
1163
  newValue = promiseReturn;
@@ -957,7 +1167,7 @@ function enableActivateSyncedNode() {
957
1167
  newValue = initial;
958
1168
  }
959
1169
  setNodeValue(node, promiseReturn ? void 0 : newValue);
960
- syncState = syncObservable(obs$, { ...node.activationState, ...pluginRemote });
1170
+ syncObservable(obs$, { ...node.activationState, get, set });
961
1171
  return { update: onChange, value: newValue };
962
1172
  } else {
963
1173
  let update = void 0;
@@ -994,21 +1204,28 @@ function installPersistActivateNode() {
994
1204
  didInstall = true;
995
1205
  }
996
1206
  }
1207
+ var { deepMerge: deepMerge2 } = state.internal;
1208
+ function configureSynced(fnOrOrigOptions, origOptions) {
1209
+ const fn = origOptions ? fnOrOrigOptions : synced;
1210
+ origOptions = origOptions != null ? origOptions : fnOrOrigOptions;
1211
+ return (options) => {
1212
+ const merged = deepMerge2(origOptions, options);
1213
+ return fn(merged);
1214
+ };
1215
+ }
997
1216
 
998
1217
  // sync.ts
999
- function isInRemoteChange() {
1000
- return state.internal.globalState.isLoadingRemote;
1001
- }
1002
- var internal3 = {
1003
- observableSyncConfiguration
1218
+ var internal4 = {
1219
+ observableSyncConfiguration,
1220
+ waitForSet
1004
1221
  };
1005
1222
 
1006
1223
  exports.combineTransforms = combineTransforms;
1007
1224
  exports.configureObservableSync = configureObservableSync;
1225
+ exports.configureSynced = configureSynced;
1008
1226
  exports.deepEqual = deepEqual;
1009
1227
  exports.diffObjects = diffObjects;
1010
- exports.internal = internal3;
1011
- exports.isInRemoteChange = isInRemoteChange;
1228
+ exports.internal = internal4;
1012
1229
  exports.mapSyncPlugins = mapSyncPlugins;
1013
1230
  exports.onChangeRemote = onChangeRemote;
1014
1231
  exports.removeNullUndefined = removeNullUndefined;