diff --git a/.changeset/new-doors-unite.md b/.changeset/new-doors-unite.md new file mode 100644 index 000000000..df7feec11 --- /dev/null +++ b/.changeset/new-doors-unite.md @@ -0,0 +1,5 @@ +--- +'@powersync/web': patch +--- + +Ensuring encryption pragma executes before setting cache size, fixes issue where encryption would throw an error during initialization. diff --git a/packages/web/src/db/adapters/wa-sqlite/WASQLiteConnection.ts b/packages/web/src/db/adapters/wa-sqlite/WASQLiteConnection.ts index 3f8336b12..0db843048 100644 --- a/packages/web/src/db/adapters/wa-sqlite/WASQLiteConnection.ts +++ b/packages/web/src/db/adapters/wa-sqlite/WASQLiteConnection.ts @@ -235,8 +235,8 @@ export class WASqliteConnection await this.openDB(); this.registerBroadcastListeners(); await this.executeSingleStatement(`PRAGMA temp_store = ${this.options.temporaryStorage};`); - await this.executeSingleStatement(`PRAGMA cache_size = -${this.options.cacheSizeKb};`); await this.executeEncryptionPragma(); + await this.executeSingleStatement(`PRAGMA cache_size = -${this.options.cacheSizeKb};`); this.sqliteAPI.update_hook(this.dbP, (updateType: number, dbName: string | null, tableName: string | null) => { if (!tableName) { diff --git a/packages/web/tests/encryption.test.ts b/packages/web/tests/encryption.test.ts new file mode 100644 index 000000000..546244890 --- /dev/null +++ b/packages/web/tests/encryption.test.ts @@ -0,0 +1,64 @@ +import { + PowerSyncDatabase, + WASQLiteOpenFactory, + WASQLiteVFS, + WebPowerSyncDatabaseOptionsWithOpenFactory, + WebPowerSyncDatabaseOptionsWithSettings +} from '@powersync/web'; +import { v4 as uuid } from 'uuid'; +import { describe, expect, it } from 'vitest'; +import { testSchema } from './utils/testDb'; + +describe('Encryption Tests', { sequential: true }, () => { + it('IDBBatchAtomicVFS encryption', async () => { + await testEncryption({ + schema: testSchema, + database: { dbFilename: 'iddb-file.db' }, + encryptionKey: 'iddb-key' + }); + }); + + it('OPFSCoopSyncVFS encryption', async () => { + await testEncryption({ + schema: testSchema, + database: new WASQLiteOpenFactory({ + dbFilename: 'opfs-file.db', + vfs: WASQLiteVFS.OPFSCoopSyncVFS, + encryptionKey: 'opfs-key' + }) + }); + }); + + it('AccessHandlePoolVFS encryption', async () => { + await testEncryption({ + schema: testSchema, + database: new WASQLiteOpenFactory({ + dbFilename: 'ahp-file.db', + vfs: WASQLiteVFS.AccessHandlePoolVFS, + encryptionKey: 'ahp-key' + }) + }); + }); +}); + +/** + * The open/close and open again flow is an easy way to verify that encryption is working. + */ +const testEncryption = async ( + options: WebPowerSyncDatabaseOptionsWithSettings | WebPowerSyncDatabaseOptionsWithOpenFactory +) => { + let powersync = new PowerSyncDatabase(options as any); + + await powersync.init(); + await powersync.close(); + + powersync = new PowerSyncDatabase(options as any); + + await powersync.init(); + await powersync.execute('INSERT INTO assets(id, make, customer_id) VALUES (uuid(), ?, ?)', ['test', uuid()]); + const results = await powersync.getAll('SELECT * FROM assets'); + expect(results.length).toBe(1); + + await powersync.disconnectAndClear(); + await powersync.close(); +};