@legendapp/state 3.0.0-alpha.9 → 3.0.0-beta.1

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