/
index.ts
95 lines (84 loc) · 1.93 KB
/
index.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
91
92
93
94
95
import type { ConfigurableFlush, MaybeComputedRef, RemovableRef } from '@vueuse/shared'
import { resolveUnref } from '@vueuse/shared'
import type { Ref } from 'vue-demi'
import { ref, shallowRef, watch } from 'vue-demi'
import { del, get, set, update } from 'idb-keyval'
export interface UseIDBOptions extends ConfigurableFlush {
/**
* Watch for deep changes
*
* @default true
*/
deep?: boolean
/**
* On error callback
*
* Default log error to `console.error`
*/
onError?: (error: unknown) => void
/**
* Use shallow ref as reference
*
* @default false
*/
shallow?: boolean
}
/**
*
* @param key
* @param initialValue
* @param options
*/
export function useIDBKeyval<T>(
key: IDBValidKey,
initialValue: MaybeComputedRef<T>,
options: UseIDBOptions = {},
): RemovableRef<T> {
const {
flush = 'pre',
deep = true,
shallow,
onError = (e) => {
console.error(e)
},
} = options
const data = (shallow ? shallowRef : ref)(initialValue) as Ref<T>
const rawInit: T = resolveUnref(initialValue)
async function read() {
try {
const rawValue = await get<T>(key)
if (rawValue === undefined) {
if (rawInit)
set(key, rawInit)
}
else {
data.value = rawValue
}
}
catch (e) {
onError(e)
}
}
read()
async function write() {
try {
if (data.value == null) {
await del(key)
}
else {
// IndexedDB does not support saving proxies, convert from proxy before saving
if (Array.isArray(data.value))
await update(key, () => (JSON.parse(JSON.stringify(data.value))))
else if (typeof data.value === 'object')
await update(key, () => ({ ...data.value }))
else
await update(key, () => (data.value))
}
}
catch (e) {
onError(e)
}
}
watch(data, () => write(), { flush, deep })
return data as RemovableRef<T>
}