@legendapp/state 3.0.0-alpha.1 → 3.0.0-alpha.3
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/.DS_Store +0 -0
- package/CHANGELOG.md +1 -831
- package/LICENSE +1 -21
- package/README.md +1 -141
- package/as/arrayAsRecord.d.mts +5 -0
- package/as/arrayAsRecord.d.ts +5 -0
- package/as/arrayAsRecord.js +28 -0
- package/as/arrayAsRecord.mjs +26 -0
- package/as/arrayAsSet.d.mts +5 -0
- package/as/arrayAsSet.d.ts +5 -0
- package/as/arrayAsSet.js +13 -0
- package/as/arrayAsSet.mjs +11 -0
- package/as/arrayAsString.d.mts +5 -0
- package/as/arrayAsString.d.ts +5 -0
- package/as/arrayAsString.js +13 -0
- package/as/arrayAsString.mjs +11 -0
- package/as/numberAsString.d.mts +5 -0
- package/as/numberAsString.d.ts +5 -0
- package/as/numberAsString.js +13 -0
- package/as/numberAsString.mjs +11 -0
- package/as/recordAsArray.d.mts +5 -0
- package/as/recordAsArray.d.ts +5 -0
- package/as/recordAsArray.js +25 -0
- package/as/recordAsArray.mjs +23 -0
- package/as/recordAsString.d.mts +5 -0
- package/as/recordAsString.d.ts +5 -0
- package/as/recordAsString.js +13 -0
- package/as/recordAsString.mjs +11 -0
- package/as/setAsArray.d.mts +5 -0
- package/as/setAsArray.d.ts +5 -0
- package/as/setAsArray.js +13 -0
- package/as/setAsArray.mjs +11 -0
- package/as/setAsString.d.mts +5 -0
- package/as/setAsString.d.ts +5 -0
- package/as/setAsString.js +13 -0
- package/as/setAsString.mjs +11 -0
- package/as/stringAsArray.d.mts +5 -0
- package/as/stringAsArray.d.ts +5 -0
- package/as/stringAsArray.js +13 -0
- package/as/stringAsArray.mjs +11 -0
- package/as/stringAsNumber.d.mts +5 -0
- package/as/stringAsNumber.d.ts +5 -0
- package/as/stringAsNumber.js +16 -0
- package/as/stringAsNumber.mjs +14 -0
- package/as/stringAsRecord.d.mts +5 -0
- package/as/stringAsRecord.d.ts +5 -0
- package/as/stringAsRecord.js +15 -0
- package/as/stringAsRecord.mjs +13 -0
- package/as/stringAsSet.d.mts +5 -0
- package/as/stringAsSet.d.ts +5 -0
- package/as/stringAsSet.js +13 -0
- package/as/stringAsSet.mjs +11 -0
- package/babel.d.mts +21 -0
- package/babel.d.ts +21 -2
- package/babel.js +57 -53
- package/babel.mjs +65 -0
- package/config/enable$GetSet.js +13 -14
- package/config/enable$GetSet.mjs +13 -14
- package/config/enableReactComponents.d.mts +9 -0
- package/config/enableReactComponents.d.ts +4 -2
- package/config/enableReactComponents.js +13 -10
- package/config/enableReactComponents.mjs +13 -10
- package/config/enableReactNativeComponents.d.mts +22 -0
- package/config/enableReactNativeComponents.d.ts +6 -4
- package/config/enableReactNativeComponents.js +43 -47
- package/config/enableReactNativeComponents.mjs +43 -47
- package/config/enableReactTracking.d.mts +7 -0
- package/config/enableReactTracking.d.ts +3 -2
- package/config/enableReactTracking.js +33 -38
- package/config/enableReactTracking.mjs +33 -38
- package/config/enableReactUse.d.mts +10 -0
- package/config/enableReactUse.d.ts +4 -1
- package/config/enableReactUse.js +15 -14
- package/config/enableReactUse.mjs +15 -14
- package/config/{enable$GetSet.d.ts → enable_GetSet.d.mts} +4 -2
- package/config/enable_GetSet.d.ts +10 -0
- package/config/enable_PeekAssign.d.mts +10 -0
- package/config/enable_PeekAssign.d.ts +4 -2
- package/config/enable_PeekAssign.js +13 -14
- package/config/enable_PeekAssign.mjs +13 -14
- package/helpers/pageHash.d.mts +9 -0
- package/helpers/pageHash.d.ts +2 -0
- package/helpers/pageHash.js +25 -30
- package/helpers/pageHash.mjs +25 -30
- package/helpers/pageHashParams.d.mts +9 -0
- package/helpers/pageHashParams.d.ts +2 -0
- package/helpers/pageHashParams.js +34 -37
- package/helpers/pageHashParams.mjs +34 -37
- package/helpers/time.d.mts +6 -0
- package/helpers/time.d.ts +6 -3
- package/helpers/time.js +17 -17
- package/helpers/time.mjs +17 -17
- package/helpers/trackHistory.d.mts +6 -0
- package/helpers/trackHistory.d.ts +4 -2
- package/helpers/trackHistory.js +13 -16
- package/helpers/trackHistory.mjs +13 -16
- package/helpers/undoRedo.d.mts +37 -0
- package/helpers/undoRedo.d.ts +5 -3
- package/helpers/undoRedo.js +59 -94
- package/helpers/undoRedo.mjs +59 -94
- package/index.d.mts +404 -0
- package/index.d.ts +371 -28
- package/index.js +2015 -2166
- package/index.mjs +2015 -2166
- package/package.json +254 -195
- package/persist-plugins/async-storage.d.mts +18 -0
- package/persist-plugins/async-storage.d.ts +6 -3
- package/persist-plugins/async-storage.js +79 -86
- package/persist-plugins/async-storage.mjs +79 -86
- package/persist-plugins/indexeddb.d.mts +29 -0
- package/persist-plugins/indexeddb.d.ts +6 -3
- package/persist-plugins/indexeddb.js +331 -352
- package/persist-plugins/indexeddb.mjs +331 -352
- package/persist-plugins/local-storage.d.mts +23 -0
- package/persist-plugins/local-storage.d.ts +8 -5
- package/persist-plugins/local-storage.js +74 -76
- package/persist-plugins/local-storage.mjs +74 -76
- package/persist-plugins/mmkv.d.mts +18 -0
- package/persist-plugins/mmkv.d.ts +6 -3
- package/persist-plugins/mmkv.js +82 -86
- package/persist-plugins/mmkv.mjs +82 -86
- package/react-hooks/createObservableHook.d.mts +5 -0
- package/react-hooks/createObservableHook.d.ts +4 -1
- package/react-hooks/createObservableHook.js +29 -30
- package/react-hooks/createObservableHook.mjs +25 -30
- package/react-hooks/useHover.d.mts +5 -0
- package/react-hooks/useHover.d.ts +5 -3
- package/react-hooks/useHover.js +29 -29
- package/react-hooks/useHover.mjs +29 -29
- package/react-hooks/useMeasure.d.mts +9 -0
- package/react-hooks/useMeasure.d.ts +5 -2
- package/react-hooks/useMeasure.js +30 -32
- package/react-hooks/useMeasure.mjs +30 -32
- package/react-hooks/useObservableNextRouter.d.mts +35 -0
- package/react-hooks/useObservableNextRouter.d.ts +9 -7
- package/react-hooks/useObservableNextRouter.js +64 -77
- package/react-hooks/useObservableNextRouter.mjs +60 -77
- package/react.d.mts +157 -0
- package/react.d.ts +157 -21
- package/react.js +458 -749
- package/react.mjs +457 -752
- package/sync-plugins/crud.d.mts +54 -0
- package/sync-plugins/crud.d.ts +12 -10
- package/sync-plugins/crud.js +253 -270
- package/sync-plugins/crud.mjs +253 -270
- package/sync-plugins/fetch.d.mts +21 -0
- package/sync-plugins/fetch.d.ts +7 -4
- package/sync-plugins/fetch.js +50 -37
- package/sync-plugins/fetch.mjs +50 -37
- package/sync-plugins/keel.d.mts +108 -0
- package/sync-plugins/keel.d.ts +17 -15
- package/sync-plugins/keel.js +229 -462
- package/sync-plugins/keel.mjs +227 -464
- package/sync-plugins/supabase.d.mts +39 -0
- package/sync-plugins/supabase.d.ts +16 -14
- package/sync-plugins/supabase.js +128 -128
- package/sync-plugins/supabase.mjs +128 -128
- package/sync-plugins/tanstack-query.d.mts +14 -0
- package/sync-plugins/tanstack-query.d.ts +7 -4
- package/sync-plugins/tanstack-query.js +51 -57
- package/sync-plugins/tanstack-query.mjs +51 -57
- package/sync-plugins/tanstack-react-query.d.mts +8 -0
- package/sync-plugins/tanstack-react-query.d.ts +6 -1
- package/sync-plugins/tanstack-react-query.js +2 -2
- package/sync-plugins/tanstack-react-query.mjs +2 -2
- package/sync.d.mts +351 -0
- package/sync.d.ts +349 -9
- package/sync.js +910 -964
- package/sync.mjs +920 -974
- package/trace.d.mts +9 -0
- package/trace.d.ts +9 -4
- package/trace.js +72 -62
- package/trace.mjs +72 -62
- package/types/babel.d.ts +1 -12
- package/babel.js.map +0 -1
- package/config/enable$GetSet.js.map +0 -1
- package/config/enable$GetSet.mjs.map +0 -1
- package/config/enableReactComponents.js.map +0 -1
- package/config/enableReactComponents.mjs.map +0 -1
- package/config/enableReactNativeComponents.js.map +0 -1
- package/config/enableReactNativeComponents.mjs.map +0 -1
- package/config/enableReactTracking.js.map +0 -1
- package/config/enableReactTracking.mjs.map +0 -1
- package/config/enableReactUse.js.map +0 -1
- package/config/enableReactUse.mjs.map +0 -1
- package/config/enable_PeekAssign.js.map +0 -1
- package/config/enable_PeekAssign.mjs.map +0 -1
- package/helpers/pageHash.js.map +0 -1
- package/helpers/pageHash.mjs.map +0 -1
- package/helpers/pageHashParams.js.map +0 -1
- package/helpers/pageHashParams.mjs.map +0 -1
- package/helpers/time.js.map +0 -1
- package/helpers/time.mjs.map +0 -1
- package/helpers/trackHistory.js.map +0 -1
- package/helpers/trackHistory.mjs.map +0 -1
- package/helpers/undoRedo.js.map +0 -1
- package/helpers/undoRedo.mjs.map +0 -1
- package/history.d.ts +0 -1
- package/history.js +0 -24
- package/history.js.map +0 -1
- package/history.mjs +0 -22
- package/history.mjs.map +0 -1
- package/index.js.map +0 -1
- package/index.mjs.map +0 -1
- package/persist-plugins/async-storage.js.map +0 -1
- package/persist-plugins/async-storage.mjs.map +0 -1
- package/persist-plugins/indexeddb.js.map +0 -1
- package/persist-plugins/indexeddb.mjs.map +0 -1
- package/persist-plugins/local-storage.js.map +0 -1
- package/persist-plugins/local-storage.mjs.map +0 -1
- package/persist-plugins/mmkv.js.map +0 -1
- package/persist-plugins/mmkv.mjs.map +0 -1
- package/react-hooks/createObservableHook.js.map +0 -1
- package/react-hooks/createObservableHook.mjs.map +0 -1
- package/react-hooks/useHover.js.map +0 -1
- package/react-hooks/useHover.mjs.map +0 -1
- package/react-hooks/useMeasure.js.map +0 -1
- package/react-hooks/useMeasure.mjs.map +0 -1
- package/react-hooks/useObservableNextRouter.js.map +0 -1
- package/react-hooks/useObservableNextRouter.mjs.map +0 -1
- package/react.js.map +0 -1
- package/react.mjs.map +0 -1
- package/src/ObservableObject.ts +0 -1350
- package/src/ObservablePrimitive.ts +0 -62
- package/src/babel/index.ts +0 -83
- package/src/batching.ts +0 -357
- package/src/computed.ts +0 -18
- package/src/config/enable$GetSet.ts +0 -30
- package/src/config/enableReactComponents.ts +0 -26
- package/src/config/enableReactNativeComponents.ts +0 -102
- package/src/config/enableReactTracking.ts +0 -62
- package/src/config/enableReactUse.ts +0 -32
- package/src/config/enable_PeekAssign.ts +0 -31
- package/src/config.ts +0 -47
- package/src/createObservable.ts +0 -47
- package/src/event.ts +0 -26
- package/src/globals.ts +0 -235
- package/src/helpers/pageHash.ts +0 -41
- package/src/helpers/pageHashParams.ts +0 -55
- package/src/helpers/time.ts +0 -30
- package/src/helpers/trackHistory.ts +0 -29
- package/src/helpers/undoRedo.ts +0 -111
- package/src/helpers.ts +0 -231
- package/src/is.ts +0 -63
- package/src/linked.ts +0 -17
- package/src/observable.ts +0 -32
- package/src/observableInterfaces.ts +0 -151
- package/src/observableTypes.ts +0 -232
- package/src/observe.ts +0 -89
- package/src/old-plugins/firebase.ts +0 -1053
- package/src/onChange.ts +0 -146
- package/src/persist/configureObservablePersistence.ts +0 -7
- package/src/persist/fieldTransformer.ts +0 -149
- package/src/persist/observablePersistRemoteFunctionsAdapter.ts +0 -39
- package/src/persist/persistObservable.ts +0 -1034
- package/src/persist-plugins/async-storage.ts +0 -99
- package/src/persist-plugins/indexeddb.ts +0 -439
- package/src/persist-plugins/local-storage.ts +0 -86
- package/src/persist-plugins/mmkv.ts +0 -91
- package/src/proxy.ts +0 -28
- package/src/react/Computed.tsx +0 -8
- package/src/react/For.tsx +0 -116
- package/src/react/Memo.tsx +0 -4
- package/src/react/Reactive.tsx +0 -53
- package/src/react/Show.tsx +0 -33
- package/src/react/Switch.tsx +0 -43
- package/src/react/react-globals.ts +0 -3
- package/src/react/reactInterfaces.ts +0 -32
- package/src/react/reactive-observer.tsx +0 -210
- package/src/react/useComputed.ts +0 -36
- package/src/react/useEffectOnce.ts +0 -41
- package/src/react/useIsMounted.ts +0 -16
- package/src/react/useMount.ts +0 -15
- package/src/react/useObservable.ts +0 -24
- package/src/react/useObservableReducer.ts +0 -52
- package/src/react/useObservableState.ts +0 -30
- package/src/react/useObserve.ts +0 -54
- package/src/react/useObserveEffect.ts +0 -40
- package/src/react/usePauseProvider.tsx +0 -16
- package/src/react/useSelector.ts +0 -167
- package/src/react/useUnmount.ts +0 -8
- package/src/react/useWhen.ts +0 -9
- package/src/react-hooks/createObservableHook.ts +0 -53
- package/src/react-hooks/useHover.ts +0 -40
- package/src/react-hooks/useMeasure.ts +0 -48
- package/src/react-hooks/useObservableNextRouter.ts +0 -137
- package/src/retry.ts +0 -71
- package/src/setupTracking.ts +0 -26
- package/src/sync/activateSyncedNode.ts +0 -128
- package/src/sync/configureObservableSync.ts +0 -7
- package/src/sync/persistTypes.ts +0 -216
- package/src/sync/syncHelpers.ts +0 -180
- package/src/sync/syncObservable.ts +0 -1056
- package/src/sync/syncObservableAdapter.ts +0 -31
- package/src/sync/syncTypes.ts +0 -189
- package/src/sync/synced.ts +0 -21
- package/src/sync-plugins/crud.ts +0 -412
- package/src/sync-plugins/fetch.ts +0 -80
- package/src/sync-plugins/keel.ts +0 -495
- package/src/sync-plugins/supabase.ts +0 -249
- package/src/sync-plugins/tanstack-query.ts +0 -113
- package/src/sync-plugins/tanstack-react-query.ts +0 -12
- package/src/trace/traceHelpers.ts +0 -11
- package/src/trace/useTraceListeners.ts +0 -34
- package/src/trace/useTraceUpdates.ts +0 -24
- package/src/trace/useVerifyNotTracking.ts +0 -33
- package/src/trace/useVerifyOneRender.ts +0 -10
- package/src/trackSelector.ts +0 -52
- package/src/tracking.ts +0 -43
- package/src/types/babel.d.ts +0 -12
- package/src/when.ts +0 -75
- package/sync-plugins/crud.js.map +0 -1
- package/sync-plugins/crud.mjs.map +0 -1
- package/sync-plugins/fetch.js.map +0 -1
- package/sync-plugins/fetch.mjs.map +0 -1
- package/sync-plugins/keel.js.map +0 -1
- package/sync-plugins/keel.mjs.map +0 -1
- package/sync-plugins/supabase.js.map +0 -1
- package/sync-plugins/supabase.mjs.map +0 -1
- package/sync-plugins/tanstack-query.js.map +0 -1
- package/sync-plugins/tanstack-query.mjs.map +0 -1
- package/sync-plugins/tanstack-react-query.js.map +0 -1
- package/sync-plugins/tanstack-react-query.mjs.map +0 -1
- package/sync.js.map +0 -1
- package/sync.mjs.map +0 -1
- package/trace.js.map +0 -1
- package/trace.mjs.map +0 -1
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import type { Change } from '@legendapp/state';
|
|
2
|
-
import { applyChanges, internal, isArray } from '@legendapp/state';
|
|
3
|
-
import type {
|
|
4
|
-
ObservablePersistPlugin,
|
|
5
|
-
ObservablePersistenceConfigLocalGlobalOptions,
|
|
6
|
-
PersistMetadata,
|
|
7
|
-
} from '@legendapp/state/sync';
|
|
8
|
-
import type { AsyncStorageStatic } from '@react-native-async-storage/async-storage';
|
|
9
|
-
|
|
10
|
-
const MetadataSuffix = '__m';
|
|
11
|
-
|
|
12
|
-
let AsyncStorage: AsyncStorageStatic;
|
|
13
|
-
|
|
14
|
-
const { safeParse, safeStringify } = internal;
|
|
15
|
-
|
|
16
|
-
export class ObservablePersistAsyncStorage implements ObservablePersistPlugin {
|
|
17
|
-
private data: Record<string, any> = {};
|
|
18
|
-
|
|
19
|
-
// Init
|
|
20
|
-
public async initialize(config: ObservablePersistenceConfigLocalGlobalOptions) {
|
|
21
|
-
let tables: readonly string[] = [];
|
|
22
|
-
const storageConfig = config.asyncStorage;
|
|
23
|
-
if (storageConfig) {
|
|
24
|
-
AsyncStorage = storageConfig.AsyncStorage;
|
|
25
|
-
const { preload } = storageConfig;
|
|
26
|
-
try {
|
|
27
|
-
if (preload === true) {
|
|
28
|
-
// If preloadAllKeys, load all keys and preload tables on startup
|
|
29
|
-
tables = await AsyncStorage.getAllKeys();
|
|
30
|
-
} else if (isArray(preload)) {
|
|
31
|
-
// If preloadKeys, preload load the tables on startup
|
|
32
|
-
tables = preload;
|
|
33
|
-
}
|
|
34
|
-
if (tables) {
|
|
35
|
-
const values = await AsyncStorage.multiGet(tables);
|
|
36
|
-
|
|
37
|
-
values.forEach(([table, value]) => {
|
|
38
|
-
this.data[table] = value ? safeParse(value) : undefined;
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
} catch (e) {
|
|
42
|
-
console.error('[legend-state] ObservablePersistAsyncStorage failed to initialize', e);
|
|
43
|
-
}
|
|
44
|
-
} else {
|
|
45
|
-
console.error('[legend-state] Missing asyncStorage configuration');
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
public loadTable(table: string): void | Promise<void> {
|
|
49
|
-
if (this.data[table] === undefined) {
|
|
50
|
-
try {
|
|
51
|
-
return (async () => {
|
|
52
|
-
const value = await AsyncStorage.getItem(table);
|
|
53
|
-
this.data[table] = value ? safeParse(value) : undefined;
|
|
54
|
-
})();
|
|
55
|
-
} catch {
|
|
56
|
-
console.error('[legend-state] ObservablePersistLocalAsyncStorage failed to parse', table);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
// Gets
|
|
61
|
-
public getTable(table: string, init: object) {
|
|
62
|
-
return this.data[table] ?? init ?? {};
|
|
63
|
-
}
|
|
64
|
-
public getMetadata(table: string): PersistMetadata {
|
|
65
|
-
return this.getTable(table + MetadataSuffix, {});
|
|
66
|
-
}
|
|
67
|
-
// Sets
|
|
68
|
-
public set(table: string, changes: Change[]): Promise<void> {
|
|
69
|
-
if (!this.data[table]) {
|
|
70
|
-
this.data[table] = {};
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
this.data[table] = applyChanges(this.data[table], changes);
|
|
74
|
-
return this.save(table);
|
|
75
|
-
}
|
|
76
|
-
public setMetadata(table: string, metadata: PersistMetadata) {
|
|
77
|
-
return this.setValue(table + MetadataSuffix, metadata);
|
|
78
|
-
}
|
|
79
|
-
public async deleteTable(table: string) {
|
|
80
|
-
return AsyncStorage.removeItem(table);
|
|
81
|
-
}
|
|
82
|
-
public deleteMetadata(table: string) {
|
|
83
|
-
return this.deleteTable(table + MetadataSuffix);
|
|
84
|
-
}
|
|
85
|
-
// Private
|
|
86
|
-
private async setValue(table: string, value: any) {
|
|
87
|
-
this.data[table] = value;
|
|
88
|
-
await this.save(table);
|
|
89
|
-
}
|
|
90
|
-
private async save(table: string) {
|
|
91
|
-
const v = this.data[table];
|
|
92
|
-
|
|
93
|
-
if (v !== undefined && v !== null) {
|
|
94
|
-
return AsyncStorage.setItem(table, safeStringify(v));
|
|
95
|
-
} else {
|
|
96
|
-
return AsyncStorage.removeItem(table);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
@@ -1,439 +0,0 @@
|
|
|
1
|
-
import type { Change, Observable } from '@legendapp/state';
|
|
2
|
-
import type {
|
|
3
|
-
ObservablePersistPluginOptions,
|
|
4
|
-
ObservablePersistPlugin,
|
|
5
|
-
PersistMetadata,
|
|
6
|
-
PersistOptions,
|
|
7
|
-
} from '@legendapp/state/sync';
|
|
8
|
-
import { isPrimitive, isPromise, observable, setAtPath, when } from '@legendapp/state';
|
|
9
|
-
|
|
10
|
-
const MetadataSuffix = '__legend_metadata';
|
|
11
|
-
const PrimitiveName = '__legend_primitive';
|
|
12
|
-
|
|
13
|
-
function requestToPromise(request: IDBRequest) {
|
|
14
|
-
return new Promise<void>((resolve) => (request.onsuccess = () => resolve()));
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export class ObservablePersistIndexedDB implements ObservablePersistPlugin {
|
|
18
|
-
private tableData: Record<string, any> = {};
|
|
19
|
-
private tableMetadata: Record<string, any> = {};
|
|
20
|
-
private tablesAdjusted: Map<string, Observable<boolean>> = new Map();
|
|
21
|
-
private db: IDBDatabase | undefined;
|
|
22
|
-
private isSaveTaskQueued = false;
|
|
23
|
-
private pendingSaves = new Map<
|
|
24
|
-
PersistOptions,
|
|
25
|
-
Record<string, { tableName: string; tablePrev?: any; items: Set<string> }>
|
|
26
|
-
>();
|
|
27
|
-
private promisesQueued: (() => void)[] = [];
|
|
28
|
-
|
|
29
|
-
constructor() {
|
|
30
|
-
this.doSave = this.doSave.bind(this);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
public async initialize(config: ObservablePersistPluginOptions) {
|
|
34
|
-
if (typeof indexedDB === 'undefined') return;
|
|
35
|
-
if (process.env.NODE_ENV === 'development' && !config?.indexedDB) {
|
|
36
|
-
console.error('[legend-state] Must configure ObservablePersistIndexedDB');
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const { databaseName, version, tableNames } = config!.indexedDB!;
|
|
40
|
-
const openRequest = indexedDB.open(databaseName, version);
|
|
41
|
-
|
|
42
|
-
openRequest.onerror = () => {
|
|
43
|
-
console.error('Error', openRequest.error);
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
openRequest.onupgradeneeded = () => {
|
|
47
|
-
const db = openRequest.result;
|
|
48
|
-
const { tableNames } = config!.indexedDB!;
|
|
49
|
-
// Create a table for each name with "id" as the key
|
|
50
|
-
tableNames.forEach((table) => {
|
|
51
|
-
if (!db.objectStoreNames.contains(table)) {
|
|
52
|
-
db.createObjectStore(table, {
|
|
53
|
-
keyPath: 'id',
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
return new Promise<void>((resolve) => {
|
|
60
|
-
openRequest.onsuccess = async () => {
|
|
61
|
-
this.db = openRequest.result;
|
|
62
|
-
|
|
63
|
-
// Load each table
|
|
64
|
-
const objectStoreNames = this.db.objectStoreNames;
|
|
65
|
-
const tables = tableNames.filter((table) => objectStoreNames.contains(table));
|
|
66
|
-
try {
|
|
67
|
-
const transaction = this.db.transaction(tables, 'readonly');
|
|
68
|
-
|
|
69
|
-
await Promise.all(tables.map((table) => this.initTable(table, transaction)));
|
|
70
|
-
} catch (err) {
|
|
71
|
-
console.error('[legend-state] Error loading IndexedDB', err);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
resolve();
|
|
75
|
-
};
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
public loadTable(table: string, config: PersistOptions): void | Promise<void> {
|
|
79
|
-
if (!this.tableData[table]) {
|
|
80
|
-
const transaction = this.db!.transaction(table, 'readonly');
|
|
81
|
-
|
|
82
|
-
return this.initTable(table, transaction).then(() => this.loadTable(table, config));
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const prefix = config.indexedDB?.prefixID;
|
|
86
|
-
|
|
87
|
-
if (prefix) {
|
|
88
|
-
const tableName = prefix ? table + '/' + prefix : table;
|
|
89
|
-
if (this.tablesAdjusted.has(tableName)) {
|
|
90
|
-
const promise = when(this.tablesAdjusted.get(tableName)!);
|
|
91
|
-
if (isPromise(promise)) {
|
|
92
|
-
return promise as unknown as Promise<void>;
|
|
93
|
-
}
|
|
94
|
-
} else {
|
|
95
|
-
const obsLoaded = observable(false);
|
|
96
|
-
this.tablesAdjusted.set(tableName, obsLoaded);
|
|
97
|
-
const data = this.getTable(table, {}, config);
|
|
98
|
-
let hasPromise = false;
|
|
99
|
-
let promises: Promise<any>[];
|
|
100
|
-
if (data) {
|
|
101
|
-
const keys = Object.keys(data);
|
|
102
|
-
promises = keys.map(async (key) => {
|
|
103
|
-
const value = data[key];
|
|
104
|
-
|
|
105
|
-
if (isPromise(value)) {
|
|
106
|
-
hasPromise = true;
|
|
107
|
-
return value.then(() => {
|
|
108
|
-
data[key] = value;
|
|
109
|
-
});
|
|
110
|
-
} else {
|
|
111
|
-
data[key] = value;
|
|
112
|
-
}
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
if (hasPromise) {
|
|
116
|
-
return Promise.all(promises!).then(() => {
|
|
117
|
-
obsLoaded.set(true);
|
|
118
|
-
});
|
|
119
|
-
} else {
|
|
120
|
-
obsLoaded.set(true);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
public getTable(table: string, init: object, config: PersistOptions) {
|
|
126
|
-
const configIDB = config.indexedDB;
|
|
127
|
-
const prefix = configIDB?.prefixID;
|
|
128
|
-
const data = this.tableData[prefix ? table + '/' + prefix : table];
|
|
129
|
-
if (data && configIDB?.itemID) {
|
|
130
|
-
return data[configIDB.itemID];
|
|
131
|
-
} else {
|
|
132
|
-
return data;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
public getMetadata(table: string, config: PersistOptions) {
|
|
136
|
-
const { tableName } = this.getMetadataTableName(table, config);
|
|
137
|
-
return this.tableMetadata[tableName];
|
|
138
|
-
}
|
|
139
|
-
public async setMetadata(table: string, metadata: PersistMetadata, config: PersistOptions) {
|
|
140
|
-
const { tableName, tableNameBase } = this.getMetadataTableName(table, config);
|
|
141
|
-
// Assign new metadata into the table, and make sure it has the id
|
|
142
|
-
this.tableMetadata[tableName] = Object.assign(metadata, {
|
|
143
|
-
id: tableNameBase + MetadataSuffix,
|
|
144
|
-
});
|
|
145
|
-
this.tableMetadata[tableName] = metadata;
|
|
146
|
-
const store = this.transactionStore(table);
|
|
147
|
-
return store.put(metadata);
|
|
148
|
-
}
|
|
149
|
-
public async deleteMetadata(table: string, config: PersistOptions): Promise<void> {
|
|
150
|
-
const { tableName, tableNameBase } = this.getMetadataTableName(table, config);
|
|
151
|
-
delete this.tableMetadata[tableName];
|
|
152
|
-
const store = this.transactionStore(table);
|
|
153
|
-
const key = tableNameBase + MetadataSuffix;
|
|
154
|
-
store.delete(key);
|
|
155
|
-
}
|
|
156
|
-
public async set(table: string, changes: Change[], config: PersistOptions) {
|
|
157
|
-
if (typeof indexedDB === 'undefined') return;
|
|
158
|
-
|
|
159
|
-
if (!this.pendingSaves.has(config)) {
|
|
160
|
-
this.pendingSaves.set(config, {});
|
|
161
|
-
}
|
|
162
|
-
const pendingSaves = this.pendingSaves.get(config)!;
|
|
163
|
-
|
|
164
|
-
const realTable = table;
|
|
165
|
-
const prefixID = config.indexedDB?.prefixID;
|
|
166
|
-
if (prefixID) {
|
|
167
|
-
table += '/' + prefixID;
|
|
168
|
-
}
|
|
169
|
-
const prev = this.tableData[table];
|
|
170
|
-
|
|
171
|
-
const itemID = config.indexedDB?.itemID;
|
|
172
|
-
|
|
173
|
-
if (!pendingSaves[table]) {
|
|
174
|
-
pendingSaves[table] = { tableName: realTable, items: new Set() };
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
const pendingTable = pendingSaves[table];
|
|
178
|
-
|
|
179
|
-
// Combine changes into a minimal set of saves
|
|
180
|
-
for (let i = 0; i < changes.length; i++) {
|
|
181
|
-
// eslint-disable-next-line prefer-const
|
|
182
|
-
let { path, valueAtPath, pathTypes } = changes[i];
|
|
183
|
-
if (itemID) {
|
|
184
|
-
path = [itemID].concat(path as string[]);
|
|
185
|
-
pathTypes.splice(0, 0, 'object');
|
|
186
|
-
}
|
|
187
|
-
if (path.length > 0) {
|
|
188
|
-
// If change is deep in an object save it to IDB by the first key
|
|
189
|
-
const key = path[0] as string;
|
|
190
|
-
if (!this.tableData[table]) {
|
|
191
|
-
this.tableData[table] = {};
|
|
192
|
-
}
|
|
193
|
-
this.tableData[table] = setAtPath(this.tableData[table], path as string[], pathTypes, valueAtPath);
|
|
194
|
-
pendingTable.items.add(key);
|
|
195
|
-
} else {
|
|
196
|
-
// Set the whole table
|
|
197
|
-
this.tableData[table] = valueAtPath;
|
|
198
|
-
pendingTable.tablePrev = prev;
|
|
199
|
-
break;
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
return new Promise<void>((resolve) => {
|
|
204
|
-
this.promisesQueued.push(resolve);
|
|
205
|
-
|
|
206
|
-
if (!this.isSaveTaskQueued) {
|
|
207
|
-
this.isSaveTaskQueued = true;
|
|
208
|
-
queueMicrotask(this.doSave);
|
|
209
|
-
}
|
|
210
|
-
});
|
|
211
|
-
}
|
|
212
|
-
private async doSave() {
|
|
213
|
-
this.isSaveTaskQueued = false;
|
|
214
|
-
const promisesQueued = this.promisesQueued;
|
|
215
|
-
this.promisesQueued = [];
|
|
216
|
-
const promises: Promise<IDBRequest>[] = [];
|
|
217
|
-
let lastPut: IDBRequest | undefined;
|
|
218
|
-
this.pendingSaves.forEach((pendingSaves, config) => {
|
|
219
|
-
Object.keys(pendingSaves).forEach((table) => {
|
|
220
|
-
const pendingTable = pendingSaves[table];
|
|
221
|
-
const { tablePrev, items, tableName } = pendingTable;
|
|
222
|
-
const store = this.transactionStore(tableName);
|
|
223
|
-
const tableValue = this.tableData[table];
|
|
224
|
-
if (tablePrev) {
|
|
225
|
-
promises.push(this._setTable(table, tablePrev, tableValue, store, config));
|
|
226
|
-
} else {
|
|
227
|
-
items.forEach((key) => {
|
|
228
|
-
lastPut = this._setItem(table, key, tableValue[key], store, config);
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
// Clear pending saves
|
|
233
|
-
items.clear();
|
|
234
|
-
delete pendingTable.tablePrev;
|
|
235
|
-
});
|
|
236
|
-
});
|
|
237
|
-
this.pendingSaves.clear();
|
|
238
|
-
|
|
239
|
-
// setTable awaits multiple sets and deletes so we need to await that to get
|
|
240
|
-
// the lastPut from it.
|
|
241
|
-
if (promises.length) {
|
|
242
|
-
const puts = await Promise.all(promises);
|
|
243
|
-
lastPut = puts[puts.length - 1];
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
if (lastPut) {
|
|
247
|
-
await requestToPromise(lastPut);
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
promisesQueued.forEach((resolve) => resolve());
|
|
251
|
-
}
|
|
252
|
-
public async deleteTable(table: string, config: PersistOptions): Promise<void> {
|
|
253
|
-
const configIDB = config.indexedDB;
|
|
254
|
-
const prefixID = configIDB?.prefixID;
|
|
255
|
-
const tableName = prefixID ? table + '/' + prefixID : table;
|
|
256
|
-
let data = this.tableData[tableName];
|
|
257
|
-
const itemID = configIDB?.itemID;
|
|
258
|
-
if (data && configIDB?.itemID) {
|
|
259
|
-
const dataTemp = data[itemID!];
|
|
260
|
-
delete data[itemID!];
|
|
261
|
-
data = dataTemp;
|
|
262
|
-
} else {
|
|
263
|
-
delete this.tableData[tableName];
|
|
264
|
-
delete this.tableData[tableName + '_transformed'];
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
if (typeof indexedDB === 'undefined') return;
|
|
268
|
-
|
|
269
|
-
this.deleteMetadata(table, config);
|
|
270
|
-
|
|
271
|
-
if (data) {
|
|
272
|
-
const store = this.transactionStore(table);
|
|
273
|
-
let result: Promise<any>;
|
|
274
|
-
if (!prefixID && !itemID) {
|
|
275
|
-
result = requestToPromise(store.clear());
|
|
276
|
-
} else {
|
|
277
|
-
const keys = Object.keys(data);
|
|
278
|
-
result = Promise.all(
|
|
279
|
-
keys.map((key) => {
|
|
280
|
-
if (prefixID) {
|
|
281
|
-
key = prefixID + '/' + key;
|
|
282
|
-
}
|
|
283
|
-
return requestToPromise(store.delete(key));
|
|
284
|
-
}),
|
|
285
|
-
);
|
|
286
|
-
}
|
|
287
|
-
// Clear the table from IDB
|
|
288
|
-
return result;
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
// Private
|
|
292
|
-
private getMetadataTableName(table: string, config: PersistOptions) {
|
|
293
|
-
const configIDB = config.indexedDB;
|
|
294
|
-
let name = '';
|
|
295
|
-
if (configIDB) {
|
|
296
|
-
const { prefixID, itemID } = configIDB;
|
|
297
|
-
|
|
298
|
-
if (itemID) {
|
|
299
|
-
name = itemID;
|
|
300
|
-
}
|
|
301
|
-
if (prefixID) {
|
|
302
|
-
name = prefixID + (name ? '/' + name : '');
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
return { tableNameBase: name, tableName: name ? table + '/' + name : table };
|
|
307
|
-
}
|
|
308
|
-
private initTable(table: string, transaction: IDBTransaction): Promise<void> {
|
|
309
|
-
const store = transaction.objectStore(table);
|
|
310
|
-
const allRequest = store.getAll();
|
|
311
|
-
|
|
312
|
-
if (!this.tableData[table]) {
|
|
313
|
-
this.tableData[table] = {};
|
|
314
|
-
}
|
|
315
|
-
return new Promise((resolve) => {
|
|
316
|
-
allRequest.onsuccess = () => {
|
|
317
|
-
const arr = allRequest.result;
|
|
318
|
-
let metadata: PersistMetadata;
|
|
319
|
-
if (!this.tableData[table]) {
|
|
320
|
-
this.tableData[table] = {};
|
|
321
|
-
}
|
|
322
|
-
for (let i = 0; i < arr.length; i++) {
|
|
323
|
-
const val = arr[i];
|
|
324
|
-
|
|
325
|
-
// In case id is a number convert it to a string
|
|
326
|
-
if (!val.id.includes) {
|
|
327
|
-
val.id = val.id + '';
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
if (val.id.endsWith(MetadataSuffix)) {
|
|
331
|
-
const id = val.id.replace(MetadataSuffix, '');
|
|
332
|
-
// Save this as metadata
|
|
333
|
-
delete val.id;
|
|
334
|
-
metadata = val;
|
|
335
|
-
const tableName = id ? table + '/' + id : table;
|
|
336
|
-
this.tableMetadata[tableName] = metadata;
|
|
337
|
-
} else {
|
|
338
|
-
let tableName = table;
|
|
339
|
-
|
|
340
|
-
if (val.id.includes('/')) {
|
|
341
|
-
const [prefix, id] = val.id.split('/');
|
|
342
|
-
tableName += '/' + prefix;
|
|
343
|
-
val.id = id;
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
const id = val.id;
|
|
347
|
-
|
|
348
|
-
const outValue = val[PrimitiveName] !== undefined ? val[PrimitiveName] : val;
|
|
349
|
-
|
|
350
|
-
if (!this.tableData[tableName]) {
|
|
351
|
-
this.tableData[tableName] = {};
|
|
352
|
-
}
|
|
353
|
-
this.tableData[tableName][id] = outValue;
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
resolve();
|
|
357
|
-
};
|
|
358
|
-
});
|
|
359
|
-
}
|
|
360
|
-
private transactionStore(table: string) {
|
|
361
|
-
const transaction = this.db!.transaction(table, 'readwrite');
|
|
362
|
-
return transaction.objectStore(table);
|
|
363
|
-
}
|
|
364
|
-
private _setItem(table: string, key: string, value: any, store: IDBObjectStore, config: PersistOptions) {
|
|
365
|
-
if (!value) {
|
|
366
|
-
if (this.tableData[table]) {
|
|
367
|
-
delete this.tableData[table][key];
|
|
368
|
-
}
|
|
369
|
-
return store.delete(key);
|
|
370
|
-
} else {
|
|
371
|
-
if (isPrimitive(value)) {
|
|
372
|
-
value = { [PrimitiveName]: value };
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
if (value.id === undefined) {
|
|
376
|
-
// If value does not have its own ID, assign it the key from the Record
|
|
377
|
-
value.id = key;
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
if (config) {
|
|
381
|
-
if (!this.tableData[table]) {
|
|
382
|
-
this.tableData[table] = {};
|
|
383
|
-
}
|
|
384
|
-
this.tableData[table][key] = value;
|
|
385
|
-
|
|
386
|
-
const didClone = false;
|
|
387
|
-
|
|
388
|
-
const prefixID = config.indexedDB?.prefixID;
|
|
389
|
-
if (prefixID) {
|
|
390
|
-
if (didClone) {
|
|
391
|
-
value.id = prefixID + '/' + value.id;
|
|
392
|
-
} else {
|
|
393
|
-
value = Object.assign({}, value, {
|
|
394
|
-
id: prefixID + '/' + value.id,
|
|
395
|
-
});
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
return store.put(value);
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
private async _setTable(
|
|
404
|
-
table: string,
|
|
405
|
-
prev: object,
|
|
406
|
-
value: Record<string, any>,
|
|
407
|
-
store: IDBObjectStore,
|
|
408
|
-
config: PersistOptions,
|
|
409
|
-
) {
|
|
410
|
-
const keys = Object.keys(value);
|
|
411
|
-
let lastSet: IDBRequest | undefined;
|
|
412
|
-
// Do a set for each key in the object
|
|
413
|
-
const sets = await Promise.all(
|
|
414
|
-
keys.map((key) => {
|
|
415
|
-
const val = value[key];
|
|
416
|
-
return this._setItem(table, key, val, store, config);
|
|
417
|
-
}),
|
|
418
|
-
);
|
|
419
|
-
lastSet = sets[sets.length - 1];
|
|
420
|
-
|
|
421
|
-
// Delete keys that are no longer in the object
|
|
422
|
-
if (prev) {
|
|
423
|
-
const keysOld = Object.keys(prev);
|
|
424
|
-
const deletes = (
|
|
425
|
-
await Promise.all(
|
|
426
|
-
keysOld.map((key) => {
|
|
427
|
-
if (value[key] === undefined) {
|
|
428
|
-
return this._setItem(table, key, null, store, config);
|
|
429
|
-
}
|
|
430
|
-
}),
|
|
431
|
-
)
|
|
432
|
-
).filter((a) => !!a);
|
|
433
|
-
if (deletes.length > 0) {
|
|
434
|
-
lastSet = deletes[deletes.length - 1];
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
return lastSet!;
|
|
438
|
-
}
|
|
439
|
-
}
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import type { Change } from '@legendapp/state';
|
|
2
|
-
import { applyChanges, internal } from '@legendapp/state';
|
|
3
|
-
import type { ObservablePersistPlugin, PersistMetadata } from '@legendapp/state/sync';
|
|
4
|
-
|
|
5
|
-
const { safeParse, safeStringify } = internal;
|
|
6
|
-
|
|
7
|
-
const MetadataSuffix = '__m';
|
|
8
|
-
|
|
9
|
-
export class ObservablePersistLocalStorageBase implements ObservablePersistPlugin {
|
|
10
|
-
private data: Record<string, any> = {};
|
|
11
|
-
private storage: Storage | undefined;
|
|
12
|
-
constructor(storage: Storage | undefined) {
|
|
13
|
-
this.storage = storage;
|
|
14
|
-
}
|
|
15
|
-
public getTable(table: string, init: any) {
|
|
16
|
-
if (!this.storage) return undefined;
|
|
17
|
-
if (this.data[table] === undefined) {
|
|
18
|
-
try {
|
|
19
|
-
const value = this.storage.getItem(table);
|
|
20
|
-
this.data[table] = value ? safeParse(value) : init;
|
|
21
|
-
} catch {
|
|
22
|
-
console.error('[legend-state] ObservablePersistLocalStorageBase failed to parse', table);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
return this.data[table];
|
|
26
|
-
}
|
|
27
|
-
public getMetadata(table: string): PersistMetadata {
|
|
28
|
-
return this.getTable(table + MetadataSuffix, {});
|
|
29
|
-
}
|
|
30
|
-
public set(table: string, changes: Change[]): void {
|
|
31
|
-
if (!this.data[table]) {
|
|
32
|
-
this.data[table] = {};
|
|
33
|
-
}
|
|
34
|
-
this.data[table] = applyChanges(this.data[table], changes);
|
|
35
|
-
this.save(table);
|
|
36
|
-
}
|
|
37
|
-
public setMetadata(table: string, metadata: PersistMetadata) {
|
|
38
|
-
table = table + MetadataSuffix;
|
|
39
|
-
this.data[table] = metadata;
|
|
40
|
-
this.save(table);
|
|
41
|
-
}
|
|
42
|
-
public deleteTable(table: string) {
|
|
43
|
-
if (!this.storage) return undefined;
|
|
44
|
-
delete this.data[table];
|
|
45
|
-
this.storage.removeItem(table);
|
|
46
|
-
}
|
|
47
|
-
public deleteMetadata(table: string) {
|
|
48
|
-
this.deleteTable(table + MetadataSuffix);
|
|
49
|
-
}
|
|
50
|
-
// Private
|
|
51
|
-
private save(table: string) {
|
|
52
|
-
if (!this.storage) return undefined;
|
|
53
|
-
|
|
54
|
-
const v = this.data[table];
|
|
55
|
-
|
|
56
|
-
if (v !== undefined && v !== null) {
|
|
57
|
-
this.storage.setItem(table, safeStringify(v));
|
|
58
|
-
} else {
|
|
59
|
-
this.storage.removeItem(table);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
export class ObservablePersistLocalStorage extends ObservablePersistLocalStorageBase {
|
|
64
|
-
constructor() {
|
|
65
|
-
super(
|
|
66
|
-
typeof localStorage !== 'undefined'
|
|
67
|
-
? localStorage
|
|
68
|
-
: process.env.NODE_ENV === 'test'
|
|
69
|
-
? // @ts-expect-error This is ok to do in jest
|
|
70
|
-
globalThis._testlocalStorage
|
|
71
|
-
: undefined,
|
|
72
|
-
);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
export class ObservablePersistSessionStorage extends ObservablePersistLocalStorageBase {
|
|
76
|
-
constructor() {
|
|
77
|
-
super(
|
|
78
|
-
typeof sessionStorage !== 'undefined'
|
|
79
|
-
? sessionStorage
|
|
80
|
-
: process.env.NODE_ENV === 'test'
|
|
81
|
-
? // @ts-expect-error This is ok to do in jest
|
|
82
|
-
globalThis._testlocalStorage
|
|
83
|
-
: undefined,
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
}
|