@legendapp/state 3.0.0-alpha.8 → 3.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/.DS_Store +0 -0
  2. package/config/configureLegendState.d.mts +13 -0
  3. package/config/configureLegendState.d.ts +13 -0
  4. package/config/configureLegendState.js +45 -0
  5. package/config/configureLegendState.mjs +43 -0
  6. package/config/enable$GetSet.js +2 -1
  7. package/config/enable$GetSet.mjs +2 -1
  8. package/config/enableReactTracking.js +2 -1
  9. package/config/enableReactTracking.mjs +2 -1
  10. package/config/enableReactUse.js +2 -1
  11. package/config/enableReactUse.mjs +2 -1
  12. package/config/enable_PeekAssign.js +2 -1
  13. package/config/enable_PeekAssign.mjs +2 -1
  14. package/helpers/trackHistory.js +2 -2
  15. package/helpers/trackHistory.mjs +2 -2
  16. package/index.d.mts +104 -80
  17. package/index.d.ts +104 -80
  18. package/index.js +328 -318
  19. package/index.mjs +325 -316
  20. package/package.json +36 -1
  21. package/persist-plugins/async-storage.d.mts +6 -3
  22. package/persist-plugins/async-storage.d.ts +6 -3
  23. package/persist-plugins/async-storage.js +8 -4
  24. package/persist-plugins/async-storage.mjs +8 -5
  25. package/persist-plugins/indexeddb.d.mts +6 -4
  26. package/persist-plugins/indexeddb.d.ts +6 -4
  27. package/persist-plugins/indexeddb.js +35 -15
  28. package/persist-plugins/indexeddb.mjs +35 -16
  29. package/persist-plugins/mmkv.d.mts +5 -1
  30. package/persist-plugins/mmkv.d.ts +5 -1
  31. package/persist-plugins/mmkv.js +10 -5
  32. package/persist-plugins/mmkv.mjs +10 -6
  33. package/react-reactive/enableReactComponents.d.mts +9 -0
  34. package/react-reactive/enableReactComponents.d.ts +9 -0
  35. package/react-reactive/enableReactComponents.js +19 -0
  36. package/react-reactive/enableReactComponents.mjs +17 -0
  37. package/react-reactive/enableReactNativeComponents.d.mts +22 -0
  38. package/react-reactive/enableReactNativeComponents.d.ts +22 -0
  39. package/react-reactive/enableReactNativeComponents.js +53 -0
  40. package/react-reactive/enableReactNativeComponents.mjs +51 -0
  41. package/react-reactive/enableReactive.d.mts +5 -0
  42. package/react-reactive/enableReactive.d.ts +5 -0
  43. package/react-reactive/enableReactive.js +24 -0
  44. package/react-reactive/enableReactive.mjs +22 -0
  45. package/react-reactive/enableReactive.native.d.mts +5 -0
  46. package/react-reactive/enableReactive.native.d.ts +5 -0
  47. package/react-reactive/enableReactive.native.js +58 -0
  48. package/react-reactive/enableReactive.native.mjs +56 -0
  49. package/react-reactive/enableReactive.web.d.mts +5 -0
  50. package/react-reactive/enableReactive.web.d.ts +5 -0
  51. package/react-reactive/enableReactive.web.js +58 -0
  52. package/react-reactive/enableReactive.web.mjs +56 -0
  53. package/react.d.mts +39 -34
  54. package/react.d.ts +39 -34
  55. package/react.js +39 -17
  56. package/react.mjs +39 -17
  57. package/sync-plugins/crud.d.mts +21 -24
  58. package/sync-plugins/crud.d.ts +21 -24
  59. package/sync-plugins/crud.js +241 -140
  60. package/sync-plugins/crud.mjs +243 -142
  61. package/sync-plugins/fetch.js +12 -8
  62. package/sync-plugins/fetch.mjs +13 -9
  63. package/sync-plugins/firebase.d.mts +27 -0
  64. package/sync-plugins/firebase.d.ts +27 -0
  65. package/sync-plugins/firebase.js +373 -0
  66. package/sync-plugins/firebase.mjs +368 -0
  67. package/sync-plugins/keel.d.mts +43 -26
  68. package/sync-plugins/keel.d.ts +43 -26
  69. package/sync-plugins/keel.js +145 -100
  70. package/sync-plugins/keel.mjs +147 -100
  71. package/sync-plugins/supabase.d.mts +19 -9
  72. package/sync-plugins/supabase.d.ts +19 -9
  73. package/sync-plugins/supabase.js +52 -22
  74. package/sync-plugins/supabase.mjs +53 -23
  75. package/sync-plugins/tanstack-query.d.mts +2 -2
  76. package/sync-plugins/tanstack-query.d.ts +2 -2
  77. package/sync-plugins/tanstack-query.js +22 -5
  78. package/sync-plugins/tanstack-query.mjs +22 -5
  79. package/sync-plugins/tanstack-react-query.d.mts +1 -1
  80. package/sync-plugins/tanstack-react-query.d.ts +1 -1
  81. package/sync-plugins/tanstack-react-query.js +8 -1
  82. package/sync-plugins/tanstack-react-query.mjs +8 -1
  83. package/sync.d.mts +74 -200
  84. package/sync.d.ts +74 -200
  85. package/sync.js +492 -293
  86. package/sync.mjs +498 -299
