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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/.DS_Store +0 -0
  2. package/config/configureLegendState.d.mts +13 -0
  3. package/config/configureLegendState.d.ts +13 -0
  4. package/config/configureLegendState.js +45 -0
  5. package/config/configureLegendState.mjs +43 -0
  6. package/config/enable$GetSet.js +2 -1
  7. package/config/enable$GetSet.mjs +2 -1
  8. package/config/enableReactTracking.js +2 -1
  9. package/config/enableReactTracking.mjs +2 -1
  10. package/config/enableReactUse.js +2 -1
  11. package/config/enableReactUse.mjs +2 -1
  12. package/config/enable_PeekAssign.js +2 -1
  13. package/config/enable_PeekAssign.mjs +2 -1
  14. package/helpers/trackHistory.js +2 -2
  15. package/helpers/trackHistory.mjs +2 -2
  16. package/index.d.mts +103 -79
  17. package/index.d.ts +103 -79
  18. package/index.js +326 -316
  19. package/index.mjs +323 -314
  20. package/package.json +36 -1
  21. package/persist-plugins/async-storage.d.mts +6 -3
  22. package/persist-plugins/async-storage.d.ts +6 -3
  23. package/persist-plugins/async-storage.js +8 -4
  24. package/persist-plugins/async-storage.mjs +8 -5
  25. package/persist-plugins/indexeddb.d.mts +6 -4
  26. package/persist-plugins/indexeddb.d.ts +6 -4
  27. package/persist-plugins/indexeddb.js +35 -15
  28. package/persist-plugins/indexeddb.mjs +35 -16
  29. package/persist-plugins/mmkv.d.mts +5 -1
  30. package/persist-plugins/mmkv.d.ts +5 -1
  31. package/persist-plugins/mmkv.js +10 -5
  32. package/persist-plugins/mmkv.mjs +10 -6
  33. package/react-reactive/enableReactComponents.d.mts +9 -0
  34. package/react-reactive/enableReactComponents.d.ts +9 -0
  35. package/react-reactive/enableReactComponents.js +19 -0
  36. package/react-reactive/enableReactComponents.mjs +17 -0
  37. package/react-reactive/enableReactNativeComponents.d.mts +22 -0
  38. package/react-reactive/enableReactNativeComponents.d.ts +22 -0
  39. package/react-reactive/enableReactNativeComponents.js +53 -0
  40. package/react-reactive/enableReactNativeComponents.mjs +51 -0
  41. package/react-reactive/enableReactive.d.mts +5 -0
  42. package/react-reactive/enableReactive.d.ts +5 -0
  43. package/react-reactive/enableReactive.js +24 -0
  44. package/react-reactive/enableReactive.mjs +22 -0
  45. package/react-reactive/enableReactive.native.d.mts +5 -0
  46. package/react-reactive/enableReactive.native.d.ts +5 -0
  47. package/react-reactive/enableReactive.native.js +58 -0
  48. package/react-reactive/enableReactive.native.mjs +56 -0
  49. package/react-reactive/enableReactive.web.d.mts +5 -0
  50. package/react-reactive/enableReactive.web.d.ts +5 -0
  51. package/react-reactive/enableReactive.web.js +58 -0
  52. package/react-reactive/enableReactive.web.mjs +56 -0
  53. package/react.d.mts +39 -34
  54. package/react.d.ts +39 -34
  55. package/react.js +39 -17
  56. package/react.mjs +39 -17
  57. package/sync-plugins/crud.d.mts +21 -23
  58. package/sync-plugins/crud.d.ts +21 -23
  59. package/sync-plugins/crud.js +224 -112
  60. package/sync-plugins/crud.mjs +226 -114
  61. package/sync-plugins/fetch.js +12 -8
  62. package/sync-plugins/fetch.mjs +13 -9
  63. package/sync-plugins/firebase.d.mts +27 -0
  64. package/sync-plugins/firebase.d.ts +27 -0
  65. package/sync-plugins/firebase.js +373 -0
  66. package/sync-plugins/firebase.mjs +368 -0
  67. package/sync-plugins/keel.d.mts +43 -26
  68. package/sync-plugins/keel.d.ts +43 -26
  69. package/sync-plugins/keel.js +145 -99
  70. package/sync-plugins/keel.mjs +147 -99
  71. package/sync-plugins/supabase.d.mts +19 -9
  72. package/sync-plugins/supabase.d.ts +19 -9
  73. package/sync-plugins/supabase.js +52 -21
  74. package/sync-plugins/supabase.mjs +53 -22
  75. package/sync-plugins/tanstack-query.d.mts +2 -2
  76. package/sync-plugins/tanstack-query.d.ts +2 -2
  77. package/sync-plugins/tanstack-query.js +22 -5
  78. package/sync-plugins/tanstack-query.mjs +22 -5
  79. package/sync-plugins/tanstack-react-query.d.mts +1 -1
  80. package/sync-plugins/tanstack-react-query.d.ts +1 -1
  81. package/sync-plugins/tanstack-react-query.js +8 -1
  82. package/sync-plugins/tanstack-react-query.mjs +8 -1
  83. package/sync.d.mts +74 -200
  84. package/sync.d.ts +74 -200
  85. package/sync.js +495 -281
  86. package/sync.mjs +500 -286
