@legendapp/state 3.0.0-alpha.9 → 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 +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 +495 -281
  86. package/sync.mjs +500 -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,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 = 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(() => {
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
+ }
560
664
  }
561
- if (pending == null ? void 0 : pending[pathStr]) {
562
- delete pending[pathStr];
665
+ if (lastSync) {
666
+ metadata.lastSync = lastSync;
563
667
  }
564
668
  }
565
- if (lastSync) {
566
- metadata.lastSync = lastSync;
669
+ if (changes && !state.isEmpty(changes)) {
670
+ transformedChanges = transformLoadData(changes, syncOptions, false, "set");
567
671
  }
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;
672
+ if (transformedChanges !== void 0) {
673
+ if (state.isPromise(transformedChanges)) {
674
+ transformedChanges = await transformedChanges;
675
+ }
676
+ onChangeRemote(() => state.mergeIntoObservable(obs$, transformedChanges));
575
677
  }
576
- onChangeRemote(() => state.mergeIntoObservable(obs, transformedChanges));
577
- }
578
- if (saveLocal) {
579
- if (shouldSaveMetadata && !state.isEmpty(metadata)) {
580
- updateMetadata(obs, localState, syncState, syncOptions, metadata);
678
+ if (saveLocal) {
679
+ if (shouldSaveMetadata && !state.isEmpty(metadata)) {
680
+ updateMetadata(obs$, localState, syncState2, syncOptions, metadata);
681
+ }
581
682
  }
582
683
  }
684
+ state$.numPendingSets.set((v) => v - 1);
685
+ state$.isSetting.set(state$.numPendingSets.peek() > 0);
583
686
  onAfterSet == null ? void 0 : onAfterSet();
584
687
  }
585
688
  }
586
689
  }
587
690
  }
