From c6f292a68c128086cd4e8249c1b98c4523931055 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joaqu=C3=ADn=20S=C3=A1nchez?= Date: Tue, 3 Jan 2023 01:18:01 +0100 Subject: [PATCH] fix: use top level await accessing users idb (#721) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 三咲智子 --- composables/idb/index.ts | 65 ++++++++++++++++++++++++++++++++++++++++ composables/users.ts | 8 ++--- 2 files changed, 69 insertions(+), 4 deletions(-) create mode 100644 composables/idb/index.ts diff --git a/composables/idb/index.ts b/composables/idb/index.ts new file mode 100644 index 00000000..1019cb88 --- /dev/null +++ b/composables/idb/index.ts @@ -0,0 +1,65 @@ +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' + +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() { + 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() { + 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 +} diff --git a/composables/users.ts b/composables/users.ts index f4db917c..f43bd79d 100644 --- a/composables/users.ts +++ b/composables/users.ts @@ -1,5 +1,4 @@ import { login as loginMasto } from 'masto' -import { useIDBKeyval } from '@vueuse/integrations/useIDBKeyval' import type { Account, AccountCredentials, Instance, MastoClient, WsEvents } from 'masto' import type { Ref } from 'vue' import type { RemovableRef } from '@vueuse/core' @@ -14,10 +13,11 @@ import { STORAGE_KEY_USERS, } from '~/constants' import type { PushNotificationPolicy, PushNotificationRequest } from '~/composables/push-notifications/types' +import { useAsyncIDBKeyval } from '~/composables/idb' const mock = process.mock -const initializeUsers = (): Ref | RemovableRef => { +const initializeUsers = async (): Promise | RemovableRef> => { let defaultUsers = mock ? [mock.user] : [] // Backward compatibility with localStorage @@ -32,7 +32,7 @@ const initializeUsers = (): Ref | RemovableRef => { const users = process.server ? ref(defaultUsers) - : useIDBKeyval(STORAGE_KEY_USERS, defaultUsers, { deep: true }) + : await useAsyncIDBKeyval(STORAGE_KEY_USERS, defaultUsers, { deep: true }) if (removeUsersOnLocalStorage) globalThis.localStorage.removeItem(STORAGE_KEY_USERS) @@ -40,7 +40,7 @@ const initializeUsers = (): Ref | RemovableRef => { return users } -const users = initializeUsers() +const users = await initializeUsers() const instances = useLocalStorage>(STORAGE_KEY_SERVERS, mock ? mock.server : {}, { deep: true }) const currentUserId = useLocalStorage(STORAGE_KEY_CURRENT_USER, mock ? mock.user.account.id : '')