package/sync.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,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 = 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(() => {
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
+ }
558
662
  }
559
- if (pending == null ? void 0 : pending[pathStr]) {
560
- delete pending[pathStr];
663
+ if (lastSync) {
664
+ metadata.lastSync = lastSync;
561
665
  }
562
666
  }
563
- if (lastSync) {
564
- metadata.lastSync = lastSync;
667
+ if (changes && !isEmpty(changes)) {
668
+ transformedChanges = transformLoadData(changes, syncOptions, false, "set");
565
669
  }
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;
670
+ if (transformedChanges !== void 0) {
671
+ if (isPromise$1(transformedChanges)) {
672
+ transformedChanges = await transformedChanges;
673
+ }
674
+ onChangeRemote(() => mergeIntoObservable(obs$, transformedChanges));
573
675
  }
574
- onChangeRemote(() => mergeIntoObservable(obs, transformedChanges));
575
- }
576
- if (saveLocal) {
577
- if (shouldSaveMetadata && !isEmpty(metadata)) {
578
- updateMetadata(obs, localState, syncState, syncOptions, metadata);
676
+ if (saveLocal) {
677
+ if (shouldSaveMetadata && !isEmpty(metadata)) {
678
+ updateMetadata(obs$, localState, syncState2, syncOptions, metadata);
679
+ }
579
680
  }
580
681
  }
682
+ state$.numPendingSets.set((v) => v - 1);
683
+ state$.isSetting.set(state$.numPendingSets.peek() > 0);
581
684
  onAfterSet == null ? void 0 : onAfterSet();
582
685
  }
583
686
  }
584
687
  }
585
688
  }
