@legendapp/state 2.2.0-next.7 → 2.2.0-next.9

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 (62) hide show
  1. package/config/enableDirectAccess.d.ts +1 -1
  2. package/config/enableDirectPeek.d.ts +1 -1
  3. package/config/enableReactTracking.d.ts +4 -3
  4. package/config/enableReactTracking.js.map +1 -1
  5. package/config/enableReactTracking.mjs.map +1 -1
  6. package/config/enableReactUse.d.ts +1 -1
  7. package/helpers/fetch.d.ts +4 -3
  8. package/helpers/fetch.js.map +1 -1
  9. package/helpers/fetch.mjs.map +1 -1
  10. package/helpers/time.d.ts +2 -2
  11. package/history.js.map +1 -1
  12. package/history.mjs.map +1 -1
  13. package/index.d.ts +6 -1
  14. package/index.js +257 -207
  15. package/index.js.map +1 -1
  16. package/index.mjs +257 -208
  17. package/index.mjs.map +1 -1
  18. package/package.json +2 -10
  19. package/persist-plugins/firebase.js.map +1 -1
  20. package/persist-plugins/firebase.mjs.map +1 -1
  21. package/persist.d.ts +7 -5
  22. package/persist.js +132 -65
  23. package/persist.js.map +1 -1
  24. package/persist.mjs +133 -66
  25. package/persist.mjs.map +1 -1
  26. package/react-hooks/createObservableHook.js +1 -1
  27. package/react-hooks/createObservableHook.js.map +1 -1
  28. package/react-hooks/createObservableHook.mjs +1 -1
  29. package/react-hooks/createObservableHook.mjs.map +1 -1
  30. package/react-hooks/useFetch.d.ts +4 -3
  31. package/react-hooks/useFetch.js.map +1 -1
  32. package/react-hooks/useFetch.mjs.map +1 -1
  33. package/react-hooks/useObservableQuery.js.map +1 -1
  34. package/react-hooks/useObservableQuery.mjs.map +1 -1
  35. package/react.js +2 -0
  36. package/react.js.map +1 -1
  37. package/react.mjs +2 -0
  38. package/react.mjs.map +1 -1
  39. package/src/ObservableObject.d.ts +4 -3
  40. package/src/ObservablePrimitive.d.ts +2 -1
  41. package/src/activated.d.ts +3 -0
  42. package/src/computed.d.ts +1 -1
  43. package/src/config/enableDirectAccess.d.ts +1 -1
  44. package/src/config/enableDirectPeek.d.ts +1 -1
  45. package/src/config/enableReactTracking.d.ts +4 -3
  46. package/src/config/enableReactUse.d.ts +1 -1
  47. package/src/createObservable.d.ts +2 -2
  48. package/src/globals.d.ts +6 -3
  49. package/src/helpers/fetch.d.ts +4 -3
  50. package/src/helpers/time.d.ts +2 -2
  51. package/src/helpers.d.ts +3 -2
  52. package/src/history/trackHistory.d.ts +1 -1
  53. package/src/observable.d.ts +7 -12
  54. package/src/observableInterfaces.d.ts +30 -327
  55. package/src/observableTypes.d.ts +92 -0
  56. package/src/persistTypes.d.ts +224 -0
  57. package/src/proxy.d.ts +2 -1
  58. package/src/react/Computed.d.ts +1 -1
  59. package/src/react/reactInterfaces.d.ts +2 -1
  60. package/src/react/usePauseProvider.d.ts +3 -3
  61. package/src/react-hooks/useFetch.d.ts +4 -3
  62. package/src/trackSelector.d.ts +1 -1
package/index.mjs CHANGED
@@ -1,3 +1,5 @@
1
+ import { noop } from '@babel/types';
2
+
1
3
  const hasOwnProperty = Object.prototype.hasOwnProperty;
