Skip to content

Commit ad18a8f

Browse files
committed
bug: Fix non-async persisted function
1 parent f7381f7 commit ad18a8f

File tree

1 file changed

+107
-80
lines changed

1 file changed

+107
-80
lines changed

index.ts

Lines changed: 107 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,153 +1,180 @@
1-
import { get, writable as internal, type Writable } from 'svelte/store'
1+
import { get, writable as internal, type Writable } from "svelte/store";
22
if (process.env.NODE_ENV === "test" || process.env.NODE_ENV === "development") {
3-
require("fake-indexeddb/auto")
3+
require("fake-indexeddb/auto");
44
}
5-
import localforage from "localforage"
6-
declare type StoreDict<T> = { [key: string]: Persisted<T> }
7-
declare type Updater<T> = (value: T) => T
5+
import localforage from "localforage";
6+
declare type StoreDict<T> = { [key: string]: Persisted<T> };
7+
declare type Updater<T> = (value: T) => T;
88

99
interface Persisted<T> extends Writable<T> {
10-
set: (this: void, value: T) => Promise<void>
11-
reset: () => Promise<void>
12-
update: (callback: Updater<T>) => Promise<void>
10+
set: (this: void, value: T) => Promise<void>;
11+
reset: () => Promise<void>;
12+
update: (callback: Updater<T>) => Promise<void>;
1313
}
1414

1515
/* eslint-disable @typescript-eslint/no-explicit-any */
1616
interface Stores {
17-
local: StoreDict<any>,
18-
session: StoreDict<any>,
19-
indexedDB: StoreDict<any>
17+
local: StoreDict<any>;
18+
session: StoreDict<any>;
19+
indexedDB: StoreDict<any>;
2020
}
2121

2222
const stores: Stores = {
2323
local: {},
2424
session: {},
25-
indexedDB: {}
26-
}
25+
indexedDB: {},
26+
};
2727

2828
export interface Serializer<T> {
29-
parse(text: string): T
30-
stringify(object: T): string
29+
parse(text: string): T;
30+
stringify(object: T): string;
3131
}
3232

33-
export type StorageType = 'local' | 'session' | 'indexedDB'
33+
export type StorageType = "local" | "session" | "indexedDB";
3434

3535
export interface Options<StoreType, SerializerType> {
36-
serializer?: Serializer<SerializerType>
37-
storage?: StorageType,
38-
syncTabs?: boolean,
39-
onError?: (e: unknown) => void
40-
onWriteError?: (e: unknown) => void
41-
onParseError?: (newValue: string | null, e: unknown) => void
42-
beforeRead?: (val: SerializerType) => StoreType
43-
beforeWrite?: (val: StoreType) => SerializerType
36+
serializer?: Serializer<SerializerType>;
37+
storage?: StorageType;
38+
syncTabs?: boolean;
39+
onError?: (e: unknown) => void;
40+
onWriteError?: (e: unknown) => void;
41+
onParseError?: (newValue: string | null, e: unknown) => void;
42+
beforeRead?: (val: SerializerType) => StoreType;
43+
beforeWrite?: (val: StoreType) => SerializerType;
4444
}
4545

4646
async function getStorage(type: StorageType) {
47-
let storage: LocalForage | Storage | null
47+
let storage: LocalForage | Storage | null;
4848
try {
49-
storage = type === "session" ? window.sessionStorage : localforage
50-
if (type === "local") await storage.setDriver(localforage.LOCALSTORAGE)
51-
if (type === "indexedDB") await storage.setDriver(localforage.INDEXEDDB)
49+
storage = type === "session" ? window.sessionStorage : localforage;
50+
if (type === "local") await storage.setDriver(localforage.LOCALSTORAGE);
51+
if (type === "indexedDB") await storage.setDriver(localforage.INDEXEDDB);
5252
} catch (error) {
53-
54-
storage = null
53+
storage = null;
5554
}
56-
return storage
55+
return storage;
5756
}
5857

