1
+ import { get , set , createStore , del } from "idb-keyval"
1
2
import Cookies from "js-cookies/src/cookies.js"
2
3
import type { Writable } from "svelte/store"
3
4
@@ -41,14 +42,16 @@ export interface StorageInterface<T> {
41
42
export interface SelfUpdateStorageInterface < T > extends StorageInterface < T > {
42
43
/**
43
44
* Add a listener to the storage values changes
44
- * @param {(key: string) => void } listener The listener callback function
45
+ * @param {string } key The key to listen
46
+ * @param {(newValue: T) => void } listener The listener callback function
45
47
*/
46
- addListener ( listener : ( key : string ) => void ) : void ;
48
+ addListener ( key : string , listener : ( newValue : T ) => void ) : void ;
47
49
/**
48
50
* Remove a listener from the storage values changes
49
- * @param {(key: string) => void } listener The listener callback function to remove
51
+ * @param {string } key The key that was listened
52
+ * @param {(newValue: T) => void } listener The listener callback function to remove
50
53
*/
51
- removeListener ( listener : ( key : string ) => void ) : void ;
54
+ removeListener ( key : string , listener : ( newValue : T ) => void ) : void ;
52
55
}
53
56
54
57
/**
@@ -65,10 +68,8 @@ export function persist<T>(store: Writable<T>, storage: StorageInterface<T>, key
65
68
}
66
69
67
70
if ( ( storage as SelfUpdateStorageInterface < T > ) . addListener ) {
68
- ( storage as SelfUpdateStorageInterface < T > ) . addListener ( eventKey => {
69
- if ( eventKey === key ) {
70
- store . set ( storage . getValue ( key ) )
71
- }
71
+ ( storage as SelfUpdateStorageInterface < T > ) . addListener ( key , newValue => {
72
+ store . set ( newValue )
72
73
} )
73
74
}
74
75
@@ -85,10 +86,13 @@ export function persist<T>(store: Writable<T>, storage: StorageInterface<T>, key
85
86
}
86
87
87
88
function getBrowserStorage ( browserStorage : Storage , listenExternalChanges = false ) : SelfUpdateStorageInterface < any > {
88
- const listeners : Array < ( key : string ) => void > = [ ]
89
+ const listeners : Array < { key : string , listener : ( newValue : any ) => void } > = [ ]
89
90
const listenerFunction = ( event : StorageEvent ) => {
91
+ const eventKey = event . key
90
92
if ( event . storageArea === browserStorage ) {
91
- listeners . forEach ( call => call ( event . key ) )
93
+ listeners
94
+ . filter ( ( { key} ) => key === eventKey )
95
+ . forEach ( ( { listener} ) => listener ( JSON . parse ( event . newValue ) ) )
92
96
}
93
97
}
94
98
const connect = ( ) => {
@@ -103,14 +107,14 @@ function getBrowserStorage(browserStorage: Storage, listenExternalChanges = fals
103
107
}
104
108
105
109
return {
106
- addListener ( listener : ( key : string ) => void ) {
107
- listeners . push ( listener )
110
+ addListener ( key : string , listener : ( newValue : any ) => void ) {
111
+ listeners . push ( { key , listener} )
108
112
if ( listeners . length === 1 ) {
109
113
connect ( )
110
114
}
111
115
} ,
112
- removeListener ( listener : ( key : string ) => void ) {
113
- const index = listeners . indexOf ( listener )
116
+ removeListener ( key : string , listener : ( newValue : any ) => void ) {
117
+ const index = listeners . indexOf ( { key , listener} )
114
118
if ( index !== - 1 ) {
115
119
listeners . splice ( index , 1 )
116
120
}
@@ -184,6 +188,48 @@ export function cookieStorage(): StorageInterface<any> {
184
188
}
185
189
}
186
190
191
+ /**
192
+ * Storage implementation that use the browser IndexedDB
193
+ */
194
+ export function indexedDBStorage < T > ( ) : SelfUpdateStorageInterface < T > {
195
+ if ( typeof indexedDB !== "object" || typeof window === "undefined" || typeof window ?. indexedDB !== "object" ) {
196
+ console . warn ( "Unable to find the IndexedDB. No data will be persisted." )
197
+ return noopSelfUpdateStorage ( )
198
+ }
199
+
200
+ const database = createStore ( "svelte-persist" , "persist" )
201
+ const listeners : Array < { key : string , listener : ( newValue : T ) => void } > = [ ]
202
+ const listenerFunction = ( eventKey : string , newValue : T ) => {
203
+ if ( newValue === undefined ) {
204
+ return
205
+ }
206
+ listeners
207
+ . filter ( ( { key} ) => key === eventKey )
208
+ . forEach ( ( { listener} ) => listener ( newValue ) )
209
+ }
210
+ return {
211
+ addListener ( key : string , listener : ( newValue : any ) => void ) {
212
+ listeners . push ( { key, listener} )
213
+ } ,
214
+ removeListener ( key : string , listener : ( newValue : any ) => void ) {
215
+ const index = listeners . indexOf ( { key, listener} )
216
+ if ( index !== - 1 ) {
217
+ listeners . splice ( index , 1 )
218
+ }
219
+ } ,
220
+ getValue ( key : string ) : T | null {
221
+ get ( key , database ) . then ( value => listenerFunction ( key , value ) )
222
+ return null
223
+ } ,
224
+ setValue ( key : string , value : T ) : void {
225
+ set ( key , value , database )
226
+ } ,
227
+ deleteValue ( key : string ) : void {
228
+ del ( key , database )
229
+ }
230
+ }
231
+ }
232
+
187
233
/**
188
234
* Storage implementation that do nothing
189
235
*/
@@ -199,4 +245,24 @@ export function noopStorage(): StorageInterface<any> {
199
245
// Do nothing
200
246
}
201
247
}
248
+ }
249
+
250
+ function noopSelfUpdateStorage ( ) : SelfUpdateStorageInterface < any > {
251
+ return {
252
+ addListener ( ) {
253
+ // Do nothing
254
+ } ,
255
+ removeListener ( ) {
256
+ // Do nothing
257
+ } ,
258
+ getValue ( ) : null {
259
+ return null
260
+ } ,
261
+ deleteValue ( ) {
262
+ // Do nothing
263
+ } ,
264
+ setValue ( ) {
265
+ // Do nothing
266
+ }
267
+ }
202
268
}
0 commit comments