@legendapp/state 2.2.0-next.2 → 2.2.0-next.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/babel.js.map +1 -1
  2. package/config/enableDirectAccess.d.ts +1 -1
  3. package/config/enableDirectPeek.d.ts +1 -1
  4. package/config/enableReactDirectRender.js.map +1 -1
  5. package/config/enableReactDirectRender.mjs.map +1 -1
  6. package/config/enableReactTracking.d.ts +4 -3
  7. package/config/enableReactTracking.js.map +1 -1
  8. package/config/enableReactTracking.mjs.map +1 -1
  9. package/config/enableReactUse.d.ts +1 -1
  10. package/helpers/fetch.d.ts +4 -3
  11. package/helpers/fetch.js.map +1 -1
  12. package/helpers/fetch.mjs.map +1 -1
  13. package/helpers/pageHash.js.map +1 -1
  14. package/helpers/pageHash.mjs.map +1 -1
  15. package/helpers/pageHashParams.js.map +1 -1
  16. package/helpers/pageHashParams.mjs.map +1 -1
  17. package/helpers/time.d.ts +2 -2
  18. package/helpers/time.js.map +1 -1
  19. package/helpers/time.mjs.map +1 -1
  20. package/history.js.map +1 -1
  21. package/history.mjs.map +1 -1
  22. package/index.d.ts +14 -9
  23. package/index.js +522 -226
  24. package/index.js.map +1 -1
  25. package/index.mjs +521 -227
  26. package/index.mjs.map +1 -1
  27. package/package.json +2 -10
  28. package/persist-plugins/async-storage.js.map +1 -1
  29. package/persist-plugins/async-storage.mjs.map +1 -1
  30. package/persist-plugins/fetch.js.map +1 -1
  31. package/persist-plugins/fetch.mjs.map +1 -1
  32. package/persist-plugins/firebase.js +3 -3
  33. package/persist-plugins/firebase.js.map +1 -1
  34. package/persist-plugins/firebase.mjs +3 -3
  35. package/persist-plugins/firebase.mjs.map +1 -1
  36. package/persist-plugins/indexeddb.js.map +1 -1
  37. package/persist-plugins/indexeddb.mjs.map +1 -1
  38. package/persist-plugins/local-storage.js +1 -1
  39. package/persist-plugins/local-storage.js.map +1 -1
  40. package/persist-plugins/local-storage.mjs +1 -1
  41. package/persist-plugins/local-storage.mjs.map +1 -1
  42. package/persist-plugins/mmkv.js.map +1 -1
  43. package/persist-plugins/mmkv.mjs.map +1 -1
  44. package/persist-plugins/query.js.map +1 -1
  45. package/persist-plugins/query.mjs.map +1 -1
  46. package/persist.d.ts +16 -1
  47. package/persist.js +279 -125
  48. package/persist.js.map +1 -1
  49. package/persist.mjs +280 -126
  50. package/persist.mjs.map +1 -1
  51. package/react-hooks/createObservableHook.js +1 -1
  52. package/react-hooks/createObservableHook.js.map +1 -1
  53. package/react-hooks/createObservableHook.mjs +1 -1
  54. package/react-hooks/createObservableHook.mjs.map +1 -1
  55. package/react-hooks/useFetch.d.ts +4 -3
  56. package/react-hooks/useFetch.js.map +1 -1
  57. package/react-hooks/useFetch.mjs.map +1 -1
  58. package/react-hooks/useHover.js.map +1 -1
  59. package/react-hooks/useHover.mjs.map +1 -1
  60. package/react-hooks/useMeasure.js.map +1 -1
  61. package/react-hooks/useMeasure.mjs.map +1 -1
  62. package/react-hooks/useObservableNextRouter.js.map +1 -1
  63. package/react-hooks/useObservableNextRouter.mjs.map +1 -1
  64. package/react-hooks/useObservableQuery.js.map +1 -1
  65. package/react-hooks/useObservableQuery.mjs.map +1 -1
  66. package/react-hooks/usePersistedObservable.d.ts +2 -2
  67. package/react-hooks/usePersistedObservable.js +3 -3
  68. package/react-hooks/usePersistedObservable.js.map +1 -1
  69. package/react-hooks/usePersistedObservable.mjs +3 -3
  70. package/react-hooks/usePersistedObservable.mjs.map +1 -1
  71. package/react.js +13 -8
  72. package/react.js.map +1 -1
  73. package/react.mjs +14 -9
  74. package/react.mjs.map +1 -1
  75. package/src/ObservableObject.d.ts +8 -4
  76. package/src/ObservablePrimitive.d.ts +2 -1
  77. package/src/activated.d.ts +3 -0
  78. package/src/batching.d.ts +3 -1
  79. package/src/computed.d.ts +1 -1
  80. package/src/config/enableDirectAccess.d.ts +1 -1
  81. package/src/config/enableDirectPeek.d.ts +1 -1
  82. package/src/config/enableReactTracking.d.ts +4 -3
  83. package/src/config/enableReactUse.d.ts +1 -1
  84. package/src/createObservable.d.ts +2 -2
  85. package/src/globals.d.ts +10 -9
  86. package/src/helpers/fetch.d.ts +4 -3
  87. package/src/helpers/time.d.ts +2 -2
  88. package/src/helpers.d.ts +3 -2
  89. package/src/history/trackHistory.d.ts +1 -1
  90. package/src/observable.d.ts +6 -15
  91. package/src/observableInterfaces.d.ts +68 -315
  92. package/src/observableTypes.d.ts +93 -0
  93. package/src/persist/observablePersistRemoteFunctionsAdapter.d.ts +1 -1
  94. package/src/persist/persistActivateNode.d.ts +1 -0
  95. package/src/persist/persistHelpers.d.ts +1 -1
  96. package/src/persist/persistObservable.d.ts +3 -3
  97. package/src/persistTypes.d.ts +229 -0
  98. package/src/proxy.d.ts +2 -1
  99. package/src/react/Computed.d.ts +1 -1
  100. package/src/react/Switch.d.ts +3 -3
  101. package/src/react/reactInterfaces.d.ts +2 -1
  102. package/src/react/usePauseProvider.d.ts +3 -3
  103. package/src/react/useWhen.d.ts +2 -2
  104. package/src/react-hooks/useFetch.d.ts +4 -3
  105. package/src/react-hooks/usePersistedObservable.d.ts +2 -2
  106. package/src/retry.d.ts +4 -0
  107. package/src/trackSelector.d.ts +3 -2
  108. package/src/when.d.ts +6 -2
  109. package/trace.js.map +1 -1
  110. package/trace.mjs.map +1 -1