package/sync.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,103 +551,148 @@ 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 = 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
- value = transformSave(clone(value));
530
- }
531
- onBeforeSet == null ? void 0 : onBeforeSet();
532
- localState.numSavesOutstanding = (localState.numSavesOutstanding || 0) + 1;
533
- let savedPromise = pluginSync.set({
534
- value$: obs,
535
- syncState,
536
- options: syncOptions,
537
- changes: changesRemote,
538
- value,
539
- valuePrevious: previous
540
- });
541
- if (isPromise(savedPromise)) {
542
- savedPromise = savedPromise.catch((err) => onSetError == null ? void 0 : onSetError(err));
543
- }
544
- const saved = await savedPromise;
545
- localState.numSavesOutstanding--;
546
- if (saved !== void 0) {
547
- const pathStrs = Array.from(new Set(changesRemote.map((change) => change.pathStr)));
548
- const { changes, lastSync } = saved;
549
- if (pathStrs.length > 0) {
550
- let transformedChanges = void 0;
551
- const metadata = {};
552
- if (saveLocal) {
553
- const pendingMetadata = (_b = pluginPersist.getMetadata(table, configLocal)) == null ? void 0 : _b.pending;
554
- const pending = localState.pendingChanges;
555
- for (let i = 0; i < pathStrs.length; i++) {
556
- const pathStr = pathStrs[i];
557
- if (pendingMetadata == null ? void 0 : pendingMetadata[pathStr]) {
558
- delete pendingMetadata[pathStr];
559
- metadata.pending = pendingMetadata;
584
+ value = transformSave(value);
585
+ }
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(() => {
641
+ didError = true;
642
+ });
643
+ }
644
+ if (!didError) {
645
+ const pathStrs = Array.from(new Set(changesRemote.map((change) => change.pathStr)));
646
+ const { value: changes, lastSync } = updateResult || {};
647
+ if (pathStrs.length > 0) {
648
+ let transformedChanges = void 0;
649
+ const metadata = {};
650
+ if (saveLocal) {
651
+ const pendingMetadata = (_b = pluginPersist.getMetadata(table, configLocal)) == null ? void 0 : _b.pending;
652
+ const pending = localState.pendingChanges;
653
+ for (let i = 0; i < pathStrs.length; i++) {
654
+ const pathStr = pathStrs[i];
655
+ if (pendingMetadata == null ? void 0 : pendingMetadata[pathStr]) {
656
+ delete pendingMetadata[pathStr];
657
+ metadata.pending = pendingMetadata;
658
+ }
659
+ if (pending == null ? void 0 : pending[pathStr]) {
660
+ delete pending[pathStr];
661
+ }
560
662
  }
561
- if (pending == null ? void 0 : pending[pathStr]) {
562
- delete pending[pathStr];
663
+ if (lastSync) {
664
+ metadata.lastSync = lastSync;
563
665
  }
564
666
  }
565
- if (lastSync) {
566
- metadata.lastSync = lastSync;
567
- }
568
- }
569
- if (changes && !isEmpty(changes)) {
570
- transformedChanges = transformLoadData(changes, syncOptions, false, "set");
571
- }
572
- if (localState.numSavesOutstanding > 0) {
573
- if (transformedChanges) {
574
- if (!localState.pendingSaveResults) {
575
- localState.pendingSaveResults = [];
576
- }
577
- localState.pendingSaveResults.push(transformedChanges);
667
+ if (changes && !isEmpty(changes)) {
668
+ transformedChanges = transformLoadData(changes, syncOptions, false, "set");
578
669
  }
579
- } else {
580
- let allChanges = [...localState.pendingSaveResults || [], transformedChanges].filter(
581
- (v) => v !== void 0
582
- );
583
- if (allChanges.length > 0) {
584
- if (allChanges.some((change) => isPromise(change))) {
585
- allChanges = await Promise.all(allChanges);
670
+ if (transformedChanges !== void 0) {
671
+ if (isPromise$1(transformedChanges)) {
672
+ transformedChanges = await transformedChanges;
586
673
  }
587
- onChangeRemote(() => mergeIntoObservable(obs, ...allChanges));
674
+ onChangeRemote(() => mergeIntoObservable(obs$, transformedChanges));
588
675
  }
589
676
  if (saveLocal) {
590
677
  if (shouldSaveMetadata && !isEmpty(metadata)) {
591
- updateMetadata(obs, localState, syncState, syncOptions, metadata);
678
+ updateMetadata(obs$, localState, syncState2, syncOptions, metadata);
592
679
  }
593
680
  }
594
- localState.pendingSaveResults = [];
595
681
  }
682
+ state$.numPendingSets.set((v) => v - 1);
683
+ state$.isSetting.set(state$.numPendingSets.peek() > 0);
596
684
  onAfterSet == null ? void 0 : onAfterSet();
597
685
  }
598
686
  }
599
687
  }
600
688
  }
601
- function onObsChange(value$, syncState, localState, syncOptions, { changes, loading, remote, getPrevious }) {
602
- if (!loading) {
603
- const inRemoteChange = remote;
689
+ function onObsChange(value$, syncState2, localState, syncOptions, { changes, isFromPersist, isFromSync, getPrevious }) {
690
+ if (!isFromPersist) {
691
+ const inRemoteChange = isFromSync;
604
692
  const isApplyingPending = localState.isApplyingPending;
605
693
  _queuedChanges.push({
606
694
  value$,
607
- syncState,
695
+ syncState: syncState2,
608
696
  localState,
609
697
  syncOptions,
610
698
  changes,
@@ -617,24 +705,27 @@ function onObsChange(value$, syncState, localState, syncOptions, { changes, load
617
705
  }
618
706
  }
619
707
  }
620
- async function loadLocal(value$, syncOptions, syncState, localState) {
708
+ async function loadLocal(value$, syncOptions, syncState$, localState) {
621
709
  var _a, _b, _c;
622
710
  const { persist } = syncOptions;
623
711
  const node = getNode(value$);
624
712
  const nodeValue = getNodeValue(getNode(node.state));
713
+ const syncStateValue = syncState$.peek();
714
+ const prevResetPersistence = nodeValue.resetPersistence;
625
715
  if (persist == null ? void 0 : persist.name) {
626
716
  const PersistPlugin = persist.plugin || ((_a = observableSyncConfiguration.persist) == null ? void 0 : _a.plugin);
627
717
  const { table, config } = parseLocalConfig(persist);
718
+ syncStateValue.numPendingLocalLoads = (syncStateValue.numPendingLocalLoads || 0) + 1;
628
719
  if (!PersistPlugin) {
629
720
  throw new Error("Local persist is not configured");
630
721
  }
631
722
  if (!mapSyncPlugins.has(PersistPlugin)) {
632
- const persistPlugin2 = new PersistPlugin();
723
+ const persistPlugin2 = isFunction(PersistPlugin) ? new PersistPlugin() : PersistPlugin;
633
724
  const mapValue = { plugin: persistPlugin2, initialized: observable(false) };
634
725
  mapSyncPlugins.set(PersistPlugin, mapValue);
635
726
  if (persistPlugin2.initialize) {
636
727
  const initializePromise = (_c = persistPlugin2.initialize) == null ? void 0 : _c.call(persistPlugin2, ((_b = observableSyncConfiguration) == null ? void 0 : _b.persist) || {});
637
- if (isPromise(initializePromise)) {
728
+ if (isPromise$1(initializePromise)) {
638
729
  await initializePromise;
639
730
  }
640
731
  }
@@ -658,14 +749,14 @@ async function loadLocal(value$, syncOptions, syncState, localState) {
658
749
  if (metadata) {
659
750
  metadatas.set(value$, metadata);
660
751
  localState.pendingChanges = metadata.pending;
661
- syncState.assign({
752
+ syncState$.assign({
662
753
  lastSync: metadata.lastSync
663
754
  });
664
755
  }
665
756
  if (value !== void 0) {
666
757
  const { transform } = config;
667
758
  value = transformLoadData(value, { transform }, true, "get");
668
- if (isPromise(value)) {
759
+ if (isPromise$1(value)) {
669
760
  value = await value;
670
761
  }
671
762
  internal.globalState.isLoadingLocal = true;
@@ -676,15 +767,19 @@ async function loadLocal(value$, syncOptions, syncState, localState) {
676
767
  }
677
768
  internal.globalState.isLoadingLocal = false;
678
769
  }
679
- nodeValue.clearPersist = () => Promise.all([
680
- persistPlugin.deleteTable(table, config),
681
- persistPlugin.deleteMetadata(table, config)
682
- ]);
770
+ syncStateValue.numPendingLocalLoads--;
771
+ nodeValue.resetPersistence = () => Promise.all(
772
+ [
773
+ prevResetPersistence,
774
+ persistPlugin.deleteTable(table, config),
775
+ persistPlugin.deleteMetadata(table, config)
776
+ ].filter(Boolean)
777
+ );
683
778
  } else {
684
- nodeValue.clearPersist = () => {
685
- };
779
+ nodeValue.resetPersistence = () => prevResetPersistence == null ? void 0 : prevResetPersistence();
686
780
  }
687
- syncState.isPersistLoaded.set(true);
781
+ nodeValue.clearPersist = nodeValue.resetPersistence;
782
+ syncState$.isPersistLoaded.set(!(syncStateValue.numPendingLocalLoads > 0));
688
783
  }
689
784
  function syncObservable(obs$, syncOptionsOrSynced) {
690
785
  let syncOptions = syncOptionsOrSynced;
@@ -695,7 +790,7 @@ function syncObservable(obs$, syncOptionsOrSynced) {
695
790
  if ((process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test") && (!obs$ || !node)) {
696
791
  throw new Error("[legend-state] syncObservable called with undefined observable");
697
792
  }
698
- syncOptions = mergeIntoObservable(
793
+ syncOptions = deepMerge(
699
794
  {
700
795
  syncMode: "auto"
701
796
  },
@@ -704,24 +799,54 @@ function syncObservable(obs$, syncOptionsOrSynced) {
704
799
  );
705
800
  const localState = {};
706
801
  let sync;
707
- const syncState = node.state = observable({
708
- isPersistLoaded: false,
709
- isLoaded: !syncOptions.get,
710
- isPersistEnabled: true,
711
- isSyncEnabled: true,
712
- clearPersist: void 0,
713
- sync: () => Promise.resolve(),
714
- getPendingChanges: () => localState.pendingChanges
715
- });
716
- loadLocal(obs$, syncOptions, syncState, localState);
717
- localState.pluginSync = syncObservableAdapter(syncOptions);
802
+ const syncState$ = syncState(obs$);
803
+ const syncStateValue = getNodeValue(getNode(syncState$));
804
+ allSyncStates.set(syncState$, node);
805
+ syncStateValue.getPendingChanges = () => localState.pendingChanges;
806
+ let errorHandled = false;
807
+ const onGetError = (error, params) => {
808
+ var _a;
809
+ syncState$.error.set(error);
810
+ if (!errorHandled) {
811
+ (_a = syncOptions.onError) == null ? void 0 : _a.call(syncOptions, error, { ...params, value$: obs$ });
812
+ }
813
+ errorHandled = true;
814
+ };
815
+ loadLocal(obs$, syncOptions, syncState$, localState);
816
+ let isWaitingForLoad = !!syncOptions.get;
817
+ if (isWaitingForLoad) {
818
+ syncStateValue.numPendingRemoteLoads = (syncStateValue.numPendingRemoteLoads || 0) + 1;
819
+ }
820
+ syncState$.isLoaded.set(!syncState$.numPendingRemoteLoads.peek());
821
+ let isSynced = false;
822
+ let isSubscribed = false;
823
+ let unsubscribe = void 0;
824
+ const applyPending = (pending) => {
825
+ if (pending && !isEmpty(pending)) {
826
+ localState.isApplyingPending = true;
827
+ const keys = Object.keys(pending);
828
+ const changes = [];
829
+ for (let i = 0; i < keys.length; i++) {
830
+ const key = keys[i];
831
+ const path = key.split("/").filter((p2) => p2 !== "");
832
+ const { p, v, t } = pending[key];
833
+ changes.push({ path, valueAtPath: v, prevAtPath: p, pathTypes: t });
834
+ }
835
+ const value = getNodeValue(node);
836
+ onObsChange(obs$, syncState$, localState, syncOptions, {
837
+ value,
838
+ isFromPersist: false,
839
+ isFromSync: false,
840
+ getPrevious: createPreviousHandler(value, changes),
841
+ changes
842
+ });
843
+ localState.isApplyingPending = false;
844
+ }
845
+ };
718
846
  if (syncOptions.get) {
719
- let isSynced = false;
720
- let isSubscribed = false;
721
- let unsubscribe = void 0;
722
847
  sync = async () => {
723
- var _a, _b;
724
- if (isSynced && shouldIgnoreUnobserved(node, sync)) {
848
+ var _a;
849
+ if (isSynced && (!getNodeValue(getNode(syncState$)).isSyncEnabled || shouldIgnoreUnobserved(node, sync))) {
725
850
  if (unsubscribe) {
726
851
  isSubscribed = false;
727
852
  unsubscribe();
@@ -731,14 +856,16 @@ function syncObservable(obs$, syncOptionsOrSynced) {
731
856
  }
732
857
  const lastSync = (_a = metadatas.get(obs$)) == null ? void 0 : _a.lastSync;
733
858
  const pending = localState.pendingChanges;
734
- const get = (_b = localState.pluginSync.get) == null ? void 0 : _b.bind(localState.pluginSync);
859
+ const get = syncOptions.get;
735
860
  if (get) {
861
+ const { waitFor } = syncOptions;
736
862
  const runGet = () => {
863
+ var _a2;
737
864
  const onChange = async ({ value, mode, lastSync: lastSync2 }) => {
738
865
  mode = mode || syncOptions.mode || "set";
739
866
  if (value !== void 0) {
740
867
  value = transformLoadData(value, syncOptions, true, "get");
741
- if (isPromise(value)) {
868
+ if (isPromise$1(value)) {
742
869
  value = await value;
743
870
  }
744
871
  const pending2 = localState.pendingChanges;
@@ -746,9 +873,11 @@ function syncObservable(obs$, syncOptionsOrSynced) {
746
873
  if (pending2) {
747
874
  let didChangeMetadata = false;
748
875
  Object.keys(pending2).forEach((key) => {
749
- const p = key.split("/").filter((p2) => p2 !== "");
876
+ const p = key.split("/").filter((k) => k !== "");
750
877
  const { v, t } = pending2[key];
751
878
  if (t.length === 0 || !value) {
879
+ const oldValue = clone(value);
880
+ pending2[key].p = oldValue;
752
881
  if (isObject(value) && isObject(v)) {
753
882
  Object.assign(value, v);
754
883
  } else {
@@ -761,6 +890,8 @@ function syncObservable(obs$, syncOptionsOrSynced) {
761
890
  delete pending2[key];
762
891
  didChangeMetadata = true;
763
892
  } else {
893
+ const oldValue = clone(value);
894
+ pending2[key].p = getValueAtPath(oldValue, p);
764
895
  value = setAtPath(
765
896
  value,
766
897
  p,
@@ -780,18 +911,27 @@ function syncObservable(obs$, syncOptionsOrSynced) {
780
911
  }
781
912
  }
782
913
  });
783
- if (didChangeMetadata) {
784
- updateMetadata(obs$, localState, syncState, syncOptions, {
914
+ if (didChangeMetadata && syncOptions.persist) {
915
+ updateMetadata(obs$, localState, syncState$, syncOptions, {
785
916
  pending: pending2
786
917
  });
787
918
  }
788
919
  }
789
920
  onChangeRemote(() => {
790
- if (mode === "assign" && isObject(value)) {
921
+ if (isPlainObject(value)) {
922
+ value = ObservableHint.plain(value);
923
+ }
924
+ if (mode === "assign") {
791
925
  obs$.assign(value);
792
- } else if (mode === "append" && isArray(value)) {
926
+ } else if (mode === "append") {
927
+ if ((process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test") && !isArray(value)) {
928
+ console.error("[legend-state] mode:append expects the value to be an array");
929
+ }
793
930
  obs$.push(...value);
794
- } else if (mode === "prepend" && isArray(value)) {
931
+ } else if (mode === "prepend") {
932
+ if ((process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test") && !isArray(value)) {
933
+ console.error("[legend-state] mode:prepend expects the value to be an array");
934
+ }
795
935
  obs$.splice(0, 0, ...value);
796
936
  } else if (mode === "merge") {
797
937
  mergeIntoObservable(obs$, value);
@@ -801,78 +941,180 @@ function syncObservable(obs$, syncOptionsOrSynced) {
801
941
  });
802
942
  }
803
943
  if (lastSync2 && syncOptions.persist) {
804
- updateMetadata(obs$, localState, syncState, syncOptions, {
944
+ updateMetadata(obs$, localState, syncState$, syncOptions, {
805
945
  lastSync: lastSync2
806
946
  });
807
947
  }
808
948
  };
809
- get({
810
- state: syncState,
949
+ if (node.activationState) {
950
+ node.activationState.onChange = onChange;
951
+ }
952
+ if (!isSubscribed && syncOptions.subscribe) {
953
+ const subscribe = syncOptions.subscribe;
954
+ isSubscribed = true;
955
+ const doSubscribe = () => {
956
+ const subscribeParams = {
957
+ node,
958
+ value$: obs$,
959
+ lastSync,
960
+ update: (params) => {
961
+ when(syncState$.isLoaded, () => {
962
+ when(waitFor || true, () => {
963
+ params.mode || (params.mode = syncOptions.mode || "merge");
964
+ onChange(params);
965
+ });
966
+ });
967
+ },
968
+ refresh: () => when(syncState$.isLoaded, sync),
969
+ onError: (error) => onGetError(error, { source: "subscribe", subscribeParams })
970
+ };
971
+ unsubscribe = subscribe(subscribeParams);
972
+ };
973
+ if (waitFor) {
974
+ whenReady(waitFor, doSubscribe);
975
+ } else {
976
+ doSubscribe();
977
+ }
978
+ }
979
+ const existingValue = getNodeValue(node);
980
+ const onError = (error) => onGetError(error, { getParams, source: "get" });
981
+ const getParams = {
982
+ node,
811
983
  value$: obs$,
984
+ value: isFunction(existingValue) || (existingValue == null ? void 0 : existingValue[symbolLinked]) ? void 0 : existingValue,
985
+ mode: syncOptions.mode,
986
+ refresh: sync,
812
987
  options: syncOptions,
813
988
  lastSync,
814
- dateModified: lastSync,
815
- onError: (error) => {
816
- var _a2;
817
- (_a2 = syncOptions.onGetError) == null ? void 0 : _a2.call(syncOptions, error);
818
- },
819
- onGet: () => {
820
- node.state.assign({
821
- isLoaded: true,
822
- error: void 0
989
+ updateLastSync: (lastSync2) => getParams.lastSync = lastSync2,
990
+ onError,
991
+ retryNum: 0,
992
+ cancelRetry: false
993
+ };
994
+ let modeBeforeReset = void 0;
995
+ const beforeGetParams = {
996
+ value: getParams.value,
997
+ lastSync,
998
+ pendingChanges: pending && !isEmpty(pending) ? pending : void 0,
999
+ clearPendingChanges: async () => {
1000
+ localState.pendingChanges = {};
1001
+ await updateMetadataImmediate(obs$, localState, syncState$, syncOptions, {
1002
+ pending: localState.pendingChanges
823
1003
  });
824
1004
  },
825
- onChange
826
- });
827
- if (!isSubscribed && syncOptions.subscribe) {
828
- isSubscribed = true;
829
- unsubscribe = syncOptions.subscribe({
830
- node,
831
- value$: obs$,
832
- update: (params) => {
833
- when(node.state.isLoaded, () => {
834
- params.mode || (params.mode = syncOptions.mode || "merge");
835
- onChange(params);
836
- });
837
- },
838
- refresh: () => when(node.state.isLoaded, sync)
1005
+ resetCache: () => {
1006
+ var _a3;
1007
+ modeBeforeReset = getParams.mode;
1008
+ getParams.mode = "set";
1009
+ return (_a3 = syncStateValue.resetPersistence) == null ? void 0 : _a3.call(syncStateValue);
1010
+ },
1011
+ cancel: false
1012
+ };
1013
+ (_a2 = syncOptions.onBeforeGet) == null ? void 0 : _a2.call(syncOptions, beforeGetParams);
1014
+ if (!beforeGetParams.cancel) {
1015
+ syncState$.assign({
1016
+ numPendingGets: (syncStateValue.numPendingGets || 0) + 1,
1017
+ isGetting: true
839
1018
  });
1019
+ const got = runWithRetry(
1020
+ getParams,
1021
+ syncOptions.retry,
1022
+ (retryEvent) => {
1023
+ const params = getParams;
1024
+ params.cancelRetry = retryEvent.cancelRetry;
1025
+ params.retryNum = retryEvent.retryNum;
1026
+ return get(params);
1027
+ },
1028
+ onError
1029
+ );
1030
+ const numGets = node.numGets = (node.numGets || 0) + 1;
1031
+ const handle = (value) => {
1032
+ syncState$.numPendingGets.set((v) => v - 1);
1033
+ if (isWaitingForLoad) {
1034
+ isWaitingForLoad = false;
1035
+ syncStateValue.numPendingRemoteLoads--;
1036
+ }
1037
+ if (numGets >= (node.getNumResolved || 0)) {
1038
+ node.getNumResolved = node.numGets;
1039
+ onChange({
1040
+ value,
1041
+ lastSync: getParams.lastSync,
1042
+ mode: getParams.mode
1043
+ });
1044
+ }
1045
+ if (modeBeforeReset) {
1046
+ getParams.mode = modeBeforeReset;
1047
+ modeBeforeReset = void 0;
1048
+ }
1049
+ syncState$.assign({
1050
+ isLoaded: syncStateValue.numPendingRemoteLoads < 1,
1051
+ error: void 0,
1052
+ isGetting: syncStateValue.numPendingGets > 0
1053
+ });
1054
+ };
1055
+ if (isPromise$1(got)) {
1056
+ got.then(handle).catch(onError);
1057
+ } else {
1058
+ handle(got);
1059
+ }
840
1060
  }
841
1061
  };
842
- runGet();
1062
+ if (waitFor) {
1063
+ whenReady(waitFor, () => trackSelector(runGet, sync));
1064
+ } else {
1065
+ trackSelector(runGet, sync);
1066
+ }
843
1067
  } else {
844
- node.state.assign({
1068
+ syncState$.assign({
845
1069
  isLoaded: true,
846
1070
  error: void 0
847
1071
  });
848
1072
  }
849
1073
  if (!isSynced) {
850
1074
  isSynced = true;
851
- await when(() => syncState.isLoaded.get() || syncOptions.allowSetIfGetError && syncState.error.get());
852
- if (pending && !isEmpty(pending)) {
853
- localState.isApplyingPending = true;
854
- const keys = Object.keys(pending);
855
- const changes = [];
856
- for (let i = 0; i < keys.length; i++) {
857
- const key = keys[i];
858
- const path = key.split("/").filter((p2) => p2 !== "");
859
- const { p, v, t } = pending[key];
860
- changes.push({ path, valueAtPath: v, prevAtPath: p, pathTypes: t });
861
- }
862
- const value = getNodeValue(node);
863
- onObsChange(obs$, syncState, localState, syncOptions, {
864
- value,
865
- loading: false,
866
- remote: false,
867
- getPrevious: createPreviousHandler(value, changes),
868
- changes
869
- });
870
- localState.isApplyingPending = false;
871
- }
1075
+ await when(syncState$.isLoaded);
1076
+ applyPending(pending);
872
1077
  }
873
1078
  };
874
- syncState.assign({ sync });
1079
+ syncStateValue.sync = sync;
1080
+ } else {
1081
+ if (!isSynced) {
1082
+ applyPending(localState.pendingChanges);
1083
+ }
875
1084
  }
1085
+ syncStateValue.reset = async () => {
1086
+ const wasPersistEnabled = syncStateValue.isPersistEnabled;
1087
+ const wasSyncEnabled = syncStateValue.isSyncEnabled;
1088
+ const metadata = metadatas.get(obs$);
1089
+ if (metadata) {
1090
+ Object.assign(metadata, { lastSync: void 0, pending: void 0 });
1091
+ }
1092
+ Object.assign(syncStateValue, {
1093
+ isPersistEnabled: false,
1094
+ isSyncEnabled: false,
1095
+ lastSync: void 0,
1096
+ numPendingGets: 0,
1097
+ isLoaded: false,
1098
+ isGetting: false,
1099
+ isSetting: false,
1100
+ numPendingSets: 0,
1101
+ syncCount: 0
1102
+ });
1103
+ isSynced = false;
1104
+ isSubscribed = false;
1105
+ unsubscribe == null ? void 0 : unsubscribe();
1106
+ unsubscribe = void 0;
1107
+ const promise = syncStateValue.resetPersistence();
1108
+ onChangeRemote(() => {
1109
+ var _a;
1110
+ obs$.set((_a = syncOptions.initial) != null ? _a : void 0);
1111
+ });
1112
+ syncState$.isLoaded.set(false);
1113
+ syncStateValue.isPersistEnabled = wasPersistEnabled;
1114
+ syncStateValue.isSyncEnabled = wasSyncEnabled;
1115
+ node.dirtyFn = sync;
1116
+ await promise;
1117
+ };
876
1118
  const onAllPersistLoaded = () => {
877
1119
  var _a, _b;
878
1120
  let parentNode = node;
@@ -890,77 +1132,27 @@ function syncObservable(obs$, syncOptionsOrSynced) {
890
1132
  }
891
1133
  if ((syncOptions == null ? void 0 : syncOptions.set) || (syncOptions == null ? void 0 : syncOptions.persist)) {
892
1134
  obs$.onChange(
893
- onObsChange.bind(this, obs$, syncState, localState, syncOptions)
1135
+ onObsChange.bind(this, obs$, syncState$, localState, syncOptions)
894
1136
  );
895
1137
  }
896
1138
  });
897
- return syncState;
1139
+ return syncState$;
898
1140
  }
899
- var { getProxy, globalState: globalState2, runWithRetry, symbolLinked: symbolLinked2, setNodeValue, getNodeValue: getNodeValue2 } = internal;
1141
+ var { getProxy, globalState: globalState2, setNodeValue, getNodeValue: getNodeValue2 } = internal;
900
1142
  function enableActivateSyncedNode() {
901
1143
  globalState2.activateSyncedNode = function activateSyncedNode(node, newValue) {
902
1144
  const obs$ = getProxy(node);
903
1145
  if (node.activationState) {
904
- const { get, initial, set, retry } = node.activationState;
905
- let onChange = void 0;
906
- const pluginRemote = {};
1146
+ const {
1147
+ get: getOrig,
1148
+ initial,
1149
+ set,
1150
+ onChange
1151
+ } = node.activationState;
907
1152
  let promiseReturn = void 0;
908
- let syncState;
909
- const refresh = () => syncState == null ? void 0 : syncState.sync();
910
- if (get) {
911
- pluginRemote.get = (params) => {
912
- var _a;
913
- onChange = params.onChange;
914
- const updateLastSync = (lastSync) => params.lastSync = lastSync;
915
- const existingValue = getNodeValue2(node);
916
- const value = runWithRetry(node, { attemptNum: 0, retry: retry || ((_a = params.options) == null ? void 0 : _a.retry) }, () => {
917
- const paramsToGet = {
918
- value: isFunction(existingValue) || (existingValue == null ? void 0 : existingValue[symbolLinked2]) ? void 0 : existingValue,
919
- lastSync: params.lastSync,
920
- updateLastSync,
921
- mode: params.mode,
922
- refresh
923
- };
924
- const ret = get(paramsToGet);
925
- params.mode = paramsToGet.mode;
926
- return ret;
927
- });
928
- promiseReturn = value;
929
- return value;
930
- };
931
- }
932
- if (set) {
933
- pluginRemote.set = async (params) => {
934
- var _a, _b;
935
- if ((_a = node.state) == null ? void 0 : _a.isLoaded.get()) {
936
- const retryAttempts = { attemptNum: 0, retry: retry || ((_b = params.options) == null ? void 0 : _b.retry) };
937
- return runWithRetry(node, retryAttempts, async (retryEvent) => {
938
- let changes = {};
939
- let maxModified = 0;
940
- if (!node.state.isLoaded.peek()) {
941
- await whenReady(node.state.isLoaded);
942
- }
943
- const cancelRetry = () => {
944
- retryEvent.cancel = true;
945
- };
946
- await set({
947
- ...params,
948
- node,
949
- update: (params2) => {
950
- const { value, lastSync } = params2;
951
- maxModified = Math.max(lastSync || 0, maxModified);
952
- changes = mergeIntoObservable(changes, value);
953
- },
954
- retryNum: retryAttempts.attemptNum,
955
- cancelRetry,
956
- refresh,
957
- fromSubscribe: false
958
- });
959
- return { changes, lastSync: maxModified || void 0 };
960
- });
961
- }
962
- };
963
- }
1153
+ const get = getOrig ? (params) => {
1154
+ return promiseReturn = getOrig(params);
1155
+ } : void 0;
964
1156
  const nodeVal = getNodeValue2(node);
965
1157
  if (promiseReturn !== void 0) {
966
1158
  newValue = promiseReturn;
@@ -970,13 +1162,13 @@ function enableActivateSyncedNode() {
970
1162
  newValue = initial;
971
1163
  }
972
1164
  setNodeValue(node, promiseReturn ? void 0 : newValue);
973
- syncState = syncObservable(obs$, { ...node.activationState, ...pluginRemote });
1165
+ syncObservable(obs$, { ...node.activationState, get, set });
974
1166
  return { update: onChange, value: newValue };
975
1167
  } else {
976
1168
  let update = void 0;
977
1169
  const get = async (params) => {
978
1170
  update = params.refresh;
979
- if (isPromise(newValue)) {
1171
+ if (isPromise$1(newValue)) {
980
1172
  try {
981
1173
  newValue = await newValue;
982
1174
  } catch (e) {
@@ -1007,13 +1199,20 @@ function installPersistActivateNode() {
1007
1199
  didInstall = true;
1008
1200
  }
1009
1201
  }
1202
+ var { deepMerge: deepMerge2 } = internal;
1203
+ function configureSynced(fnOrOrigOptions, origOptions) {
1204
+ const fn = origOptions ? fnOrOrigOptions : synced;
1205
+ origOptions = origOptions != null ? origOptions : fnOrOrigOptions;
1206
+ return (options) => {
1207
+ const merged = deepMerge2(origOptions, options);
1208
+ return fn(merged);
1209
+ };
1210
+ }
1010
1211
 
1011
1212
  // sync.ts
1012
- function isInRemoteChange() {
1013
- return internal.globalState.isLoadingRemote;
1014
- }
1015
- var internal3 = {
1016
- observableSyncConfiguration
1213
+ var internal4 = {
1214
+ observableSyncConfiguration,
1215
+ waitForSet
1017
1216
  };
1018
1217
 
1019
- export { combineTransforms, configureObservableSync, deepEqual, diffObjects, internal3 as internal, isInRemoteChange, mapSyncPlugins, onChangeRemote, removeNullUndefined, syncObservable, synced, transformStringifyDates, transformStringifyKeys };
1218
+ export { combineTransforms, configureObservableSync, configureSynced, deepEqual, diffObjects, internal4 as internal, mapSyncPlugins, onChangeRemote, removeNullUndefined, syncObservable, synced, transformStringifyDates, transformStringifyKeys };