import type { MaybeComputedRef, RemovableRef } from '@vueuse/core' import type { Ref } from 'vue' import { del, get, set, update } from 'idb-keyval' import type { UseIDBOptions } from '@vueuse/integrations/useIDBKeyval' const isIDBSupported = !process.test && typeof indexedDB !== 'undefined' export async function useAsyncIDBKeyval( key: IDBValidKey, initialValue: MaybeComputedRef, options: UseIDBOptions = {}, ): Promise> { const { flush = 'pre', deep = true, shallow, onError = (e: unknown) => { console.error(e) }, } = options const data = (shallow ? shallowRef : ref)(initialValue) as Ref const rawInit: T = resolveUnref(initialValue) async function read() { if (!isIDBSupported) return try { const rawValue = await get(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() { if (!isIDBSupported) return 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 }