@legendapp/state 2.2.0-next.65 → 2.2.0-next.67
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +29 -15
- package/index.js.map +1 -1
- package/index.mjs +29 -15
- package/index.mjs.map +1 -1
- package/package.json +21 -21
- package/{cache-plugins → persist-plugins}/async-storage.d.ts +3 -3
- package/{cache-plugins → persist-plugins}/async-storage.js +4 -4
- package/persist-plugins/async-storage.js.map +1 -0
- package/{cache-plugins → persist-plugins}/async-storage.mjs +4 -4
- package/persist-plugins/async-storage.mjs.map +1 -0
- package/persist-plugins/firebase.js.map +1 -1
- package/persist-plugins/firebase.mjs.map +1 -1
- package/persist-plugins/indexeddb.d.ts +25 -0
- package/{cache-plugins → persist-plugins}/indexeddb.js +2 -2
- package/persist-plugins/indexeddb.js.map +1 -0
- package/{cache-plugins → persist-plugins}/indexeddb.mjs +2 -2
- package/persist-plugins/indexeddb.mjs.map +1 -0
- package/persist-plugins/local-storage.d.ts +20 -0
- package/{cache-plugins → persist-plugins}/local-storage.js +10 -10
- package/persist-plugins/local-storage.js.map +1 -0
- package/{cache-plugins → persist-plugins}/local-storage.mjs +8 -8
- package/persist-plugins/local-storage.mjs.map +1 -0
- package/persist-plugins/mmkv.d.ts +14 -0
- package/{cache-plugins → persist-plugins}/mmkv.js +3 -3
- package/persist-plugins/mmkv.js.map +1 -0
- package/{cache-plugins → persist-plugins}/mmkv.mjs +3 -3
- package/persist-plugins/mmkv.mjs.map +1 -0
- package/persist.js +56 -53
- package/persist.js.map +1 -1
- package/persist.mjs +56 -53
- package/persist.mjs.map +1 -1
- package/react-hooks/usePersistedObservable.d.ts +2 -2
- package/src/helpers.ts +28 -14
- package/src/observableInterfaces.ts +2 -3
- package/src/persist/persistObservable.ts +24 -20
- package/src/{cache-plugins → persist-plugins}/async-storage.ts +6 -6
- package/src/persist-plugins/firebase.ts +3 -3
- package/src/{cache-plugins → persist-plugins}/indexeddb.ts +17 -17
- package/src/{cache-plugins → persist-plugins}/local-storage.ts +8 -8
- package/src/{cache-plugins → persist-plugins}/mmkv.ts +13 -13
- package/src/persistTypes.ts +15 -22
- package/src/react-hooks/usePersistedObservable.ts +2 -2
- package/src/sync/syncObservable.ts +93 -84
- package/src/sync/syncObservableAdapter.ts +2 -2
- package/src/sync/synced.ts +2 -2
- package/src/sync-plugins/fetch.ts +3 -3
- package/src/syncTypes.ts +19 -20
- package/sync-plugins/fetch.d.ts +2 -2
- package/sync-plugins/fetch.js.map +1 -1
- package/sync-plugins/fetch.mjs.map +1 -1
- package/sync.js +56 -53
- package/sync.js.map +1 -1
- package/sync.mjs +56 -53
- package/sync.mjs.map +1 -1
- package/cache-plugins/async-storage.js.map +0 -1
- package/cache-plugins/async-storage.mjs.map +0 -1
- package/cache-plugins/indexeddb.d.ts +0 -25
- package/cache-plugins/indexeddb.js.map +0 -1
- package/cache-plugins/indexeddb.mjs.map +0 -1
- package/cache-plugins/local-storage.d.ts +0 -20
- package/cache-plugins/local-storage.js.map +0 -1
- package/cache-plugins/local-storage.mjs.map +0 -1
- package/cache-plugins/mmkv.d.ts +0 -14
- package/cache-plugins/mmkv.js.map +0 -1
- package/cache-plugins/mmkv.mjs.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Observable, ObservableParam,
|
|
1
|
+
import { Observable, ObservableParam, LegacyPersistOptions, observable } from '@legendapp/state';
|
|
2
2
|
import { persistObservable } from '@legendapp/state/persist';
|
|
3
3
|
import { useMemo } from 'react';
|
|
4
4
|
|
|
@@ -13,7 +13,7 @@ import { useMemo } from 'react';
|
|
|
13
13
|
* @see https://www.legendapp.com/dev/state/react/#useObservable
|
|
14
14
|
*/
|
|
15
15
|
export function usePersistedObservable<T>(params: {
|
|
16
|
-
options:
|
|
16
|
+
options: LegacyPersistOptions<T>;
|
|
17
17
|
initialValue?: T | (() => T) | (() => Promise<T>);
|
|
18
18
|
}): Observable<T> {
|
|
19
19
|
// Create the observable from the default value
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
PersistMetadata,
|
|
3
|
+
PersistOptions,
|
|
4
4
|
Change,
|
|
5
5
|
ClassConstructor,
|
|
6
6
|
ListenerParams,
|
|
7
7
|
NodeValue,
|
|
8
8
|
Observable,
|
|
9
|
-
|
|
9
|
+
ObservablePersistPlugin,
|
|
10
10
|
ObservableObject,
|
|
11
11
|
ObservableParam,
|
|
12
12
|
ObservableSyncClass,
|
|
13
13
|
ObservableSyncState,
|
|
14
14
|
SyncTransform,
|
|
15
|
-
|
|
15
|
+
SyncedOptions,
|
|
16
16
|
TypeAtPath,
|
|
17
17
|
} from '@legendapp/state';
|
|
18
18
|
import {
|
|
@@ -36,21 +36,21 @@ import { observableSyncConfiguration } from './configureObservableSync';
|
|
|
36
36
|
import { removeNullUndefined } from './syncHelpers';
|
|
37
37
|
import { syncObservableAdapter } from './syncObservableAdapter';
|
|
38
38
|
|
|
39
|
-
const { globalState, symbolLinked, getNode } = internal;
|
|
39
|
+
const { globalState, symbolLinked, getNode, getNodeValue } = internal;
|
|
40
40
|
|
|
41
41
|
export const mapSyncPlugins: WeakMap<
|
|
42
|
-
ClassConstructor<
|
|
42
|
+
ClassConstructor<ObservablePersistPlugin | ObservableSyncClass>,
|
|
43
43
|
{
|
|
44
|
-
plugin:
|
|
44
|
+
plugin: ObservablePersistPlugin | ObservableSyncClass;
|
|
45
45
|
initialized: Observable<boolean>;
|
|
46
46
|
}
|
|
47
47
|
> = new WeakMap();
|
|
48
48
|
|
|
49
|
-
const metadatas = new WeakMap<ObservableParam<any>,
|
|
49
|
+
const metadatas = new WeakMap<ObservableParam<any>, PersistMetadata>();
|
|
50
50
|
const promisesLocalSaves = new Set<Promise<void>>();
|
|
51
51
|
|
|
52
52
|
interface LocalState {
|
|
53
|
-
|
|
53
|
+
pluginPersist?: ObservablePersistPlugin;
|
|
54
54
|
pluginSync?: ObservableSyncClass;
|
|
55
55
|
pendingChanges?: Record<string, { p: any; v?: any; t: TypeAtPath[] }>;
|
|
56
56
|
numSavesOutstanding?: number;
|
|
@@ -72,15 +72,15 @@ interface PreppedChangeRemote {
|
|
|
72
72
|
|
|
73
73
|
type ChangeWithPathStr = Change & { pathStr: string };
|
|
74
74
|
|
|
75
|
-
function parseLocalConfig(config: string |
|
|
75
|
+
function parseLocalConfig(config: string | PersistOptions | undefined): {
|
|
76
76
|
table: string;
|
|
77
|
-
config:
|
|
77
|
+
config: PersistOptions;
|
|
78
78
|
} {
|
|
79
79
|
return config
|
|
80
80
|
? isString(config)
|
|
81
81
|
? { table: config, config: { name: config } }
|
|
82
82
|
: { table: config.name, config }
|
|
83
|
-
: ({} as { table: string; config:
|
|
83
|
+
: ({} as { table: string; config: PersistOptions });
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
function doInOrder<T>(arg1: T | Promise<T>, arg2: (value: T) => void): any {
|
|
@@ -128,19 +128,19 @@ async function updateMetadataImmediate<T>(
|
|
|
128
128
|
obs: ObservableParam<any>,
|
|
129
129
|
localState: LocalState,
|
|
130
130
|
syncState: Observable<ObservableSyncState>,
|
|
131
|
-
syncOptions:
|
|
132
|
-
newMetadata:
|
|
131
|
+
syncOptions: SyncedOptions<T>,
|
|
132
|
+
newMetadata: PersistMetadata,
|
|
133
133
|
) {
|
|
134
134
|
const saves = Array.from(promisesLocalSaves);
|
|
135
135
|
if (saves.length > 0) {
|
|
136
136
|
await Promise.all(saves);
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
-
const {
|
|
140
|
-
const { table, config } = parseLocalConfig(syncOptions?.
|
|
139
|
+
const { pluginPersist } = localState;
|
|
140
|
+
const { table, config } = parseLocalConfig(syncOptions?.persist);
|
|
141
141
|
|
|
142
142
|
// Save metadata
|
|
143
|
-
const oldMetadata:
|
|
143
|
+
const oldMetadata: PersistMetadata | undefined = metadatas.get(obs);
|
|
144
144
|
|
|
145
145
|
const { lastSync, pending } = newMetadata;
|
|
146
146
|
|
|
@@ -149,14 +149,13 @@ async function updateMetadataImmediate<T>(
|
|
|
149
149
|
if (needsUpdate) {
|
|
150
150
|
const metadata = Object.assign({}, oldMetadata, newMetadata);
|
|
151
151
|
metadatas.set(obs, metadata);
|
|
152
|
-
if (
|
|
153
|
-
await
|
|
152
|
+
if (pluginPersist) {
|
|
153
|
+
await pluginPersist!.setMetadata(table, metadata, config);
|
|
154
154
|
}
|
|
155
155
|
|
|
156
156
|
if (lastSync) {
|
|
157
157
|
syncState.assign({
|
|
158
158
|
lastSync: lastSync,
|
|
159
|
-
dateModified: lastSync,
|
|
160
159
|
});
|
|
161
160
|
}
|
|
162
161
|
}
|
|
@@ -166,14 +165,14 @@ function updateMetadata<T>(
|
|
|
166
165
|
obs: ObservableParam<any>,
|
|
167
166
|
localState: LocalState,
|
|
168
167
|
syncState: ObservableObject<ObservableSyncState>,
|
|
169
|
-
syncOptions:
|
|
170
|
-
newMetadata:
|
|
168
|
+
syncOptions: SyncedOptions<T>,
|
|
169
|
+
newMetadata: PersistMetadata,
|
|
171
170
|
) {
|
|
172
171
|
if (localState.timeoutSaveMetadata) {
|
|
173
172
|
clearTimeout(localState.timeoutSaveMetadata);
|
|
174
173
|
}
|
|
175
174
|
localState.timeoutSaveMetadata = setTimeout(
|
|
176
|
-
() => updateMetadataImmediate(obs, localState, syncState, syncOptions as
|
|
175
|
+
() => updateMetadataImmediate(obs, localState, syncState, syncOptions as SyncedOptions<T>, newMetadata),
|
|
177
176
|
0,
|
|
178
177
|
);
|
|
179
178
|
}
|
|
@@ -184,13 +183,13 @@ interface QueuedChange<T = any> {
|
|
|
184
183
|
obs: Observable<T>;
|
|
185
184
|
syncState: ObservableObject<ObservableSyncState>;
|
|
186
185
|
localState: LocalState;
|
|
187
|
-
syncOptions:
|
|
186
|
+
syncOptions: SyncedOptions<T>;
|
|
188
187
|
changes: ListenerParams['changes'];
|
|
189
188
|
}
|
|
190
189
|
|
|
191
190
|
let _queuedChanges: QueuedChange[] = [];
|
|
192
|
-
const _queuedRemoteChanges: Map<
|
|
193
|
-
const _queuedRemoteChangesTimeouts: Map<
|
|
191
|
+
const _queuedRemoteChanges: Map<SyncedOptions, QueuedChange[]> = new Map();
|
|
192
|
+
const _queuedRemoteChangesTimeouts: Map<SyncedOptions, number> = new Map();
|
|
194
193
|
|
|
195
194
|
function mergeChanges(changes: Change[]) {
|
|
196
195
|
const changesByPath = new Map<string, Change>();
|
|
@@ -235,7 +234,7 @@ async function processQueuedChanges() {
|
|
|
235
234
|
const queuedChanges = mergeQueuedChanges(_queuedChanges);
|
|
236
235
|
_queuedChanges = [];
|
|
237
236
|
|
|
238
|
-
const pendingSyncOptions = new Set<
|
|
237
|
+
const pendingSyncOptions = new Set<SyncedOptions>();
|
|
239
238
|
for (let i = 0; i < queuedChanges.length; i++) {
|
|
240
239
|
const change = queuedChanges[i];
|
|
241
240
|
if (!change.inRemoteChange) {
|
|
@@ -284,7 +283,7 @@ async function processQueuedChanges() {
|
|
|
284
283
|
}
|
|
285
284
|
}
|
|
286
285
|
|
|
287
|
-
async function processQueuedRemoteChanges(syncOptions:
|
|
286
|
+
async function processQueuedRemoteChanges(syncOptions: SyncedOptions) {
|
|
288
287
|
const arr = _queuedRemoteChanges.get(syncOptions);
|
|
289
288
|
if (arr?.length) {
|
|
290
289
|
const queuedRemoteChanges = mergeQueuedChanges(arr);
|
|
@@ -299,11 +298,11 @@ async function processQueuedRemoteChanges(syncOptions: SyncedParams) {
|
|
|
299
298
|
async function prepChangeLocal(queuedChange: QueuedChange): Promise<PreppedChangeLocal | undefined> {
|
|
300
299
|
const { syncState, changes, localState, syncOptions, inRemoteChange, isApplyingPending } = queuedChange;
|
|
301
300
|
|
|
302
|
-
const
|
|
301
|
+
const persist = syncOptions.persist;
|
|
303
302
|
const { pluginSync } = localState;
|
|
304
|
-
const { config: configLocal } = parseLocalConfig(
|
|
303
|
+
const { config: configLocal } = parseLocalConfig(persist);
|
|
305
304
|
const configRemote = syncOptions;
|
|
306
|
-
const saveLocal =
|
|
305
|
+
const saveLocal = persist?.name && !configLocal.readonly && !isApplyingPending && syncState.isEnabledLocal.peek();
|
|
307
306
|
const saveRemote = !!(
|
|
308
307
|
!inRemoteChange &&
|
|
309
308
|
pluginSync?.set &&
|
|
@@ -313,7 +312,10 @@ async function prepChangeLocal(queuedChange: QueuedChange): Promise<PreppedChang
|
|
|
313
312
|
|
|
314
313
|
if (saveLocal || saveRemote) {
|
|
315
314
|
if (saveLocal && !syncState.isLoadedLocal.peek()) {
|
|
316
|
-
console.error(
|
|
315
|
+
console.error(
|
|
316
|
+
'[legend-state] WARNING: An observable was changed before being loaded from persist',
|
|
317
|
+
persist,
|
|
318
|
+
);
|
|
317
319
|
return undefined;
|
|
318
320
|
}
|
|
319
321
|
const changesLocal: ChangeWithPathStr[] = [];
|
|
@@ -387,17 +389,20 @@ async function prepChangeRemote(queuedChange: QueuedChange): Promise<PreppedChan
|
|
|
387
389
|
isApplyingPending,
|
|
388
390
|
} = queuedChange;
|
|
389
391
|
|
|
390
|
-
const
|
|
392
|
+
const persist = syncOptions.persist;
|
|
391
393
|
const { pluginSync } = localState;
|
|
392
|
-
const { config: configLocal } = parseLocalConfig(
|
|
394
|
+
const { config: configLocal } = parseLocalConfig(persist!);
|
|
393
395
|
const configRemote = syncOptions;
|
|
394
|
-
const saveLocal =
|
|
396
|
+
const saveLocal = persist && !configLocal.readonly && !isApplyingPending && syncState.isEnabledLocal.peek();
|
|
395
397
|
const saveRemote =
|
|
396
398
|
!inRemoteChange && pluginSync?.set && configRemote?.enableSync !== false && syncState.isEnabledRemote.peek();
|
|
397
399
|
|
|
398
400
|
if (saveLocal || saveRemote) {
|
|
399
401
|
if (saveLocal && !syncState.isLoadedLocal.peek()) {
|
|
400
|
-
console.error(
|
|
402
|
+
console.error(
|
|
403
|
+
'[legend-state] WARNING: An observable was changed before being loaded from persist',
|
|
404
|
+
persist,
|
|
405
|
+
);
|
|
401
406
|
return undefined;
|
|
402
407
|
}
|
|
403
408
|
const changesRemote: ChangeWithPathStr[] = [];
|
|
@@ -509,12 +514,12 @@ async function doChangeLocal(changeInfo: PreppedChangeLocal | undefined) {
|
|
|
509
514
|
|
|
510
515
|
const { queuedChange, changesLocal, saveRemote } = changeInfo;
|
|
511
516
|
const { obs, syncState, localState, syncOptions: syncOptions } = queuedChange;
|
|
512
|
-
const {
|
|
517
|
+
const { pluginPersist } = localState;
|
|
513
518
|
|
|
514
|
-
const
|
|
515
|
-
const { table, config: configLocal } = parseLocalConfig(
|
|
519
|
+
const persist = syncOptions.persist;
|
|
520
|
+
const { table, config: configLocal } = parseLocalConfig(persist!);
|
|
516
521
|
const configRemote = syncOptions;
|
|
517
|
-
const shouldSaveMetadata =
|
|
522
|
+
const shouldSaveMetadata = persist && configRemote?.offlineBehavior === 'retry';
|
|
518
523
|
|
|
519
524
|
if (saveRemote && shouldSaveMetadata) {
|
|
520
525
|
// First save pending changes before saving local or remote
|
|
@@ -526,7 +531,7 @@ async function doChangeLocal(changeInfo: PreppedChangeLocal | undefined) {
|
|
|
526
531
|
if (changesLocal.length > 0) {
|
|
527
532
|
// Save the changes to local cache before saving to remote. They are already marked as pending so
|
|
528
533
|
// if remote sync fails or the app is closed before remote sync, it will attempt to sync them on the next load.
|
|
529
|
-
let promiseSet =
|
|
534
|
+
let promiseSet = pluginPersist!.set(table, changesLocal, configLocal);
|
|
530
535
|
|
|
531
536
|
if (promiseSet) {
|
|
532
537
|
promiseSet = promiseSet.then(() => {
|
|
@@ -545,13 +550,13 @@ async function doChangeRemote(changeInfo: PreppedChangeRemote | undefined) {
|
|
|
545
550
|
|
|
546
551
|
const { queuedChange, changesRemote } = changeInfo;
|
|
547
552
|
const { obs, syncState, localState, syncOptions: syncOptions } = queuedChange;
|
|
548
|
-
const {
|
|
553
|
+
const { pluginPersist, pluginSync } = localState;
|
|
549
554
|
|
|
550
|
-
const
|
|
551
|
-
const { table, config: configLocal } = parseLocalConfig(
|
|
555
|
+
const persist = syncOptions.persist;
|
|
556
|
+
const { table, config: configLocal } = parseLocalConfig(persist!);
|
|
552
557
|
const { offlineBehavior, allowSetIfGetError, onBeforeSet, onSetError, waitForSet, onAfterSet } =
|
|
553
|
-
syncOptions || ({} as
|
|
554
|
-
const shouldSaveMetadata =
|
|
558
|
+
syncOptions || ({} as SyncedOptions);
|
|
559
|
+
const shouldSaveMetadata = persist && offlineBehavior === 'retry';
|
|
555
560
|
|
|
556
561
|
if (changesRemote.length > 0) {
|
|
557
562
|
// Wait for remote to be ready before saving
|
|
@@ -598,9 +603,9 @@ async function doChangeRemote(changeInfo: PreppedChangeRemote | undefined) {
|
|
|
598
603
|
const pathStrs = Array.from(new Set(changesRemote.map((change) => change.pathStr)));
|
|
599
604
|
const { changes, lastSync } = saved;
|
|
600
605
|
if (pathStrs.length > 0) {
|
|
601
|
-
if (
|
|
602
|
-
const metadata:
|
|
603
|
-
const pending =
|
|
606
|
+
if (persist) {
|
|
607
|
+
const metadata: PersistMetadata = {};
|
|
608
|
+
const pending = pluginPersist!.getMetadata(table, configLocal)?.pending;
|
|
604
609
|
let transformedChanges: object | undefined = undefined;
|
|
605
610
|
|
|
606
611
|
for (let i = 0; i < pathStrs.length; i++) {
|
|
@@ -656,7 +661,7 @@ function onObsChange<T>(
|
|
|
656
661
|
obs: Observable<T>,
|
|
657
662
|
syncState: ObservableObject<ObservableSyncState>,
|
|
658
663
|
localState: LocalState,
|
|
659
|
-
syncOptions:
|
|
664
|
+
syncOptions: SyncedOptions<T>,
|
|
660
665
|
{ changes, loading, remote }: ListenerParams,
|
|
661
666
|
) {
|
|
662
667
|
if (!loading) {
|
|
@@ -680,27 +685,28 @@ function onObsChange<T>(
|
|
|
680
685
|
|
|
681
686
|
async function loadLocal<T>(
|
|
682
687
|
obs: ObservableParam<T>,
|
|
683
|
-
syncOptions:
|
|
688
|
+
syncOptions: SyncedOptions<any>,
|
|
684
689
|
syncState: ObservableObject<ObservableSyncState>,
|
|
685
690
|
localState: LocalState,
|
|
686
691
|
) {
|
|
687
|
-
const {
|
|
692
|
+
const { persist } = syncOptions;
|
|
688
693
|
|
|
689
|
-
if (
|
|
690
|
-
const
|
|
691
|
-
|
|
692
|
-
const { table, config } = parseLocalConfig(
|
|
694
|
+
if (persist) {
|
|
695
|
+
const PersistPlugin: ClassConstructor<ObservablePersistPlugin> =
|
|
696
|
+
persist.plugin! || observableSyncConfiguration.persist?.plugin;
|
|
697
|
+
const { table, config } = parseLocalConfig(persist);
|
|
698
|
+
const node = getNode(obs);
|
|
693
699
|
|
|
694
|
-
if (!
|
|
695
|
-
throw new Error('Local
|
|
700
|
+
if (!PersistPlugin) {
|
|
701
|
+
throw new Error('Local persist is not configured');
|
|
696
702
|
}
|
|
697
703
|
// Ensure there's only one instance of the cache plugin
|
|
698
|
-
if (!mapSyncPlugins.has(
|
|
699
|
-
const
|
|
700
|
-
const mapValue = { plugin:
|
|
701
|
-
mapSyncPlugins.set(
|
|
702
|
-
if (
|
|
703
|
-
const initializePromise =
|
|
704
|
+
if (!mapSyncPlugins.has(PersistPlugin)) {
|
|
705
|
+
const persistPlugin = new PersistPlugin();
|
|
706
|
+
const mapValue = { plugin: persistPlugin, initialized: observable(false) };
|
|
707
|
+
mapSyncPlugins.set(PersistPlugin, mapValue);
|
|
708
|
+
if (persistPlugin.initialize) {
|
|
709
|
+
const initializePromise = persistPlugin.initialize?.(observableSyncConfiguration?.persist || {});
|
|
704
710
|
if (isPromise(initializePromise)) {
|
|
705
711
|
await initializePromise;
|
|
706
712
|
}
|
|
@@ -708,33 +714,34 @@ async function loadLocal<T>(
|
|
|
708
714
|
mapValue.initialized.set(true);
|
|
709
715
|
}
|
|
710
716
|
|
|
711
|
-
const { plugin, initialized: initialized$ } = mapSyncPlugins.get(
|
|
712
|
-
const
|
|
717
|
+
const { plugin, initialized: initialized$ } = mapSyncPlugins.get(PersistPlugin)!;
|
|
718
|
+
const persistPlugin = plugin as ObservablePersistPlugin;
|
|
713
719
|
|
|
714
|
-
localState.
|
|
720
|
+
localState.pluginPersist = persistPlugin as ObservablePersistPlugin;
|
|
715
721
|
|
|
716
722
|
if (!initialized$.peek()) {
|
|
717
723
|
await when(initialized$);
|
|
718
724
|
}
|
|
719
725
|
|
|
720
726
|
// If cache has an asynchronous load, wait for it
|
|
721
|
-
if (
|
|
722
|
-
const promise =
|
|
727
|
+
if (persistPlugin.loadTable) {
|
|
728
|
+
const promise = persistPlugin.loadTable(table, config);
|
|
723
729
|
if (promise) {
|
|
724
730
|
await promise;
|
|
725
731
|
}
|
|
726
732
|
}
|
|
727
733
|
|
|
734
|
+
// Get current value for init
|
|
735
|
+
const prevValue = getNodeValue(node) as object;
|
|
736
|
+
|
|
728
737
|
// Get the value from state
|
|
729
|
-
let value =
|
|
730
|
-
const metadata =
|
|
738
|
+
let value = persistPlugin.getTable(table, prevValue, config);
|
|
739
|
+
const metadata = persistPlugin.getMetadata(table, config);
|
|
731
740
|
|
|
732
741
|
if (metadata) {
|
|
733
742
|
metadatas.set(obs, metadata);
|
|
734
743
|
localState.pendingChanges = metadata.pending;
|
|
735
|
-
// TODOV3 Remove dateModified
|
|
736
744
|
syncState.assign({
|
|
737
|
-
dateModified: metadata.lastSync,
|
|
738
745
|
lastSync: metadata.lastSync,
|
|
739
746
|
});
|
|
740
747
|
}
|
|
@@ -754,7 +761,6 @@ async function loadLocal<T>(
|
|
|
754
761
|
internal.globalState.isLoadingLocal = true;
|
|
755
762
|
|
|
756
763
|
// We want to merge the local data on top of any initial state the object is created with
|
|
757
|
-
const prevValue = obs.peek();
|
|
758
764
|
if (value === null && (!prevValue || (prevValue as any)[symbolLinked])) {
|
|
759
765
|
obs.set(value);
|
|
760
766
|
} else {
|
|
@@ -764,12 +770,10 @@ async function loadLocal<T>(
|
|
|
764
770
|
internal.globalState.isLoadingLocal = false;
|
|
765
771
|
}
|
|
766
772
|
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
(node.state as Observable<ObservableSyncState>).peek().clearLocal = () =>
|
|
773
|
+
node.state!.peek().clearLocal = () =>
|
|
770
774
|
Promise.all([
|
|
771
|
-
|
|
772
|
-
|
|
775
|
+
persistPlugin.deleteTable(table, config),
|
|
776
|
+
persistPlugin.deleteMetadata(table, config),
|
|
773
777
|
]) as unknown as Promise<void>;
|
|
774
778
|
}
|
|
775
779
|
syncState.isLoadedLocal.set(true);
|
|
@@ -777,7 +781,7 @@ async function loadLocal<T>(
|
|
|
777
781
|
|
|
778
782
|
export function syncObservable<T>(
|
|
779
783
|
obs$: ObservableParam<T>,
|
|
780
|
-
syncOptions:
|
|
784
|
+
syncOptions: SyncedOptions<T>,
|
|
781
785
|
): Observable<ObservableSyncState> {
|
|
782
786
|
const node = getNode(obs$);
|
|
783
787
|
|
|
@@ -786,7 +790,7 @@ export function syncObservable<T>(
|
|
|
786
790
|
syncOptions = Object.assign(
|
|
787
791
|
{
|
|
788
792
|
syncMode: 'auto',
|
|
789
|
-
} as
|
|
793
|
+
} as SyncedOptions,
|
|
790
794
|
observableSyncConfiguration,
|
|
791
795
|
removeNullUndefined(syncOptions),
|
|
792
796
|
);
|
|
@@ -847,13 +851,18 @@ export function syncObservable<T>(
|
|
|
847
851
|
const { v, t } = pending[key];
|
|
848
852
|
|
|
849
853
|
if (t.length === 0 || !value) {
|
|
850
|
-
value
|
|
854
|
+
if (isObject(value) && isObject(v)) {
|
|
855
|
+
Object.assign(value, v);
|
|
856
|
+
} else {
|
|
857
|
+
value = v;
|
|
858
|
+
}
|
|
851
859
|
} else if ((value as any)[p[0]] !== undefined) {
|
|
852
860
|
(value as any) = setAtPath(
|
|
853
861
|
value as any,
|
|
854
862
|
p,
|
|
855
863
|
t,
|
|
856
864
|
v,
|
|
865
|
+
'merge',
|
|
857
866
|
obs$.peek(),
|
|
858
867
|
(path: string[], value: any) => {
|
|
859
868
|
delete pending[key];
|
|
@@ -882,7 +891,7 @@ export function syncObservable<T>(
|
|
|
882
891
|
}
|
|
883
892
|
});
|
|
884
893
|
}
|
|
885
|
-
if (lastSync && syncOptions.
|
|
894
|
+
if (lastSync && syncOptions.persist) {
|
|
886
895
|
updateMetadata(obs$, localState, syncState, syncOptions, {
|
|
887
896
|
lastSync,
|
|
888
897
|
});
|
|
@@ -951,7 +960,7 @@ export function syncObservable<T>(
|
|
|
951
960
|
sync();
|
|
952
961
|
}
|
|
953
962
|
|
|
954
|
-
obs$.onChange(onObsChange.bind(this, obs$ as any, syncState, localState, syncOptions as
|
|
963
|
+
obs$.onChange(onObsChange.bind(this, obs$ as any, syncState, localState, syncOptions as SyncedOptions<any>));
|
|
955
964
|
});
|
|
956
965
|
|
|
957
966
|
return syncState;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { ObservableSyncGetParams,
|
|
1
|
+
import { ObservableSyncGetParams, SyncedOptions, isPromise, type ObservableSyncClass } from '@legendapp/state';
|
|
2
2
|
|
|
3
|
-
export function syncObservableAdapter<T = {}>({ get, set }:
|
|
3
|
+
export function syncObservableAdapter<T = {}>({ get, set }: SyncedOptions<T>): ObservableSyncClass {
|
|
4
4
|
const ret: ObservableSyncClass = {};
|
|
5
5
|
|
|
6
6
|
if (get) {
|
package/src/sync/synced.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type { Synced,
|
|
1
|
+
import type { Synced, SyncedOptions } from '@legendapp/state';
|
|
2
2
|
import { internal } from '@legendapp/state';
|
|
3
3
|
import { enableActivateSyncedNode } from './activateSyncedNode';
|
|
4
4
|
|
|
5
5
|
const { symbolLinked } = internal;
|
|
6
6
|
|
|
7
|
-
export function synced<T>(params:
|
|
7
|
+
export function synced<T>(params: SyncedOptions<T>): Synced<T> {
|
|
8
8
|
installPersistActivateNode();
|
|
9
9
|
return (() => ({
|
|
10
10
|
[symbolLinked]: { ...params, synced: true },
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Synced,
|
|
1
|
+
import { Synced, SyncedOptions, SyncedSetParams, isString } from '@legendapp/state';
|
|
2
2
|
import { synced } from '@legendapp/state/persist';
|
|
3
3
|
|
|
4
|
-
export interface SyncedFetchProps extends Omit<
|
|
4
|
+
export interface SyncedFetchProps extends Omit<SyncedOptions, 'get' | 'set'> {
|
|
5
5
|
get: string | RequestInfo;
|
|
6
6
|
set?: string | RequestInfo;
|
|
7
7
|
getInit?: RequestInit;
|
|
@@ -20,7 +20,7 @@ export function syncedFetch<T>({
|
|
|
20
20
|
onSet,
|
|
21
21
|
onSetValueType,
|
|
22
22
|
}: SyncedFetchProps): Synced<T> {
|
|
23
|
-
const ret:
|
|
23
|
+
const ret: SyncedOptions = {
|
|
24
24
|
get: () => fetch(get, getInit).then((response) => response[valueType || 'json']()),
|
|
25
25
|
};
|
|
26
26
|
|
package/src/syncTypes.ts
CHANGED
|
@@ -16,9 +16,9 @@ import {
|
|
|
16
16
|
} from './observableInterfaces';
|
|
17
17
|
import { Observable, ObservableParam, ObservableState } from './observableTypes';
|
|
18
18
|
|
|
19
|
-
export interface
|
|
19
|
+
export interface PersistOptions<T = any> {
|
|
20
20
|
name: string;
|
|
21
|
-
plugin?: ClassConstructor<
|
|
21
|
+
plugin?: ClassConstructor<ObservablePersistPlugin, T[]>;
|
|
22
22
|
transform?: SyncTransform<T>;
|
|
23
23
|
readonly?: boolean;
|
|
24
24
|
mmkv?: MMKVConfiguration;
|
|
@@ -48,13 +48,13 @@ export type SyncedSetParams<T> = SetParams<T> & {
|
|
|
48
48
|
|
|
49
49
|
export type GetMode = 'set' | 'assign' | 'merge' | 'append' | 'prepend';
|
|
50
50
|
|
|
51
|
-
export interface
|
|
51
|
+
export interface SyncedOptions<T = any> extends Omit<LinkedParams<T>, 'get' | 'set'> {
|
|
52
52
|
get?: (params: SyncedGetParams) => Promise<T> | T;
|
|
53
53
|
set?: (params: SyncedSetParams<T>) => void | Promise<any>;
|
|
54
54
|
subscribe?: (params: { node: NodeValue; update: UpdateFn; refresh: () => void }) => void;
|
|
55
55
|
retry?: RetryOptions;
|
|
56
56
|
offlineBehavior?: false | 'retry';
|
|
57
|
-
|
|
57
|
+
persist?: PersistOptions<any>;
|
|
58
58
|
debounceSet?: number;
|
|
59
59
|
syncMode?: 'auto' | 'manual';
|
|
60
60
|
getMode?: GetMode;
|
|
@@ -69,11 +69,11 @@ export interface SyncedParams<T = any> extends Omit<LinkedParams<T>, 'get' | 'se
|
|
|
69
69
|
allowSetIfGetError?: boolean;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
export interface SyncedParamsGlobal<T = any> extends Omit<
|
|
73
|
-
|
|
72
|
+
export interface SyncedParamsGlobal<T = any> extends Omit<SyncedOptions<T>, 'get' | 'set' | 'persist'> {
|
|
73
|
+
persist?: ObservablePersistPluginOptions & { plugin?: ClassConstructor<ObservablePersistPlugin, T[]> };
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
export interface
|
|
76
|
+
export interface ObservablePersistPluginOptions {
|
|
77
77
|
onGetError?: (error: Error) => void;
|
|
78
78
|
onSetError?: (error: Error) => void;
|
|
79
79
|
indexedDB?: {
|
|
@@ -86,17 +86,17 @@ export interface ObservableCachePluginOptions {
|
|
|
86
86
|
preload?: boolean | string[];
|
|
87
87
|
};
|
|
88
88
|
}
|
|
89
|
-
export interface
|
|
90
|
-
initialize?(config:
|
|
91
|
-
loadTable?(table: string, config:
|
|
92
|
-
getTable<T = any>(table: string, config:
|
|
93
|
-
set(table: string, changes: Change[], config:
|
|
94
|
-
deleteTable(table: string, config:
|
|
95
|
-
getMetadata(table: string, config:
|
|
96
|
-
setMetadata(table: string, metadata:
|
|
97
|
-
deleteMetadata(table: string, config:
|
|
89
|
+
export interface ObservablePersistPlugin {
|
|
90
|
+
initialize?(config: ObservablePersistPluginOptions): void | Promise<void>;
|
|
91
|
+
loadTable?(table: string, config: PersistOptions): Promise<any> | void;
|
|
92
|
+
getTable<T = any>(table: string, init: object, config: PersistOptions): T;
|
|
93
|
+
set(table: string, changes: Change[], config: PersistOptions): Promise<any> | void;
|
|
94
|
+
deleteTable(table: string, config: PersistOptions): Promise<any> | void;
|
|
95
|
+
getMetadata(table: string, config: PersistOptions): PersistMetadata;
|
|
96
|
+
setMetadata(table: string, metadata: PersistMetadata, config: PersistOptions): Promise<any> | void;
|
|
97
|
+
deleteMetadata(table: string, config: PersistOptions): Promise<any> | void;
|
|
98
98
|
}
|
|
99
|
-
export interface
|
|
99
|
+
export interface PersistMetadata {
|
|
100
100
|
id?: '__legend_metadata';
|
|
101
101
|
// modified ?: number;
|
|
102
102
|
lastSync?: number;
|
|
@@ -110,7 +110,6 @@ export interface ObservableSyncStateBase {
|
|
|
110
110
|
isLoadedLocal: boolean;
|
|
111
111
|
isEnabledLocal: boolean;
|
|
112
112
|
isEnabledRemote: boolean;
|
|
113
|
-
dateModified?: number;
|
|
114
113
|
lastSync?: number;
|
|
115
114
|
syncCount?: number;
|
|
116
115
|
clearLocal: () => Promise<void>;
|
|
@@ -130,14 +129,14 @@ export type ObservableSyncState = ObservableState & ObservableSyncStateBase;
|
|
|
130
129
|
export interface ObservableSyncSetParams<T> {
|
|
131
130
|
syncState: Observable<ObservableSyncState>;
|
|
132
131
|
obs: ObservableParam<T>;
|
|
133
|
-
options:
|
|
132
|
+
options: SyncedOptions<T>;
|
|
134
133
|
changes: Change[];
|
|
135
134
|
value: T;
|
|
136
135
|
}
|
|
137
136
|
export interface ObservableSyncGetParams<T> {
|
|
138
137
|
state: Observable<ObservableSyncState>;
|
|
139
138
|
obs: ObservableParam<T>;
|
|
140
|
-
options:
|
|
139
|
+
options: SyncedOptions<T>;
|
|
141
140
|
dateModified?: number;
|
|
142
141
|
lastSync?: number;
|
|
143
142
|
mode?: GetMode;
|
package/sync-plugins/fetch.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Synced,
|
|
2
|
-
export interface SyncedFetchProps extends Omit<
|
|
1
|
+
import { Synced, SyncedOptions, SyncedSetParams } from '@legendapp/state';
|
|
2
|
+
export interface SyncedFetchProps extends Omit<SyncedOptions, 'get' | 'set'> {
|
|
3
3
|
get: string | RequestInfo;
|
|
4
4
|
set?: string | RequestInfo;
|
|
5
5
|
getInit?: RequestInit;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch.js","sources":["../src/sync-plugins/fetch.ts"],"sourcesContent":[null],"names":["isString","synced"],"mappings":";;;;;SAagB,WAAW,CAAI,EAC3B,GAAG,EACH,GAAG,EACH,OAAO,EACP,OAAO,EACP,SAAS,EACT,KAAK,EACL,cAAc,GACC,EAAA;AACf,IAAA,MAAM,GAAG,
|
|
1
|
+
{"version":3,"file":"fetch.js","sources":["../src/sync-plugins/fetch.ts"],"sourcesContent":[null],"names":["isString","synced"],"mappings":";;;;;SAagB,WAAW,CAAI,EAC3B,GAAG,EACH,GAAG,EACH,OAAO,EACP,OAAO,EACP,SAAS,EACT,KAAK,EACL,cAAc,GACC,EAAA;AACf,IAAA,MAAM,GAAG,GAAkB;QACvB,GAAG,EAAE,MAAM,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,SAAS,IAAI,MAAM,CAAC,EAAE,CAAC;KACrF,CAAC;IAEF,IAAI,GAAG,EAAE;AACL,QAAA,GAAG,CAAC,GAAG,GAAG,OAAO,MAA4B,KAAI;AAC7C,YAAA,MAAM,WAAW,GAAGA,cAAQ,CAAC,GAAG,CAAC,GAAI,EAAE,GAAG,EAAE,GAAG,EAAkB,GAAG,GAAG,CAAC;AACxE,YAAA,MAAM,QAAQ,GAAG,MAAM,KAAK,CACxB,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,EACtF,OAAO,CACV,CAAC;YACF,IAAI,KAAK,EAAE;AACP,gBAAA,MAAM,CAAC,KAAK,GAAG,QAAQ,CAAC,cAAc,IAAI,SAAS,IAAI,MAAM,CAAC,EAAE,CAAC;gBACjE,KAAK,CAAC,MAAM,CAAC,CAAC;aACjB;AACL,SAAC,CAAC;KACL;AAED,IAAA,OAAOC,cAAM,CAAC,GAAG,CAAC,CAAC;AACvB;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch.mjs","sources":["../src/sync-plugins/fetch.ts"],"sourcesContent":[null],"names":[],"mappings":";;;SAagB,WAAW,CAAI,EAC3B,GAAG,EACH,GAAG,EACH,OAAO,EACP,OAAO,EACP,SAAS,EACT,KAAK,EACL,cAAc,GACC,EAAA;AACf,IAAA,MAAM,GAAG,
|
|
1
|
+
{"version":3,"file":"fetch.mjs","sources":["../src/sync-plugins/fetch.ts"],"sourcesContent":[null],"names":[],"mappings":";;;SAagB,WAAW,CAAI,EAC3B,GAAG,EACH,GAAG,EACH,OAAO,EACP,OAAO,EACP,SAAS,EACT,KAAK,EACL,cAAc,GACC,EAAA;AACf,IAAA,MAAM,GAAG,GAAkB;QACvB,GAAG,EAAE,MAAM,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,SAAS,IAAI,MAAM,CAAC,EAAE,CAAC;KACrF,CAAC;IAEF,IAAI,GAAG,EAAE;AACL,QAAA,GAAG,CAAC,GAAG,GAAG,OAAO,MAA4B,KAAI;AAC7C,YAAA,MAAM,WAAW,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAI,EAAE,GAAG,EAAE,GAAG,EAAkB,GAAG,GAAG,CAAC;AACxE,YAAA,MAAM,QAAQ,GAAG,MAAM,KAAK,CACxB,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,EACtF,OAAO,CACV,CAAC;YACF,IAAI,KAAK,EAAE;AACP,gBAAA,MAAM,CAAC,KAAK,GAAG,QAAQ,CAAC,cAAc,IAAI,SAAS,IAAI,MAAM,CAAC,EAAE,CAAC;gBACjE,KAAK,CAAC,MAAM,CAAC,CAAC;aACjB;AACL,SAAC,CAAC;KACL;AAED,IAAA,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;AACvB;;;;"}
|