diff --git a/src/client/initMatrix.ts b/src/client/initMatrix.ts index ca33ebd39..605d0f300 100644 --- a/src/client/initMatrix.ts +++ b/src/client/initMatrix.ts @@ -20,9 +20,12 @@ export const IDB_VERSION_CONFLICT = 'IDB_VERSION_CONFLICT'; * session. When that happens the device "resurrects" with a blank key store and the * client re-uploads a one-time key at an id Synapse already holds → a permanent * `400 M_UNKNOWN: … already exists` upload-conflict storm (and, downstream, - * undecryptable to-device/media keys). `persist()` grants based on engagement / PWA - * install and shows no prompt; denial/absence is non-fatal. + * undecryptable to-device/media keys). Chromium/WebKit answer `persist()` at once + * (engagement / PWA install); Firefox shows a permission prompt and the promise + * stays pending until it's answered. Denial/absence is non-fatal. */ +const PERSIST_WAIT_MS = 1500; + export const requestPersistentStorage = async (): Promise => { try { if (!navigator.storage?.persist) return false; @@ -39,7 +42,15 @@ export const requestPersistentStorage = async (): Promise => { export const initClient = async (session: Session): Promise => { // Protect the crypto store from eviction before we create and write to it. - await requestPersistentStorage(); + // [Gitea #303] Never block startup on the answer: Firefox prompts and leaves + // the promise pending until the user responds, which froze the app on + // "Heating up". KE-1 only needs the request made; give it 1.5 s at most. + await Promise.race([ + requestPersistentStorage(), + new Promise((resolve) => { + setTimeout(() => resolve(false), PERSIST_WAIT_MS); + }), + ]); const indexedDBStore = new IndexedDBStore({ indexedDB: globalThis.indexedDB,