package/persist.js CHANGED
@@ -139,9 +139,21 @@ function observablePersistRemoteFunctionsAdapter({ get, set, }) {
139
139
  const ret = {};
140
140
  if (get) {
141
141
  ret.get = (async (params) => {
142
- const value = (await get(params));
143
- params.onChange({ value, dateModified: params.dateModified || Date.now() });
144
- params.onGet();
142
+ try {
143
+ let value = get(params);
144
+ if (state.isPromise(value)) {
145
+ value = await value;
146
+ }
147
+ params.onChange({
148
+ value,
149
+ dateModified: params.dateModified,
150
+ lastSync: params.lastSync,
151
+ mode: params.mode,
152
+ });
153
+ params.onGet();
154
+ // eslint-disable-next-line no-empty
155
+ }
156
+ catch (_a) { }
145
157
  });
146
158
  }
147
159
  if (set) {
@@ -150,7 +162,22 @@ function observablePersistRemoteFunctionsAdapter({ get, set, }) {
150
162
  return ret;
151
163
  }
152
164
 
153
- const { getProxy, globalState } = state.internal;
165
+ function removeNullUndefined(val) {
166
+ if (val) {
167
+ Object.keys(val).forEach((key) => {
168
+ const v = val[key];
169
+ if (v === null || v === undefined) {
170
+ delete val[key];
171
+ }
172
+ else if (state.isObject(v)) {
173
+ removeNullUndefined(v);
174
+ }
175
+ });
176
+ }
177
+ return val;
178
+ }
179
+
180
+ const { globalState: globalState$1 } = state.internal;
154
181
  const mapPersistences = new WeakMap();
155
182
  const metadatas = new WeakMap();
156
183
  const promisesLocalSaves = new Set();
@@ -165,11 +192,12 @@ function doInOrder(arg1, arg2) {
165
192
  return state.isPromise(arg1) ? arg1.then(arg2) : arg2(arg1);
166
193
  }
167
194
  function onChangeRemote(cb) {
168
- state.when(() => !globalState.isLoadingRemote$.get(), () => {
195
+ state.when(() => !globalState$1.isLoadingRemote$.get(), () => {
196
+ state.endBatch(true);
169
197
  // Remote changes should only update local state
170
- globalState.isLoadingRemote$.set(true);
198
+ globalState$1.isLoadingRemote$.set(true);
171
199
  state.batch(cb, () => {
172
- globalState.isLoadingRemote$.set(false);
200
+ globalState$1.isLoadingRemote$.set(false);
173
201
  });
174
202
  });
175
203
  }
@@ -216,24 +244,28 @@ async function updateMetadataImmediate(obs, localState, syncState, persistOption
216
244
  const { table, config } = parseLocalConfig(local);
217
245
  // Save metadata
218
246
  const oldMetadata = metadatas.get(obs);
219
- const { modified, pending } = newMetadata;
220
- const needsUpdate = pending || (modified && (!oldMetadata || modified !== oldMetadata.modified));
247
+ const { lastSync, pending } = newMetadata;
248
+ const needsUpdate = pending || (lastSync && (!oldMetadata || lastSync !== oldMetadata.lastSync));
221
249
  if (needsUpdate) {
222
250
  const metadata = Object.assign({}, oldMetadata, newMetadata);
223
251
  metadatas.set(obs, metadata);
224
252
  if (persistenceLocal) {
225
253
  await persistenceLocal.setMetadata(table, metadata, config);
226
254
  }
227
- if (modified) {
228
- syncState.dateModified.set(modified);
255
+ if (lastSync) {
256
+ syncState.assign({
257
+ lastSync: lastSync,
258
+ dateModified: lastSync,
259
+ });
229
260
  }
230
261
  }
231
262
  }
232
263
  function updateMetadata(obs, localState, syncState, persistOptions, newMetadata) {
264
+ var _a;
233
265
  if (localState.timeoutSaveMetadata) {
234
266
  clearTimeout(localState.timeoutSaveMetadata);
235
267
  }
236
- localState.timeoutSaveMetadata = setTimeout(() => updateMetadataImmediate(obs, localState, syncState, persistOptions, newMetadata), 30);
268
+ localState.timeoutSaveMetadata = setTimeout(() => updateMetadataImmediate(obs, localState, syncState, persistOptions, newMetadata), ((_a = persistOptions === null || persistOptions === void 0 ? void 0 : persistOptions.remote) === null || _a === void 0 ? void 0 : _a.metadataTimeout) || 0);
237
269
  }
238
270
  let _queuedChanges = [];
239
271
  async function processQueuedChanges() {
@@ -252,7 +284,7 @@ async function processQueuedChanges() {
252
284
  // 4. Wait for remote load or error if allowed
253
285
  // 5. Save to remote
254
286
  // 6. On successful save, merge changes (if any) back into observable
255
- // 7. Lastly, update metadata to clear pending and update dateModified. Doing this earlier could potentially cause
287
+ // 7. Lastly, update metadata to clear pending and update lastSync. Doing this earlier could potentially cause
256
288
  // sync inconsistences so it's very important that this is last.
257
289
  changes.forEach(doChange);
258
290
  }
@@ -405,6 +437,7 @@ async function doChange(changeInfo) {
405
437
  await state.when(() => syncState.isLoaded.get() || ((configRemote === null || configRemote === void 0 ? void 0 : configRemote.allowSetIfError) && syncState.error.get()));
406
438
  const value = obs.peek();
407
439
  (_a = configRemote === null || configRemote === void 0 ? void 0 : configRemote.onBeforeSet) === null || _a === void 0 ? void 0 : _a.call(configRemote);
440
+ localState.numSavesOutstanding = (localState.numSavesOutstanding || 0) + 1;
408
441
  const saved = await ((_b = persistenceRemote.set({
409
442
  obs,
410
443
  syncState: syncState,
@@ -412,17 +445,18 @@ async function doChange(changeInfo) {
412
445
  changes: changesRemote,
413
446
  value,
414
447
  })) === null || _b === void 0 ? void 0 : _b.catch((err) => { var _a; return (_a = configRemote === null || configRemote === void 0 ? void 0 : configRemote.onSetError) === null || _a === void 0 ? void 0 : _a.call(configRemote, err); }));
448
+ localState.numSavesOutstanding--;
415
449
  // If this remote save changed anything then update persistence and metadata
416
450
  // Because save happens after a timeout and they're batched together, some calls to save will
417
451
  // return saved data and others won't, so those can be ignored.
418
452
  if (saved) {
419
453
  const pathStrs = Array.from(new Set(changesRemote.map((change) => change.pathStr)));
420
- const { changes, dateModified } = saved;
454
+ const { changes, lastSync } = saved;
421
455
  if (pathStrs.length > 0) {
422
456
  if (local) {
423
457
  const metadata = {};
424
458
  const pending = (_c = persistenceLocal.getMetadata(table, configLocal)) === null || _c === void 0 ? void 0 : _c.pending;
425
- let transformedChanges = [];
459
+ let transformedChanges = undefined;
426
460
  for (let i = 0; i < pathStrs.length; i++) {
427
461
  const pathStr = pathStrs[i];
428
462
  // Clear pending for this path
@@ -432,22 +466,34 @@ async function doChange(changeInfo) {
432
466
  metadata.pending = pending;
433
467
  }
434
468
  }
435
- if (dateModified) {
436
- metadata.modified = dateModified;
469
+ if (lastSync) {
470
+ metadata.lastSync = lastSync;
437
471
  }
438
472
  // Remote can optionally have data that needs to be merged back into the observable,
439
473
  // for example Firebase may update dateModified with the server timestamp
440
474
  if (changes && !state.isEmpty(changes)) {
441
- transformedChanges.push(transformLoadData(changes, persistOptions.remote, false));
475
+ transformedChanges = transformLoadData(changes, persistOptions.remote, false);
442
476
  }
443
- if (transformedChanges.length > 0) {
444
- if (transformedChanges.some((change) => state.isPromise(change))) {
445
- transformedChanges = await Promise.all(transformedChanges);
477
+ if (localState.numSavesOutstanding > 0) {
478
+ if (transformedChanges) {
479
+ if (!localState.pendingSaveResults) {
480
+ localState.pendingSaveResults = [];
481
+ }
482
+ localState.pendingSaveResults.push(transformedChanges);
446
483
  }
447
- onChangeRemote(() => state.mergeIntoObservable(obs, ...transformedChanges));
448
484
  }
449
- if (shouldSaveMetadata && !state.isEmpty(metadata)) {
450
- updateMetadata(obs, localState, syncState, persistOptions, metadata);
485
+ else {
486
+ let allChanges = [...(localState.pendingSaveResults || []), transformedChanges];
487
+ if (allChanges.length > 0) {
488
+ if (allChanges.some((change) => state.isPromise(change))) {
489
+ allChanges = await Promise.all(allChanges);
490
+ }
491
+ onChangeRemote(() => state.mergeIntoObservable(obs, ...allChanges));
492
+ }
493
+ if (shouldSaveMetadata && !state.isEmpty(metadata)) {
494
+ updateMetadata(obs, localState, syncState, persistOptions, metadata);
495
+ }
496
+ localState.pendingSaveResults = [];
451
497
  }
452
498
  }
453
499
  (_d = configRemote === null || configRemote === void 0 ? void 0 : configRemote.onSet) === null || _d === void 0 ? void 0 : _d.call(configRemote);
@@ -498,7 +544,7 @@ async function loadLocal(obs, persistOptions, syncState, localState) {
498
544
  }
499
545
  const { persist: persistenceLocal, initialized } = mapPersistences.get(localPersistence);
500
546
  localState.persistenceLocal = persistenceLocal;
501
- if (!initialized.get()) {
547
+ if (!initialized.peek()) {
502
548
  await state.when(initialized);
503
549
  }
504
550
  // If persistence has an asynchronous load, wait for it
@@ -512,12 +558,21 @@ async function loadLocal(obs, persistOptions, syncState, localState) {
512
558
  let value = persistenceLocal.getTable(table, config);
513
559
  const metadata = persistenceLocal.getMetadata(table, config);
514
560
  if (metadata) {
561
+ // @ts-expect-error Migration from old version
562
+ if (!metadata.lastSync && metadata.modified) {
563
+ // @ts-expect-error Migration from old
564
+ metadata.lastSync = metadata.modified;
565
+ }
515
566
  metadatas.set(obs, metadata);
516
567
  localState.pendingChanges = metadata.pending;
517
- syncState.dateModified.set(metadata.modified);
568
+ // TODOV3 Remove dateModified
569
+ syncState.assign({
570
+ dateModified: metadata.lastSync,
571
+ lastSync: metadata.lastSync,
572
+ });
518
573
  }
519
574
  // Merge the data from local persistence into the default state
520
- if (value !== null && value !== undefined) {
575
+ if (value !== undefined) {
521
576
  const { transform, fieldTransforms } = config;
522
577
  value = transformLoadData(value, { transform, fieldTransforms }, true);
523
578
  if (state.isPromise(value)) {
@@ -528,7 +583,12 @@ async function loadLocal(obs, persistOptions, syncState, localState) {
528
583
  // are set on the same observable
529
584
  state.internal.globalState.isLoadingLocal = true;
530
585
  // We want to merge the local data on top of any initial state the object is created with
531
- state.mergeIntoObservable(obs, value);
586
+ if (value === null && !obs.peek()) {
587
+ obs.set(value);
588
+ }
589
+ else {
590
+ state.mergeIntoObservable(obs, value);
591
+ }
532
592
  }, () => {
533
593
  state.internal.globalState.isLoadingLocal = false;
534
594
  });
@@ -541,18 +601,11 @@ async function loadLocal(obs, persistOptions, syncState, localState) {
541
601
  }
542
602
  syncState.isLoadedLocal.set(true);
543
603
  }
544
- function persistObservable(initialOrObservable, persistOptions) {
545
- var _a;
546
- const obs = (state.isObservable(initialOrObservable)
547
- ? initialOrObservable
548
- : state.observable(state.isFunction(initialOrObservable) ? initialOrObservable() : initialOrObservable));
604
+ function persistObservable(obs, persistOptions) {
549
605
  const node = state.getNode(obs);
550
- if (process.env.NODE_ENV === 'development' && ((_a = obs === null || obs === void 0 ? void 0 : obs.peek()) === null || _a === void 0 ? void 0 : _a._state)) {
551
- console.warn('[legend-state] WARNING: persistObservable creates a property named "_state" but your observable already has "state" in it');
552
- }
553
606
  // Merge remote persist options with clobal options
554
607
  if (persistOptions.remote) {
555
- persistOptions.remote = Object.assign({}, observablePersistConfiguration.remoteOptions, persistOptions.remote);
608
+ persistOptions.remote = Object.assign({}, observablePersistConfiguration.remoteOptions, removeNullUndefined(persistOptions.remote));
556
609
  }
557
610
  let { remote } = persistOptions;
558
611
  const { local } = persistOptions;
@@ -564,6 +617,7 @@ function persistObservable(initialOrObservable, persistOptions) {
564
617
  isLoaded: false,
565
618
  isEnabledLocal: true,
566
619
  isEnabledRemote: true,
620
+ refreshNum: 0,
567
621
  clearLocal: undefined,
568
622
  sync: () => Promise.resolve(),
569
623
  getPendingChanges: () => localState.pendingChanges,
@@ -594,73 +648,93 @@ function persistObservable(initialOrObservable, persistOptions) {
594
648
  var _a, _b;
595
649
  if (!isSynced) {
596
650
  isSynced = true;
597
- const dateModified = (_a = metadatas.get(obs)) === null || _a === void 0 ? void 0 : _a.modified;
651
+ const lastSync = (_a = metadatas.get(obs)) === null || _a === void 0 ? void 0 : _a.lastSync;
652
+ const pending = localState.pendingChanges;
598
653
  const get = (_b = localState.persistenceRemote.get) === null || _b === void 0 ? void 0 : _b.bind(localState.persistenceRemote);
599
654
  if (get) {
600
- get({
601
- state: syncState,
602
- obs,
603
- options: persistOptions,
604
- dateModified,
605
- onGet: () => {
606
- syncState.isLoaded.set(true);
607
- },
608
- onChange: async ({ value, path = [], pathTypes = [], mode = 'set', dateModified }) => {
609
- // Note: value is the constructed value, path is used for setInObservableAtPath
610
- // to start the set into the observable from the path
611
- if (value !== undefined) {
612
- value = transformLoadData(value, remote, true);
613
- if (state.isPromise(value)) {
614
- value = await value;
615
- }
616
- const invertedMap = remote.fieldTransforms && invertFieldMap(remote.fieldTransforms);
617
- if (path.length && invertedMap) {
618
- path = transformPath(path, pathTypes, invertedMap);
619
- }
620
- if (mode === 'dateModified') {
621
- if (dateModified && !state.isEmpty(value)) {
655
+ const runGet = () => {
656
+ get({
657
+ state: syncState,
658
+ obs,
659
+ options: persistOptions,
660
+ lastSync,
661
+ dateModified: lastSync,
662
+ onError: (error) => {
663
+ var _a;
664
+ (_a = remote.onGetError) === null || _a === void 0 ? void 0 : _a.call(remote, error);
665
+ },
666
+ onGet: () => {
667
+ node.state.assign({
668
+ isLoaded: true,
669
+ error: undefined,
670
+ });
671
+ },
672
+ onChange: async ({ value, path = [], pathTypes = [], mode = 'set', lastSync }) => {
673
+ // Note: value is the constructed value, path is used for setInObservableAtPath
674
+ // to start the set into the observable from the path
675
+ if (value !== undefined) {
676
+ value = transformLoadData(value, remote, true);
677
+ if (state.isPromise(value)) {
678
+ value = await value;
679
+ }
680
+ const invertedMap = remote.fieldTransforms && invertFieldMap(remote.fieldTransforms);
681
+ if (path.length && invertedMap) {
682
+ path = transformPath(path, pathTypes, invertedMap);
683
+ }
684
+ if (mode === 'lastSync' || mode === 'dateModified') {
685
+ if (lastSync && !state.isEmpty(value)) {
686
+ onChangeRemote(() => {
687
+ state.setInObservableAtPath(
688
+ // @ts-expect-error Fix this type
689
+ obs, path, pathTypes, value, 'assign');
690
+ });
691
+ }
692
+ }
693
+ else {
694
+ const pending = localState.pendingChanges;
695
+ if (pending) {
696
+ Object.keys(pending).forEach((key) => {
697
+ const p = key.split('/').filter((p) => p !== '');
698
+ const { v, t } = pending[key];
699
+ if (t.length === 0) {
700
+ value = v;
701
+ }
702
+ else if (value[p[0]] !== undefined) {
703
+ value = state.setAtPath(value, p, t, v, obs.peek(), (path, value) => {
704
+ delete pending[key];
705
+ pending[path.join('/')] = {
706
+ p: null,
707
+ v: value,
708
+ t: t.slice(0, path.length),
709
+ };
710
+ });
711
+ }
712
+ });
713
+ }
622
714
  onChangeRemote(() => {
623
- state.setInObservableAtPath(obs, path, pathTypes, value, 'assign');
715
+ // @ts-expect-error Fix this type
716
+ state.setInObservableAtPath(obs, path, pathTypes, value, mode);
624
717
  });
625
718
  }
626
719
  }
627
- else {
628
- const pending = localState.pendingChanges;
629
- if (pending) {
630
- Object.keys(pending).forEach((key) => {
631
- const p = key.split('/').filter((p) => p !== '');
632
- const { v, t } = pending[key];
633
- if (value[p[0]] !== undefined) {
634
- value = state.setAtPath(value, p, t, v, obs.peek(), (path, value) => {
635
- delete pending[key];
636
- pending[path.join('/')] = {
637
- p: null,
638
- v: value,
639
- t: t.slice(0, path.length),
640
- };
641
- });
642
- }
643
- });
644
- }
645
- onChangeRemote(() => {
646
- state.setInObservableAtPath(obs, path, pathTypes, value, mode);
720
+ if (lastSync && local) {
721
+ updateMetadata(obs, localState, syncState, persistOptions, {
722
+ lastSync,
647
723
  });
648
724
  }
649
- }
650
- if (dateModified && local) {
651
- updateMetadata(obs, localState, syncState, persistOptions, {
652
- modified: dateModified,
653
- });
654
- }
655
- },
656
- });
725
+ },
726
+ });
727
+ };
728
+ runGet();
657
729
  }
658
730
  else {
659
- syncState.isLoaded.set(true);
731
+ node.state.assign({
732
+ isLoaded: true,
733
+ error: undefined,
734
+ });
660
735
  }
661
736
  // Wait for remote to be ready before saving pending
662
737
  await state.when(() => syncState.isLoaded.get() || (remote.allowSetIfError && syncState.error.get()));
663
- const pending = localState.pendingChanges;
664
738
  if (pending && !state.isEmpty(pending)) {
665
739
  localState.isApplyingPending = true;
666
740
  const keys = Object.keys(pending);
@@ -673,6 +747,7 @@ function persistObservable(initialOrObservable, persistOptions) {
673
747
  changes.push({ path, valueAtPath: v, prevAtPath: p, pathTypes: t });
674
748
  }
675
749
  // Send the changes into onObsChange so that they get persisted remotely
750
+ // @ts-expect-error Fix this type
676
751
  onObsChange(obs, syncState, localState, persistOptions, {
677
752
  value: obs.peek(),
678
753
  // TODO getPrevious if any remote persistence layers need it
@@ -708,44 +783,122 @@ function persistObservable(initialOrObservable, persistOptions) {
708
783
  }
709
784
  obs.onChange(onObsChange.bind(this, obs, syncState, localState, persistOptions));
710
785
  });
711
- return obs;
786
+ return syncState;
712
787
  }
713
- globalState.activateNode = function activateNodePersist(node, newValue, setter, subscriber, cacheOptions, lastSync) {
714
- let onChange = undefined;
715
- const pluginRemote = {
716
- get: async (params) => {
717
- onChange = params.onChange;
718
- if (state.isPromise(newValue)) {
719
- newValue = await newValue;
788
+
789
+ const { getProxy, globalState, runWithRetry, symbolActivated } = state.internal;
790
+ function persistActivateNode() {
791
+ globalState.activateNode = function activateNodePersist(node, refresh, wasPromise, newValue) {
792
+ if (node.activationState) {
793
+ const { get, initial, onSet, subscribe, cache, retry, offlineBehavior } = node.activationState;
794
+ let onChange = undefined;
795
+ const pluginRemote = {};
796
+ if (get) {
797
+ pluginRemote.get = (params) => {
798
+ onChange = params.onChange;
799
+ const updateLastSync = (lastSync) => (params.lastSync = lastSync);
800
+ const setMode = (mode) => (params.mode = mode);
801
+ const nodeValue = state.getNodeValue(node);
802
+ const value = runWithRetry(node, { attemptNum: 0 }, () => {
803
+ return get({
804
+ value: state.isFunction(nodeValue) || (nodeValue === null || nodeValue === void 0 ? void 0 : nodeValue[symbolActivated]) ? undefined : nodeValue,
805
+ lastSync: params.lastSync,
806
+ updateLastSync,
807
+ setMode,
808
+ });
809
+ });
810
+ return value;
811
+ };
812
+ }
813
+ if (onSet) {
814
+ // TODO: Work out these types better
815
+ pluginRemote.set = async (params) => {
816
+ var _a;
817
+ if ((_a = node.state) === null || _a === void 0 ? void 0 : _a.isLoaded.get()) {
818
+ return runWithRetry(node, { attemptNum: 0 }, async () => {
819
+ let changes = {};
820
+ let maxModified = 0;
821
+ let didError = false;
822
+ if (!node.state.isLoaded.peek()) {
823
+ await state.whenReady(node.state.isLoaded);
824
+ }
825
+ await onSet({
826
+ ...params,
827
+ node,
828
+ update: (params) => {
829
+ const { value, lastSync } = params;
830
+ maxModified = Math.max(lastSync || 0, maxModified);
831
+ changes = state.mergeIntoObservable(changes, value);
832
+ },
833
+ onError: () => {
834
+ // TODO Is this necessary?
835
+ didError = true;
836
+ throw new Error();
837
+ },
838
+ refresh,
839
+ fromSubscribe: false,
840
+ });
841
+ if (!didError) {
842
+ return { changes, lastSync: maxModified || undefined };
843
+ }
844
+ });
845
+ }
846
+ };
847
+ }
848
+ if (subscribe) {
849
+ subscribe({
850
+ node,
851
+ update: (params) => {
852
+ if (!onChange) {
853
+ // TODO: Make this message better
854
+ console.log('[legend-state] Cannot update immediately before the first return');
855
+ }
856
+ else {
857
+ onChange(params);
858
+ }
859
+ },
860
+ refresh,
861
+ });
862
+ }
863
+ persistObservable(getProxy(node), {
864
+ pluginRemote,
865
+ ...(cache || {}),
866
+ remote: {
867
+ retry: retry,
868
+ offlineBehavior,
869
+ },
870
+ });
871
+ const nodeVal = state.getNodeValue(node);
872
+ if (nodeVal !== undefined) {
873
+ newValue = nodeVal;
720
874
  }
721
- if (lastSync.value) {
722
- params.dateModified = lastSync.value;
875
+ else if (newValue === undefined) {
876
+ newValue = initial;
723
877
  }
724
- return newValue;
725
- },
878
+ return { update: onChange, value: newValue };
879
+ }
880
+ else {
881
+ let onChange = undefined;
882
+ const pluginRemote = {
883
+ get: async (params) => {
884
+ onChange = params.onChange;
885
+ if (state.isPromise(newValue)) {
886
+ try {
887
+ newValue = await newValue;
888
+ // eslint-disable-next-line no-empty
889
+ }
890
+ catch (_a) { }
891
+ }
892
+ return newValue;
893
+ },
894
+ };
895
+ persistObservable(getProxy(node), {
896
+ pluginRemote,
897
+ });
898
+ return { update: onChange, value: newValue };
899
+ }
726
900
  };
727
- if (setter) {
728
- pluginRemote.set = setter;
729
- }
730
- if (subscriber) {
731
- subscriber({
732
- update: (params) => {
733
- if (!onChange) {
734
- // TODO: Make this message better
735
- console.log('[legend-state] Cannot update immediately before the first return');
736
- }
737
- else {
738
- onChange(params);
739
- }
740
- },
741
- });
742
- }
743
- persistObservable(getProxy(node), {
744
- pluginRemote,
745
- ...(cacheOptions || {}),
746
- });
747
- return { update: onChange };
748
- };
901
+ }
749
902
 
750
903
  function isInRemoteChange() {
751
904
  return state.internal.globalState.isLoadingRemote$.get();
@@ -753,6 +906,7 @@ function isInRemoteChange() {
753
906
  const internal = {
754
907
  observablePersistConfiguration,
755
908
  };
909
+ persistActivateNode();
756
910
 
757
911
  exports.configureObservablePersistence = configureObservablePersistence;
758
912
  exports.internal = internal;