@legendapp/state 3.0.0-beta.2 → 3.0.0-beta.20

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 (74) hide show
  1. package/.DS_Store +0 -0
  2. package/config/enableReactComponents.js +3 -1
  3. package/config/enableReactComponents.mjs +3 -1
  4. package/config/enableReactTracking.d.mts +2 -1
  5. package/config/enableReactTracking.d.ts +2 -1
  6. package/config/enableReactTracking.js +32 -13
  7. package/config/enableReactTracking.mjs +32 -13
  8. package/index.d.mts +13 -4
  9. package/index.d.ts +13 -4
  10. package/index.js +70 -22
  11. package/index.mjs +70 -22
  12. package/package.json +22 -1
  13. package/persist-plugins/async-storage.js +17 -9
  14. package/persist-plugins/async-storage.mjs +17 -9
  15. package/react-native.d.mts +4 -0
  16. package/react-native.d.ts +4 -0
  17. package/react-native.js +53 -0
  18. package/react-native.mjs +40 -0
  19. package/react-reactive/Components.d.mts +19 -0
  20. package/react-reactive/Components.d.ts +19 -0
  21. package/react-reactive/Components.js +53 -0
  22. package/react-reactive/Components.mjs +40 -0
  23. package/react-reactive/enableReactComponents.d.mts +3 -2
  24. package/react-reactive/enableReactComponents.d.ts +3 -2
  25. package/react-reactive/enableReactComponents.js +10 -3
  26. package/react-reactive/enableReactComponents.mjs +10 -3
  27. package/react-reactive/enableReactNativeComponents.d.mts +3 -20
  28. package/react-reactive/enableReactNativeComponents.d.ts +3 -20
  29. package/react-reactive/enableReactNativeComponents.js +8 -3
  30. package/react-reactive/enableReactNativeComponents.mjs +8 -3
  31. package/react-reactive/enableReactive.js +10 -3
  32. package/react-reactive/enableReactive.mjs +10 -3
  33. package/react-reactive/enableReactive.native.js +8 -3
  34. package/react-reactive/enableReactive.native.mjs +8 -3
  35. package/react-reactive/enableReactive.web.js +8 -3
  36. package/react-reactive/enableReactive.web.mjs +8 -3
  37. package/react-web.d.mts +6 -0
  38. package/react-web.d.ts +6 -0
  39. package/react-web.js +39 -0
  40. package/react-web.mjs +37 -0
  41. package/react.d.mts +38 -20
  42. package/react.d.ts +38 -20
  43. package/react.js +36 -23
  44. package/react.mjs +37 -25
  45. package/sync-plugins/crud.d.mts +24 -9
  46. package/sync-plugins/crud.d.ts +24 -9
  47. package/sync-plugins/crud.js +199 -108
  48. package/sync-plugins/crud.mjs +200 -109
  49. package/sync-plugins/firebase.d.mts +7 -3
  50. package/sync-plugins/firebase.d.ts +7 -3
  51. package/sync-plugins/firebase.js +4 -2
  52. package/sync-plugins/firebase.mjs +4 -2
  53. package/sync-plugins/keel.d.mts +9 -13
  54. package/sync-plugins/keel.d.ts +9 -13
  55. package/sync-plugins/keel.js +52 -41
  56. package/sync-plugins/keel.mjs +53 -37
  57. package/sync-plugins/supabase.d.mts +7 -3
  58. package/sync-plugins/supabase.d.ts +7 -3
  59. package/sync-plugins/supabase.js +87 -31
  60. package/sync-plugins/supabase.mjs +88 -32
  61. package/sync-plugins/tanstack-query.d.mts +5 -5
  62. package/sync-plugins/tanstack-query.d.ts +5 -5
  63. package/sync-plugins/tanstack-query.js +10 -1
  64. package/sync-plugins/tanstack-query.mjs +10 -1
  65. package/sync-plugins/tanstack-react-query.d.mts +4 -2
  66. package/sync-plugins/tanstack-react-query.d.ts +4 -2
  67. package/sync.d.mts +16 -8
  68. package/sync.d.ts +16 -8
  69. package/sync.js +267 -174
  70. package/sync.mjs +266 -174
  71. package/trace.js +5 -6
  72. package/trace.mjs +5 -6
  73. package/types/reactive-native.d.ts +19 -0
  74. package/types/reactive-web.d.ts +7 -0
