@legendapp/state 3.0.0-beta.13 → 3.0.0-beta.15

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.
package/sync.js CHANGED
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var state = require('@legendapp/state');
4
+ var sync = require('@legendapp/state/sync');
4
5
 
5
6
  // src/sync/configureObservableSync.ts
6
7
  var observableSyncConfiguration = {};
@@ -161,13 +162,13 @@ function createRetryTimeout(retryOptions, retryNum, fn) {
161
162
  }
162
163
  }
163
164
  var mapRetryTimeouts = /* @__PURE__ */ new Map();
164
- function runWithRetry(state, retryOptions, fn, onError) {
165
+ function runWithRetry(state, retryOptions, retryId, fn) {
165
166
  try {
166
167
  let value = fn(state);
167
168
  if (isPromise(value) && retryOptions) {
168
169
  let timeoutRetry;
169
- if (mapRetryTimeouts.has(state.node)) {
170
- clearTimeout(mapRetryTimeouts.get(state.node));
170
+ if (mapRetryTimeouts.has(retryId)) {
171
+ clearTimeout(mapRetryTimeouts.get(retryId));
171
172
  }
172
173
  return new Promise((resolve, reject) => {
173
174
  const run = () => {
@@ -178,9 +179,6 @@ function runWithRetry(state, retryOptions, fn, onError) {
178
179
  if (timeoutRetry) {
179
180
  clearTimeout(timeoutRetry);
180
181
  }
181
- if (onError) {
182
- onError(error, state);
183
- }
184
182
  if (!state.cancelRetry) {
185
183
  const timeout = createRetryTimeout(retryOptions, state.retryNum, () => {
186
184
  value = fn(state);
@@ -190,7 +188,7 @@ function runWithRetry(state, retryOptions, fn, onError) {
190
188
  state.cancelRetry = true;
191
189
  reject(error);
192
190
  } else {
193
- mapRetryTimeouts.set(state.node, timeout);
191
+ mapRetryTimeouts.set(retryId, timeout);
194
192
  timeoutRetry = timeout;
195
193
  }
196
194
  }
@@ -210,9 +208,23 @@ async function waitForSet(waitForSet2, changes, value, params = {}) {
210
208
  await state.when(waitFn);
211
209
  }
212
210
  }
211
+ var { clone } = state.internal;
212
+ function createRevertChanges(obs$, changes) {
213
+ return () => {
214
+ const previous = state.applyChanges(
215
+ clone(obs$.peek()),
216
+ changes,
217
+ /*applyPrevious*/
218
+ true
219
+ );
220
+ sync.onChangeRemote(() => {
221
+ obs$.set(previous);
222
+ });
223
+ };
224
+ }
213
225
 
214
226
  // src/sync/syncObservable.ts
215
- var { clone, deepMerge, getNode, getNodeValue, getValueAtPath, globalState, symbolLinked, createPreviousHandler } = state.internal;
227
+ var { clone: clone2, deepMerge, getNode, getNodeValue, getValueAtPath, globalState, symbolLinked, createPreviousHandler } = state.internal;
216
228
  var mapSyncPlugins = /* @__PURE__ */ new WeakMap();
217
229
  var allSyncStates = /* @__PURE__ */ new Map();
218
230
  var metadatas = /* @__PURE__ */ new WeakMap();
@@ -223,7 +235,7 @@ function parseLocalConfig(config) {
223
235
  function doInOrder(arg1, arg2) {
224
236
  return state.isPromise(arg1) ? arg1.then(arg2) : arg2(arg1);
225
237
  }
226
- function onChangeRemote(cb) {
238
+ function onChangeRemote2(cb) {
227
239
  state.endBatch(true);
228
240
  globalState.isLoadingRemote = true;
229
241
  state.beginBatch();
@@ -580,7 +592,7 @@ async function doChangeRemote(changeInfo) {
580
592
  if (waitForSetParam) {
581
593
  await waitForSet(waitForSetParam, changesRemote, obs$.peek());
582
594
  }
583
- let value = clone(obs$.peek());
595
+ let value = clone2(obs$.peek());
584
596
  const transformSave = (_a = syncOptions == null ? void 0 : syncOptions.transform) == null ? void 0 : _a.save;
585
597
  if (transformSave) {
586
598
  value = transformSave(value);
@@ -593,31 +605,38 @@ async function doChangeRemote(changeInfo) {
593
605
  onBeforeSet == null ? void 0 : onBeforeSet(beforeSetParams);
594
606
  if (!beforeSetParams.cancel) {
595
607
  let updateResult = void 0;
596
- let errorHandled = false;
597
- const onError = (error, retryParams) => {
608
+ let lastErrorHandled;
609
+ const onSetError = (error, params, noThrow) => {
598
610
  var _a2;
599
- state$.error.set(error);
600
- if (!errorHandled) {
601
- (_a2 = syncOptions.onError) == null ? void 0 : _a2.call(syncOptions, error, {
602
- setParams,
603
- source: "set",
604
- value$: obs$,
605
- retryParams
606
- });
611
+ if (lastErrorHandled !== error) {
612
+ if (!params) {
613
+ params = {
614
+ setParams,
615
+ source: "set",
616
+ type: "set",
617
+ input: value,
618
+ retry: setParams,
619
+ revert: createRevertChanges(setParams.value$, setParams.changes)
620
+ };
621
+ }
622
+ state$.error.set(error);
623
+ (_a2 = syncOptions.onError) == null ? void 0 : _a2.call(syncOptions, error, params);
624
+ lastErrorHandled = error;
625
+ if (!noThrow) {
626
+ throw error;
627
+ }
607
628
  }
608
- errorHandled = true;
609
629
  };
610
630
  const setParams = {
611
631
  node,
612
632
  value$: obs$,
613
633
  changes: changesRemote,
614
634
  value,
615
- onError,
635
+ onError: onSetError,
616
636
  update: (params) => {
617
637
  if (updateResult) {
618
- const { value: value2, lastSync, mode } = params;
638
+ const { value: value2, mode } = params;
619
639
  updateResult = {
620
- lastSync: Math.max(updateResult.lastSync || 0, lastSync || 0),
621
640
  value: deepMerge(updateResult.value, value2),
622
641
  mode
623
642
  };
@@ -629,26 +648,21 @@ async function doChangeRemote(changeInfo) {
629
648
  retryNum: 0,
630
649
  cancelRetry: false
631
650
  };
632
- const savedPromise = runWithRetry(
633
- setParams,
634
- syncOptions.retry,
635
- async () => {
636
- return syncOptions.set(setParams);
637
- },
638
- onError
639
- );
651
+ const savedPromise = runWithRetry(setParams, syncOptions.retry, node, async () => {
652
+ return syncOptions.set(setParams);
653
+ });
640
654
  let didError = false;
641
655
  if (state.isPromise(savedPromise)) {
642
656
  await savedPromise.catch((error) => {
643
657
  didError = true;
644
658
  if (!syncOptions.retry) {
645
- onError(error);
659
+ onSetError(error, void 0, true);
646
660
  }
647
661
  });
648
662
  }
649
663
  if (!didError) {
650
664
  const pathStrs = Array.from(new Set(changesRemote.map((change) => change.pathStr)));
651
- const { value: changes, lastSync } = updateResult || {};
665
+ const { value: changes } = updateResult || {};
652
666
  if (pathStrs.length > 0) {
653
667
  let transformedChanges = void 0;
654
668
  const metadata = {};
@@ -665,9 +679,6 @@ async function doChangeRemote(changeInfo) {
665
679
  delete pending[pathStr];
666
680
  }
667
681
  }
668
- if (lastSync) {
669
- metadata.lastSync = lastSync;
670
- }
671
682
  }
672
683
  if (changes && !state.isEmpty(changes)) {
673
684
  transformedChanges = transformLoadData(changes, syncOptions, false, "set");
@@ -676,7 +687,7 @@ async function doChangeRemote(changeInfo) {
676
687
  if (state.isPromise(transformedChanges)) {
677
688
  transformedChanges = await transformedChanges;
678
689
  }
679
- onChangeRemote(() => state.mergeIntoObservable(obs$, transformedChanges));
690
+ onChangeRemote2(() => state.mergeIntoObservable(obs$, transformedChanges));
680
691
  }
681
692
  if (saveLocal) {
682
693
  if (shouldSaveMetadata && !state.isEmpty(metadata)) {
@@ -819,14 +830,24 @@ function syncObservable(obs$, syncOptionsOrSynced) {
819
830
  const syncStateValue = getNodeValue(getNode(syncState$));
820
831
  allSyncStates.set(syncState$, node);
821
832
  syncStateValue.getPendingChanges = () => localState.pendingChanges;
822
- let errorHandled = false;
823
- const onGetError = (error, params) => {
833
+ let lastErrorHandled;
834
+ const onGetError = (error, params, noThrow) => {
824
835
  var _a;
825
- syncState$.error.set(error);
826
- if (!errorHandled) {
827
- (_a = syncOptions.onError) == null ? void 0 : _a.call(syncOptions, error, { ...params, value$: obs$ });
836
+ if (lastErrorHandled !== error) {
837
+ if (!params) {
838
+ params = {
839
+ source: "get",
840
+ type: "get",
841
+ retry: params
842
+ };
843
+ }
844
+ syncState$.error.set(error);
845
+ (_a = syncOptions.onError) == null ? void 0 : _a.call(syncOptions, error, params);
846
+ lastErrorHandled = error;
847
+ if (!noThrow) {
848
+ throw error;
849
+ }
828
850
  }
829
- errorHandled = true;
830
851
  };
831
852
  loadLocal(obs$, syncOptions, syncState$, localState);
832
853
  let isWaitingForLoad = !!syncOptions.get;
@@ -892,7 +913,7 @@ function syncObservable(obs$, syncOptionsOrSynced) {
892
913
  const p = key.split("/").filter((k) => k !== "");
893
914
  const { v, t } = pending2[key];
894
915
  if (t.length === 0 || !value) {
895
- const oldValue = clone(value);
916
+ const oldValue = clone2(value);
896
917
  pending2[key].p = oldValue;
897
918
  if (state.isObject(value) && state.isObject(v)) {
898
919
  Object.assign(value, v);
@@ -906,7 +927,7 @@ function syncObservable(obs$, syncOptionsOrSynced) {
906
927
  delete pending2[key];
907
928
  didChangeMetadata = true;
908
929
  } else {
909
- const oldValue = clone(value);
930
+ const oldValue = clone2(value);
910
931
  pending2[key].p = getValueAtPath(oldValue, p);
911
932
  value = state.setAtPath(
912
933
  value,
@@ -933,7 +954,7 @@ function syncObservable(obs$, syncOptionsOrSynced) {
933
954
  });
934
955
  }
935
956
  }
936
- onChangeRemote(() => {
957
+ onChangeRemote2(() => {
937
958
  if (state.isPlainObject(value)) {
938
959
  value = state.ObservableHint.plain(value);
939
960
  }
@@ -992,7 +1013,12 @@ function syncObservable(obs$, syncOptionsOrSynced) {
992
1013
  );
993
1014
  },
994
1015
  refresh: () => state.when(syncState$.isLoaded, sync),
995
- onError: (error) => onGetError(error, { source: "subscribe", subscribeParams })
1016
+ onError: (error) => onGetError(error, {
1017
+ source: "subscribe",
1018
+ subscribeParams,
1019
+ type: "get",
1020
+ retry: {}
1021
+ })
996
1022
  };
997
1023
  unsubscribe = subscribe2(subscribeParams);
998
1024
  };
@@ -1004,7 +1030,6 @@ function syncObservable(obs$, syncOptionsOrSynced) {
1004
1030
  }
1005
1031
  const existingValue = getNodeValue(node);
1006
1032
  if (get) {
1007
- const onError = (error) => onGetError(error, { getParams, source: "get" });
1008
1033
  const getParams = {
1009
1034
  node,
1010
1035
  value$: obs$,
@@ -1014,7 +1039,7 @@ function syncObservable(obs$, syncOptionsOrSynced) {
1014
1039
  options: syncOptions,
1015
1040
  lastSync,
1016
1041
  updateLastSync: (lastSync2) => getParams.lastSync = lastSync2,
1017
- onError,
1042
+ onError: onGetError,
1018
1043
  retryNum: 0,
1019
1044
  cancelRetry: false
1020
1045
  };
@@ -1043,17 +1068,12 @@ function syncObservable(obs$, syncOptionsOrSynced) {
1043
1068
  numPendingGets: (syncStateValue.numPendingGets || 0) + 1,
1044
1069
  isGetting: true
1045
1070
  });
1046
- const got = runWithRetry(
1047
- getParams,
1048
- syncOptions.retry,
1049
- (retryEvent) => {
1050
- const params = getParams;
1051
- params.cancelRetry = retryEvent.cancelRetry;
1052
- params.retryNum = retryEvent.retryNum;
1053
- return get(params);
1054
- },
1055
- onError
1056
- );
1071
+ const got = runWithRetry(getParams, syncOptions.retry, node, (retryEvent) => {
1072
+ const params = getParams;
1073
+ params.cancelRetry = retryEvent.cancelRetry;
1074
+ params.retryNum = retryEvent.retryNum;
1075
+ return get(params);
1076
+ });
1057
1077
  const numGets = node.numGets = (node.numGets || 0) + 1;
1058
1078
  const handle = (value) => {
1059
1079
  syncState$.numPendingGets.set((v) => v - 1);
@@ -1080,7 +1100,13 @@ function syncObservable(obs$, syncOptionsOrSynced) {
1080
1100
  });
1081
1101
  };
1082
1102
  if (state.isPromise(got)) {
1083
- got.then(handle).catch(onError);
1103
+ got.then(handle).catch((error) => {
1104
+ onGetError(
1105
+ error,
1106
+ { getParams, source: "get", type: "get", retry: getParams },
1107
+ true
1108
+ );
1109
+ });
1084
1110
  } else {
1085
1111
  handle(got);
1086
1112
  }
@@ -1133,7 +1159,7 @@ function syncObservable(obs$, syncOptionsOrSynced) {
1133
1159
  unsubscribe == null ? void 0 : unsubscribe();
1134
1160
  unsubscribe = void 0;
1135
1161
  const promise = syncStateValue.resetPersistence();
1136
- onChangeRemote(() => {
1162
+ onChangeRemote2(() => {
1137
1163
  var _a;
1138
1164
  obs$.set((_a = syncOptions.initial) != null ? _a : void 0);
1139
1165
  });
@@ -1238,19 +1264,21 @@ function configureSynced(fnOrOrigOptions, origOptions) {
1238
1264
  }
1239
1265
 
1240
1266
  // sync.ts
1241
- var internal4 = {
1267
+ var internal5 = {
1242
1268
  observableSyncConfiguration,
1243
- waitForSet
1269
+ waitForSet,
1270
+ runWithRetry
1244
1271
  };
1245
1272
 
1246
1273
  exports.combineTransforms = combineTransforms;
1247
1274
  exports.configureObservableSync = configureObservableSync;
1248
1275
  exports.configureSynced = configureSynced;
1276
+ exports.createRevertChanges = createRevertChanges;
1249
1277
  exports.deepEqual = deepEqual;
1250
1278
  exports.diffObjects = diffObjects;
1251
- exports.internal = internal4;
1279
+ exports.internal = internal5;
1252
1280
  exports.mapSyncPlugins = mapSyncPlugins;
1253
- exports.onChangeRemote = onChangeRemote;
1281
+ exports.onChangeRemote = onChangeRemote2;
1254
1282
  exports.removeNullUndefined = removeNullUndefined;
1255
1283
  exports.syncObservable = syncObservable;
1256
1284
  exports.synced = synced;
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 = {};
@@ -159,13 +160,13 @@ function createRetryTimeout(retryOptions, retryNum, fn) {
159
160
  }
160
161
  }
161
162
  var mapRetryTimeouts = /* @__PURE__ */ new Map();
162
- function runWithRetry(state, retryOptions, fn, onError) {
163
+ function runWithRetry(state, retryOptions, retryId, fn) {
163
164
  try {
164
165
  let value = fn(state);
165
166
  if (isPromise(value) && retryOptions) {
166
167
  let timeoutRetry;
167
- if (mapRetryTimeouts.has(state.node)) {
168
- clearTimeout(mapRetryTimeouts.get(state.node));
168
+ if (mapRetryTimeouts.has(retryId)) {
169
+ clearTimeout(mapRetryTimeouts.get(retryId));
169
170
  }
170
171
  return new Promise((resolve, reject) => {
171
172
  const run = () => {
@@ -176,9 +177,6 @@ function runWithRetry(state, retryOptions, fn, onError) {
176
177
  if (timeoutRetry) {
177
178
  clearTimeout(timeoutRetry);
178
179
  }
179
- if (onError) {
180
- onError(error, state);
181
- }
182
180
  if (!state.cancelRetry) {
183
181
  const timeout = createRetryTimeout(retryOptions, state.retryNum, () => {
184
182
  value = fn(state);
@@ -188,7 +186,7 @@ function runWithRetry(state, retryOptions, fn, onError) {
188
186
  state.cancelRetry = true;
189
187
  reject(error);
190
188
  } else {
191
- mapRetryTimeouts.set(state.node, timeout);
189
+ mapRetryTimeouts.set(retryId, timeout);
192
190
  timeoutRetry = timeout;
193
191
  }
194
192
  }
@@ -208,9 +206,23 @@ async function waitForSet(waitForSet2, changes, value, params = {}) {
208
206
  await when(waitFn);
209
207
  }
210
208
  }
209
+ var { clone } = internal;
210
+ function createRevertChanges(obs$, changes) {
211
+ return () => {
212
+ const previous = applyChanges(
213
+ clone(obs$.peek()),
214
+ changes,
215
+ /*applyPrevious*/
216
+ true
217
+ );
218
+ onChangeRemote(() => {
219
+ obs$.set(previous);
220
+ });
221
+ };
222
+ }
211
223
 
212
224
  // src/sync/syncObservable.ts
213
- var { clone, deepMerge, getNode, getNodeValue, getValueAtPath, globalState, symbolLinked, createPreviousHandler } = internal;
225
+ var { clone: clone2, deepMerge, getNode, getNodeValue, getValueAtPath, globalState, symbolLinked, createPreviousHandler } = internal;
214
226
  var mapSyncPlugins = /* @__PURE__ */ new WeakMap();
215
227
  var allSyncStates = /* @__PURE__ */ new Map();
216
228
  var metadatas = /* @__PURE__ */ new WeakMap();
@@ -221,7 +233,7 @@ function parseLocalConfig(config) {
221
233
  function doInOrder(arg1, arg2) {
222
234
  return isPromise$1(arg1) ? arg1.then(arg2) : arg2(arg1);
223
235
  }
224
- function onChangeRemote(cb) {
236
+ function onChangeRemote2(cb) {
225
237
  endBatch(true);
226
238
  globalState.isLoadingRemote = true;
227
239
  beginBatch();
@@ -578,7 +590,7 @@ async function doChangeRemote(changeInfo) {
578
590
  if (waitForSetParam) {
579
591
  await waitForSet(waitForSetParam, changesRemote, obs$.peek());
580
592
  }
581
- let value = clone(obs$.peek());
593
+ let value = clone2(obs$.peek());
582
594
  const transformSave = (_a = syncOptions == null ? void 0 : syncOptions.transform) == null ? void 0 : _a.save;
583
595
  if (transformSave) {
584
596
  value = transformSave(value);
@@ -591,31 +603,38 @@ async function doChangeRemote(changeInfo) {
591
603
  onBeforeSet == null ? void 0 : onBeforeSet(beforeSetParams);
592
604
  if (!beforeSetParams.cancel) {
593
605
  let updateResult = void 0;
594
- let errorHandled = false;
595
- const onError = (error, retryParams) => {
606
+ let lastErrorHandled;
607
+ const onSetError = (error, params, noThrow) => {
596
608
  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
- });
609
+ if (lastErrorHandled !== error) {
610
+ if (!params) {
611
+ params = {
612
+ setParams,
613
+ source: "set",
614
+ type: "set",
615
+ input: value,
616
+ retry: setParams,
617
+ revert: createRevertChanges(setParams.value$, setParams.changes)
618
+ };
619
+ }
620
+ state$.error.set(error);
621
+ (_a2 = syncOptions.onError) == null ? void 0 : _a2.call(syncOptions, error, params);
622
+ lastErrorHandled = error;
623
+ if (!noThrow) {
624
+ throw error;
625
+ }
605
626
  }
606
- errorHandled = true;
607
627
  };
608
628
  const setParams = {
609
629
  node,
610
630
  value$: obs$,
611
631
  changes: changesRemote,
612
632
  value,
613
- onError,
633
+ onError: onSetError,
614
634
  update: (params) => {
615
635
  if (updateResult) {
616
- const { value: value2, lastSync, mode } = params;
636
+ const { value: value2, mode } = params;
617
637
  updateResult = {
618
- lastSync: Math.max(updateResult.lastSync || 0, lastSync || 0),
619
638
  value: deepMerge(updateResult.value, value2),
620
639
  mode
621
640
  };
@@ -627,26 +646,21 @@ async function doChangeRemote(changeInfo) {
627
646
  retryNum: 0,
628
647
  cancelRetry: false
629
648
  };
630
- const savedPromise = runWithRetry(
631
- setParams,
632
- syncOptions.retry,
633
- async () => {
634
- return syncOptions.set(setParams);
635
- },
636
- onError
637
- );
649
+ const savedPromise = runWithRetry(setParams, syncOptions.retry, node, async () => {
650
+ return syncOptions.set(setParams);
651
+ });
638
652
  let didError = false;
639
653
  if (isPromise$1(savedPromise)) {
640
654
  await savedPromise.catch((error) => {
641
655
  didError = true;
642
656
  if (!syncOptions.retry) {
643
- onError(error);
657
+ onSetError(error, void 0, true);
644
658
  }
645
659
  });
646
660
  }
647
661
  if (!didError) {
648
662
  const pathStrs = Array.from(new Set(changesRemote.map((change) => change.pathStr)));
649
- const { value: changes, lastSync } = updateResult || {};
663
+ const { value: changes } = updateResult || {};
650
664
  if (pathStrs.length > 0) {
651
665
  let transformedChanges = void 0;
652
666
  const metadata = {};
@@ -663,9 +677,6 @@ async function doChangeRemote(changeInfo) {
663
677
  delete pending[pathStr];
664
678
  }
665
679
  }
666
- if (lastSync) {
667
- metadata.lastSync = lastSync;
668
- }
669
680
  }
670
681
  if (changes && !isEmpty(changes)) {
671
682
  transformedChanges = transformLoadData(changes, syncOptions, false, "set");
@@ -674,7 +685,7 @@ async function doChangeRemote(changeInfo) {
674
685
  if (isPromise$1(transformedChanges)) {
675
686
  transformedChanges = await transformedChanges;
676
687
  }
677
- onChangeRemote(() => mergeIntoObservable(obs$, transformedChanges));
688
+ onChangeRemote2(() => mergeIntoObservable(obs$, transformedChanges));
678
689
  }
679
690
  if (saveLocal) {
680
691
  if (shouldSaveMetadata && !isEmpty(metadata)) {
@@ -817,14 +828,24 @@ function syncObservable(obs$, syncOptionsOrSynced) {
817
828
  const syncStateValue = getNodeValue(getNode(syncState$));
818
829
  allSyncStates.set(syncState$, node);
819
830
  syncStateValue.getPendingChanges = () => localState.pendingChanges;
820
- let errorHandled = false;
821
- const onGetError = (error, params) => {
831
+ let lastErrorHandled;
832
+ const onGetError = (error, params, noThrow) => {
822
833
  var _a;
823
- syncState$.error.set(error);
824
- if (!errorHandled) {
825
- (_a = syncOptions.onError) == null ? void 0 : _a.call(syncOptions, error, { ...params, value$: obs$ });
834
+ if (lastErrorHandled !== error) {
835
+ if (!params) {
836
+ params = {
837
+ source: "get",
838
+ type: "get",
839
+ retry: params
840
+ };
841
+ }
842
+ syncState$.error.set(error);
843
+ (_a = syncOptions.onError) == null ? void 0 : _a.call(syncOptions, error, params);
844
+ lastErrorHandled = error;
845
+ if (!noThrow) {
846
+ throw error;
847
+ }
826
848
  }
827
- errorHandled = true;
828
849
  };
829
850
  loadLocal(obs$, syncOptions, syncState$, localState);
830
851
  let isWaitingForLoad = !!syncOptions.get;
@@ -890,7 +911,7 @@ function syncObservable(obs$, syncOptionsOrSynced) {
890
911
  const p = key.split("/").filter((k) => k !== "");
891
912
  const { v, t } = pending2[key];
892
913
  if (t.length === 0 || !value) {
893
- const oldValue = clone(value);
914
+ const oldValue = clone2(value);
894
915
  pending2[key].p = oldValue;
895
916
  if (isObject(value) && isObject(v)) {
896
917
  Object.assign(value, v);
@@ -904,7 +925,7 @@ function syncObservable(obs$, syncOptionsOrSynced) {
904
925
  delete pending2[key];
905
926
  didChangeMetadata = true;
906
927
  } else {
907
- const oldValue = clone(value);
928
+ const oldValue = clone2(value);
908
929
  pending2[key].p = getValueAtPath(oldValue, p);
909
930
  value = setAtPath(
910
931
  value,
@@ -931,7 +952,7 @@ function syncObservable(obs$, syncOptionsOrSynced) {
931
952
  });
932
953
  }
933
954
  }
934
- onChangeRemote(() => {
955
+ onChangeRemote2(() => {
935
956
  if (isPlainObject(value)) {
936
957
  value = ObservableHint.plain(value);
937
958
  }
@@ -990,7 +1011,12 @@ function syncObservable(obs$, syncOptionsOrSynced) {
990
1011
  );
991
1012
  },
992
1013
  refresh: () => when(syncState$.isLoaded, sync),
993
- onError: (error) => onGetError(error, { source: "subscribe", subscribeParams })
1014
+ onError: (error) => onGetError(error, {
1015
+ source: "subscribe",
1016
+ subscribeParams,
1017
+ type: "get",
1018
+ retry: {}
1019
+ })
994
1020
  };
995
1021
  unsubscribe = subscribe2(subscribeParams);
996
1022
  };
@@ -1002,7 +1028,6 @@ function syncObservable(obs$, syncOptionsOrSynced) {
1002
1028
  }
1003
1029
  const existingValue = getNodeValue(node);
1004
1030
  if (get) {
1005
- const onError = (error) => onGetError(error, { getParams, source: "get" });
1006
1031
  const getParams = {
1007
1032
  node,
1008
1033
  value$: obs$,
@@ -1012,7 +1037,7 @@ function syncObservable(obs$, syncOptionsOrSynced) {
1012
1037
  options: syncOptions,
1013
1038
  lastSync,
1014
1039
  updateLastSync: (lastSync2) => getParams.lastSync = lastSync2,
1015
- onError,
1040
+ onError: onGetError,
1016
1041
  retryNum: 0,
1017
1042
  cancelRetry: false
1018
1043
  };
@@ -1041,17 +1066,12 @@ function syncObservable(obs$, syncOptionsOrSynced) {
1041
1066
  numPendingGets: (syncStateValue.numPendingGets || 0) + 1,
1042
1067
  isGetting: true
1043
1068
  });
1044
- const got = runWithRetry(
1045
- getParams,
1046
- syncOptions.retry,
1047
- (retryEvent) => {
1048
- const params = getParams;
1049
- params.cancelRetry = retryEvent.cancelRetry;
1050
- params.retryNum = retryEvent.retryNum;
1051
- return get(params);
1052
- },
1053
- onError
1054
- );
1069
+ const got = runWithRetry(getParams, syncOptions.retry, node, (retryEvent) => {
1070
+ const params = getParams;
1071
+ params.cancelRetry = retryEvent.cancelRetry;
1072
+ params.retryNum = retryEvent.retryNum;
1073
+ return get(params);
1074
+ });
1055
1075
  const numGets = node.numGets = (node.numGets || 0) + 1;
1056
1076
  const handle = (value) => {
1057
1077
  syncState$.numPendingGets.set((v) => v - 1);
@@ -1078,7 +1098,13 @@ function syncObservable(obs$, syncOptionsOrSynced) {
1078
1098
  });
1079
1099
  };
1080
1100
  if (isPromise$1(got)) {
1081
- got.then(handle).catch(onError);
1101
+ got.then(handle).catch((error) => {
1102
+ onGetError(
1103
+ error,
1104
+ { getParams, source: "get", type: "get", retry: getParams },
1105
+ true
1106
+ );
1107
+ });
1082
1108
  } else {
1083
1109
  handle(got);
1084
1110
  }
@@ -1131,7 +1157,7 @@ function syncObservable(obs$, syncOptionsOrSynced) {
1131
1157
  unsubscribe == null ? void 0 : unsubscribe();
1132
1158
  unsubscribe = void 0;
1133
1159
  const promise = syncStateValue.resetPersistence();
1134
- onChangeRemote(() => {
1160
+ onChangeRemote2(() => {
1135
1161
  var _a;
1136
1162
  obs$.set((_a = syncOptions.initial) != null ? _a : void 0);
1137
1163
  });
@@ -1236,9 +1262,10 @@ function configureSynced(fnOrOrigOptions, origOptions) {
1236
1262
  }
1237
1263
 
1238
1264
  // sync.ts
1239
- var internal4 = {
1265
+ var internal5 = {
1240
1266
  observableSyncConfiguration,
1241
- waitForSet
1267
+ waitForSet,
1268
+ runWithRetry
1242
1269
  };
1243
1270
 
1244
- export { combineTransforms, configureObservableSync, configureSynced, deepEqual, diffObjects, internal4 as internal, mapSyncPlugins, onChangeRemote, removeNullUndefined, syncObservable, synced, transformStringifyDates, transformStringifyKeys };
1271
+ export { combineTransforms, configureObservableSync, configureSynced, createRevertChanges, deepEqual, diffObjects, internal5 as internal, mapSyncPlugins, onChangeRemote2 as onChangeRemote, removeNullUndefined, syncObservable, synced, transformStringifyDates, transformStringifyKeys };