diff --git a/.changeset/eleven-moons-sit.md b/.changeset/eleven-moons-sit.md new file mode 100644 index 0000000..3081ff5 --- /dev/null +++ b/.changeset/eleven-moons-sit.md @@ -0,0 +1,5 @@ +--- +'@journeyapps/powersync-sdk-web': patch +--- + +Fixed watched queries not updating due to race condition when opening multiple WA-SQLite connections due to initiating multiple PowerSync instances simultaneously. diff --git a/packages/powersync-sdk-web/src/worker/db/SharedWASQLiteDB.worker.ts b/packages/powersync-sdk-web/src/worker/db/SharedWASQLiteDB.worker.ts index 9c72222..ebf7dcd 100644 --- a/packages/powersync-sdk-web/src/worker/db/SharedWASQLiteDB.worker.ts +++ b/packages/powersync-sdk-web/src/worker/db/SharedWASQLiteDB.worker.ts @@ -6,24 +6,30 @@ import { DBWorkerInterface, _openDB } from './open-db'; const _self: SharedWorkerGlobalScope = self as any; -const DBMap = new Map(); +const DBMap = new Map>(); const openDB = async (dbFileName: string): Promise => { if (!DBMap.has(dbFileName)) { - DBMap.set(dbFileName, await _openDB(dbFileName)); + const openPromise = _openDB(dbFileName); + DBMap.set(dbFileName, openPromise); + openPromise.catch((error) => { + // Allow for retries if an error ocurred + console.error(error); + DBMap.delete(dbFileName); + }); } - return Comlink.proxy(DBMap.get(dbFileName)!); + return Comlink.proxy(await DBMap.get(dbFileName)!); }; _self.onconnect = function (event: MessageEvent) { const port = event.ports[0]; - console.debug('Exposing db on port', port); Comlink.expose(openDB, port); }; addEventListener('beforeunload', (event) => { - Array.from(DBMap.values()).forEach((db) => { + Array.from(DBMap.values()).forEach(async (dbPromise) => { + const db = await dbPromise; db.close?.(); }); }); diff --git a/packages/powersync-sdk-web/src/worker/db/open-db.ts b/packages/powersync-sdk-web/src/worker/db/open-db.ts index 69dd176..7d0cf53 100644 --- a/packages/powersync-sdk-web/src/worker/db/open-db.ts +++ b/packages/powersync-sdk-web/src/worker/db/open-db.ts @@ -24,8 +24,6 @@ export type WASQLiteExecuteMethod = (sql: string, params?: any[]) => Promise void; export type OpenDB = (dbFileName: string) => DBWorkerInterface; -const listeners = new Map(); - export async function _openDB(dbFileName: string): Promise { const { default: moduleFactory } = await import('@journeyapps/wa-sqlite/dist/wa-sqlite-async.mjs'); const module = await moduleFactory(); @@ -37,6 +35,11 @@ export async function _openDB(dbFileName: string): Promise { const db = await sqlite3.open_v2(dbFileName); + /** + * Listeners are exclusive to the DB connection. + */ + const listeners = new Map(); + sqlite3.register_table_onchange_hook(db, (opType: number, tableName: string, rowId: number) => { Array.from(listeners.values()).forEach((l) => l(opType, tableName, rowId)); });