package/sync.mjs CHANGED
@@ -1,4 +1,5 @@
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';
1
+ import { isObject, isDate, isNullOrUndefined, isString, applyChanges, 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';
2
+ import { onChangeRemote } from '@legendapp/state/sync';
2
3
 
3
4
  // src/sync/configureObservableSync.ts
4
5
  var observableSyncConfiguration = {};
@@ -33,12 +34,12 @@ function diffObjects(obj1, obj2, deep = false) {
33
34
  return diff;
34
35
  }
35
36
  function deepEqual(a, b, ignoreFields, nullVsUndefined) {
36
- if (a === b) {
37
+ if (a === b)
37
38
  return true;
38
- }
39
- if (isNullOrUndefined(a) !== isNullOrUndefined(b)) {
39
+ if (isNullOrUndefined(a) !== isNullOrUndefined(b))
40
40
  return false;
41
- }
41
+ if (!isObject(a) || !isObject(b))
42
+ return a === b;
42
43
  if (nullVsUndefined) {
43
44
  a = removeNullUndefined(
44
45
  a,
@@ -51,8 +52,18 @@ function deepEqual(a, b, ignoreFields, nullVsUndefined) {
51
52
  true
52
53
  );
53
54
  }
54
- const replacer = ignoreFields ? (key, value) => ignoreFields.includes(key) ? void 0 : value : void 0;
55
- return JSON.stringify(a, replacer) === JSON.stringify(b, replacer);
55
+ const keysA = Object.keys(a).filter((key) => !(ignoreFields == null ? void 0 : ignoreFields.includes(key)));
56
+ const keysB = Object.keys(b).filter((key) => !(ignoreFields == null ? void 0 : ignoreFields.includes(key)));
57
+ if (keysA.length !== keysB.length)
58
+ return false;
59
+ return keysA.every((key) => {
60
+ if (!Object.prototype.hasOwnProperty.call(b, key))
61
+ return false;
62
+ if (isDate(a[key]) && isDate(b[key])) {
63
+ return a[key].getTime() === b[key].getTime();
64
+ }
65
+ return deepEqual(a[key], b[key], ignoreFields, nullVsUndefined);
66
+ });
56
67
  }
57
68
  function combineTransforms(...transforms) {
58
69
  return {
@@ -159,13 +170,13 @@ function createRetryTimeout(retryOptions, retryNum, fn) {
159
170
  }
160
171
  }
161
172
  var mapRetryTimeouts = /* @__PURE__ */ new Map();
162
- function runWithRetry(state, retryOptions, fn, onError) {
173
+ function runWithRetry(state, retryOptions, retryId, fn) {
163
174
  try {
164
175
  let value = fn(state);
165
176
  if (isPromise(value) && retryOptions) {
166
177
  let timeoutRetry;
167
- if (mapRetryTimeouts.has(state.node)) {
168
- clearTimeout(mapRetryTimeouts.get(state.node));
178
+ if (mapRetryTimeouts.has(retryId)) {
179
+ clearTimeout(mapRetryTimeouts.get(retryId));
169
180
  }
170
181
  return new Promise((resolve, reject) => {
171
182
  const run = () => {
@@ -176,9 +187,6 @@ function runWithRetry(state, retryOptions, fn, onError) {
176
187
  if (timeoutRetry) {
177
188
  clearTimeout(timeoutRetry);
178
189
  }
179
- if (onError) {
180
- onError(error, state);
181
- }
182
190
  if (!state.cancelRetry) {
183
191
  const timeout = createRetryTimeout(retryOptions, state.retryNum, () => {
184
192
  value = fn(state);
@@ -188,7 +196,7 @@ function runWithRetry(state, retryOptions, fn, onError) {
188
196
  state.cancelRetry = true;
189
197
  reject(error);
190
198
  } else {
191
- mapRetryTimeouts.set(state.node, timeout);
199
+ mapRetryTimeouts.set(retryId, timeout);
192
200
  timeoutRetry = timeout;
193
201
  }
194
202
  }
@@ -208,9 +216,23 @@ async function waitForSet(waitForSet2, changes, value, params = {}) {
208
216
  await when(waitFn);
209
217
  }
210
218
  }
219
+ var { clone } = internal;
220
+ function createRevertChanges(obs$, changes) {
221
+ return () => {
222
+ const previous = applyChanges(
223
+ clone(obs$.peek()),
224
+ changes,
225
+ /*applyPrevious*/
226
+ true
227
+ );
228
+ onChangeRemote(() => {
229
+ obs$.set(previous);
230
+ });
231
+ };
232
+ }
211
233
 
212
234
  // src/sync/syncObservable.ts
213
- var { clone, deepMerge, getNode, getNodeValue, getValueAtPath, globalState, symbolLinked, createPreviousHandler } = internal;
235
+ var { clone: clone2, deepMerge, getNode, getNodeValue, getValueAtPath, globalState, symbolLinked, createPreviousHandler } = internal;
214
236
  var mapSyncPlugins = /* @__PURE__ */ new WeakMap();
215
237
  var allSyncStates = /* @__PURE__ */ new Map();
216
238
  var metadatas = /* @__PURE__ */ new WeakMap();
@@ -221,7 +243,7 @@ function parseLocalConfig(config) {
221
243
  function doInOrder(arg1, arg2) {
222
244
  return isPromise$1(arg1) ? arg1.then(arg2) : arg2(arg1);
223
245
  }
224
- function onChangeRemote(cb) {
246
+ function onChangeRemote2(cb) {
225
247
  endBatch(true);
226
248
  globalState.isLoadingRemote = true;
227
249
  beginBatch();
@@ -273,10 +295,10 @@ function updateMetadata(value$, localState, syncState2, syncOptions, newMetadata
273
295
  if (localState.timeoutSaveMetadata) {
274
296
  clearTimeout(localState.timeoutSaveMetadata);
275
297
  }
276
- localState.timeoutSaveMetadata = setTimeout(
277
- () => updateMetadataImmediate(value$, localState, syncState2, syncOptions, newMetadata),
278
- 0
279
- );
298
+ metadatas.set(value$, { ...metadatas.get(value$) || {}, ...newMetadata });
299
+ localState.timeoutSaveMetadata = setTimeout(() => {
300
+ updateMetadataImmediate(value$, localState, syncState2, syncOptions, metadatas.get(value$));
301
+ }, 0);
280
302
  }
281
303
  var _queuedChanges = [];
282
304
  var _queuedRemoteChanges = /* @__PURE__ */ new Map();
@@ -295,8 +317,25 @@ function mergeChanges(changes) {
295
317
  existing.valueAtPath = change.valueAtPath;
296
318
  }
297
319
  } else {
298
- changesByPath.set(pathStr, change);
299
- changesOut.push(change);
320
+ let found = false;
321
+ for (let u = 0; u < change.path.length; u++) {
322
+ const path = change.path.slice(0, u).join("/");
323
+ if (changesByPath.has(path)) {
324
+ const remaining = change.path.slice(u);
325
+ setAtPath(
326
+ changesByPath.get(path).valueAtPath,
327
+ remaining,
328
+ change.pathTypes.slice(u),
329
+ change.valueAtPath
330
+ );
331
+ found = true;
332
+ break;
333
+ }
334
+ }
335
+ if (!found) {
336
+ changesByPath.set(pathStr, change);
337
+ changesOut.push(change);
338
+ }
300
339
  }
301
340
  }
302
341
  return changesOut;
@@ -578,7 +617,7 @@ async function doChangeRemote(changeInfo) {
578
617
  if (waitForSetParam) {
579
618
  await waitForSet(waitForSetParam, changesRemote, obs$.peek());
580
619
  }
581
- let value = clone(obs$.peek());
620
+ let value = clone2(obs$.peek());
582
621
  const transformSave = (_a = syncOptions == null ? void 0 : syncOptions.transform) == null ? void 0 : _a.save;
583
622
  if (transformSave) {
584
623
  value = transformSave(value);
@@ -591,33 +630,41 @@ async function doChangeRemote(changeInfo) {
591
630
  onBeforeSet == null ? void 0 : onBeforeSet(beforeSetParams);
592
631
  if (!beforeSetParams.cancel) {
593
632
  let updateResult = void 0;
594
- let errorHandled = false;
595
- const onError = (error, retryParams) => {
633
+ let lastErrorHandled;
634
+ const onSetError = (error, params, noThrow) => {
596
635
  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
- });
636
+ if (lastErrorHandled !== error) {
637
+ if (!params) {
638
+ params = {
639
+ setParams,
640
+ source: "set",
641
+ type: "set",
642
+ input: value,
643
+ retry: setParams,
644
+ revert: createRevertChanges(setParams.value$, setParams.changes)
645
+ };
646
+ }
647
+ state$.error.set(error);
648
+ (_a2 = syncOptions.onError) == null ? void 0 : _a2.call(syncOptions, error, params);
649
+ lastErrorHandled = error;
650
+ if (!noThrow) {
651
+ throw error;
652
+ }
605
653
  }
606
- errorHandled = true;
607
654
  };
608
655
  const setParams = {
609
656
  node,
610
657
  value$: obs$,
611
658
  changes: changesRemote,
612
659
  value,
613
- onError,
660
+ onError: onSetError,
614
661
  update: (params) => {
615
662
  if (updateResult) {
616
- const { value: value2, lastSync, mode } = params;
663
+ const { value: value2, mode, changes } = params;
617
664
  updateResult = {
618
- lastSync: Math.max(updateResult.lastSync || 0, lastSync || 0),
619
665
  value: deepMerge(updateResult.value, value2),
620
- mode
666
+ mode,
667
+ changes: changes ? [...updateResult.changes || [], ...changes] : updateResult.changes
621
668
  };
622
669
  } else {
623
670
  updateResult = params;
@@ -627,26 +674,23 @@ async function doChangeRemote(changeInfo) {
627
674
  retryNum: 0,
628
675
  cancelRetry: false
629
676
  };
630
- const savedPromise = runWithRetry(
631
- setParams,
632
- syncOptions.retry,
633
- async () => {
634
- return syncOptions.set(setParams);
635
- },
636
- onError
637
- );
677
+ const savedPromise = runWithRetry(setParams, syncOptions.retry, node, async () => {
678
+ return syncOptions.set(setParams);
679
+ });
638
680
  let didError = false;
639
681
  if (isPromise$1(savedPromise)) {
640
682
  await savedPromise.catch((error) => {
641
683
  didError = true;
642
684
  if (!syncOptions.retry) {
643
- onError(error);
685
+ onSetError(error, void 0, true);
644
686
  }
645
687
  });
646
688
  }
647
- if (!didError) {
648
- const pathStrs = Array.from(new Set(changesRemote.map((change) => change.pathStr)));
649
- const { value: changes, lastSync } = updateResult || {};
689
+ if (!didError || (updateResult == null ? void 0 : updateResult.changes)) {
690
+ const { value: updateValue, changes: updateChanges = changesRemote } = updateResult || {};
691
+ const pathStrs = Array.from(
692
+ new Set(updateChanges.map((change) => change.pathStr))
693
+ );
650
694
  if (pathStrs.length > 0) {
651
695
  let transformedChanges = void 0;
652
696
  const metadata = {};
@@ -663,18 +707,15 @@ async function doChangeRemote(changeInfo) {
663
707
  delete pending[pathStr];
664
708
  }
665
709
  }
666
- if (lastSync) {
667
- metadata.lastSync = lastSync;
668
- }
669
710
  }
670
- if (changes && !isEmpty(changes)) {
671
- transformedChanges = transformLoadData(changes, syncOptions, false, "set");
711
+ if (updateValue && !isEmpty(updateValue)) {
712
+ transformedChanges = transformLoadData(updateValue, syncOptions, false, "set");
672
713
  }
673
714
  if (transformedChanges !== void 0) {
674
715
  if (isPromise$1(transformedChanges)) {
675
716
  transformedChanges = await transformedChanges;
676
717
  }
677
- onChangeRemote(() => mergeIntoObservable(obs$, transformedChanges));
718
+ onChangeRemote2(() => mergeIntoObservable(obs$, transformedChanges));
678
719
  }
679
720
  if (saveLocal) {
680
721
  if (shouldSaveMetadata && !isEmpty(metadata)) {
@@ -741,9 +782,20 @@ async function loadLocal(value$, syncOptions, syncState$, localState) {
741
782
  await when(initialized$);
742
783
  }
743
784
  if (persistPlugin.loadTable) {
744
- const promise = persistPlugin.loadTable(table, config);
745
- if (promise) {
746
- await promise;
785
+ try {
786
+ const promise = persistPlugin.loadTable(table, config);
787
+ if (promise) {
788
+ await promise;
789
+ }
790
+ } catch (err) {
791
+ if (process.env.NODE_ENV === "development") {
792
+ console.error(
793
+ "[legend-state] Error loading local cache. This would be a crashing error in production.",
794
+ err
795
+ );
796
+ } else {
797
+ throw err;
798
+ }
747
799
  }
748
800
  }
749
801
  const prevValue = getNodeValue(node);
@@ -762,12 +814,14 @@ async function loadLocal(value$, syncOptions, syncState$, localState) {
762
814
  if (isPromise$1(value)) {
763
815
  value = await value;
764
816
  }
817
+ node.root.isLoadingLocal = true;
765
818
  internal.globalState.isLoadingLocal = true;
766
819
  if (value === null && (!prevValue || prevValue[symbolLinked])) {
767
820
  value$.set(value);
768
821
  } else {
769
822
  mergeIntoObservable(value$, value);
770
823
  }
824
+ node.root.isLoadingLocal = false;
771
825
  internal.globalState.isLoadingLocal = false;
772
826
  }
773
827
  syncStateValue.numPendingLocalLoads--;
@@ -806,14 +860,24 @@ function syncObservable(obs$, syncOptionsOrSynced) {
806
860
  const syncStateValue = getNodeValue(getNode(syncState$));
807
861
  allSyncStates.set(syncState$, node);
808
862
  syncStateValue.getPendingChanges = () => localState.pendingChanges;
809
- let errorHandled = false;
810
- const onGetError = (error, params) => {
863
+ let lastErrorHandled;
864
+ const onGetError = (error, params, noThrow) => {
811
865
  var _a;
812
- syncState$.error.set(error);
813
- if (!errorHandled) {
814
- (_a = syncOptions.onError) == null ? void 0 : _a.call(syncOptions, error, { ...params, value$: obs$ });
866
+ if (lastErrorHandled !== error) {
867
+ if (!params) {
868
+ params = {
869
+ source: "get",
870
+ type: "get",
871
+ retry: params
872
+ };
873
+ }
874
+ syncState$.error.set(error);
875
+ (_a = syncOptions.onError) == null ? void 0 : _a.call(syncOptions, error, params);
876
+ lastErrorHandled = error;
877
+ if (!noThrow) {
878
+ throw error;
879
+ }
815
880
  }
816
- errorHandled = true;
817
881
  };
818
882
  loadLocal(obs$, syncOptions, syncState$, localState);
819
883
  let isWaitingForLoad = !!syncOptions.get;
@@ -823,30 +887,37 @@ function syncObservable(obs$, syncOptionsOrSynced) {
823
887
  syncState$.isLoaded.set(!syncState$.numPendingRemoteLoads.peek());
824
888
  let isSynced = false;
825
889
  let isSubscribed = false;
890
+ let isApplyingPendingAfterSync = false;
826
891
  let unsubscribe = void 0;
827
892
  const applyPending = (pending) => {
828
893
  if (pending && !isEmpty(pending)) {
829
- localState.isApplyingPending = true;
830
894
  const keys = Object.keys(pending);
895
+ const value = getNodeValue(node);
831
896
  const changes = [];
832
897
  for (let i = 0; i < keys.length; i++) {
833
898
  const key = keys[i];
834
899
  const path = key.split("/").filter((p2) => p2 !== "");
835
- const { p, v, t } = pending[key];
836
- changes.push({ path, valueAtPath: v, prevAtPath: p, pathTypes: t });
900
+ const { p, t, v } = pending[key];
901
+ const valueAtPath = getValueAtPath(value, path);
902
+ if (isApplyingPendingAfterSync || !deepEqual(valueAtPath, v)) {
903
+ changes.push({ path, valueAtPath: v, prevAtPath: p, pathTypes: t });
904
+ }
905
+ }
906
+ if (changes.length > 0) {
907
+ localState.isApplyingPending = true;
908
+ onObsChange(obs$, syncState$, localState, syncOptions, {
909
+ value,
910
+ isFromPersist: false,
911
+ isFromSync: false,
912
+ getPrevious: createPreviousHandler(value, changes),
913
+ changes
914
+ });
915
+ localState.isApplyingPending = false;
837
916
  }
838
- const value = getNodeValue(node);
839
- onObsChange(obs$, syncState$, localState, syncOptions, {
840
- value,
841
- isFromPersist: false,
842
- isFromSync: false,
843
- getPrevious: createPreviousHandler(value, changes),
844
- changes
845
- });
846
- localState.isApplyingPending = false;
847
917
  }
848
918
  };
849
- if (syncOptions.get) {
919
+ const { get, subscribe } = syncOptions;
920
+ if (get || subscribe) {
850
921
  sync = async () => {
851
922
  var _a;
852
923
  if (isSynced && (!getNodeValue(getNode(syncState$)).isSyncEnabled || shouldIgnoreUnobserved(node, sync))) {
@@ -859,8 +930,7 @@ function syncObservable(obs$, syncOptionsOrSynced) {
859
930
  }
860
931
  const lastSync = (_a = metadatas.get(obs$)) == null ? void 0 : _a.lastSync;
861
932
  const pending = localState.pendingChanges;
862
- const get = syncOptions.get;
863
- if (get) {
933
+ if (get || subscribe) {
864
934
  const { waitFor } = syncOptions;
865
935
  const runGet = () => {
866
936
  var _a2;
@@ -879,11 +949,11 @@ function syncObservable(obs$, syncOptionsOrSynced) {
879
949
  const p = key.split("/").filter((k) => k !== "");
880
950
  const { v, t } = pending2[key];
881
951
  if (t.length === 0 || !value) {
882
- const oldValue = clone(value);
883
- pending2[key].p = oldValue;
952
+ const oldValue = clone2(value);
953
+ pending2[key].p = key ? oldValue[key] : oldValue;
884
954
  if (isObject(value) && isObject(v)) {
885
- Object.assign(value, v);
886
- } else {
955
+ Object.assign(value, key ? { [key]: v } : v);
956
+ } else if (!key) {
887
957
  value = v;
888
958
  }
889
959
  } else if (value[p[0]] !== void 0) {
@@ -893,8 +963,9 @@ function syncObservable(obs$, syncOptionsOrSynced) {
893
963
  delete pending2[key];
894
964
  didChangeMetadata = true;
895
965
  } else {
896
- const oldValue = clone(value);
966
+ const oldValue = clone2(value);
897
967
  pending2[key].p = getValueAtPath(oldValue, p);
968
+ didChangeMetadata = true;
898
969
  value = setAtPath(
899
970
  value,
900
971
  p,
@@ -915,12 +986,12 @@ function syncObservable(obs$, syncOptionsOrSynced) {
915
986
  }
916
987
  });
917
988
  if (didChangeMetadata && syncOptions.persist) {
918
- updateMetadata(obs$, localState, syncState$, syncOptions, {
989
+ updateMetadataImmediate(obs$, localState, syncState$, syncOptions, {
919
990
  pending: pending2
920
991
  });
921
992
  }
922
993
  }
923
- onChangeRemote(() => {
994
+ onChangeRemote2(() => {
924
995
  if (isPlainObject(value)) {
925
996
  value = ObservableHint.plain(value);
926
997
  }
@@ -953,7 +1024,7 @@ function syncObservable(obs$, syncOptionsOrSynced) {
953
1024
  node.activationState.onChange = onChange;
954
1025
  }
955
1026
  if (!isSubscribed && syncOptions.subscribe) {
956
- const subscribe = syncOptions.subscribe;
1027
+ const subscribe2 = syncOptions.subscribe;
957
1028
  isSubscribed = true;
958
1029
  const doSubscribe = () => {
959
1030
  const subscribeParams = {
@@ -961,17 +1032,32 @@ function syncObservable(obs$, syncOptionsOrSynced) {
961
1032
  value$: obs$,
962
1033
  lastSync,
963
1034
  update: (params) => {
964
- when(syncState$.isLoaded, () => {
965
- when(waitFor || true, () => {
966
- params.mode || (params.mode = syncOptions.mode || "merge");
967
- onChange(params);
968
- });
969
- });
1035
+ when(
1036
+ () => !get || syncState$.isLoaded.get(),
1037
+ () => {
1038
+ when(waitFor || true, () => {
1039
+ params.mode || (params.mode = syncOptions.mode || "merge");
1040
+ onChange(params);
1041
+ if (!syncState$.isLoaded.peek()) {
1042
+ syncState$.assign({
1043
+ isLoaded: syncStateValue.numPendingRemoteLoads < 1,
1044
+ error: void 0,
1045
+ isGetting: syncStateValue.numPendingGets > 0
1046
+ });
1047
+ }
1048
+ });
1049
+ }
1050
+ );
970
1051
  },
971
1052
  refresh: () => when(syncState$.isLoaded, sync),
972
- onError: (error) => onGetError(error, { source: "subscribe", subscribeParams })
1053
+ onError: (error) => onGetError(error, {
1054
+ source: "subscribe",
1055
+ subscribeParams,
1056
+ type: "get",
1057
+ retry: {}
1058
+ })
973
1059
  };
974
- unsubscribe = subscribe(subscribeParams);
1060
+ unsubscribe = subscribe2(subscribeParams);
975
1061
  };
976
1062
  if (waitFor) {
977
1063
  whenReady(waitFor, doSubscribe);
@@ -980,85 +1066,87 @@ function syncObservable(obs$, syncOptionsOrSynced) {
980
1066
  }
981
1067
  }
982
1068
  const existingValue = getNodeValue(node);
983
- const onError = (error) => onGetError(error, { getParams, source: "get" });
984
- const getParams = {
985
- node,
986
- value$: obs$,
987
- value: isFunction(existingValue) || (existingValue == null ? void 0 : existingValue[symbolLinked]) ? void 0 : existingValue,
988
- mode: syncOptions.mode,
989
- refresh: sync,
990
- options: syncOptions,
991
- lastSync,
992
- updateLastSync: (lastSync2) => getParams.lastSync = lastSync2,
993
- onError,
994
- retryNum: 0,
995
- cancelRetry: false
996
- };
997
- let modeBeforeReset = void 0;
998
- const beforeGetParams = {
999
- value: getParams.value,
1000
- lastSync,
1001
- pendingChanges: pending && !isEmpty(pending) ? pending : void 0,
1002
- clearPendingChanges: async () => {
1003
- localState.pendingChanges = {};
1004
- await updateMetadataImmediate(obs$, localState, syncState$, syncOptions, {
1005
- pending: localState.pendingChanges
1069
+ if (get) {
1070
+ const getParams = {
1071
+ node,
1072
+ value$: obs$,
1073
+ value: isFunction(existingValue) || (existingValue == null ? void 0 : existingValue[symbolLinked]) ? void 0 : existingValue,
1074
+ mode: syncOptions.mode,
1075
+ refresh: sync,
1076
+ options: syncOptions,
1077
+ lastSync,
1078
+ updateLastSync: (lastSync2) => getParams.lastSync = lastSync2,
1079
+ onError: onGetError,
1080
+ retryNum: 0,
1081
+ cancelRetry: false
1082
+ };
1083
+ let modeBeforeReset = void 0;
1084
+ const beforeGetParams = {
1085
+ value: getParams.value,
1086
+ lastSync,
1087
+ pendingChanges: pending && !isEmpty(pending) ? pending : void 0,
1088
+ clearPendingChanges: async () => {
1089
+ localState.pendingChanges = {};
1090
+ await updateMetadataImmediate(obs$, localState, syncState$, syncOptions, {
1091
+ pending: localState.pendingChanges
1092
+ });
1093
+ },
1094
+ resetCache: () => {
1095
+ var _a3;
1096
+ modeBeforeReset = getParams.mode;
1097
+ getParams.mode = "set";
1098
+ return (_a3 = syncStateValue.resetPersistence) == null ? void 0 : _a3.call(syncStateValue);
1099
+ },
1100
+ cancel: false
1101
+ };
1102
+ (_a2 = syncOptions.onBeforeGet) == null ? void 0 : _a2.call(syncOptions, beforeGetParams);
1103
+ if (!beforeGetParams.cancel) {
1104
+ syncState$.assign({
1105
+ numPendingGets: (syncStateValue.numPendingGets || 0) + 1,
1106
+ isGetting: true
1006
1107
  });
1007
- },
1008
- resetCache: () => {
1009
- var _a3;
1010
- modeBeforeReset = getParams.mode;
1011
- getParams.mode = "set";
1012
- return (_a3 = syncStateValue.resetPersistence) == null ? void 0 : _a3.call(syncStateValue);
1013
- },
1014
- cancel: false
1015
- };
1016
- (_a2 = syncOptions.onBeforeGet) == null ? void 0 : _a2.call(syncOptions, beforeGetParams);
1017
- if (!beforeGetParams.cancel) {
1018
- syncState$.assign({
1019
- numPendingGets: (syncStateValue.numPendingGets || 0) + 1,
1020
- isGetting: true
1021
- });
1022
- const got = runWithRetry(
1023
- getParams,
1024
- syncOptions.retry,
1025
- (retryEvent) => {
1108
+ const got = runWithRetry(getParams, syncOptions.retry, node, (retryEvent) => {
1026
1109
  const params = getParams;
1027
1110
  params.cancelRetry = retryEvent.cancelRetry;
1028
1111
  params.retryNum = retryEvent.retryNum;
1029
1112
  return get(params);
1030
- },
1031
- onError
1032
- );
1033
- const numGets = node.numGets = (node.numGets || 0) + 1;
1034
- const handle = (value) => {
1035
- syncState$.numPendingGets.set((v) => v - 1);
1036
- if (isWaitingForLoad) {
1037
- isWaitingForLoad = false;
1038
- syncStateValue.numPendingRemoteLoads--;
1039
- }
1040
- if (numGets >= (node.getNumResolved || 0)) {
1041
- node.getNumResolved = node.numGets;
1042
- onChange({
1043
- value,
1044
- lastSync: getParams.lastSync,
1045
- mode: getParams.mode
1113
+ });
1114
+ const numGets = node.numGets = (node.numGets || 0) + 1;
1115
+ const handle = (value) => {
1116
+ syncState$.numPendingGets.set((v) => v - 1);
1117
+ if (isWaitingForLoad) {
1118
+ isWaitingForLoad = false;
1119
+ syncStateValue.numPendingRemoteLoads--;
1120
+ }
1121
+ if (numGets >= (node.getNumResolved || 0)) {
1122
+ node.getNumResolved = node.numGets;
1123
+ onChange({
1124
+ value,
1125
+ lastSync: getParams.lastSync,
1126
+ mode: getParams.mode
1127
+ });
1128
+ }
1129
+ if (modeBeforeReset) {
1130
+ getParams.mode = modeBeforeReset;
1131
+ modeBeforeReset = void 0;
1132
+ }
1133
+ syncState$.assign({
1134
+ isLoaded: syncStateValue.numPendingRemoteLoads < 1,
1135
+ error: void 0,
1136
+ isGetting: syncStateValue.numPendingGets > 0
1046
1137
  });
1138
+ };
1139
+ if (isPromise$1(got)) {
1140
+ got.then(handle).catch((error) => {
1141
+ onGetError(
1142
+ error,
1143
+ { getParams, source: "get", type: "get", retry: getParams },
1144
+ true
1145
+ );
1146
+ });
1147
+ } else {
1148
+ handle(got);
1047
1149
  }
1048
- if (modeBeforeReset) {
1049
- getParams.mode = modeBeforeReset;
1050
- modeBeforeReset = void 0;
1051
- }
1052
- syncState$.assign({
1053
- isLoaded: syncStateValue.numPendingRemoteLoads < 1,
1054
- error: void 0,
1055
- isGetting: syncStateValue.numPendingGets > 0
1056
- });
1057
- };
1058
- if (isPromise$1(got)) {
1059
- got.then(handle).catch(onError);
1060
- } else {
1061
- handle(got);
1062
1150
  }
1063
1151
  }
1064
1152
  };
@@ -1075,14 +1163,17 @@ function syncObservable(obs$, syncOptionsOrSynced) {
1075
1163
  }
1076
1164
  if (!isSynced) {
1077
1165
  isSynced = true;
1078
- await when(syncState$.isLoaded);
1166
+ isApplyingPendingAfterSync = true;
1079
1167
  applyPending(pending);
1168
+ isApplyingPendingAfterSync = false;
1080
1169
  }
1081
1170
  };
1082
1171
  syncStateValue.sync = sync;
1083
1172
  } else {
1084
1173
  if (!isSynced) {
1174
+ isApplyingPendingAfterSync = true;
1085
1175
  applyPending(localState.pendingChanges);
1176
+ isApplyingPendingAfterSync = false;
1086
1177
  }
1087
1178
  }
1088
1179
  syncStateValue.reset = async () => {
@@ -1108,7 +1199,7 @@ function syncObservable(obs$, syncOptionsOrSynced) {
1108
1199
  unsubscribe == null ? void 0 : unsubscribe();
1109
1200
  unsubscribe = void 0;
1110
1201
  const promise = syncStateValue.resetPersistence();
1111
- onChangeRemote(() => {
1202
+ onChangeRemote2(() => {
1112
1203
  var _a;
1113
1204
  obs$.set((_a = syncOptions.initial) != null ? _a : void 0);
1114
1205
  });
@@ -1130,7 +1221,7 @@ function syncObservable(obs$, syncOptionsOrSynced) {
1130
1221
  return true;
1131
1222
  };
1132
1223
  when(onAllPersistLoaded, function() {
1133
- if (syncOptions.get && syncOptions.syncMode === "auto") {
1224
+ if ((syncOptions.get || syncOptions.subscribe) && syncOptions.syncMode === "auto") {
1134
1225
  sync();
1135
1226
  }
1136
1227
  if ((syncOptions == null ? void 0 : syncOptions.set) || (syncOptions == null ? void 0 : syncOptions.persist)) {
@@ -1213,9 +1304,10 @@ function configureSynced(fnOrOrigOptions, origOptions) {
1213
1304
  }
1214
1305
 
1215
1306
  // sync.ts
1216
- var internal4 = {
1307
+ var internal5 = {
1217
1308
  observableSyncConfiguration,
1218
- waitForSet
1309
+ waitForSet,
1310
+ runWithRetry
1219
1311
  };
1220
1312
 
1221
- export { combineTransforms, configureObservableSync, configureSynced, deepEqual, diffObjects, internal4 as internal, mapSyncPlugins, onChangeRemote, removeNullUndefined, syncObservable, synced, transformStringifyDates, transformStringifyKeys };
1313
+ export { combineTransforms, configureObservableSync, configureSynced, createRevertChanges, deepEqual, diffObjects, internal5 as internal, mapSyncPlugins, onChangeRemote2 as onChangeRemote, removeNullUndefined, syncObservable, synced, transformStringifyDates, transformStringifyKeys };