5958
/** @deprecated `writable()` has been renamed to `persisted()` */
60-
export async function writable<StoreType, SerializerType = StoreType>(key: string, initialValue: StoreType, options?: Options<StoreType, SerializerType>): Promise<Persisted<StoreType>> {
61-
console.warn("writable() has been deprecated. Please use persisted() instead.\n\nchange:\n\nimport { writable } from 'svelte-persisted-store'\n\nto:\n\nimport { persisted } from 'svelte-persisted-store'")
62-
return await persisted<StoreType, SerializerType>(key, initialValue, options)
59+
export async function writable<StoreType, SerializerType = StoreType>(
60+
key: string,
61+
initialValue: StoreType,
62+
options?: Options<StoreType, SerializerType>
63+
): Promise<Persisted<StoreType>> {
64+
console.warn(
65+
"writable() has been deprecated. Please use persisted() instead.\n\nchange:\n\nimport { writable } from 'svelte-persisted-store'\n\nto:\n\nimport { persisted } from 'svelte-persisted-store'"
66+
);
67+
return await persisted<StoreType, SerializerType>(key, initialValue, options);
6368
}
64-
export function persisted<StoreType, SerializerType = StoreType>(key: string, initialValue: StoreType, options?: Options<StoreType, SerializerType>): Persisted<StoreType> {
65-
if (options?.onError) console.warn("onError has been deprecated. Please use onWriteError instead")
66-
67-
const serializer = options?.serializer ?? JSON
68-
const storageType = options?.storage ?? 'local'
69-
const syncTabs = options?.syncTabs ?? true
70-
const onWriteError = options?.onWriteError ?? options?.onError ?? ((e) => console.error(`Error when writing value from persisted store "${key}" to ${storageType}`, e))
71-
const onParseError = options?.onParseError ?? ((newVal, e) => console.error(`Error when parsing ${newVal ? '"' + newVal + '"' : "value"} from persisted store "${key}"`, e))
72-
73-
const beforeRead = options?.beforeRead ?? ((val) => val as unknown as StoreType)
74-
const beforeWrite = options?.beforeWrite ?? ((val) => val as unknown as SerializerType)
75-
69+
export async function persisted<StoreType, SerializerType = StoreType>(
70+
key: string,
71+
initialValue: StoreType,
72+
options?: Options<StoreType, SerializerType>
73+
): Promise<Persisted<StoreType>> {
74+
if (options?.onError)
75+
console.warn(
76+
"onError has been deprecated. Please use onWriteError instead"
77+
);
78+
79+
const serializer = options?.serializer ?? JSON;
80+
const storageType = options?.storage ?? "local";
81+
const syncTabs = options?.syncTabs ?? true;
82+
const onWriteError =
83+
options?.onWriteError ??
84+
options?.onError ??
85+
((e) =>
86+
console.error(
87+
`Error when writing value from persisted store "${key}" to ${storageType}`,
88+
e
89+
));
90+
const onParseError =
91+
options?.onParseError ??
92+
((newVal, e) =>
93+
console.error(
94+
`Error when parsing ${
95+
newVal ? '"' + newVal + '"' : "value"
96+
} from persisted store "${key}"`,
97+
e
98+
));
99+
100+
const beforeRead =
101+
options?.beforeRead ?? ((val) => val as unknown as StoreType);
102+
const beforeWrite =
103+
options?.beforeWrite ?? ((val) => val as unknown as SerializerType);
76104

77105
const browser =
78-
typeof window !== "undefined" && typeof document !== "undefined"
106+
typeof window !== "undefined" && typeof document !== "undefined";
79107
const storage: Storage | LocalForage | null = browser
80108
? await getStorage(storageType)
81-
: null
109+
: null;
82110
async function updateStorage(key: string, value: StoreType) {
83-
const newVal = beforeWrite(value)
111+
const newVal = beforeWrite(value);
84112
try {
85-
await storage?.setItem(key, serializer.stringify(newVal))
86-
113+
await storage?.setItem(key, serializer.stringify(newVal));
87114
} catch (e) {
88-
onWriteError(e)
115+
onWriteError(e);
89116
}
90117
}
91118

92119
async function maybeLoadInitial(): Promise<StoreType> {
93120
function serialize(json: any) {
94121
try {
95-
return <SerializerType>serializer.parse(json)
122+
return <SerializerType>serializer.parse(json);
96123
} catch (e) {
97-
onParseError(json, e)
124+
onParseError(json, e);
98125
}
99126
}
100-
const json = await storage?.getItem(key)
101-
if (json == null) return initialValue
127+
const json = await storage?.getItem(key);
128+
if (json == null) return initialValue;
102129

103-
const serialized = serialize(json)
104-
if (serialized == null) return initialValue
130+
const serialized = serialize(json);
131+
if (serialized == null) return initialValue;
105132

106-
const newVal = beforeRead(serialized)
107-
return newVal
133+
const newVal = beforeRead(serialized);
134+
return newVal;
108135
}
109136

110137
if (!stores[storageType][key]) {
111-
const initial: StoreType = await maybeLoadInitial()
138+
const initial: StoreType = await maybeLoadInitial();
112139
const store = internal(initial, (set) => {
113-
if (browser && storageType == 'local' && syncTabs) {
140+
if (browser && storageType == "local" && syncTabs) {
114141
const handleStorage = async (event: StorageEvent) => {
115142
if (event.key === key && event.newValue) {
116-
let newVal: any
143+
let newVal: any;
117144
try {
118-
newVal = serializer.parse(event.newValue)
145+
newVal = serializer.parse(event.newValue);
119146
} catch (e) {
120-
onParseError(event.newValue, e)
121-
return
147+
onParseError(event.newValue, e);
148+
return;
122149
}
123-
const processedVal = beforeRead(newVal)
150+
const processedVal = beforeRead(newVal);
124151

125-
set(processedVal)
152+
set(processedVal);
126153
}
127-
}
154+
};
128155

129-
window.addEventListener("storage", handleStorage)
156+
window.addEventListener("storage", handleStorage);
130157

131-
return () => window.removeEventListener("storage", handleStorage)
158+
return () => window.removeEventListener("storage", handleStorage);
132159
}
133-
})
160+
});
134161

135-
const { subscribe, set } = store
162+
const { subscribe, set } = store;
136163

137164
stores[storageType][key] = {
138165
async set(value: StoreType) {
139-
set(value)
140-
await updateStorage(key, value)
166+
set(value);
167+
await updateStorage(key, value);
141168
},
142169
async update(callback: Updater<StoreType>) {
143170
// this is more concise than store.update
144-
await this.set(callback(get(store)))
171+
await this.set(callback(get(store)));
145172
},
146173
async reset() {
147-
await this.set(initialValue)
174+
await this.set(initialValue);
148175
},
149-
subscribe
150-
}
176+
subscribe,
177+
};
151178
}
152-
return stores[storageType][key]
179+
return stores[storageType][key];
153180
}

0 commit comments

Comments
 (0)