588
- function onObsChange(value$, syncState, localState, syncOptions, { changes, loading, remote, getPrevious }) {
589
- if (!loading) {
590
- const inRemoteChange = remote;
691
+ function onObsChange(value$, syncState2, localState, syncOptions, { changes, isFromPersist, isFromSync, getPrevious }) {
692
+ if (!isFromPersist) {
693
+ const inRemoteChange = isFromSync;
591
694
  const isApplyingPending = localState.isApplyingPending;
592
695
  _queuedChanges.push({
593
696
  value$,
594
- syncState,
697
+ syncState: syncState2,
595
698
  localState,
596
699
  syncOptions,
597
700
  changes,
@@ -604,19 +707,22 @@ function onObsChange(value$, syncState, localState, syncOptions, { changes, load
604
707
  }
605
708
  }
606
709
  }
607
- async function loadLocal(value$, syncOptions, syncState, localState) {
710
+ async function loadLocal(value$, syncOptions, syncState$, localState) {
608
711
  var _a, _b, _c;
609
712
  const { persist } = syncOptions;
610
713
  const node = getNode(value$);
611
714
  const nodeValue = getNodeValue(getNode(node.state));
715
+ const syncStateValue = syncState$.peek();
716
+ const prevResetPersistence = nodeValue.resetPersistence;
612
717
  if (persist == null ? void 0 : persist.name) {
613
718
  const PersistPlugin = persist.plugin || ((_a = observableSyncConfiguration.persist) == null ? void 0 : _a.plugin);
614
719
  const { table, config } = parseLocalConfig(persist);
720
+ syncStateValue.numPendingLocalLoads = (syncStateValue.numPendingLocalLoads || 0) + 1;
615
721
  if (!PersistPlugin) {
616
722
  throw new Error("Local persist is not configured");
617
723
  }
618
724
  if (!mapSyncPlugins.has(PersistPlugin)) {
619
- const persistPlugin2 = new PersistPlugin();
725
+ const persistPlugin2 = state.isFunction(PersistPlugin) ? new PersistPlugin() : PersistPlugin;
620
726
  const mapValue = { plugin: persistPlugin2, initialized: state.observable(false) };
621
727
  mapSyncPlugins.set(PersistPlugin, mapValue);
622
728
  if (persistPlugin2.initialize) {
@@ -645,7 +751,7 @@ async function loadLocal(value$, syncOptions, syncState, localState) {
645
751
  if (metadata) {
646
752
  metadatas.set(value$, metadata);
647
753
  localState.pendingChanges = metadata.pending;
648
- syncState.assign({
754
+ syncState$.assign({
649
755
  lastSync: metadata.lastSync
650
756
  });
651
757
  }
@@ -663,15 +769,19 @@ async function loadLocal(value$, syncOptions, syncState, localState) {
663
769
  }
664
770
  state.internal.globalState.isLoadingLocal = false;
665
771
  }
666
- nodeValue.clearPersist = () => Promise.all([
667
- persistPlugin.deleteTable(table, config),
668
- persistPlugin.deleteMetadata(table, config)
669
- ]);
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
+ );
670
780
  } else {
671
- nodeValue.clearPersist = () => {
672
- };
781
+ nodeValue.resetPersistence = () => prevResetPersistence == null ? void 0 : prevResetPersistence();
673
782
  }
674
- syncState.isPersistLoaded.set(true);
783
+ nodeValue.clearPersist = nodeValue.resetPersistence;
784
+ syncState$.isPersistLoaded.set(!(syncStateValue.numPendingLocalLoads > 0));
675
785
  }
676
786
  function syncObservable(obs$, syncOptionsOrSynced) {
677
787
  let syncOptions = syncOptionsOrSynced;
@@ -682,7 +792,7 @@ function syncObservable(obs$, syncOptionsOrSynced) {
682
792
  if ((process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test") && (!obs$ || !node)) {
683
793
  throw new Error("[legend-state] syncObservable called with undefined observable");
684
794
  }
685
- syncOptions = state.mergeIntoObservable(
795
+ syncOptions = deepMerge(
686
796
  {
687
797
  syncMode: "auto"
688
798
  },
@@ -691,24 +801,54 @@ function syncObservable(obs$, syncOptionsOrSynced) {
691
801
  );
692
802
  const localState = {};
693
803
  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);
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
+ };
705
848
  if (syncOptions.get) {
706
- let isSynced = false;
707
- let isSubscribed = false;
708
- let unsubscribe = void 0;
709
849
  sync = async () => {
710
- var _a, _b;
711
- if (isSynced && state.shouldIgnoreUnobserved(node, sync)) {
850
+ var _a;
851
+ if (isSynced && (!getNodeValue(getNode(syncState$)).isSyncEnabled || state.shouldIgnoreUnobserved(node, sync))) {
712
852
  if (unsubscribe) {
713
853
  isSubscribed = false;
714
854
  unsubscribe();
@@ -718,9 +858,11 @@ function syncObservable(obs$, syncOptionsOrSynced) {
718
858
  }
719
859
  const lastSync = (_a = metadatas.get(obs$)) == null ? void 0 : _a.lastSync;
720
860
  const pending = localState.pendingChanges;
721
- const get = (_b = localState.pluginSync.get) == null ? void 0 : _b.bind(localState.pluginSync);
861
+ const get = syncOptions.get;
722
862
  if (get) {
863
+ const { waitFor } = syncOptions;
723
864
  const runGet = () => {
865
+ var _a2;
724
866
  const onChange = async ({ value, mode, lastSync: lastSync2 }) => {
725
867
  mode = mode || syncOptions.mode || "set";
726
868
  if (value !== void 0) {
@@ -733,9 +875,11 @@ function syncObservable(obs$, syncOptionsOrSynced) {
733
875
  if (pending2) {
734
876
  let didChangeMetadata = false;
735
877
  Object.keys(pending2).forEach((key) => {
736
- const p = key.split("/").filter((p2) => p2 !== "");
878
+ const p = key.split("/").filter((k) => k !== "");
737
879
  const { v, t } = pending2[key];
738
880
  if (t.length === 0 || !value) {
881
+ const oldValue = clone(value);
882
+ pending2[key].p = oldValue;
739
883
  if (state.isObject(value) && state.isObject(v)) {
740
884
  Object.assign(value, v);
741
885
  } else {
@@ -748,6 +892,8 @@ function syncObservable(obs$, syncOptionsOrSynced) {
748
892
  delete pending2[key];
749
893
  didChangeMetadata = true;
750
894
  } else {
895
+ const oldValue = clone(value);
896
+ pending2[key].p = getValueAtPath(oldValue, p);
751
897
  value = state.setAtPath(
752
898
  value,
753
899
  p,
@@ -767,18 +913,27 @@ function syncObservable(obs$, syncOptionsOrSynced) {
767
913
  }
768
914
  }
769
915
  });
770
- if (didChangeMetadata) {
771
- updateMetadata(obs$, localState, syncState, syncOptions, {
916
+ if (didChangeMetadata && syncOptions.persist) {
917
+ updateMetadata(obs$, localState, syncState$, syncOptions, {
772
918
  pending: pending2
773
919
  });
774
920
  }
775
921
  }
776
922
  onChangeRemote(() => {
777
- if (mode === "assign" && state.isObject(value)) {
923
+ if (state.isPlainObject(value)) {
924
+ value = state.ObservableHint.plain(value);
925
+ }
926
+ if (mode === "assign") {
778
927
  obs$.assign(value);
779
- } 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
+ }
780
932
  obs$.push(...value);
781
- } 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
+ }
782
937
  obs$.splice(0, 0, ...value);
783
938
  } else if (mode === "merge") {
784
939
  state.mergeIntoObservable(obs$, value);
@@ -788,78 +943,180 @@ function syncObservable(obs$, syncOptionsOrSynced) {
788
943
  });
789
944
  }
790
945
  if (lastSync2 && syncOptions.persist) {
791
- updateMetadata(obs$, localState, syncState, syncOptions, {
946
+ updateMetadata(obs$, localState, syncState$, syncOptions, {
792
947
  lastSync: lastSync2
793
948
  });
794
949
  }
795
950
  };
796
- get({
797
- 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,
798
985
  value$: obs$,
986
+ value: state.isFunction(existingValue) || (existingValue == null ? void 0 : existingValue[symbolLinked]) ? void 0 : existingValue,
987
+ mode: syncOptions.mode,
988
+ refresh: sync,
799
989
  options: syncOptions,
800
990
  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
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
810
1005
  });
811
1006
  },
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)
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
826
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
+ }
827
1062
  }
828
1063
  };
829
- runGet();
1064
+ if (waitFor) {
1065
+ state.whenReady(waitFor, () => state.trackSelector(runGet, sync));
1066
+ } else {
1067
+ state.trackSelector(runGet, sync);
1068
+ }
830
1069
  } else {
831
- node.state.assign({
1070
+ syncState$.assign({
832
1071
  isLoaded: true,
833
1072
  error: void 0
834
1073
  });
835
1074
  }
836
1075
  if (!isSynced) {
837
1076
  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
- }
1077
+ await state.when(syncState$.isLoaded);
1078
+ applyPending(pending);
859
1079
  }
860
1080
  };
861
- syncState.assign({ sync });
1081
+ syncStateValue.sync = sync;
1082
+ } else {
1083
+ if (!isSynced) {
1084
+ applyPending(localState.pendingChanges);
1085
+ }
862
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
+ };
863
1120
  const onAllPersistLoaded = () => {
864
1121
  var _a, _b;
865
1122
  let parentNode = node;
@@ -877,77 +1134,27 @@ function syncObservable(obs$, syncOptionsOrSynced) {
877
1134
  }
878
1135
  if ((syncOptions == null ? void 0 : syncOptions.set) || (syncOptions == null ? void 0 : syncOptions.persist)) {
879
1136
  obs$.onChange(
880
- onObsChange.bind(this, obs$, syncState, localState, syncOptions)
1137
+ onObsChange.bind(this, obs$, syncState$, localState, syncOptions)
881
1138
  );
882
1139
  }
883
1140
  });
884
- return syncState;
1141
+ return syncState$;
885
1142
  }
886
- var { getProxy, globalState: globalState2, runWithRetry, symbolLinked: symbolLinked2, setNodeValue, getNodeValue: getNodeValue2 } = state.internal;
1143
+ var { getProxy, globalState: globalState2, setNodeValue, getNodeValue: getNodeValue2 } = state.internal;
887
1144
  function enableActivateSyncedNode() {
888
1145
  globalState2.activateSyncedNode = function activateSyncedNode(node, newValue) {
889
1146
  const obs$ = getProxy(node);
890
1147
  if (node.activationState) {
891
- const { get, initial, set, retry } = node.activationState;
892
- let onChange = void 0;
893
- const pluginRemote = {};
1148
+ const {
1149
+ get: getOrig,
1150
+ initial,
1151
+ set,
1152
+ onChange
1153
+ } = node.activationState;
894
1154
  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
- }
1155
+ const get = getOrig ? (params) => {
1156
+ return promiseReturn = getOrig(params);
1157
+ } : void 0;
951
1158
  const nodeVal = getNodeValue2(node);
952
1159
  if (promiseReturn !== void 0) {
953
1160
  newValue = promiseReturn;
@@ -957,7 +1164,7 @@ function enableActivateSyncedNode() {
957
1164
  newValue = initial;
958
1165
  }
959
1166
  setNodeValue(node, promiseReturn ? void 0 : newValue);
960
- syncState = syncObservable(obs$, { ...node.activationState, ...pluginRemote });
1167
+ syncObservable(obs$, { ...node.activationState, get, set });
961
1168
  return { update: onChange, value: newValue };
962
1169
  } else {
963
1170
  let update = void 0;
@@ -994,21 +1201,28 @@ function installPersistActivateNode() {
994
1201
  didInstall = true;
995
1202
  }
996
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
+ }
997
1213
 
998
1214
  // sync.ts
999
- function isInRemoteChange() {
1000
- return state.internal.globalState.isLoadingRemote;
1001
- }
1002
- var internal3 = {
1003
- observableSyncConfiguration
1215
+ var internal4 = {
1216
+ observableSyncConfiguration,
1217
+ waitForSet
1004
1218
  };
1005
1219
 
1006
1220
  exports.combineTransforms = combineTransforms;
1007
1221
  exports.configureObservableSync = configureObservableSync;
1222
+ exports.configureSynced = configureSynced;
1008
1223
  exports.deepEqual = deepEqual;
1009
1224
  exports.diffObjects = diffObjects;
1010
- exports.internal = internal3;
1011
- exports.isInRemoteChange = isInRemoteChange;
1225
+ exports.internal = internal4;
1012
1226
  exports.mapSyncPlugins = mapSyncPlugins;
1013
1227
  exports.onChangeRemote = onChangeRemote;
1014
1228
  exports.removeNullUndefined = removeNullUndefined;