-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
createStorage.ts
90 lines (82 loc) · 2.83 KB
/
createStorage.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import type { PartializedState } from './createConfig.js'
import type { Compute } from './types/utils.js'
import { deserialize as deserialize_ } from './utils/deserialize.js'
import { serialize as serialize_ } from './utils/serialize.js'
// key-values for loose autocomplete and typing
export type StorageItemMap = {
recentConnectorId: string
state: PartializedState
}
export type Storage<
itemMap extends Record<string, unknown> = Record<string, unknown>,
///
storageItemMap extends StorageItemMap = StorageItemMap & itemMap,
> = {
key: string
getItem<
key extends keyof storageItemMap,
value extends storageItemMap[key],
defaultValue extends value | null | undefined,
>(
key: key,
defaultValue?: defaultValue | undefined,
):
| (defaultValue extends null ? value | null : value)
| Promise<defaultValue extends null ? value | null : value>
setItem<
key extends keyof storageItemMap,
value extends storageItemMap[key] | null,
>(key: key, value: value): void | Promise<void>
removeItem(key: keyof storageItemMap): void | Promise<void>
}
export type BaseStorage = {
getItem(
key: string,
): string | null | undefined | Promise<string | null | undefined>
setItem(key: string, value: string): void | Promise<void>
removeItem(key: string): void | Promise<void>
}
export type CreateStorageParameters = {
deserialize?: (<type>(value: string) => type | unknown) | undefined
key?: string | undefined
serialize?: (<type>(value: type | any) => string) | undefined
storage?: Compute<BaseStorage> | undefined
}
export function createStorage<
itemMap extends Record<string, unknown> = Record<string, unknown>,
storageItemMap extends StorageItemMap = StorageItemMap & itemMap,
>(parameters: CreateStorageParameters): Compute<Storage<storageItemMap>> {
const {
deserialize = deserialize_,
key: prefix = 'wagmi',
serialize = serialize_,
storage = noopStorage,
} = parameters
function unwrap<type>(value: type): type | Promise<type> {
if (value instanceof Promise) return value.then((x) => x).catch(() => null)
return value
}
return {
...storage,
key: prefix,
async getItem(key, defaultValue) {
const value = storage.getItem(`${prefix}.${key as string}`)
const unwrapped = await unwrap(value)
if (unwrapped) return deserialize(unwrapped) ?? null
return (defaultValue ?? null) as any
},
async setItem(key, value) {
const storageKey = `${prefix}.${key as string}`
if (value === null) await unwrap(storage.removeItem(storageKey))
else await unwrap(storage.setItem(storageKey, serialize(value)))
},
async removeItem(key) {
await unwrap(storage.removeItem(`${prefix}.${key as string}`))
},
}
}
export const noopStorage = {
getItem: () => null,
setItem: () => {},
removeItem: () => {},
} satisfies BaseStorage