@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.
- package/babel.js.map +1 -1
- package/config/enableDirectAccess.d.ts +1 -1
- package/config/enableDirectPeek.d.ts +1 -1
- package/config/enableReactDirectRender.js.map +1 -1
- package/config/enableReactDirectRender.mjs.map +1 -1
- package/config/enableReactTracking.d.ts +4 -3
- package/config/enableReactTracking.js.map +1 -1
- package/config/enableReactTracking.mjs.map +1 -1
- package/config/enableReactUse.d.ts +1 -1
- package/helpers/fetch.d.ts +4 -3
- package/helpers/fetch.js.map +1 -1
- package/helpers/fetch.mjs.map +1 -1
- package/helpers/pageHash.js.map +1 -1
- package/helpers/pageHash.mjs.map +1 -1
- package/helpers/pageHashParams.js.map +1 -1
- package/helpers/pageHashParams.mjs.map +1 -1
- package/helpers/time.d.ts +2 -2
- package/helpers/time.js.map +1 -1
- package/helpers/time.mjs.map +1 -1
- package/history.js.map +1 -1
- package/history.mjs.map +1 -1
- package/index.d.ts +14 -9
- package/index.js +522 -226
- package/index.js.map +1 -1
- package/index.mjs +521 -227
- package/index.mjs.map +1 -1
- package/package.json +2 -10
- package/persist-plugins/async-storage.js.map +1 -1
- package/persist-plugins/async-storage.mjs.map +1 -1
- package/persist-plugins/fetch.js.map +1 -1
- package/persist-plugins/fetch.mjs.map +1 -1
- package/persist-plugins/firebase.js +3 -3
- package/persist-plugins/firebase.js.map +1 -1
- package/persist-plugins/firebase.mjs +3 -3
- package/persist-plugins/firebase.mjs.map +1 -1
- package/persist-plugins/indexeddb.js.map +1 -1
- package/persist-plugins/indexeddb.mjs.map +1 -1
- package/persist-plugins/local-storage.js +1 -1
- package/persist-plugins/local-storage.js.map +1 -1
- package/persist-plugins/local-storage.mjs +1 -1
- package/persist-plugins/local-storage.mjs.map +1 -1
- package/persist-plugins/mmkv.js.map +1 -1
- package/persist-plugins/mmkv.mjs.map +1 -1
- package/persist-plugins/query.js.map +1 -1
- package/persist-plugins/query.mjs.map +1 -1
- package/persist.d.ts +16 -1
- package/persist.js +279 -125
- package/persist.js.map +1 -1
- package/persist.mjs +280 -126
- package/persist.mjs.map +1 -1
- package/react-hooks/createObservableHook.js +1 -1
- package/react-hooks/createObservableHook.js.map +1 -1
- package/react-hooks/createObservableHook.mjs +1 -1
- package/react-hooks/createObservableHook.mjs.map +1 -1
- package/react-hooks/useFetch.d.ts +4 -3
- package/react-hooks/useFetch.js.map +1 -1
- package/react-hooks/useFetch.mjs.map +1 -1
- package/react-hooks/useHover.js.map +1 -1
- package/react-hooks/useHover.mjs.map +1 -1
- package/react-hooks/useMeasure.js.map +1 -1
- package/react-hooks/useMeasure.mjs.map +1 -1
- package/react-hooks/useObservableNextRouter.js.map +1 -1
- package/react-hooks/useObservableNextRouter.mjs.map +1 -1
- package/react-hooks/useObservableQuery.js.map +1 -1
- package/react-hooks/useObservableQuery.mjs.map +1 -1
- package/react-hooks/usePersistedObservable.d.ts +2 -2
- package/react-hooks/usePersistedObservable.js +3 -3
- package/react-hooks/usePersistedObservable.js.map +1 -1
- package/react-hooks/usePersistedObservable.mjs +3 -3
- package/react-hooks/usePersistedObservable.mjs.map +1 -1
- package/react.js +13 -8
- package/react.js.map +1 -1
- package/react.mjs +14 -9
- package/react.mjs.map +1 -1
- package/src/ObservableObject.d.ts +8 -4
- package/src/ObservablePrimitive.d.ts +2 -1
- package/src/activated.d.ts +3 -0
- package/src/batching.d.ts +3 -1
- package/src/computed.d.ts +1 -1
- package/src/config/enableDirectAccess.d.ts +1 -1
- package/src/config/enableDirectPeek.d.ts +1 -1
- package/src/config/enableReactTracking.d.ts +4 -3
- package/src/config/enableReactUse.d.ts +1 -1
- package/src/createObservable.d.ts +2 -2
- package/src/globals.d.ts +10 -9
- package/src/helpers/fetch.d.ts +4 -3
- package/src/helpers/time.d.ts +2 -2
- package/src/helpers.d.ts +3 -2
- package/src/history/trackHistory.d.ts +1 -1
- package/src/observable.d.ts +6 -15
- package/src/observableInterfaces.d.ts +68 -315
- package/src/observableTypes.d.ts +93 -0
- package/src/persist/observablePersistRemoteFunctionsAdapter.d.ts +1 -1
- package/src/persist/persistActivateNode.d.ts +1 -0
- package/src/persist/persistHelpers.d.ts +1 -1
- package/src/persist/persistObservable.d.ts +3 -3
- package/src/persistTypes.d.ts +229 -0
- package/src/proxy.d.ts +2 -1
- package/src/react/Computed.d.ts +1 -1
- package/src/react/Switch.d.ts +3 -3
- package/src/react/reactInterfaces.d.ts +2 -1
- package/src/react/usePauseProvider.d.ts +3 -3
- package/src/react/useWhen.d.ts +2 -2
- package/src/react-hooks/useFetch.d.ts +4 -3
- package/src/react-hooks/usePersistedObservable.d.ts +2 -2
- package/src/retry.d.ts +4 -0
- package/src/trackSelector.d.ts +3 -2
- package/src/when.d.ts +6 -2
- package/trace.js.map +1 -1
- 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
|
-
|
|
143
|
-
|
|
144
|
-
|
|
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
|
-
|
|
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 {
|
|
220
|
-
const needsUpdate = pending || (
|
|
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 (
|
|
228
|
-
syncState.
|
|
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),
|
|
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
|
|
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,
|
|
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 (
|
|
436
|
-
metadata.
|
|
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
|
|
475
|
+
transformedChanges = transformLoadData(changes, persistOptions.remote, false);
|
|
442
476
|
}
|
|
443
|
-
if (
|
|
444
|
-
if (transformedChanges
|
|
445
|
-
|
|
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
|
-
|
|
450
|
-
|
|
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.
|
|
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
|
-
|
|
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 !==
|
|
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
|
-
|
|
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(
|
|
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
|
|
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
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
if (
|
|
621
|
-
|
|
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
|
-
|
|
715
|
+
// @ts-expect-error Fix this type
|
|
716
|
+
state.setInObservableAtPath(obs, path, pathTypes, value, mode);
|
|
624
717
|
});
|
|
625
718
|
}
|
|
626
719
|
}
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
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
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
});
|
|
654
|
-
}
|
|
655
|
-
},
|
|
656
|
-
});
|
|
725
|
+
},
|
|
726
|
+
});
|
|
727
|
+
};
|
|
728
|
+
runGet();
|
|
657
729
|
}
|
|
658
730
|
else {
|
|
659
|
-
|
|
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
|
|
786
|
+
return syncState;
|
|
712
787
|
}
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
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 (
|
|
722
|
-
|
|
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
|
-
|
|
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;
|