@@ -4,7 +4,7 @@ import { createSubscriber } from "svelte/reactivity";
4
4
5
5
type Serializer < T > = {
6
6
serialize : ( value : T ) => string ;
7
- deserialize : ( value : string ) => T ;
7
+ deserialize : ( value : string ) => T | undefined ;
8
8
} ;
9
9
10
10
type StorageType = "local" | "session" ;
@@ -36,11 +36,12 @@ type PersistedStateOptions<T> = {
36
36
* @see {@link https://runed.dev/docs/utilities/persisted-state }
37
37
*/
38
38
export class PersistedState < T > {
39
- #current: T = $state ( ) ! ;
39
+ #current: T | undefined ;
40
40
#key: string ;
41
41
#serializer: Serializer < T > ;
42
42
#storage?: Storage ;
43
43
#subscribe?: VoidFunction ;
44
+ #version = $state ( 0 )
44
45
45
46
constructor ( key : string , initialValue : T , options : PersistedStateOptions < T > = { } ) {
46
47
const {
@@ -61,7 +62,9 @@ export class PersistedState<T> {
61
62
62
63
const existingValue = storage . getItem ( key ) ;
63
64
if ( existingValue !== null ) {
64
- this . #deserialize( existingValue ) ;
65
+ this . #current = this . #deserialize( existingValue ) ;
66
+ } else {
67
+ this . #serialize( initialValue )
65
68
}
66
69
67
70
if ( syncTabs && storageType === "local" ) {
@@ -73,36 +76,62 @@ export class PersistedState<T> {
73
76
74
77
get current ( ) : T {
75
78
this . #subscribe?.( ) ;
76
- return this . #current;
79
+ const root = this . #deserialize( this . #storage?. getItem ( this . #key) as string ) ?? this . #current
80
+ const proxies = new WeakMap ( ) ;
81
+ const proxy = ( value : unknown ) => {
82
+ if ( value === null || value ?. constructor . name === 'Date' || typeof value !== 'object' ) {
83
+ return value ;
84
+ }
85
+ let p = proxies . get ( value ) ;
86
+ if ( ! p ) {
87
+ p = new Proxy ( value , {
88
+ get : ( target , property ) => {
89
+ this . #version;
90
+ return proxy ( Reflect . get ( target , property ) ) ;
91
+ } ,
92
+ set : ( target , property , value ) => {
93
+ this . #version += 1 ;
94
+ Reflect . set ( target , property , value ) ;
95
+ this . #serialize( root )
96
+ return true ;
97
+ }
98
+ } ) ;
99
+ proxies . set ( value , p ) ;
100
+ }
101
+ return p ;
102
+ }
103
+ return proxy ( root ) ;
77
104
}
78
105
79
106
set current ( newValue : T ) {
80
- this . #current = newValue ;
81
107
this . #serialize( newValue ) ;
108
+ this . #version += 1 ;
82
109
}
83
110
84
111
#handleStorageEvent = ( event : StorageEvent ) : void => {
85
112
if ( event . key !== this . #key || event . newValue === null ) return ;
86
-
87
- this . #deserialize( event . newValue ) ;
113
+ this . #current = this . #deserialize( event . newValue ) ;
88
114
} ;
89
115
90
- #deserialize( value : string ) : void {
116
+ #deserialize( value : string ) : T | undefined {
91
117
try {
92
- this . #current = this . #serializer. deserialize ( value ) ;
118
+ return this . #serializer. deserialize ( value ) ;
93
119
} catch ( error ) {
94
120
console . error ( `Error when parsing "${ value } " from persisted store "${ this . #key} "` , error ) ;
121
+ return
95
122
}
96
123
}
97
124
98
- #serialize( value : T ) : void {
125
+ #serialize( value : T | undefined ) : void {
99
126
try {
100
- this . #storage?. setItem ( this . #key, this . #serializer. serialize ( value ) ) ;
127
+ if ( value != undefined ) {
128
+ this . #storage?. setItem ( this . #key, this . #serializer. serialize ( value ) ) ;
129
+ }
101
130
} catch ( error ) {
102
131
console . error (
103
132
`Error when writing value from persisted store "${ this . #key} " to ${ this . #storage} ` ,
104
133
error
105
134
) ;
106
135
}
107
136
}
108
- }
137
+ }
0 commit comments