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