@legendapp/state 2.2.0-next.41 → 2.2.0-next.43

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/index.d.ts CHANGED
@@ -28,7 +28,7 @@ export declare const internal: {
28
28
  isLoadingLocal: boolean;
29
29
  isMerging: boolean;
30
30
  isLoadingRemote$: import("./src/observableTypes").ObservablePrimitive<boolean>;
31
- activateNode: (node: import("./src/observableInterfaces").NodeValue, refresh: () => void, wasPromise: boolean, newValue: any) => {
31
+ activateNodePersist: (node: import("./src/observableInterfaces").NodeValue, newValue: any) => {
32
32
  update: import("./src/observableInterfaces").UpdateFn;
33
33
  value: any;
34
34
  };
package/index.js CHANGED
@@ -62,14 +62,11 @@ const symbolDelete = /* @__PURE__ */ Symbol('delete');
62
62
  const symbolOpaque = Symbol('opaque');
63
63
  const optimized = Symbol('optimized');
64
64
  const symbolActivated = Symbol('activated');
65
- // TODOV3 Remove these
66
- const extraPrimitiveActivators = new Map();
67
- const extraPrimitiveProps = new Map();
68
65
  const globalState = {
69
66
  isLoadingLocal: false,
70
67
  isMerging: false,
71
68
  isLoadingRemote$: undefined,
72
- activateNode: undefined,
69
+ activateNodePersist: undefined,
73
70
  pendingNodes: new Map(),
74
71
  dirtyNodes: new Set(),
75
72
  };
@@ -94,13 +91,6 @@ function setNodeValue(node, newValue) {
94
91
  const isFunc = isFunction(newValue);
95
92
  // Compute newValue if newValue is a function or an observable
96
93
  newValue = !parentNode.isAssigning && isFunc ? newValue(prevValue) : newValue;
97
- // If setting an observable, set a link to the observable instead
98
- if (isObservable(newValue)) {
99
- const val = newValue;
100
- node.lazy = true;
101
- node.lazyFn = () => val;
102
- newValue = undefined;
103
- }
104
94
  if (!globalState.isMerging ||
105
95
  prevValue === undefined ||
106
96
  isFunction(prevValue) ||
@@ -137,7 +127,7 @@ function getNodeValue(node) {
137
127
  return child;
138
128
  }
139
129
  function getChildNode(node, key, asFunction) {
140
- var _a;
130
+ var _a, _b;
141
131
  // Get the child by key
142
132
  let child = (_a = node.children) === null || _a === void 0 ? void 0 : _a.get(key);
143
133
  // Create the child node if it doesn't already exist
@@ -148,11 +138,9 @@ function getChildNode(node, key, asFunction) {
148
138
  key,
149
139
  lazy: true,
150
140
  };
151
- if (node.activationState) {
152
- const { lookup } = node.activationState;
153
- if (lookup) {
154
- asFunction = lookup.bind(node, key);
155
- }
141
+ // Lookup functions are bound with the child key
142
+ if (((_b = node.lazyFn) === null || _b === void 0 ? void 0 : _b.length) === 1) {
143
+ asFunction = node.lazyFn.bind(node, key);
156
144
  }
157
145
  if (asFunction) {
158
146
  child = Object.assign(() => { }, child);
@@ -167,7 +155,7 @@ function getChildNode(node, key, asFunction) {
167
155
  }
168
156
  function ensureNodeValue(node) {
169
157
  let value = getNodeValue(node);
170
- if (!value) {
158
+ if (!value || isFunction(value)) {
171
159
  if (isChildNodeValue(node)) {
172
160
  const parent = ensureNodeValue(node.parent);
173
161
  value = parent[node.key] = {};
@@ -322,7 +310,8 @@ function computeChangesRecursive(changesInBatch, node, value, path, pathTypes, v
322
310
  computeChangesAtNode(changesInBatch, node, value, path, pathTypes, valueAtPath, prevAtPath, immediate, level, whenOptimizedOnlyIf);
323
311
  if (node.linkedFromNodes) {
324
312
  for (const linkedFromNode of node.linkedFromNodes) {
325
- computeChangesAtNode(changesInBatch, linkedFromNode, value, path, pathTypes, valueAtPath, prevAtPath, immediate, level, whenOptimizedOnlyIf);
313
+ const childNode = getNodeAtPath(linkedFromNode, path);
314
+ computeChangesRecursive(changesInBatch, childNode, valueAtPath, [], [], valueAtPath, prevAtPath, immediate, 0, whenOptimizedOnlyIf);
326
315
  }
327
316
  }
328
317
  // If not root notify up through parents
@@ -461,6 +450,14 @@ function endBatch(force) {
461
450
  }
462
451
  }
463
452
  }
453
+ function getNodeAtPath(obj, path) {
454
+ let o = obj;
455
+ for (let i = 0; i < path.length; i++) {
456
+ const p = path[i];
457
+ o = getChildNode(o, p);
458
+ }
459
+ return o;
460
+ }
464
461
 
465
462
  function createObservable(value, makePrimitive, extractPromise, createObject, createPrimitive) {
466
463
  const valueIsPromise = isPromise(value);
@@ -651,7 +648,8 @@ function setSilently(obs, newValue) {
651
648
  return setNodeValue(node, newValue).newValue;
652
649
  }
653
650
 
654
- function onChange(node, callback, options = {}) {
651
+ function onChange(node, callback, options = {}, fromLinks) {
652
+ var _a;
655
653
  const { initial, immediate, noArgs } = options;
656
654
  const { trackingType } = options;
657
655
  let listeners = immediate ? node.listenersImmediate : node.listeners;
@@ -685,15 +683,79 @@ function onChange(node, callback, options = {}) {
685
683
  getPrevious: () => undefined,
686
684
  });
687
685
  }
688
- let extraDispose;
686
+ let extraDisposes;
687
+ function addLinkedNodeListeners(childNode, cb = callback, from) {
688
+ // Don't add listeners for the same node more than once
689
+ if (!(fromLinks === null || fromLinks === void 0 ? void 0 : fromLinks.has(childNode))) {
690
+ fromLinks || (fromLinks = new Set());
691
+ fromLinks.add(from || node);
692
+ cb || (cb = callback);
693
+ const childOptions = {
694
+ trackingType: true,
695
+ ...options,
696
+ };
697
+ // onChange for the linked node
698
+ extraDisposes = [...(extraDisposes || []), onChange(childNode, cb, childOptions, fromLinks)];
699
+ }
700
+ }
701
+ // Add listeners for linked to nodes
689
702
  if (node.linkedToNode) {
690
- extraDispose = onChange(node.linkedToNode, callback, options);
703
+ addLinkedNodeListeners(node.linkedToNode);
704
+ }
705
+ // Add listeners for linked from nodes
706
+ (_a = node.linkedFromNodes) === null || _a === void 0 ? void 0 : _a.forEach((linkedFromNode) => addLinkedNodeListeners(linkedFromNode));
707
+ // Go up through the parents and add listeners for linked from nodes
708
+ let parent = node.parent;
709
+ let pathParent = [node.key];
710
+ while (parent) {
711
+ if (parent.linkedFromNodes) {
712
+ for (const linkedFromNode of parent.linkedFromNodes) {
713
+ if (!(fromLinks === null || fromLinks === void 0 ? void 0 : fromLinks.has(linkedFromNode))) {
714
+ const cb = createCb(linkedFromNode, pathParent, callback);
715
+ addLinkedNodeListeners(linkedFromNode, cb, parent);
716
+ }
717
+ }
718
+ }
719
+ pathParent = [parent.key, ...pathParent];
720
+ parent = parent.parent;
691
721
  }
692
722
  return () => {
693
723
  listeners.delete(listener);
694
- extraDispose === null || extraDispose === void 0 ? void 0 : extraDispose();
724
+ extraDisposes === null || extraDisposes === void 0 ? void 0 : extraDisposes.forEach((fn) => fn());
725
+ };
726
+ }
727
+ function createCb(linkedFromNode, path, callback) {
728
+ // Create a callback for a path that calls it with the current value at the path
729
+ let { valueAtPath: prevAtPath } = getValueAtPath(getNodeValue(linkedFromNode), path);
730
+ return function ({ value: valueA }) {
731
+ const { valueAtPath, pathTypes } = getValueAtPath(valueA, path);
732
+ if (valueAtPath !== prevAtPath) {
733
+ callback({
734
+ value: valueAtPath,
735
+ changes: [
736
+ {
737
+ path,
738
+ pathTypes,
739
+ prevAtPath,
740
+ valueAtPath,
741
+ },
742
+ ],
743
+ getPrevious: () => prevAtPath,
744
+ });
745
+ }
746
+ prevAtPath = valueAtPath;
695
747
  };
696
748
  }
749
+ function getValueAtPath(obj, path) {
750
+ let o = obj;
751
+ const pathTypes = [];
752
+ for (let i = 0; o && i < path.length; i++) {
753
+ pathTypes.push(isArray(o) ? 'array' : 'object');
754
+ const p = path[i];
755
+ o = o[p];
756
+ }
757
+ return { valueAtPath: o, pathTypes };
758
+ }
697
759
 
698
760
  function setupTracking(nodes, update, noArgs, immediate) {
699
761
  let listeners = [];
@@ -902,65 +964,6 @@ function whenReady(predicate, effect) {
902
964
  return _when(predicate, effect, true);
903
965
  }
904
966
 
905
- function calculateRetryDelay(retryOptions, attemptNum) {
906
- const { backoff, delay = 1000, infinite, times = 3, maxDelay = 30000 } = retryOptions;
907
- if (infinite || attemptNum < times) {
908
- const delayTime = Math.min(delay * (backoff === 'constant' ? 1 : 2 ** attemptNum), maxDelay);
909
- return delayTime;
910
- }
911
- return null;
912
- }
913
- function createRetryTimeout(retryOptions, attemptNum, fn) {
914
- const delayTime = calculateRetryDelay(retryOptions, attemptNum);
915
- if (delayTime) {
916
- return setTimeout(fn, delayTime);
917
- }
918
- }
919
- function runWithRetry(node, state, fn) {
920
- const { retry, waitFor } = node.activationState;
921
- const e = { cancel: false };
922
- let value = undefined;
923
- if (waitFor) {
924
- value = whenReady(waitFor, () => {
925
- node.activationState.waitFor = undefined;
926
- return fn(e);
927
- });
928
- }
929
- else {
930
- value = fn(e);
931
- }
932
- if (isPromise(value) && retry) {
933
- let timeoutRetry;
934
- return new Promise((resolve) => {
935
- const run = () => {
936
- value
937
- .then((val) => {
938
- node.activationState.persistedRetry = false;
939
- resolve(val);
940
- })
941
- .catch(() => {
942
- state.attemptNum++;
943
- if (timeoutRetry) {
944
- clearTimeout(timeoutRetry);
945
- }
946
- if (!e.cancel) {
947
- timeoutRetry = createRetryTimeout(retry, state.attemptNum, () => {
948
- value = fn(e);
949
- run();
950
- });
951
- }
952
- })
953
- .finally(() => {
954
- node.activationState.persistedRetry = false;
955
- });
956
- };
957
- run();
958
- });
959
- }
960
- return value;
961
- }
962
-
963
- const noop = () => { };
964
967
  const ArrayModifiers = new Set([
965
968
  'copyWithin',
966
969
  'fill',
@@ -979,7 +982,6 @@ const ArrayLoopers = new Set([
979
982
  'find',
980
983
  'findIndex',
981
984
  'forEach',
982
- 'includes',
983
985
  'join',
984
986
  'map',
985
987
  'some',
@@ -1249,7 +1251,6 @@ const proxyHandler = {
1249
1251
  // The exception is onChange because it needs to listen to this node for changes.
1250
1252
  // This needs to be below peek because it activates there.
1251
1253
  if (node.linkedToNode && p !== 'onChange') {
1252
- updateTracking(node);
1253
1254
  return proxyHandler.get(node.linkedToNode, p, receiver);
1254
1255
  }
1255
1256
  if (value instanceof Map || value instanceof WeakMap || value instanceof Set || value instanceof WeakSet) {
@@ -1285,20 +1286,6 @@ const proxyHandler = {
1285
1286
  if (property) {
1286
1287
  return property.get(node);
1287
1288
  }
1288
- // TODOV3 Remove this
1289
- const isValuePrimitive = isPrimitive(value);
1290
- // If accessing a key that doesn't already exist, and this node has been activated with extra keys
1291
- // then return the values that were set. This is used by enableLegendStateReact for example.
1292
- if (value === undefined || value === null || isValuePrimitive) {
1293
- if (extraPrimitiveProps.size && (node.isActivatedPrimitive || extraPrimitiveActivators.has(p))) {
1294
- node.isActivatedPrimitive = true;
1295
- const vPrim = extraPrimitiveProps.get(p);
1296
- if (vPrim !== undefined) {
1297
- return isFunction(vPrim) ? vPrim(getProxy(node)) : vPrim;
1298
- }
1299
- }
1300
- }
1301
- // /TODOV3 Remove this
1302
1289
  let vProp = value === null || value === void 0 ? void 0 : value[p];
1303
1290
  if (isObject(value) && value[symbolOpaque]) {
1304
1291
  return vProp;
@@ -1679,8 +1666,14 @@ function peek(node) {
1679
1666
  if (lazy) {
1680
1667
  const lazyFn = node.lazyFn;
1681
1668
  delete node.lazy;
1682
- if (isFunction(node) || isFunction(lazyFn)) {
1683
- value = activateNodeFunction(node, lazyFn);
1669
+ if (isFunction(lazyFn)) {
1670
+ if (lazyFn.length === 1) {
1671
+ // This is a lookup function, so return a record object
1672
+ value = {};
1673
+ }
1674
+ else {
1675
+ value = activateNodeFunction(node, lazyFn);
1676
+ }
1684
1677
  }
1685
1678
  }
1686
1679
  if (lazy || node.needsExtract) {
@@ -1695,10 +1688,8 @@ function peek(node) {
1695
1688
  function reactivateNode(node, lazyFn) {
1696
1689
  var _a, _b;
1697
1690
  (_a = node.activatedObserveDispose) === null || _a === void 0 ? void 0 : _a.call(node);
1698
- node.activatedObserveDispose = undefined;
1699
1691
  (_b = node.linkedToNodeDispose) === null || _b === void 0 ? void 0 : _b.call(node);
1700
- node.linkedToNodeDispose = undefined;
1701
- node.linkedToNode = undefined;
1692
+ node.activatedObserveDispose = node.linkedToNodeDispose = node.linkedToNode = undefined;
1702
1693
  node.lazyFn = lazyFn;
1703
1694
  node.lazy = true;
1704
1695
  }
@@ -1709,7 +1700,6 @@ function activateNodeFunction(node, lazyFn) {
1709
1700
  let wasPromise;
1710
1701
  let ignoreThisUpdate;
1711
1702
  const activateFn = lazyFn;
1712
- const doRetry = () => { var _a; return (_a = node.state) === null || _a === void 0 ? void 0 : _a.refreshNum.set((v) => v + 1); };
1713
1703
  let activatedValue;
1714
1704
  let disposes = [];
1715
1705
  let refreshFn;
@@ -1718,7 +1708,7 @@ function activateNodeFunction(node, lazyFn) {
1718
1708
  globalState.dirtyNodes.add(node);
1719
1709
  }
1720
1710
  node.activatedObserveDispose = observe(() => {
1721
- var _a, _b, _c, _d, _e, _f;
1711
+ var _a, _b, _c, _d;
1722
1712
  // const params = createNodeActivationParams(node);
1723
1713
  // Run the function at this node
1724
1714
  let value = activateFn();
@@ -1740,29 +1730,25 @@ function activateNodeFunction(node, lazyFn) {
1740
1730
  // TODO: Is calling recursively bad? If so can it be fixed?
1741
1731
  if (!node.activated) {
1742
1732
  node.activated = true;
1743
- const isCached = !!((_a = node.activationState) === null || _a === void 0 ? void 0 : _a.cache);
1744
- wasPromise = wasPromise || !!isCached;
1745
- const activateNodeFn = wasPromise ? globalState.activateNode : activateNodeBase;
1746
- const { update: newUpdate, value: newValue } = activateNodeFn(node, doRetry, !!wasPromise, value);
1733
+ let activateNodeFn = activateNodeBase;
1734
+ // If this is a Synced then run it through persistence instead of base
1735
+ if (activated === null || activated === void 0 ? void 0 : activated.synced) {
1736
+ activateNodeFn = globalState.activateNodePersist;
1737
+ wasPromise = true;
1738
+ }
1739
+ const { update: newUpdate, value: newValue } = activateNodeFn(node, value);
1747
1740
  update = newUpdate;
1748
1741
  value = newValue !== null && newValue !== void 0 ? newValue : activated === null || activated === void 0 ? void 0 : activated.initial;
1749
1742
  }
1750
1743
  else if (node.activationState) {
1751
1744
  if (!node.activationState.persistedRetry && !node.activationState.waitFor) {
1752
1745
  const activated = node.activationState;
1753
- if ((_c = (_b = node.state) === null || _b === void 0 ? void 0 : _b.peek()) === null || _c === void 0 ? void 0 : _c.sync) {
1746
+ if ((_b = (_a = node.state) === null || _a === void 0 ? void 0 : _a.peek()) === null || _b === void 0 ? void 0 : _b.sync) {
1754
1747
  node.state.sync();
1755
1748
  ignoreThisUpdate = true;
1756
1749
  }
1757
1750
  else {
1758
- value =
1759
- (_e = (_d = activated.get) === null || _d === void 0 ? void 0 : _d.call(activated, {
1760
- updateLastSync: noop,
1761
- setMode: noop,
1762
- lastSync: undefined,
1763
- value: undefined,
1764
- refresh: doRetry,
1765
- })) !== null && _e !== void 0 ? _e : activated.initial;
1751
+ value = (_d = (_c = activated.get) === null || _c === void 0 ? void 0 : _c.call(activated)) !== null && _d !== void 0 ? _d : activated.initial;
1766
1752
  }
1767
1753
  }
1768
1754
  else {
@@ -1771,7 +1757,6 @@ function activateNodeFunction(node, lazyFn) {
1771
1757
  }
1772
1758
  // value is undefined if it's in a persisted retry
1773
1759
  wasPromise = wasPromise || isPromise(value);
1774
- get(getNode((_f = node.state) === null || _f === void 0 ? void 0 : _f.refreshNum));
1775
1760
  return value;
1776
1761
  }, (e) => {
1777
1762
  if (!ignoreThisUpdate) {
@@ -1827,29 +1812,16 @@ function activateNodeFunction(node, lazyFn) {
1827
1812
  }, { fromComputed: true });
1828
1813
  return activatedValue;
1829
1814
  }
1830
- const activateNodeBase = (globalState.activateNode = function activateNodeBase(node, refresh, wasPromise, value) {
1815
+ function activateNodeBase(node, value) {
1831
1816
  if (!node.state) {
1832
1817
  node.state = createObservable({
1833
1818
  isLoaded: false,
1834
1819
  }, false, extractPromise, getProxy);
1835
1820
  }
1836
1821
  let isSetting = false;
1837
- let isSettingFromSubscribe = false;
1838
- let _mode = 'set';
1839
1822
  if (node.activationState) {
1840
- const { onSet, subscribe, get: getFn, initial } = node.activationState;
1841
- value = getFn
1842
- ? runWithRetry(node, { attemptNum: 0 }, () => {
1843
- return getFn({
1844
- updateLastSync: noop,
1845
- setMode: (mode) => (_mode = mode),
1846
- lastSync: undefined,
1847
- value: undefined,
1848
- refresh,
1849
- });
1850
- })
1851
- : undefined;
1852
- // TODO Should this have lastSync and value somehow?
1823
+ const { onSet, get: getFn, initial } = node.activationState;
1824
+ value = getFn === null || getFn === void 0 ? void 0 : getFn();
1853
1825
  if (value == undefined || value === null) {
1854
1826
  value = initial;
1855
1827
  }
@@ -1885,49 +1857,22 @@ const activateNodeBase = (globalState.activateNode = function activateNodeBase(n
1885
1857
  // set may get called multiple times before it loads so ignore any previous runs
1886
1858
  return;
1887
1859
  }
1888
- const retryAttempts = { attemptNum: 0 };
1889
- return runWithRetry(node, retryAttempts, (eventRetry) => {
1890
- const cancelRetry = () => {
1891
- eventRetry.cancel = true;
1892
- };
1893
- return new Promise((resolve, reject) => {
1894
- isSetting = true;
1895
- let isProm = false;
1896
- batch(() => {
1897
- try {
1898
- const val = onSet({
1899
- value,
1900
- changes,
1901
- getPrevious,
1902
- node,
1903
- update,
1904
- refresh,
1905
- retryNum: retryAttempts.attemptNum,
1906
- cancelRetry,
1907
- fromSubscribe: isSettingFromSubscribe,
1908
- });
1909
- isProm = isPromise(val);
1910
- if (isProm) {
1911
- val.then(resolve).catch(reject);
1912
- }
1913
- }
1914
- catch (e) {
1915
- reject(e);
1916
- }
1917
- }, () => {
1918
- if (!isProm) {
1919
- isSetting = false;
1920
- resolve();
1921
- }
1922
- });
1860
+ isSetting = true;
1861
+ batch(() => {
1862
+ onSet({
1863
+ value,
1864
+ changes,
1865
+ getPrevious,
1923
1866
  });
1867
+ }, () => {
1868
+ isSetting = false;
1924
1869
  });
1925
1870
  };
1926
1871
  whenReady(node.state.isLoaded, run);
1927
1872
  }
1928
1873
  };
1929
1874
  const onChangeImmediate = ({ value, changes }) => {
1930
- if (!isSetting || isSettingFromSubscribe) {
1875
+ if (!isSetting) {
1931
1876
  if (changes.length > 1 || !isFunction(changes[0].prevAtPath)) {
1932
1877
  latestValue = value;
1933
1878
  if (allChanges.length > 0) {
@@ -1945,68 +1890,32 @@ const activateNodeBase = (globalState.activateNode = function activateNodeBase(n
1945
1890
  onChange(node, onChangeImmediate, { immediate: true });
1946
1891
  onChange(node, runChanges);
1947
1892
  }
1948
- if (process.env.NODE_ENV === 'development' && node.activationState.cache) {
1949
- // TODO Better message
1950
- console.log('[legend-state] Using cache without setting up persistence first');
1951
- }
1952
- if (process.env.NODE_ENV === 'development' && node.activationState.retry) {
1953
- // TODO Better message
1954
- console.log('[legend-state] Using retry without setting up persistence first');
1955
- }
1956
- if (subscribe) {
1957
- const updateFromSubscribe = (params) => {
1958
- whenReady(node.state.isLoaded, () => {
1959
- isSettingFromSubscribe = true;
1960
- update(params);
1961
- isSettingFromSubscribe = false;
1962
- });
1963
- };
1964
- subscribe({ node, update: updateFromSubscribe, refresh });
1965
- }
1966
1893
  }
1967
- const update = ({ value, mode }) => {
1894
+ const update = ({ value }) => {
1968
1895
  // TODO: This isSetting might not be necessary? Tests still work if removing it.
1969
1896
  // Write tests that would break it if removed? I'd guess a combination of subscribe and
1970
1897
  if (!isSetting) {
1971
1898
  isSetting = true;
1972
- if (_mode === 'assign' || mode === 'assign') {
1973
- assign(node, value);
1974
- }
1975
- else if (_mode === 'merge' || mode === 'merge') {
1976
- mergeIntoObservable(getProxy(node), value);
1977
- }
1978
- else {
1979
- set(node, value);
1980
- }
1899
+ set(node, value);
1981
1900
  isSetting = false;
1982
1901
  }
1983
1902
  };
1984
1903
  return { update, value };
1985
- });
1904
+ }
1986
1905
  function setToObservable(node, value) {
1987
1906
  var _a;
1988
1907
  // If the computed is a proxy to another observable
1989
1908
  // link it to the target observable
1990
1909
  const linkedNode = getNode(value);
1991
1910
  if (linkedNode !== node && (linkedNode === null || linkedNode === void 0 ? void 0 : linkedNode.linkedToNode) !== node) {
1992
- const prevNode = node.linkedToNode;
1993
1911
  node.linkedToNode = linkedNode;
1994
- if (!linkedNode.linkedFromNodes) {
1995
- linkedNode.linkedFromNodes = new Set();
1996
- }
1912
+ linkedNode.linkedFromNodes || (linkedNode.linkedFromNodes = new Set());
1997
1913
  linkedNode.linkedFromNodes.add(node);
1998
- peek(linkedNode);
1999
1914
  (_a = node.linkedToNodeDispose) === null || _a === void 0 ? void 0 : _a.call(node);
2000
1915
  node.linkedToNodeDispose = onChange(linkedNode, () => {
2001
1916
  value = peek(linkedNode);
2002
1917
  set(node, value);
2003
- }, { initial: true });
2004
- // If the target observable is different then notify for the change
2005
- if (prevNode) {
2006
- const value = getNodeValue(linkedNode);
2007
- const prevValue = getNodeValue(prevNode);
2008
- notify(node, value, prevValue, 0);
2009
- }
1918
+ }, { initial: true }, new Set([node]));
2010
1919
  }
2011
1920
  return value;
2012
1921
  }
@@ -2136,14 +2045,70 @@ function event() {
2136
2045
  }
2137
2046
 
2138
2047
  function proxy(get, set) {
2139
- return observable(activated({
2140
- lookup: (key) => set
2141
- ? activated({
2142
- get: () => get(key),
2143
- onSet: ({ value }) => set(key, value),
2144
- })
2145
- : get(key),
2146
- }));
2048
+ return observable((key) => set
2049
+ ? activated({
2050
+ get: () => get(key),
2051
+ onSet: ({ value }) => set(key, value),
2052
+ })
2053
+ : get(key));
2054
+ }
2055
+
2056
+ function calculateRetryDelay(retryOptions, attemptNum) {
2057
+ const { backoff, delay = 1000, infinite, times = 3, maxDelay = 30000 } = retryOptions;
2058
+ if (infinite || attemptNum < times) {
2059
+ const delayTime = Math.min(delay * (backoff === 'constant' ? 1 : 2 ** attemptNum), maxDelay);
2060
+ return delayTime;
2061
+ }
2062
+ return null;
2063
+ }
2064
+ function createRetryTimeout(retryOptions, attemptNum, fn) {
2065
+ const delayTime = calculateRetryDelay(retryOptions, attemptNum);
2066
+ if (delayTime) {
2067
+ return setTimeout(fn, delayTime);
2068
+ }
2069
+ }
2070
+ function runWithRetry(node, state, fn) {
2071
+ const { retry, waitFor } = node.activationState;
2072
+ const e = { cancel: false };
2073
+ let value = undefined;
2074
+ if (waitFor) {
2075
+ value = whenReady(waitFor, () => {
2076
+ node.activationState.waitFor = undefined;
2077
+ return fn(e);
2078
+ });
2079
+ }
2080
+ else {
2081
+ value = fn(e);
2082
+ }
2083
+ if (isPromise(value) && retry) {
2084
+ let timeoutRetry;
2085
+ return new Promise((resolve) => {
2086
+ const run = () => {
2087
+ value
2088
+ .then((val) => {
2089
+ node.activationState.persistedRetry = false;
2090
+ resolve(val);
2091
+ })
2092
+ .catch(() => {
2093
+ state.attemptNum++;
2094
+ if (timeoutRetry) {
2095
+ clearTimeout(timeoutRetry);
2096
+ }
2097
+ if (!e.cancel) {
2098
+ timeoutRetry = createRetryTimeout(retry, state.attemptNum, () => {
2099
+ value = fn(e);
2100
+ run();
2101
+ });
2102
+ }
2103
+ })
2104
+ .finally(() => {
2105
+ node.activationState.persistedRetry = false;
2106
+ });
2107
+ };
2108
+ run();
2109
+ });
2110
+ }
2111
+ return value;
2147
2112
  }
2148
2113
 
2149
2114
  const internal = {
@@ -2177,8 +2142,6 @@ exports.deconstructObjectWithPath = deconstructObjectWithPath;
2177
2142
  exports.endBatch = endBatch;
2178
2143
  exports.endTracking = endTracking;
2179
2144
  exports.event = event;
2180
- exports.extraPrimitiveActivators = extraPrimitiveActivators;
2181
- exports.extraPrimitiveProps = extraPrimitiveProps;
2182
2145
  exports.findIDKey = findIDKey;
2183
2146
  exports.getNode = getNode;
2184
2147
  exports.getNodeValue = getNodeValue;