586
- function onObsChange(value$, syncState, localState, syncOptions, { changes, loading, remote, getPrevious }) {
587
- if (!loading) {
588
- const inRemoteChange = remote;
689
+ function onObsChange(value$, syncState2, localState, syncOptions, { changes, isFromPersist, isFromSync, getPrevious }) {
690
+ if (!isFromPersist) {
691
+ const inRemoteChange = isFromSync;
589
692
  const isApplyingPending = localState.isApplyingPending;
590
693
  _queuedChanges.push({
591
694
  value$,
592
- syncState,
695
+ syncState: syncState2,
593
696
  localState,
594
697
  syncOptions,
595
698
  changes,
@@ -602,24 +705,27 @@ function onObsChange(value$, syncState, localState, syncOptions, { changes, load
602
705
  }
603
706
  }
604
707
  }
605
- async function loadLocal(value$, syncOptions, syncState, localState) {
708
+ async function loadLocal(value$, syncOptions, syncState$, localState) {
606
709
  var _a, _b, _c;
607
710
  const { persist } = syncOptions;
608
711
  const node = getNode(value$);
609
712
  const nodeValue = getNodeValue(getNode(node.state));
713
+ const syncStateValue = syncState$.peek();
714
+ const prevResetPersistence = nodeValue.resetPersistence;
610
715
  if (persist == null ? void 0 : persist.name) {
611
716
  const PersistPlugin = persist.plugin || ((_a = observableSyncConfiguration.persist) == null ? void 0 : _a.plugin);
612
717
  const { table, config } = parseLocalConfig(persist);
718
+ syncStateValue.numPendingLocalLoads = (syncStateValue.numPendingLocalLoads || 0) + 1;
613
719
  if (!PersistPlugin) {
614
720
  throw new Error("Local persist is not configured");
615
721
  }
616
722
  if (!mapSyncPlugins.has(PersistPlugin)) {
617
- const persistPlugin2 = new PersistPlugin();
723
+ const persistPlugin2 = isFunction(PersistPlugin) ? new PersistPlugin() : PersistPlugin;
618
724
  const mapValue = { plugin: persistPlugin2, initialized: observable(false) };
619
725
  mapSyncPlugins.set(PersistPlugin, mapValue);
620
726
  if (persistPlugin2.initialize) {
621
727
  const initializePromise = (_c = persistPlugin2.initialize) == null ? void 0 : _c.call(persistPlugin2, ((_b = observableSyncConfiguration) == null ? void 0 : _b.persist) || {});
622
- if (isPromise(initializePromise)) {
728
+ if (isPromise$1(initializePromise)) {
623
729
  await initializePromise;
624
730
  }
625
731
  }
@@ -643,14 +749,14 @@ async function loadLocal(value$, syncOptions, syncState, localState) {
643
749
  if (metadata) {
644
750
  metadatas.set(value$, metadata);
645
751
  localState.pendingChanges = metadata.pending;
646
- syncState.assign({
752
+ syncState$.assign({
647
753
  lastSync: metadata.lastSync
648
754
  });
649
755
  }
650
756
  if (value !== void 0) {
651
757
  const { transform } = config;
652
758
  value = transformLoadData(value, { transform }, true, "get");
653
- if (isPromise(value)) {
759
+ if (isPromise$1(value)) {
654
760
  value = await value;
655
761
  }
656
762
  internal.globalState.isLoadingLocal = true;
@@ -661,15 +767,19 @@ async function loadLocal(value$, syncOptions, syncState, localState) {
661
767
  }
662
768
  internal.globalState.isLoadingLocal = false;
663
769
  }
664
- nodeValue.clearPersist = () => Promise.all([
665
- persistPlugin.deleteTable(table, config),
666
- persistPlugin.deleteMetadata(table, config)
667
- ]);
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
+ );
668
778
  } else {
669
- nodeValue.clearPersist = () => {
670
- };
779
+ nodeValue.resetPersistence = () => prevResetPersistence == null ? void 0 : prevResetPersistence();
671
780
  }
672
- syncState.isPersistLoaded.set(true);
781
+ nodeValue.clearPersist = nodeValue.resetPersistence;
782
+ syncState$.isPersistLoaded.set(!(syncStateValue.numPendingLocalLoads > 0));
673
783
  }
674
784
  function syncObservable(obs$, syncOptionsOrSynced) {
675
785
  let syncOptions = syncOptionsOrSynced;
@@ -680,7 +790,7 @@ function syncObservable(obs$, syncOptionsOrSynced) {
680
790
  if ((process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test") && (!obs$ || !node)) {
681
791
  throw new Error("[legend-state] syncObservable called with undefined observable");
682
792
  }
683
- syncOptions = mergeIntoObservable(
793
+ syncOptions = deepMerge(
684
794
  {
685
795
  syncMode: "auto"
686
796
  },
@@ -689,24 +799,54 @@ function syncObservable(obs$, syncOptionsOrSynced) {
689
799
  );
690
800
  const localState = {};
691
801
  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);
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
+ };
703
846
  if (syncOptions.get) {
704
- let isSynced = false;
705
- let isSubscribed = false;
706
- let unsubscribe = void 0;
707
847
  sync = async () => {
708
- var _a, _b;
709
- if (isSynced && shouldIgnoreUnobserved(node, sync)) {
848
+ var _a;
849
+ if (isSynced && (!getNodeValue(getNode(syncState$)).isSyncEnabled || shouldIgnoreUnobserved(node, sync))) {
710
850
  if (unsubscribe) {
711
851
  isSubscribed = false;
712
852
  unsubscribe();
@@ -716,14 +856,16 @@ function syncObservable(obs$, syncOptionsOrSynced) {
716
856
  }
717
857
  const lastSync = (_a = metadatas.get(obs$)) == null ? void 0 : _a.lastSync;
718
858
  const pending = localState.pendingChanges;
719
- const get = (_b = localState.pluginSync.get) == null ? void 0 : _b.bind(localState.pluginSync);
859
+ const get = syncOptions.get;
720
860
  if (get) {
861
+ const { waitFor } = syncOptions;
721
862
  const runGet = () => {
863
+ var _a2;
722
864
  const onChange = async ({ value, mode, lastSync: lastSync2 }) => {
723
865
  mode = mode || syncOptions.mode || "set";
724
866
  if (value !== void 0) {
725
867
  value = transformLoadData(value, syncOptions, true, "get");
726
- if (isPromise(value)) {
868
+ if (isPromise$1(value)) {
727
869
  value = await value;
728
870
  }
729
871
  const pending2 = localState.pendingChanges;
@@ -731,9 +873,11 @@ function syncObservable(obs$, syncOptionsOrSynced) {
731
873
  if (pending2) {
732
874
  let didChangeMetadata = false;
733
875
  Object.keys(pending2).forEach((key) => {
734
- const p = key.split("/").filter((p2) => p2 !== "");
876
+ const p = key.split("/").filter((k) => k !== "");
735
877
  const { v, t } = pending2[key];
736
878
  if (t.length === 0 || !value) {
879
+ const oldValue = clone(value);
880
+ pending2[key].p = oldValue;
737
881
  if (isObject(value) && isObject(v)) {
738
882
  Object.assign(value, v);
739
883
  } else {
@@ -746,6 +890,8 @@ function syncObservable(obs$, syncOptionsOrSynced) {
746
890
  delete pending2[key];
747
891
  didChangeMetadata = true;
748
892
  } else {
893
+ const oldValue = clone(value);
894
+ pending2[key].p = getValueAtPath(oldValue, p);
749
895
  value = setAtPath(
750
896
  value,
751
897
  p,
@@ -765,18 +911,27 @@ function syncObservable(obs$, syncOptionsOrSynced) {
765
911
  }
766
912
  }
767
913
  });
768
- if (didChangeMetadata) {
769
- updateMetadata(obs$, localState, syncState, syncOptions, {
914
+ if (didChangeMetadata && syncOptions.persist) {
915
+ updateMetadata(obs$, localState, syncState$, syncOptions, {
770
916
  pending: pending2
771
917
  });
772
918
  }
773
919
  }
774
920
  onChangeRemote(() => {
775
- if (mode === "assign" && isObject(value)) {
921
+ if (isPlainObject(value)) {
922
+ value = ObservableHint.plain(value);
923
+ }
924
+ if (mode === "assign") {
776
925
  obs$.assign(value);
777
- } 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
+ }
778
930
  obs$.push(...value);
779
- } 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
+ }
780
935
  obs$.splice(0, 0, ...value);
781
936
  } else if (mode === "merge") {
782
937
  mergeIntoObservable(obs$, value);
@@ -786,78 +941,180 @@ function syncObservable(obs$, syncOptionsOrSynced) {
786
941
  });
787
942
  }
788
943
  if (lastSync2 && syncOptions.persist) {
789
- updateMetadata(obs$, localState, syncState, syncOptions, {
944
+ updateMetadata(obs$, localState, syncState$, syncOptions, {
790
945
  lastSync: lastSync2
791
946
  });
792
947
  }
793
948
  };
794
- get({
795
- 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,
796
983
  value$: obs$,
984
+ value: isFunction(existingValue) || (existingValue == null ? void 0 : existingValue[symbolLinked]) ? void 0 : existingValue,
985
+ mode: syncOptions.mode,
986
+ refresh: sync,
797
987
  options: syncOptions,
798
988
  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
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
808
1003
  });
809
1004
  },
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)
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
824
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
+ }
825
1060
  }
826
1061
  };
827
- runGet();
1062
+ if (waitFor) {
1063
+ whenReady(waitFor, () => trackSelector(runGet, sync));
1064
+ } else {
1065
+ trackSelector(runGet, sync);
1066
+ }
828
1067
  } else {
829
- node.state.assign({
1068
+ syncState$.assign({
830
1069
  isLoaded: true,
831
1070
  error: void 0
832
1071
  });
833
1072
  }
834
1073
  if (!isSynced) {
835
1074
  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
- }
1075
+ await when(syncState$.isLoaded);
1076
+ applyPending(pending);
857
1077
  }
858
1078
  };
859
- syncState.assign({ sync });
1079
+ syncStateValue.sync = sync;
1080
+ } else {
1081
+ if (!isSynced) {
1082
+ applyPending(localState.pendingChanges);
1083
+ }
860
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
+ };
861
1118
  const onAllPersistLoaded = () => {
862
1119
  var _a, _b;
863
1120
  let parentNode = node;
@@ -875,77 +1132,27 @@ function syncObservable(obs$, syncOptionsOrSynced) {
875
1132
  }
876
1133
  if ((syncOptions == null ? void 0 : syncOptions.set) || (syncOptions == null ? void 0 : syncOptions.persist)) {
877
1134
  obs$.onChange(
878
- onObsChange.bind(this, obs$, syncState, localState, syncOptions)
1135
+ onObsChange.bind(this, obs$, syncState$, localState, syncOptions)
879
1136
  );
880
1137
  }
881
1138
  });
882
- return syncState;
1139
+ return syncState$;
883
1140
  }
884
- var { getProxy, globalState: globalState2, runWithRetry, symbolLinked: symbolLinked2, setNodeValue, getNodeValue: getNodeValue2 } = internal;
1141
+ var { getProxy, globalState: globalState2, setNodeValue, getNodeValue: getNodeValue2 } = internal;
885
1142
  function enableActivateSyncedNode() {
886
1143
  globalState2.activateSyncedNode = function activateSyncedNode(node, newValue) {
887
1144
  const obs$ = getProxy(node);
888
1145
  if (node.activationState) {
889
- const { get, initial, set, retry } = node.activationState;
890
- let onChange = void 0;
891
- const pluginRemote = {};
1146
+ const {
1147
+ get: getOrig,
1148
+ initial,
1149
+ set,
1150
+ onChange
1151
+ } = node.activationState;
892
1152
  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
- }
1153
+ const get = getOrig ? (params) => {
1154
+ return promiseReturn = getOrig(params);
1155
+ } : void 0;
949
1156
  const nodeVal = getNodeValue2(node);
950
1157
  if (promiseReturn !== void 0) {
951
1158
  newValue = promiseReturn;
@@ -955,13 +1162,13 @@ function enableActivateSyncedNode() {
955
1162
  newValue = initial;
956
1163
  }
957
1164
  setNodeValue(node, promiseReturn ? void 0 : newValue);
958
- syncState = syncObservable(obs$, { ...node.activationState, ...pluginRemote });
1165
+ syncObservable(obs$, { ...node.activationState, get, set });
959
1166
  return { update: onChange, value: newValue };
960
1167
  } else {
961
1168
  let update = void 0;
962
1169
  const get = async (params) => {
963
1170
  update = params.refresh;
964
- if (isPromise(newValue)) {
1171
+ if (isPromise$1(newValue)) {
965
1172
  try {
966
1173
  newValue = await newValue;
967
1174
  } catch (e) {
@@ -992,13 +1199,20 @@ function installPersistActivateNode() {
992
1199
  didInstall = true;
993
1200
  }
994
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
+ }
995
1211
 
996
1212
  // sync.ts
997
- function isInRemoteChange() {
998
- return internal.globalState.isLoadingRemote;
999
- }
1000
- var internal3 = {
1001
- observableSyncConfiguration
1213
+ var internal4 = {
1214
+ observableSyncConfiguration,
1215
+ waitForSet
1002
1216
  };
1003
1217
 
1004
- 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 };