2
4
  function isArray(obj) {
3
5
  return Array.isArray(obj);
@@ -53,6 +55,7 @@ const symbolGetNode = Symbol('getNode');
53
55
  const symbolDelete = /* @__PURE__ */ Symbol('delete');
54
56
  const symbolOpaque = Symbol('opaque');
55
57
  const optimized = Symbol('optimized');
58
+ const symbolActivated = Symbol('activated');
56
59
  // TODOV3 Remove these
57
60
  const extraPrimitiveActivators = new Map();
58
61
  const extraPrimitiveProps = new Map();
@@ -156,8 +159,16 @@ function getChildNode(node, key, asFunction) {
156
159
  if (asFunction) {
157
160
  child = Object.assign(cloneFunction(asFunction), child);
158
161
  }
159
- else if (node.proxyFn2) {
160
- child = Object.assign(node.proxyFn2.bind(node, key), child);
162
+ else {
163
+ if (node.activationState) {
164
+ const { lookup } = node.activationState;
165
+ if (lookup) {
166
+ child = Object.assign(lookup.bind(node, key), child);
167
+ if (isFunction(child)) {
168
+ extractFunction(node, key, child);
169
+ }
170
+ }
171
+ }
161
172
  }
162
173
  if (!node.children) {
163
174
  node.children = new Map();
@@ -202,9 +213,11 @@ function findIDKey(obj, node) {
202
213
  return idKey;
203
214
  }
204
215
  function extractFunction(node, key, fnOrComputed, computedChildNode) {
216
+ var _a;
205
217
  if (!node.functions) {
206
218
  node.functions = new Map();
207
219
  }
220
+ (_a = node.children) === null || _a === void 0 ? void 0 : _a.delete(key);
208
221
  node.functions.set(key, fnOrComputed);
209
222
  if (computedChildNode) {
210
223
  computedChildNode.parentOther = getChildNode(node, key);
@@ -215,6 +228,12 @@ function extractFunction(node, key, fnOrComputed, computedChildNode) {
215
228
  }
216
229
  }
217
230
 
231
+ function activated(params) {
232
+ return (() => ({
233
+ [symbolActivated]: params,
234
+ }));
235
+ }
236
+
218
237
  let timeout;
219
238
  let numInBatch = 0;
220
239
  let isRunningBatch = false;
@@ -450,13 +469,37 @@ function endBatch(force) {
450
469
  }
451
470
  }
452
471
 
472
+ function createObservable(value, makePrimitive, extractPromise, createObject, createPrimitive) {
473
+ const valueIsPromise = isPromise(value);
474
+ const valueIsFunction = isFunction(value);
475
+ const root = {
476
+ _: value,
477
+ };
478
+ let node = {
479
+ root,
480
+ lazy: true,
481
+ };
482
+ if (valueIsFunction) {
483
+ node = Object.assign(cloneFunction(value), node);
484
+ }
485
+ const prim = makePrimitive || isActualPrimitive(value);
486
+ const obs = prim
487
+ ? new createPrimitive(node)
488
+ : createObject(node);
489
+ if (valueIsPromise) {
490
+ setNodeValue(node, undefined);
491
+ extractPromise(node, value);
492
+ }
493
+ return obs;
494
+ }
495
+
453
496
  function isEvent(obs) {
454
497
  var _a;
455
498
  return obs && ((_a = obs[symbolGetNode]) === null || _a === void 0 ? void 0 : _a.isEvent);
456
499
  }
457
500
  function computeSelector(selector, e, retainObservable) {
458
501
  let c = selector;
459
- if (isFunction(c)) {
502
+ if (!isObservable(c) && isFunction(c)) {
460
503
  c = e ? c(e) : c();
461
504
  }
462
505
  return isObservable(c) && !retainObservable ? c.get() : c;
@@ -561,7 +604,9 @@ function _mergeIntoObservable(target, source) {
561
604
  const key = keys[i];
562
605
  const sourceValue = source[key];
563
606
  if (sourceValue === symbolDelete) {
564
- needsSet && ((_a = target[key]) === null || _a === void 0 ? void 0 : _a.delete) ? target[key].delete() : delete target[key];
607
+ needsSet && ((_a = target[key]) === null || _a === void 0 ? void 0 : _a.delete)
608
+ ? target[key].delete()
609
+ : delete target[key];
565
610
  }
566
611
  else {
567
612
  const isObj = isObject(sourceValue);
@@ -805,6 +850,40 @@ function observe(selectorOrRun, reactionOrOptions, options) {
805
850
  };
806
851
  }
807
852
 
853
+ function setupRetry(retryOptions, refresh, attemptNum) {
854
+ const timeout = {};
855
+ let didGiveUp = false;
856
+ const { backoff, delay = 1000, infinite, times = 3, maxDelay = 30000 } = retryOptions;
857
+ let handleError;
858
+ attemptNum.current++;
859
+ if (infinite || attemptNum.current < times) {
860
+ const delayTime = Math.min(delay * (backoff === 'constant' ? 1 : 2 ** attemptNum.current), maxDelay);
861
+ handleError = () => {
862
+ timeout.current = setTimeout(refresh, delayTime);
863
+ };
864
+ }
865
+ else {
866
+ handleError = () => {
867
+ didGiveUp = true;
868
+ };
869
+ }
870
+ if (typeof window !== 'undefined') {
871
+ window.addEventListener('online', () => {
872
+ if (didGiveUp || timeout) {
873
+ if (timeout) {
874
+ clearTimeout(timeout.current);
875
+ timeout.current = undefined;
876
+ }
877
+ // Restart the backoff when coming back online
878
+ attemptNum.current = 0;
879
+ didGiveUp = false;
880
+ refresh();
881
+ }
882
+ });
883
+ }
884
+ return { handleError, timeout };
885
+ }
886
+
808
887
  function _when(predicate, effect, checkReady) {
809
888
  // If predicate is a regular Promise skip all the observable stuff
810
889
  if (isPromise(predicate)) {
@@ -859,64 +938,6 @@ function whenReady(predicate, effect) {
859
938
  return _when(predicate, effect, true);
860
939
  }
861
940
 
862
- function createObservable(value, makePrimitive, extractPromise, createObject, createPrimitive) {
863
- const valueIsPromise = isPromise(value);
864
- const valueIsFunction = isFunction(value);
865
- const root = {
866
- _: value,
867
- };
868
- let node = {
869
- root,
870
- lazy: true,
871
- };
872
- if (valueIsFunction) {
873
- node = Object.assign(cloneFunction(value), node);
874
- }
875
- const prim = makePrimitive || isActualPrimitive(value);
876
- const obs = prim
877
- ? new createPrimitive(node)
878
- : createObject(node);
879
- if (valueIsPromise) {
880
- setNodeValue(node, undefined);
881
- extractPromise(node, value);
882
- }
883
- return obs;
884
- }
885
-
886
- function setupRetry(retryOptions, refresh, attemptNum) {
887
- const timeout = {};
888
- let didGiveUp = false;
889
- const { backoff, delay = 1000, infinite, times = 3, maxDelay = 30000 } = retryOptions;
890
- let handleError;
891
- attemptNum.current++;
892
- if (infinite || attemptNum.current < times) {
893
- const delayTime = Math.min(delay * (backoff === 'constant' ? 1 : 2 ** attemptNum.current), maxDelay);
894
- handleError = () => {
895
- timeout.current = setTimeout(refresh, delayTime);
896
- };
897
- }
898
- else {
899
- handleError = () => {
900
- didGiveUp = true;
901
- };
902
- }
903
- if (typeof window !== 'undefined') {
904
- window.addEventListener('online', () => {
905
- if (didGiveUp || timeout) {
906
- if (timeout) {
907
- clearTimeout(timeout.current);
908
- timeout.current = undefined;
909
- }
910
- // Restart the backoff when coming back online
911
- attemptNum.current = 0;
912
- didGiveUp = false;
913
- refresh();
914
- }
915
- });
916
- }
917
- return { handleError, timeout };
918
- }
919
-
920
941
  const ArrayModifiers = new Set([
921
942
  'copyWithin',
922
943
  'fill',
@@ -1394,12 +1415,14 @@ function setKey(node, key, newValue, level) {
1394
1415
  console.warn(`[legend-state] Set an HTMLElement into state. You probably don't want to do that.`);
1395
1416
  }
1396
1417
  }
1418
+ const isRoot = !node.parent && key === '_';
1419
+ // TODOv3 root locking will be removed with old computeds
1397
1420
  if (node.root.locked && !node.root.set) {
1398
1421
  // This happens when modifying a locked observable such as a computed.
1399
1422
  // If merging this could be happening deep in a hierarchy so we don't want to throw errors so we'll just do nothing.
1400
1423
  // This could happen during persistence local load for example.
1401
1424
  if (globalState.isMerging) {
1402
- return;
1425
+ return isRoot ? getProxy(node) : getProxy(node, key);
1403
1426
  }
1404
1427
  else {
1405
1428
  throw new Error(process.env.NODE_ENV === 'development'
@@ -1407,7 +1430,9 @@ function setKey(node, key, newValue, level) {
1407
1430
  : '[legend-state] Modified locked observable');
1408
1431
  }
1409
1432
  }
1410
- const isRoot = !node.parent && key === '_';
1433
+ if (node.parent && !getNodeValue(node)) {
1434
+ return set(node, { [key]: newValue });
1435
+ }
1411
1436
  // Get the child node for updating and notifying
1412
1437
  const childNode = isRoot ? node : getChildNode(node, key, isFunction(newValue) ? newValue : undefined);
1413
1438
  // Set the raw value on the parent object
@@ -1593,19 +1618,17 @@ function get(node, options) {
1593
1618
  return peek(node);
1594
1619
  }
1595
1620
  function peek(node) {
1596
- const value = getNodeValue(node);
1621
+ let value = getNodeValue(node);
1597
1622
  // If node is not yet lazily computed go do that
1598
1623
  const lazy = node.lazy;
1599
1624
  if (lazy) {
1600
1625
  delete node.lazy;
1601
1626
  if (isFunction(node) || isFunction(lazy)) {
1602
- activateNodeFunction(node, lazy);
1627
+ value = activateNodeFunction(node, lazy);
1603
1628
  }
1604
- else {
1605
- for (const key in value) {
1606
- if (hasOwnProperty.call(value, key)) {
1607
- extractFunctionOrComputed(node, value, key, value[key]);
1608
- }
1629
+ for (const key in value) {
1630
+ if (hasOwnProperty.call(value, key)) {
1631
+ extractFunctionOrComputed(node, value, key, value[key]);
1609
1632
  }
1610
1633
  }
1611
1634
  }
@@ -1613,138 +1636,112 @@ function peek(node) {
1613
1636
  checkActivate(node);
1614
1637
  return value;
1615
1638
  }
1616
- function createNodeActivationParams(node) {
1617
- node.activationState = {
1618
- lastSync: {},
1619
- };
1620
- const state = node.activationState;
1621
- // The onSet function handles the observable being set
1622
- // and forwards the set elsewhere
1623
- const onSet = (onSetFnParam) => {
1624
- state.onSetFn = onSetFnParam;
1625
- };
1626
- // The onSet function handles the observable being set
1627
- // and forwards the set elsewhere
1628
- const updateLastSync = (fn) => {
1629
- state.lastSync.value = fn;
1630
- };
1631
- // The subscribe function runs a function that listens to
1632
- // a data source and sends updates into the observable
1633
- const subscribe = (fn) => {
1634
- if (!state.subscriber) {
1635
- state.subscriber = fn;
1636
- }
1637
- };
1638
- const cache = (fn) => {
1639
- if (!state.cacheOptions) {
1640
- state.cacheOptions = isFunction(fn) ? fn() : fn;
1641
- }
1642
- return new Promise((resolve) => {
1643
- const wait = () => {
1644
- if (node.state) {
1645
- when(node.state.isLoadedLocal, () => {
1646
- const dateModified = node.state.dateModified.get();
1647
- resolve({ dateModified, value: peek(node) });
1648
- });
1649
- }
1650
- else {
1651
- queueMicrotask(wait);
1652
- }
1653
- };
1654
- wait();
1655
- });
1656
- };
1657
- const retry = (params) => {
1658
- if (!state.retryOptions) {
1659
- state.retryOptions = params || {};
1660
- }
1661
- };
1662
- // The proxy function simply marks the node as a proxy with this function
1663
- // so that child nodes will be created with this function, and then simply
1664
- // activated as a function
1665
- const proxy = (fn) => {
1666
- node.proxyFn2 = fn;
1667
- };
1668
- return {
1669
- onSet,
1670
- proxy,
1671
- cache,
1672
- retry,
1673
- subscribe,
1674
- updateLastSync,
1675
- obs$: getProxy(node),
1676
- };
1677
- }
1678
1639
  function activateNodeFunction(node, lazyFn) {
1679
- let prevTarget$;
1680
- let curTarget$;
1640
+ // let prevTarget$: Observable<any>;
1641
+ // let curTarget$: Observable<any>;
1681
1642
  let update;
1682
1643
  let wasPromise;
1683
1644
  let timeoutRetry;
1684
1645
  const attemptNum = { current: 0 };
1685
- const activator = (isFunction(node) ? node : lazyFn);
1686
- const refresh = () => node.state.refreshNum.set((v) => v + 1);
1646
+ const activateFn = (isFunction(node) ? node : lazyFn);
1647
+ const refresh = () => { var _a; return (_a = node.state) === null || _a === void 0 ? void 0 : _a.refreshNum.set((v) => v + 1); };
1648
+ let activatedValue;
1687
1649
  observe(() => {
1688
- const params = createNodeActivationParams(node);
1650
+ var _a, _b, _c, _d;
1651
+ // const params = createNodeActivationParams(node);
1689
1652
  // Run the function at this node
1690
- let value = activator(params);
1691
- // If target is an observable, get() it to make sure we listen to its changes
1692
- // and set up an onSet to write changes back to it
1653
+ let value = activateFn();
1654
+ // If target is an observable, make this node a link to it
1693
1655
  if (isObservable(value)) {
1694
- prevTarget$ = curTarget$;
1695
- curTarget$ = value;
1696
- params.onSet(({ value: newValue, getPrevious }) => {
1697
- // Don't set the target observable if the target has changed since the last run
1698
- if (!prevTarget$ || curTarget$ === prevTarget$) {
1699
- // Set the node value back to what it was before before setting it.
1700
- // This is a workaround for linked objects because it might not notify
1701
- // if setting a property of an object
1702
- // TODO: Is there a way to not do this? Or at least only do it in a
1703
- // small subset of cases?
1704
- setNodeValue(getNode(curTarget$), getPrevious());
1705
- // Set the value on the curTarget
1706
- curTarget$.set(newValue);
1707
- }
1708
- });
1709
- // Get the value from the observable because we still want the raw value
1710
- // for the effect.
1711
- value = value.get();
1656
+ // If the computed is a proxy to another observable
1657
+ // link it to the target observable
1658
+ const linkedNode = getNode(value);
1659
+ const prevNode = node.linkedToNode;
1660
+ node.linkedToNode = linkedNode;
1661
+ if (!linkedNode.linkedFromNodes) {
1662
+ linkedNode.linkedFromNodes = new Set();
1663
+ }
1664
+ linkedNode.linkedFromNodes.add(node);
1665
+ onChange(linkedNode, ({ value: newValue }) => {
1666
+ value = newValue;
1667
+ set(node, value);
1668
+ }, { initial: true });
1669
+ // If the target observable is different then notify for the change
1670
+ if (prevNode) {
1671
+ const value = getNodeValue(linkedNode);
1672
+ const prevValue = getNodeValue(prevNode);
1673
+ notify(node, value, prevValue, 0);
1674
+ }
1712
1675
  }
1713
- else {
1714
- wasPromise = isPromise(value) ? value : undefined;
1676
+ if (isFunction(value)) {
1677
+ value = value();
1678
+ }
1679
+ const activated = value === null || value === void 0 ? void 0 : value[symbolActivated];
1680
+ if (activated) {
1681
+ node.activationState = activated;
1682
+ value = activated.initial;
1715
1683
  }
1684
+ wasPromise = isPromise(value);
1716
1685
  // Activate this node if not activated already (may be called recursively)
1717
1686
  // TODO: Is calling recursively bad? If so can it be fixed?
1718
1687
  if (!node.activated) {
1719
1688
  node.activated = true;
1689
+ const isCached = !!((_a = node.activationState) === null || _a === void 0 ? void 0 : _a.cache);
1690
+ wasPromise = wasPromise || !!isCached;
1720
1691
  const activateNodeFn = wasPromise ? globalState.activateNode : activateNodeBase;
1721
- update = activateNodeFn(node, refresh, !!wasPromise, value).update;
1692
+ const { update: newUpdate, value: newValue } = activateNodeFn(node, refresh, !!wasPromise, value);
1693
+ update = newUpdate;
1694
+ value = newValue;
1695
+ }
1696
+ else if (node.activationState) {
1697
+ if (!node.activationState.persistedRetry) {
1698
+ const activated = node.activationState;
1699
+ value = (_c = (_b = activated.get) === null || _b === void 0 ? void 0 : _b.call(activated, {})) !== null && _c !== void 0 ? _c : activated.initial;
1700
+ }
1722
1701
  }
1723
- node.state.refreshNum.get();
1702
+ wasPromise = wasPromise || isPromise(value);
1703
+ (_d = node.state) === null || _d === void 0 ? void 0 : _d.refreshNum.get();
1724
1704
  return value;
1725
1705
  }, ({ value }) => {
1726
1706
  if (!globalState.isLoadingRemote$.peek()) {
1727
1707
  if (wasPromise) {
1728
- const { retryOptions } = node.activationState;
1729
- let onError;
1730
- if (retryOptions) {
1731
- if (timeoutRetry) {
1732
- clearTimeout(timeoutRetry.current);
1708
+ if (node.activationState) {
1709
+ const { retry, initial } = node.activationState;
1710
+ let onError;
1711
+ if (retry) {
1712
+ if (timeoutRetry === null || timeoutRetry === void 0 ? void 0 : timeoutRetry.current) {
1713
+ clearTimeout(timeoutRetry.current);
1714
+ }
1715
+ const { handleError, timeout } = setupRetry(retry, refresh, attemptNum);
1716
+ onError = handleError;
1717
+ timeoutRetry = timeout;
1718
+ node.activationState.onError = onError;
1719
+ }
1720
+ if (value && isPromise(value)) {
1721
+ // Extract the promise to make it set the value/error when it comes in
1722
+ extractPromise(node, value, update, onError);
1723
+ }
1724
+ // Set this to undefined only if it's replacing the activation function,
1725
+ // so we don't overwrite it if it already has real data from either local
1726
+ // cache or a previous run
1727
+ if (isFunction(getNodeValue(node))) {
1728
+ setNodeValue(node, initial !== null && initial !== void 0 ? initial : undefined);
1733
1729
  }
1734
- const { handleError, timeout } = setupRetry(retryOptions, refresh, attemptNum);
1735
- onError = handleError;
1736
- timeoutRetry = timeout;
1737
1730
  }
1738
- // Extract the promise to make it set the value/error when it comes in
1739
- extractPromise(node, value, update, onError);
1740
- // Set this to undefined only if it's replacing the activation function,
1741
- // so we don't overwrite it if it already has real data from either local
1742
- // cache or a previous run
1743
- if (isFunction(getNodeValue(node))) {
1744
- setNodeValue(node, undefined);
1731
+ else if (node.activated) {
1732
+ let onError;
1733
+ // Extract the promise to make it set the value/error when it comes in
1734
+ extractPromise(node, value, update, onError);
1735
+ // Set this to undefined only if it's replacing the activation function,
1736
+ // so we don't overwrite it if it already has real data from either local
1737
+ // cache or a previous run
1738
+ if (isFunction(getNodeValue(node))) {
1739
+ setNodeValue(node, undefined);
1740
+ }
1745
1741
  }
1746
1742
  }
1747
1743
  else {
1744
+ activatedValue = value;
1748
1745
  set(node, value);
1749
1746
  node.state.assign({
1750
1747
  isLoaded: true,
@@ -1753,49 +1750,100 @@ function activateNodeFunction(node, lazyFn) {
1753
1750
  }
1754
1751
  }
1755
1752
  }, { immediate: true, fromComputed: true });
1753
+ return activatedValue;
1756
1754
  }
1757
- const activateNodeBase = (globalState.activateNode = function activateNodeBase(node, refresh, wasPromise) {
1758
- const { onSetFn, subscriber } = node.activationState;
1759
- let isSetting = false;
1755
+ const activateNodeBase = (globalState.activateNode = function activateNodeBase(node, refresh, wasPromise, value) {
1760
1756
  if (!node.state) {
1761
1757
  node.state = createObservable({
1762
1758
  isLoaded: false,
1763
1759
  }, false, extractPromise, getProxy);
1764
1760
  }
1765
- if (onSetFn) {
1766
- const doSet = (params) => {
1767
- // Don't call the set if this is the first value coming in
1768
- if (!isSetting) {
1769
- if ((!wasPromise || node.state.isLoaded.get()) &&
1770
- (params.changes.length > 1 || !isFunction(params.changes[0].prevAtPath))) {
1771
- isSetting = true;
1772
- batch(() => onSetFn(params, { update }), () => {
1773
- isSetting = false;
1761
+ let isSetting = false;
1762
+ let isSettingFromSubscribe = false;
1763
+ let _mode = 'set';
1764
+ if (node.activationState) {
1765
+ const { onSet, subscribe, get, initial, retry, waitFor } = node.activationState;
1766
+ // @ts-expect-error asdf
1767
+ const run = () => get({ updateLastSync: noop, setMode: (mode) => (_mode = mode) });
1768
+ value = get
1769
+ ? waitFor
1770
+ ? new Promise((resolve) => {
1771
+ whenReady(waitFor, () => {
1772
+ resolve(run());
1774
1773
  });
1774
+ })
1775
+ : run()
1776
+ : undefined;
1777
+ if (value == undefined || value === null) {
1778
+ value = initial;
1779
+ }
1780
+ let timeoutRetry;
1781
+ if (onSet) {
1782
+ const doSet = (params) => {
1783
+ // Don't call the set if this is the first value coming in
1784
+ if (!isSetting || isSettingFromSubscribe) {
1785
+ if (node.state.isLoaded.get() &&
1786
+ (params.changes.length > 1 || !isFunction(params.changes[0].prevAtPath))) {
1787
+ const attemptNum = { current: 0 };
1788
+ const run = () => {
1789
+ let onError;
1790
+ if (retry) {
1791
+ if (timeoutRetry === null || timeoutRetry === void 0 ? void 0 : timeoutRetry.current) {
1792
+ clearTimeout(timeoutRetry.current);
1793
+ }
1794
+ const { handleError, timeout } = setupRetry(retry, run, attemptNum);
1795
+ onError = handleError;
1796
+ timeoutRetry = timeout;
1797
+ }
1798
+ isSetting = true;
1799
+ batch(() => onSet(params, {
1800
+ node,
1801
+ update,
1802
+ refresh,
1803
+ onError,
1804
+ fromSubscribe: isSettingFromSubscribe,
1805
+ }), () => {
1806
+ isSetting = false;
1807
+ });
1808
+ };
1809
+ run();
1810
+ }
1775
1811
  }
1776
- }
1777
- };
1778
- onChange(node, doSet, wasPromise ? undefined : { immediate: true });
1779
- }
1780
- if (process.env.NODE_ENV === 'development' && node.activationState.cacheOptions) {
1781
- // TODO Better message
1782
- console.log('[legend-state] Using cacheOptions without setting up persistence first');
1783
- }
1784
- if (process.env.NODE_ENV === 'development' && node.activationState.retryOptions) {
1785
- // TODO Better message
1786
- console.log('[legend-state] Using retryOptions without setting up persistence first');
1812
+ };
1813
+ onChange(node, doSet, wasPromise ? undefined : { immediate: true });
1814
+ }
1815
+ if (process.env.NODE_ENV === 'development' && node.activationState.cache) {
1816
+ // TODO Better message
1817
+ console.log('[legend-state] Using cache without setting up persistence first');
1818
+ }
1819
+ if (process.env.NODE_ENV === 'development' && node.activationState.retry) {
1820
+ // TODO Better message
1821
+ console.log('[legend-state] Using retry without setting up persistence first');
1822
+ }
1823
+ if (subscribe) {
1824
+ const updateFromSubscribe = (params) => {
1825
+ isSettingFromSubscribe = true;
1826
+ update(params);
1827
+ isSettingFromSubscribe = false;
1828
+ };
1829
+ subscribe({ node, update: updateFromSubscribe, refresh });
1830
+ }
1787
1831
  }
1788
- const update = ({ value }) => {
1832
+ const update = ({ value, mode }) => {
1789
1833
  // TODO: This isSetting might not be necessary? Tests still work if removing it.
1790
1834
  // Write tests that would break it if removed? I'd guess a combination of subscribe and
1791
1835
  if (!isSetting) {
1792
- set(node, value);
1836
+ isSetting = true;
1837
+ if (_mode === 'assign' || mode === 'assign') {
1838
+ assign(node, value);
1839
+ }
1840
+ else {
1841
+ set(node, value);
1842
+ }
1843
+ isSetting = false;
1793
1844
  }
1794
1845
  };
1795
- if (subscriber) {
1796
- subscriber({ update, refresh });
1797
- }
1798
- return { update };
1846
+ return { update, value };
1799
1847
  });
1800
1848
 
1801
1849
  const fns = ['get', 'set', 'peek', 'onChange', 'toggle'];
@@ -2023,8 +2071,9 @@ const internal = {
2023
2071
  setAtPath,
2024
2072
  setNodeValue,
2025
2073
  setupRetry,
2074
+ symbolActivated,
2026
2075
  symbolDelete,
2027
2076
  };
2028
2077
 
2029
- export { ObservablePrimitiveClass, batch, beginBatch, beginTracking, checkActivate, computeSelector, computed, configureLegendState, constructObjectWithPath, deconstructObjectWithPath, endBatch, endTracking, event, extraPrimitiveActivators, extraPrimitiveProps, findIDKey, getNode, getNodeValue, getObservableIndex, hasOwnProperty, internal, isArray, isBoolean, isEmpty, isFunction, isObject, isObservable, isObservableValueReady, isPrimitive, isPromise, isString, isSymbol, lockObservable, mergeIntoObservable, observable, observablePrimitive, observe, opaqueObject, optimized, proxy, setAtPath, setInObservableAtPath, setSilently, setupTracking, symbolDelete, trackSelector, tracking, updateTracking, when, whenReady };
2078
+ export { ObservablePrimitiveClass, activated, batch, beginBatch, beginTracking, checkActivate, computeSelector, computed, configureLegendState, constructObjectWithPath, deconstructObjectWithPath, endBatch, endTracking, event, extraPrimitiveActivators, extraPrimitiveProps, findIDKey, getNode, getNodeValue, getObservableIndex, hasOwnProperty, internal, isArray, isBoolean, isEmpty, isFunction, isObject, isObservable, isObservableValueReady, isPrimitive, isPromise, isString, isSymbol, lockObservable, mergeIntoObservable, observable, observablePrimitive, observe, opaqueObject, optimized, proxy, setAtPath, setInObservableAtPath, setSilently, setupTracking, symbolDelete, trackSelector, tracking, updateTracking, when, whenReady };
2030
2079
  //# sourceMappingURL=index.mjs.map