yjs / y-indexeddb

IndexedDB database adapter for Yjs
https://docs.yjs.dev/ecosystem/database-provider/y-indexeddb
Other
196 stars 30 forks source link

Catch and emit error from idb.openDB #15

Open jpobley opened 2 years ago

jpobley commented 2 years ago

Firefox Private Browsing disables IndexedDb by default, which causes an error. We need to catch and emit that error so clients using IndexedDbProvider can do something about it.

It turns out there is a workaround, but if we don't catch the error, we can't suggest it.

jpobley commented 2 years ago

I should also point out that one can also await and catch the error via indexedDbProvider.whenSynced, so this PR isn't totally necessary.

dmonad commented 2 years ago

Thanks for this @jpobley!

I think that whenSynced should indeed be a rejected promise when the initialization fails for some reason. It is also idiomatic to throw an error as you do.

Could you please do a small modification and change this to:

this.whenSynced = new Promise(..)
this.whenSynced.catch(err => { this.emit('error', ..) })

Otherwise this.whenSynced is resolved because the error is caught.

This issue is fairly preventable. The example should probably show that you only create a y-indexeddb provider when IndexedDB is supported and enabled. Not sure how one can check for that.

jpobley commented 2 years ago

Cool. Updated. I wasn't entirely sure what you meant by your request, so lemme know if I misunderstood it.

This issue is fairly preventable. The example should probably show that you only create a y-indexeddb provider when IndexedDB is supported and enabled. Not sure how one can check for that.

Yeah, you'd think there would be a flag set or something, but I haven't found anything. One idea off the cuff might be updating lib0/indexeddb.js to have an isEnabled() export that resembles:

import {uuidv4} from './random.js'

export const isEnabled = (function checkIdbEnabled() {
    let idbEnabled;

    const name = `lib0-idb-enabled-check-${uuidv4()}`;
    const request = indexedDB.open(name)
    request.onerror = e => idbEnabled = false
    request.onsuccess = e => {
        e.target.result.close()
        indexedDB.deleteDatabase(name)
        idbEnabled = true
    }

    return () => idbEnabled
})()