@legendapp/state 3.0.0-alpha.4 → 3.0.0-alpha.41

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