2023-05-01 23:58:55 +00:00
|
|
|
import type { MaybeRefOrGetter, RemovableRef } from '@vueuse/core'
|
2023-01-03 00:18:01 +00:00
|
|
|
import type { Ref } from 'vue'
|
|
|
|
import type { UseIDBOptions } from '@vueuse/integrations/useIDBKeyval'
|
2023-02-06 22:22:56 +00:00
|
|
|
import { del, get, set, update } from '~/utils/elk-idb'
|
2023-01-03 00:18:01 +00:00
|
|
|
|
2023-01-15 19:09:01 +00:00
|
|
|
const isIDBSupported = !process.test && typeof indexedDB !== 'undefined'
|
|
|
|
|
2023-01-03 00:18:01 +00:00
|
|
|
export async function useAsyncIDBKeyval<T>(
|
|
|
|
key: IDBValidKey,
|
2023-05-01 23:58:55 +00:00
|
|
|
initialValue: MaybeRefOrGetter<T>,
|
2023-01-03 00:18:01 +00:00
|
|
|
options: UseIDBOptions = {},
|
|
|
|
): Promise<RemovableRef<T>> {
|
|
|
|
const {
|
|
|
|
flush = 'pre',
|
|
|
|
deep = true,
|
|
|
|
shallow,
|
|
|
|
onError = (e: unknown) => {
|
|
|
|
console.error(e)
|
|
|
|
},
|
|
|
|
} = options
|
|
|
|
|
|
|
|
const data = (shallow ? shallowRef : ref)(initialValue) as Ref<T>
|
|
|
|
|
2024-08-20 15:51:05 +00:00
|
|
|
const rawInit: T = toValue<T>(initialValue)
|
2023-01-03 00:18:01 +00:00
|
|
|
|
|
|
|
async function read() {
|
2023-01-15 19:09:01 +00:00
|
|
|
if (!isIDBSupported)
|
|
|
|
return
|
2023-01-03 00:18:01 +00:00
|
|
|
try {
|
|
|
|
const rawValue = await get<T>(key)
|
|
|
|
if (rawValue === undefined) {
|
|
|
|
if (rawInit !== undefined && rawInit !== null)
|
|
|
|
await set(key, rawInit)
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
data.value = rawValue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
onError(e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
await read()
|
|
|
|
|
|
|
|
async function write() {
|
2023-01-15 19:09:01 +00:00
|
|
|
if (!isIDBSupported)
|
|
|
|
return
|
2023-01-03 00:18:01 +00:00
|
|
|
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>
|
|
|
|
}
|