@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
package/src/helpers.ts
CHANGED
|
@@ -41,37 +41,49 @@ export function setAtPath<T extends object>(
|
|
|
41
41
|
path: string[],
|
|
42
42
|
pathTypes: TypeAtPath[],
|
|
43
43
|
value: any,
|
|
44
|
+
mode?: 'set' | 'merge',
|
|
44
45
|
fullObj?: T,
|
|
45
46
|
restore?: (path: string[], value: any) => void,
|
|
46
47
|
) {
|
|
47
48
|
let o: Record<string, any> = obj;
|
|
48
49
|
let oFull: Record<string, any> | undefined = fullObj;
|
|
50
|
+
let p: string | undefined = undefined;
|
|
49
51
|
if (path.length > 0) {
|
|
50
52
|
for (let i = 0; i < path.length; i++) {
|
|
51
|
-
|
|
52
|
-
if (
|
|
53
|
-
// Don't set if the value is the same. This prevents creating a new key
|
|
54
|
-
// when setting undefined on an object without this key
|
|
55
|
-
if (o[p] !== value) {
|
|
56
|
-
o[p] = value;
|
|
57
|
-
}
|
|
58
|
-
} else if (o[p] === symbolDelete) {
|
|
53
|
+
p = path[i];
|
|
54
|
+
if (o[p] === symbolDelete) {
|
|
59
55
|
// If this was previously deleted, restore it
|
|
60
56
|
if (oFull) {
|
|
61
57
|
o[p] = oFull[p];
|
|
62
58
|
restore?.(path.slice(0, i + 1), o[p]);
|
|
63
59
|
}
|
|
64
|
-
|
|
60
|
+
return obj;
|
|
65
61
|
} else if (o[p] === undefined || o[p] === null) {
|
|
66
62
|
o[p] = initializePathType(pathTypes[i]);
|
|
67
63
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
oFull
|
|
64
|
+
if (i < path.length - 1) {
|
|
65
|
+
o = o[p];
|
|
66
|
+
if (oFull) {
|
|
67
|
+
oFull = oFull[p];
|
|
68
|
+
}
|
|
71
69
|
}
|
|
72
70
|
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Don't set if the value is the same. This prevents creating a new key
|
|
74
|
+
// when setting undefined on an object without this key
|
|
75
|
+
if (p === undefined) {
|
|
76
|
+
if (mode === 'merge') {
|
|
77
|
+
obj = _mergeIntoObservable(obj, value);
|
|
78
|
+
} else {
|
|
79
|
+
obj = value;
|
|
80
|
+
}
|
|
73
81
|
} else {
|
|
74
|
-
|
|
82
|
+
if (mode === 'merge') {
|
|
83
|
+
o[p] = _mergeIntoObservable(o[p], value);
|
|
84
|
+
} else {
|
|
85
|
+
o[p] = value;
|
|
86
|
+
}
|
|
75
87
|
}
|
|
76
88
|
|
|
77
89
|
return obj;
|
|
@@ -81,7 +93,7 @@ export function setInObservableAtPath(
|
|
|
81
93
|
path: string[],
|
|
82
94
|
pathTypes: TypeAtPath[],
|
|
83
95
|
value: any,
|
|
84
|
-
mode: 'assign' | 'set',
|
|
96
|
+
mode: 'assign' | 'set' | 'merge',
|
|
85
97
|
) {
|
|
86
98
|
let o: Record<string, any> = obs;
|
|
87
99
|
let v = value;
|
|
@@ -100,6 +112,8 @@ export function setInObservableAtPath(
|
|
|
100
112
|
// Assign if possible, or set otherwise
|
|
101
113
|
else if (mode === 'assign' && (o as Observable).assign && isObject(o.peek())) {
|
|
102
114
|
(o as Observable<{}>).assign(v);
|
|
115
|
+
} else if (mode === 'merge') {
|
|
116
|
+
mergeIntoObservable(o, v);
|
|
103
117
|
} else {
|
|
104
118
|
o.set(v);
|
|
105
119
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { symbolOpaque } from './globals';
|
|
2
2
|
import type { Observable, ObservableParam } from './observableTypes';
|
|
3
|
-
import { GetMode, ObservableSyncState,
|
|
3
|
+
import { GetMode, ObservableSyncState, SyncedOptions } from './syncTypes';
|
|
4
4
|
|
|
5
5
|
export type TrackingType = undefined | true | symbol; // true === shallow
|
|
6
6
|
|
|
@@ -67,7 +67,6 @@ export interface TrackingState {
|
|
|
67
67
|
interface BaseNodeValue {
|
|
68
68
|
children?: Map<string, ChildNodeValue>;
|
|
69
69
|
proxy?: object;
|
|
70
|
-
// TODOV3 Remove this
|
|
71
70
|
root: ObservableRoot;
|
|
72
71
|
listeners?: Set<NodeValueListener>;
|
|
73
72
|
listenersImmediate?: Set<NodeValueListener>;
|
|
@@ -86,7 +85,7 @@ interface BaseNodeValue {
|
|
|
86
85
|
needsExtract?: boolean;
|
|
87
86
|
state?: Observable<ObservableSyncState>;
|
|
88
87
|
activated?: boolean;
|
|
89
|
-
activationState?:
|
|
88
|
+
activationState?: SyncedOptions & { onError?: () => void; persistedRetry?: boolean };
|
|
90
89
|
dirtyFn?: () => void;
|
|
91
90
|
}
|
|
92
91
|
|
|
@@ -12,9 +12,9 @@ import type {
|
|
|
12
12
|
ObservablePersistRemoteFunctions,
|
|
13
13
|
ObservablePersistState,
|
|
14
14
|
PersistMetadata,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
LegacyPersistOptions,
|
|
16
|
+
LegacyPersistOptionsLocal,
|
|
17
|
+
LegacyPersistOptionsRemote,
|
|
18
18
|
PersistTransform,
|
|
19
19
|
TypeAtPath,
|
|
20
20
|
} from '@legendapp/state';
|
|
@@ -77,15 +77,15 @@ interface PreppedChangeRemote {
|
|
|
77
77
|
|
|
78
78
|
type ChangeWithPathStr = Change & { pathStr: string };
|
|
79
79
|
|
|
80
|
-
function parseLocalConfig(config: string |
|
|
80
|
+
function parseLocalConfig(config: string | LegacyPersistOptionsLocal | undefined): {
|
|
81
81
|
table: string;
|
|
82
|
-
config:
|
|
82
|
+
config: LegacyPersistOptionsLocal;
|
|
83
83
|
} {
|
|
84
84
|
return config
|
|
85
85
|
? isString(config)
|
|
86
86
|
? { table: config, config: { name: config } }
|
|
87
87
|
: { table: config.name, config }
|
|
88
|
-
: ({} as { table: string; config:
|
|
88
|
+
: ({} as { table: string; config: LegacyPersistOptionsLocal });
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
function doInOrder<T>(arg1: T | Promise<T>, arg2: (value: T) => void): any {
|
|
@@ -155,7 +155,7 @@ async function updateMetadataImmediate<T>(
|
|
|
155
155
|
obs: ObservableParam<any>,
|
|
156
156
|
localState: LocalState,
|
|
157
157
|
syncState: Observable<ObservablePersistState>,
|
|
158
|
-
persistOptions:
|
|
158
|
+
persistOptions: LegacyPersistOptions<T>,
|
|
159
159
|
newMetadata: PersistMetadata,
|
|
160
160
|
) {
|
|
161
161
|
const saves = Array.from(promisesLocalSaves);
|
|
@@ -194,14 +194,15 @@ function updateMetadata<T>(
|
|
|
194
194
|
obs: ObservableParam<any>,
|
|
195
195
|
localState: LocalState,
|
|
196
196
|
syncState: ObservableObject<ObservablePersistState>,
|
|
197
|
-
persistOptions:
|
|
197
|
+
persistOptions: LegacyPersistOptions<T>,
|
|
198
198
|
newMetadata: PersistMetadata,
|
|
199
199
|
) {
|
|
200
200
|
if (localState.timeoutSaveMetadata) {
|
|
201
201
|
clearTimeout(localState.timeoutSaveMetadata);
|
|
202
202
|
}
|
|
203
203
|
localState.timeoutSaveMetadata = setTimeout(
|
|
204
|
-
() =>
|
|
204
|
+
() =>
|
|
205
|
+
updateMetadataImmediate(obs, localState, syncState, persistOptions as LegacyPersistOptions<T>, newMetadata),
|
|
205
206
|
persistOptions?.remote?.metadataTimeout || 0,
|
|
206
207
|
);
|
|
207
208
|
}
|
|
@@ -212,7 +213,7 @@ interface QueuedChange<T = any> {
|
|
|
212
213
|
obs: Observable<T>;
|
|
213
214
|
syncState: ObservableObject<ObservablePersistState>;
|
|
214
215
|
localState: LocalState;
|
|
215
|
-
persistOptions:
|
|
216
|
+
persistOptions: LegacyPersistOptions<T>;
|
|
216
217
|
changes: ListenerParams['changes'];
|
|
217
218
|
}
|
|
218
219
|
|
|
@@ -566,7 +567,7 @@ async function doChangeRemote(changeInfo: PreppedChangeRemote | undefined) {
|
|
|
566
567
|
const local = persistOptions.local;
|
|
567
568
|
const { table, config: configLocal } = parseLocalConfig(local!);
|
|
568
569
|
const { offlineBehavior, allowSetIfError, onBeforeSet, onSetError, waitForSet, onAfterSet } =
|
|
569
|
-
persistOptions.remote || ({} as
|
|
570
|
+
persistOptions.remote || ({} as LegacyPersistOptionsRemote);
|
|
570
571
|
const shouldSaveMetadata = local && offlineBehavior === 'retry';
|
|
571
572
|
|
|
572
573
|
if (changesRemote.length > 0) {
|
|
@@ -668,7 +669,7 @@ function onObsChange<T>(
|
|
|
668
669
|
obs: Observable<T>,
|
|
669
670
|
syncState: ObservableObject<ObservablePersistState>,
|
|
670
671
|
localState: LocalState,
|
|
671
|
-
persistOptions:
|
|
672
|
+
persistOptions: LegacyPersistOptions<T>,
|
|
672
673
|
{ changes, loading, remote }: ListenerParams,
|
|
673
674
|
) {
|
|
674
675
|
if (!loading) {
|
|
@@ -692,7 +693,7 @@ function onObsChange<T>(
|
|
|
692
693
|
|
|
693
694
|
async function loadLocal<T>(
|
|
694
695
|
obs: ObservableParam<T>,
|
|
695
|
-
persistOptions:
|
|
696
|
+
persistOptions: LegacyPersistOptions<any>,
|
|
696
697
|
syncState: ObservableObject<ObservablePersistState>,
|
|
697
698
|
localState: LocalState,
|
|
698
699
|
) {
|
|
@@ -796,14 +797,17 @@ async function loadLocal<T>(
|
|
|
796
797
|
syncState.isLoadedLocal.set(true);
|
|
797
798
|
}
|
|
798
799
|
|
|
799
|
-
export function persistObservable<T>(
|
|
800
|
+
export function persistObservable<T>(
|
|
801
|
+
observable: ObservableParam<T>,
|
|
802
|
+
persistOptions: LegacyPersistOptions<T>,
|
|
803
|
+
): Observable<T>;
|
|
800
804
|
export function persistObservable<T>(
|
|
801
805
|
initial: T | (() => T) | (() => Promise<T>),
|
|
802
|
-
persistOptions:
|
|
806
|
+
persistOptions: LegacyPersistOptions<T>,
|
|
803
807
|
): Observable<T>;
|
|
804
808
|
export function persistObservable<T>(
|
|
805
809
|
initialOrObservable: ObservableParam<T> | T | (() => T) | (() => Promise<T>),
|
|
806
|
-
persistOptions:
|
|
810
|
+
persistOptions: LegacyPersistOptions<T>,
|
|
807
811
|
): Observable<T> {
|
|
808
812
|
const obs$ = (
|
|
809
813
|
isObservable(initialOrObservable)
|
|
@@ -820,7 +824,7 @@ export function persistObservable<T>(
|
|
|
820
824
|
removeNullUndefined(persistOptions.remote),
|
|
821
825
|
);
|
|
822
826
|
}
|
|
823
|
-
let { remote } = persistOptions as { remote:
|
|
827
|
+
let { remote } = persistOptions as { remote: LegacyPersistOptionsRemote<T> };
|
|
824
828
|
const { local } = persistOptions;
|
|
825
829
|
const remotePersistence = persistOptions.pluginRemote! || observablePersistConfiguration?.pluginRemote;
|
|
826
830
|
const localState: LocalState = {};
|
|
@@ -871,7 +875,7 @@ export function persistObservable<T>(
|
|
|
871
875
|
get({
|
|
872
876
|
state: syncState,
|
|
873
877
|
obs: obs$,
|
|
874
|
-
options: persistOptions as
|
|
878
|
+
options: persistOptions as LegacyPersistOptions<any>,
|
|
875
879
|
lastSync,
|
|
876
880
|
dateModified: lastSync,
|
|
877
881
|
onError: (error: Error) => {
|
|
@@ -945,7 +949,7 @@ export function persistObservable<T>(
|
|
|
945
949
|
}
|
|
946
950
|
}
|
|
947
951
|
if (lastSync && local) {
|
|
948
|
-
updateMetadata(obs$, localState, syncState, persistOptions as
|
|
952
|
+
updateMetadata(obs$, localState, syncState, persistOptions as LegacyPersistOptions<T>, {
|
|
949
953
|
lastSync,
|
|
950
954
|
});
|
|
951
955
|
}
|
|
@@ -1014,7 +1018,7 @@ export function persistObservable<T>(
|
|
|
1014
1018
|
}
|
|
1015
1019
|
|
|
1016
1020
|
obs$.onChange(
|
|
1017
|
-
onObsChange.bind(this, obs$ as any, syncState, localState, persistOptions as
|
|
1021
|
+
onObsChange.bind(this, obs$ as any, syncState, localState, persistOptions as LegacyPersistOptions<any>),
|
|
1018
1022
|
);
|
|
1019
1023
|
});
|
|
1020
1024
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
Change,
|
|
3
|
-
|
|
3
|
+
ObservablePersistPlugin,
|
|
4
4
|
ObservablePersistenceConfigLocalGlobalOptions,
|
|
5
5
|
PersistMetadata,
|
|
6
6
|
} from '@legendapp/state';
|
|
7
|
-
import { isArray, setAtPath
|
|
7
|
+
import { internal, isArray, setAtPath } from '@legendapp/state';
|
|
8
8
|
import type { AsyncStorageStatic } from '@react-native-async-storage/async-storage';
|
|
9
9
|
|
|
10
10
|
const MetadataSuffix = '__m';
|
|
@@ -13,7 +13,7 @@ let AsyncStorage: AsyncStorageStatic;
|
|
|
13
13
|
|
|
14
14
|
const { safeParse, safeStringify } = internal;
|
|
15
15
|
|
|
16
|
-
export class ObservablePersistAsyncStorage implements
|
|
16
|
+
export class ObservablePersistAsyncStorage implements ObservablePersistPlugin {
|
|
17
17
|
private data: Record<string, any> = {};
|
|
18
18
|
|
|
19
19
|
// Init
|
|
@@ -58,11 +58,11 @@ export class ObservablePersistAsyncStorage implements ObservablePersistLocal {
|
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
// Gets
|
|
61
|
-
public getTable(table: string) {
|
|
62
|
-
return this.data[table] ?? {};
|
|
61
|
+
public getTable(table: string, init: object) {
|
|
62
|
+
return this.data[table] ?? init ?? {};
|
|
63
63
|
}
|
|
64
64
|
public getMetadata(table: string): PersistMetadata {
|
|
65
|
-
return this.getTable(table + MetadataSuffix);
|
|
65
|
+
return this.getTable(table + MetadataSuffix, {});
|
|
66
66
|
}
|
|
67
67
|
// Sets
|
|
68
68
|
public set(table: string, changes: Change[]): Promise<void> {
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
ObservablePersistRemoteSetParams,
|
|
6
6
|
ObservablePrimitive,
|
|
7
7
|
ObservableParam,
|
|
8
|
-
|
|
8
|
+
LegacyPersistOptions,
|
|
9
9
|
QueryByModified,
|
|
10
10
|
TypeAtPath,
|
|
11
11
|
batch,
|
|
@@ -82,7 +82,7 @@ type SaveInfoDictionary<T = any> = {
|
|
|
82
82
|
};
|
|
83
83
|
|
|
84
84
|
interface PendingSaves {
|
|
85
|
-
options:
|
|
85
|
+
options: LegacyPersistOptions;
|
|
86
86
|
saves: SaveInfoDictionary;
|
|
87
87
|
}
|
|
88
88
|
|
|
@@ -564,7 +564,7 @@ class ObservablePersistFirebaseBase implements ObservablePersistRemoteClass {
|
|
|
564
564
|
return {};
|
|
565
565
|
}
|
|
566
566
|
private _constructBatch(
|
|
567
|
-
options:
|
|
567
|
+
options: LegacyPersistOptions,
|
|
568
568
|
batch: Record<string, string | object>,
|
|
569
569
|
basePath: string,
|
|
570
570
|
saves: SaveInfoDictionary,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
Change,
|
|
3
3
|
Observable,
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
ObservablePersistPluginOptions,
|
|
5
|
+
ObservablePersistPlugin,
|
|
6
6
|
PersistMetadata,
|
|
7
|
-
|
|
7
|
+
PersistOptions,
|
|
8
8
|
} from '@legendapp/state';
|
|
9
9
|
import { isPrimitive, isPromise, observable, setAtPath, when } from '@legendapp/state';
|
|
10
10
|
|
|
@@ -14,14 +14,14 @@ function requestToPromise(request: IDBRequest) {
|
|
|
14
14
|
return new Promise<void>((resolve) => (request.onsuccess = () => resolve()));
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
export class ObservablePersistIndexedDB implements
|
|
17
|
+
export class ObservablePersistIndexedDB implements ObservablePersistPlugin {
|
|
18
18
|
private tableData: Record<string, any> = {};
|
|
19
19
|
private tableMetadata: Record<string, any> = {};
|
|
20
20
|
private tablesAdjusted: Map<string, Observable<boolean>> = new Map();
|
|
21
21
|
private db: IDBDatabase | undefined;
|
|
22
22
|
private isSaveTaskQueued = false;
|
|
23
23
|
private pendingSaves = new Map<
|
|
24
|
-
|
|
24
|
+
PersistOptions,
|
|
25
25
|
Record<string, { tableName: string; tablePrev?: any; items: Set<string> }>
|
|
26
26
|
>();
|
|
27
27
|
private promisesQueued: (() => void)[] = [];
|
|
@@ -30,7 +30,7 @@ export class ObservablePersistIndexedDB implements ObservablePersistLocal {
|
|
|
30
30
|
this.doSave = this.doSave.bind(this);
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
public async initialize(config:
|
|
33
|
+
public async initialize(config: ObservablePersistPluginOptions) {
|
|
34
34
|
if (typeof indexedDB === 'undefined') return;
|
|
35
35
|
if (process.env.NODE_ENV === 'development' && !config?.indexedDB) {
|
|
36
36
|
console.error('[legend-state] Must configure ObservablePersistIndexedDB');
|
|
@@ -75,7 +75,7 @@ export class ObservablePersistIndexedDB implements ObservablePersistLocal {
|
|
|
75
75
|
};
|
|
76
76
|
});
|
|
77
77
|
}
|
|
78
|
-
public loadTable(table: string, config:
|
|
78
|
+
public loadTable(table: string, config: PersistOptions): void | Promise<void> {
|
|
79
79
|
if (!this.tableData[table]) {
|
|
80
80
|
const transaction = this.db!.transaction(table, 'readonly');
|
|
81
81
|
|
|
@@ -94,7 +94,7 @@ export class ObservablePersistIndexedDB implements ObservablePersistLocal {
|
|
|
94
94
|
} else {
|
|
95
95
|
const obsLoaded = observable(false);
|
|
96
96
|
this.tablesAdjusted.set(tableName, obsLoaded);
|
|
97
|
-
const data = this.getTable(table, config);
|
|
97
|
+
const data = this.getTable(table, {}, config);
|
|
98
98
|
let hasPromise = false;
|
|
99
99
|
let promises: Promise<any>[];
|
|
100
100
|
if (data) {
|
|
@@ -122,7 +122,7 @@ export class ObservablePersistIndexedDB implements ObservablePersistLocal {
|
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
|
-
public getTable(table: string, config:
|
|
125
|
+
public getTable(table: string, init: object, config: PersistOptions) {
|
|
126
126
|
const configIDB = config.indexedDB;
|
|
127
127
|
const prefix = configIDB?.prefixID;
|
|
128
128
|
const data = this.tableData[prefix ? table + '/' + prefix : table];
|
|
@@ -132,11 +132,11 @@ export class ObservablePersistIndexedDB implements ObservablePersistLocal {
|
|
|
132
132
|
return data;
|
|
133
133
|
}
|
|
134
134
|
}
|
|
135
|
-
public getMetadata(table: string, config:
|
|
135
|
+
public getMetadata(table: string, config: PersistOptions) {
|
|
136
136
|
const { tableName } = this.getMetadataTableName(table, config);
|
|
137
137
|
return this.tableMetadata[tableName];
|
|
138
138
|
}
|
|
139
|
-
public async setMetadata(table: string, metadata: PersistMetadata, config:
|
|
139
|
+
public async setMetadata(table: string, metadata: PersistMetadata, config: PersistOptions) {
|
|
140
140
|
const { tableName, tableNameBase } = this.getMetadataTableName(table, config);
|
|
141
141
|
// Assign new metadata into the table, and make sure it has the id
|
|
142
142
|
this.tableMetadata[tableName] = Object.assign(metadata, {
|
|
@@ -146,14 +146,14 @@ export class ObservablePersistIndexedDB implements ObservablePersistLocal {
|
|
|
146
146
|
const store = this.transactionStore(table);
|
|
147
147
|
return store.put(metadata);
|
|
148
148
|
}
|
|
149
|
-
public async deleteMetadata(table: string, config:
|
|
149
|
+
public async deleteMetadata(table: string, config: PersistOptions): Promise<void> {
|
|
150
150
|
const { tableName, tableNameBase } = this.getMetadataTableName(table, config);
|
|
151
151
|
delete this.tableMetadata[tableName];
|
|
152
152
|
const store = this.transactionStore(table);
|
|
153
153
|
const key = tableNameBase + MetadataSuffix;
|
|
154
154
|
store.delete(key);
|
|
155
155
|
}
|
|
156
|
-
public async set(table: string, changes: Change[], config:
|
|
156
|
+
public async set(table: string, changes: Change[], config: PersistOptions) {
|
|
157
157
|
if (typeof indexedDB === 'undefined') return;
|
|
158
158
|
|
|
159
159
|
if (!this.pendingSaves.has(config)) {
|
|
@@ -249,7 +249,7 @@ export class ObservablePersistIndexedDB implements ObservablePersistLocal {
|
|
|
249
249
|
|
|
250
250
|
promisesQueued.forEach((resolve) => resolve());
|
|
251
251
|
}
|
|
252
|
-
public async deleteTable(table: string, config:
|
|
252
|
+
public async deleteTable(table: string, config: PersistOptions): Promise<void> {
|
|
253
253
|
const configIDB = config.indexedDB;
|
|
254
254
|
const prefixID = configIDB?.prefixID;
|
|
255
255
|
const tableName = prefixID ? table + '/' + prefixID : table;
|
|
@@ -289,7 +289,7 @@ export class ObservablePersistIndexedDB implements ObservablePersistLocal {
|
|
|
289
289
|
}
|
|
290
290
|
}
|
|
291
291
|
// Private
|
|
292
|
-
private getMetadataTableName(table: string, config:
|
|
292
|
+
private getMetadataTableName(table: string, config: PersistOptions) {
|
|
293
293
|
const configIDB = config.indexedDB;
|
|
294
294
|
let name = '';
|
|
295
295
|
if (configIDB) {
|
|
@@ -357,7 +357,7 @@ export class ObservablePersistIndexedDB implements ObservablePersistLocal {
|
|
|
357
357
|
const transaction = this.db!.transaction(table, 'readwrite');
|
|
358
358
|
return transaction.objectStore(table);
|
|
359
359
|
}
|
|
360
|
-
private _setItem(table: string, key: string, value: any, store: IDBObjectStore, config:
|
|
360
|
+
private _setItem(table: string, key: string, value: any, store: IDBObjectStore, config: PersistOptions) {
|
|
361
361
|
if (!value) {
|
|
362
362
|
if (this.tableData[table]) {
|
|
363
363
|
delete this.tableData[table][key];
|
|
@@ -399,7 +399,7 @@ export class ObservablePersistIndexedDB implements ObservablePersistLocal {
|
|
|
399
399
|
prev: object,
|
|
400
400
|
value: Record<string, any>,
|
|
401
401
|
store: IDBObjectStore,
|
|
402
|
-
config:
|
|
402
|
+
config: PersistOptions,
|
|
403
403
|
) {
|
|
404
404
|
const keys = Object.keys(value);
|
|
405
405
|
let lastSet: IDBRequest | undefined;
|
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
import type { Change,
|
|
1
|
+
import type { Change, ObservablePersistPlugin, PersistMetadata } from '@legendapp/state';
|
|
2
2
|
import { internal, setAtPath } from '@legendapp/state';
|
|
3
3
|
|
|
4
4
|
const MetadataSuffix = '__m';
|
|
5
5
|
|
|
6
6
|
const { safeParse, safeStringify } = internal;
|
|
7
7
|
|
|
8
|
-
export class
|
|
8
|
+
export class ObservablePersistLocalStorageBase implements ObservablePersistPlugin {
|
|
9
9
|
private data: Record<string, any> = {};
|
|
10
10
|
private storage: Storage | undefined;
|
|
11
11
|
constructor(storage: Storage | undefined) {
|
|
12
12
|
this.storage = storage;
|
|
13
13
|
}
|
|
14
|
-
public getTable(table: string) {
|
|
14
|
+
public getTable(table: string, init: any) {
|
|
15
15
|
if (!this.storage) return undefined;
|
|
16
16
|
if (this.data[table] === undefined) {
|
|
17
17
|
try {
|
|
18
18
|
const value = this.storage.getItem(table);
|
|
19
|
-
this.data[table] = value ? safeParse(value) :
|
|
19
|
+
this.data[table] = value ? safeParse(value) : init;
|
|
20
20
|
} catch {
|
|
21
|
-
console.error('[legend-state]
|
|
21
|
+
console.error('[legend-state] ObservablePersistLocalStorageBase failed to parse', table);
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
return this.data[table];
|
|
25
25
|
}
|
|
26
26
|
public getMetadata(table: string): PersistMetadata {
|
|
27
|
-
return this.getTable(table + MetadataSuffix);
|
|
27
|
+
return this.getTable(table + MetadataSuffix, {});
|
|
28
28
|
}
|
|
29
29
|
public set(table: string, changes: Change[]): void {
|
|
30
30
|
if (!this.data[table]) {
|
|
@@ -64,7 +64,7 @@ export class ObservableCacheLocalStorageBase implements ObservableCachePlugin {
|
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
|
-
export class
|
|
67
|
+
export class ObservablePersistLocalStorage extends ObservablePersistLocalStorageBase {
|
|
68
68
|
constructor() {
|
|
69
69
|
super(
|
|
70
70
|
typeof localStorage !== 'undefined'
|
|
@@ -76,7 +76,7 @@ export class ObservableCacheLocalStorage extends ObservableCacheLocalStorageBase
|
|
|
76
76
|
);
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
|
-
export class
|
|
79
|
+
export class ObservablePersistSessionStorage extends ObservablePersistLocalStorageBase {
|
|
80
80
|
constructor() {
|
|
81
81
|
super(
|
|
82
82
|
typeof sessionStorage !== 'undefined'
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Change,
|
|
1
|
+
import type { Change, ObservablePersistPlugin, PersistMetadata, PersistOptions } from '@legendapp/state';
|
|
2
2
|
import { internal, setAtPath } from '@legendapp/state';
|
|
3
3
|
import { MMKV } from 'react-native-mmkv';
|
|
4
4
|
|
|
@@ -7,7 +7,7 @@ const MetadataSuffix = '__m';
|
|
|
7
7
|
|
|
8
8
|
const { safeParse, safeStringify } = internal;
|
|
9
9
|
|
|
10
|
-
export class ObservablePersistMMKV implements
|
|
10
|
+
export class ObservablePersistMMKV implements ObservablePersistPlugin {
|
|
11
11
|
private data: Record<string, any> = {};
|
|
12
12
|
private storages = new Map<symbol | string, MMKV>([
|
|
13
13
|
[
|
|
@@ -18,23 +18,23 @@ export class ObservablePersistMMKV implements ObservablePersistLocal {
|
|
|
18
18
|
],
|
|
19
19
|
]);
|
|
20
20
|
// Gets
|
|
21
|
-
public getTable<T = any>(table: string, config:
|
|
21
|
+
public getTable<T = any>(table: string, init: object, config: PersistOptions): T {
|
|
22
22
|
const storage = this.getStorage(config);
|
|
23
23
|
if (this.data[table] === undefined) {
|
|
24
24
|
try {
|
|
25
25
|
const value = storage.getString(table);
|
|
26
|
-
this.data[table] = value ? safeParse(value) :
|
|
26
|
+
this.data[table] = value ? safeParse(value) : init;
|
|
27
27
|
} catch {
|
|
28
28
|
console.error('[legend-state] MMKV failed to parse', table);
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
return this.data[table];
|
|
32
32
|
}
|
|
33
|
-
public getMetadata(table: string, config:
|
|
34
|
-
return this.getTable(table + MetadataSuffix, config);
|
|
33
|
+
public getMetadata(table: string, config: PersistOptions): PersistMetadata {
|
|
34
|
+
return this.getTable(table + MetadataSuffix, {}, config);
|
|
35
35
|
}
|
|
36
36
|
// Sets
|
|
37
|
-
public set(table: string, changes: Change[], config:
|
|
37
|
+
public set(table: string, changes: Change[], config: PersistOptions) {
|
|
38
38
|
if (!this.data[table]) {
|
|
39
39
|
this.data[table] = {};
|
|
40
40
|
}
|
|
@@ -44,19 +44,19 @@ export class ObservablePersistMMKV implements ObservablePersistLocal {
|
|
|
44
44
|
}
|
|
45
45
|
this.save(table, config);
|
|
46
46
|
}
|
|
47
|
-
public setMetadata(table: string, metadata: PersistMetadata, config:
|
|
47
|
+
public setMetadata(table: string, metadata: PersistMetadata, config: PersistOptions) {
|
|
48
48
|
return this.setValue(table + MetadataSuffix, metadata, config);
|
|
49
49
|
}
|
|
50
|
-
public deleteTable(table: string, config:
|
|
50
|
+
public deleteTable(table: string, config: PersistOptions): void {
|
|
51
51
|
const storage = this.getStorage(config);
|
|
52
52
|
delete this.data[table];
|
|
53
53
|
storage.delete(table);
|
|
54
54
|
}
|
|
55
|
-
public deleteMetadata(table: string, config:
|
|
55
|
+
public deleteMetadata(table: string, config: PersistOptions) {
|
|
56
56
|
this.deleteTable(table + MetadataSuffix, config);
|
|
57
57
|
}
|
|
58
58
|
// Private
|
|
59
|
-
private getStorage(config:
|
|
59
|
+
private getStorage(config: PersistOptions): MMKV {
|
|
60
60
|
const { mmkv } = config;
|
|
61
61
|
if (mmkv) {
|
|
62
62
|
const key = JSON.stringify(mmkv);
|
|
@@ -70,11 +70,11 @@ export class ObservablePersistMMKV implements ObservablePersistLocal {
|
|
|
70
70
|
return this.storages.get(symbolDefault)!;
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
|
-
private async setValue(table: string, value: any, config:
|
|
73
|
+
private async setValue(table: string, value: any, config: PersistOptions) {
|
|
74
74
|
this.data[table] = value;
|
|
75
75
|
this.save(table, config);
|
|
76
76
|
}
|
|
77
|
-
private save(table: string, config:
|
|
77
|
+
private save(table: string, config: PersistOptions) {
|
|
78
78
|
const storage = this.getStorage(config);
|
|
79
79
|
const v = this.data[table];
|
|
80
80
|
if (v !== undefined) {
|
package/src/persistTypes.ts
CHANGED
|
@@ -6,7 +6,7 @@ import type { AsyncStorageStatic } from '@react-native-async-storage/async-stora
|
|
|
6
6
|
// @ts-ignore
|
|
7
7
|
import type { DatabaseReference, Query } from 'firebase/database';
|
|
8
8
|
|
|
9
|
-
import type { GetMode } from './syncTypes';
|
|
9
|
+
import type { GetMode, PersistMetadata } from './syncTypes';
|
|
10
10
|
import type {
|
|
11
11
|
ArrayValue,
|
|
12
12
|
Change,
|
|
@@ -24,7 +24,7 @@ export interface PersistTransform<TOrig = any, TSaved = TOrig> {
|
|
|
24
24
|
save?: (value: TOrig) => TSaved | Promise<TSaved>;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
export interface
|
|
27
|
+
export interface LegacyPersistOptionsLocal<T = any> {
|
|
28
28
|
name: string;
|
|
29
29
|
transform?: PersistTransform<T>;
|
|
30
30
|
fieldTransforms?: FieldTransforms<T>;
|
|
@@ -36,7 +36,7 @@ export interface PersistOptionsLocal<T = any> {
|
|
|
36
36
|
};
|
|
37
37
|
options?: any;
|
|
38
38
|
}
|
|
39
|
-
export type
|
|
39
|
+
export type LegacyPersistOptionsRemote<T = any> = ObservablePersistenceConfigRemoteGlobalOptions & {
|
|
40
40
|
readonly?: boolean;
|
|
41
41
|
waitForGet?: Selector<any>;
|
|
42
42
|
waitForSet?: LinkedParams['waitForSet'];
|
|
@@ -92,29 +92,22 @@ export interface ObservablePersistenceConfig {
|
|
|
92
92
|
localOptions?: ObservablePersistenceConfigLocalGlobalOptions;
|
|
93
93
|
remoteOptions?: ObservablePersistenceConfigRemoteGlobalOptions;
|
|
94
94
|
}
|
|
95
|
-
export interface
|
|
96
|
-
local?: string |
|
|
97
|
-
remote?:
|
|
95
|
+
export interface LegacyPersistOptions<T = any> {
|
|
96
|
+
local?: string | LegacyPersistOptionsLocal<T>;
|
|
97
|
+
remote?: LegacyPersistOptionsRemote<T>;
|
|
98
98
|
pluginLocal?: ClassConstructor<ObservablePersistLocal>;
|
|
99
99
|
pluginRemote?: ClassConstructor<ObservablePersistRemoteClass> | ObservablePersistRemoteFunctions<T>;
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
export interface PersistMetadata {
|
|
103
|
-
id?: '__legend_metadata';
|
|
104
|
-
// modified ?: number;
|
|
105
|
-
lastSync?: number;
|
|
106
|
-
pending?: any;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
102
|
export interface ObservablePersistLocal {
|
|
110
103
|
initialize?(config: ObservablePersistenceConfigLocalGlobalOptions): void | Promise<void>;
|
|
111
|
-
loadTable?(table: string, config:
|
|
112
|
-
getTable<T = any>(table: string, config:
|
|
113
|
-
set(table: string, changes: Change[], config:
|
|
114
|
-
deleteTable(table: string, config:
|
|
115
|
-
getMetadata(table: string, config:
|
|
116
|
-
setMetadata(table: string, metadata: PersistMetadata, config:
|
|
117
|
-
deleteMetadata(table: string, config:
|
|
104
|
+
loadTable?(table: string, config: LegacyPersistOptionsLocal): Promise<any> | void;
|
|
105
|
+
getTable<T = any>(table: string, config: LegacyPersistOptionsLocal): T;
|
|
106
|
+
set(table: string, changes: Change[], config: LegacyPersistOptionsLocal): Promise<any> | void;
|
|
107
|
+
deleteTable(table: string, config: LegacyPersistOptionsLocal): Promise<any> | void;
|
|
108
|
+
getMetadata(table: string, config: LegacyPersistOptionsLocal): PersistMetadata;
|
|
109
|
+
setMetadata(table: string, metadata: PersistMetadata, config: LegacyPersistOptionsLocal): Promise<any> | void;
|
|
110
|
+
deleteMetadata(table: string, config: LegacyPersistOptionsLocal): Promise<any> | void;
|
|
118
111
|
}
|
|
119
112
|
export interface ObservableOnChangeParams {
|
|
120
113
|
value: unknown;
|
|
@@ -127,14 +120,14 @@ export interface ObservableOnChangeParams {
|
|
|
127
120
|
export interface ObservablePersistRemoteSetParams<T> {
|
|
128
121
|
syncState: Observable<ObservablePersistState>;
|
|
129
122
|
obs: ObservableParam<T>;
|
|
130
|
-
options:
|
|
123
|
+
options: LegacyPersistOptions<T>;
|
|
131
124
|
changes: Change[];
|
|
132
125
|
value: T;
|
|
133
126
|
}
|
|
134
127
|
export interface ObservablePersistRemoteGetParams<T> {
|
|
135
128
|
state: Observable<ObservablePersistState>;
|
|
136
129
|
obs: ObservableParam<T>;
|
|
137
|
-
options:
|
|
130
|
+
options: LegacyPersistOptions<T>;
|
|
138
131
|
dateModified?: number;
|
|
139
132
|
lastSync?: number;
|
|
140
133
|
mode?: GetMode;
|