From b6cd4350689c18b609d9c591d28fa5c7f5e55abd Mon Sep 17 00:00:00 2001 From: Kacper Kula Date: Sun, 26 Apr 2026 16:06:18 +0100 Subject: [PATCH 1/4] fix: wa-sqlite initialisation fix --- esbuild.config.mjs | 14 ++++++++++---- .../database/sqlocal/sqlocalWorkerDatabase.ts | 12 ++---------- .../__tests__/__mocks__/wa-sqlite-wasm-url.ts | 8 ++++---- .../explorer/database/waSqliteMemoryDatabase.ts | 12 ++---------- 4 files changed, 18 insertions(+), 28 deletions(-) diff --git a/esbuild.config.mjs b/esbuild.config.mjs index fb1794d..b58689d 100644 --- a/esbuild.config.mjs +++ b/esbuild.config.mjs @@ -112,10 +112,13 @@ const workerPlugin = { const wasmPath = join(process.cwd(), 'node_modules/wa-sqlite/dist/wa-sqlite-async.wasm'); const wasmContents = readFileSync(wasmPath); const wasmBase64 = wasmContents.toString('base64'); - const wasmDataUrl = `data:application/wasm;base64,${wasmBase64}`; return { - contents: `export default ${JSON.stringify(wasmDataUrl)};`, + contents: ` + const wasmBase64 = "${wasmBase64}"; + const wasmBinary = Uint8Array.from(atob(wasmBase64), c => c.charCodeAt(0)); + export default wasmBinary; + `, loader: 'js', }; }); @@ -158,10 +161,13 @@ const workerPlugin = { const wasmPath = join(process.cwd(), 'node_modules/wa-sqlite/dist/wa-sqlite-async.wasm'); const wasmContents = readFileSync(wasmPath); const wasmBase64 = wasmContents.toString('base64'); - const wasmDataUrl = `data:application/wasm;base64,${wasmBase64}`; return { - contents: `export default ${JSON.stringify(wasmDataUrl)};`, + contents: ` + const wasmBase64 = "${wasmBase64}"; + const wasmBinary = Uint8Array.from(atob(wasmBase64), c => c.charCodeAt(0)); + export default wasmBinary; + `, loader: 'js', }; }); diff --git a/src/modules/database/sqlocal/sqlocalWorkerDatabase.ts b/src/modules/database/sqlocal/sqlocalWorkerDatabase.ts index cc39ec6..f7c1085 100644 --- a/src/modules/database/sqlocal/sqlocalWorkerDatabase.ts +++ b/src/modules/database/sqlocal/sqlocalWorkerDatabase.ts @@ -7,7 +7,7 @@ import { sanitise } from "../../../utils/sanitiseColumn"; // Get the WASM URL from the virtual module // @ts-ignore -import wasmUrl from 'virtual:wa-sqlite-wasm-url'; +import wasmBinary from 'virtual:wa-sqlite-wasm-url'; /** * Retry an async operation with exponential backoff @@ -110,15 +110,7 @@ export class SqlocalWorkerDatabase { } try { - // Initialize the module with bundled WASM - const asyncModule = await SQLiteAsyncESMFactory({ - locateFile: (file: string) => { - if (file.endsWith('.wasm')) { - return wasmUrl; - } - return file; - } - }); + const asyncModule = await SQLiteAsyncESMFactory({ wasmBinary, locateFile: (file: string) => file }); // Use Factory to get the actual sqlite3 API this.sqlite3 = SQLite.Factory(asyncModule); diff --git a/src/modules/explorer/database/__tests__/__mocks__/wa-sqlite-wasm-url.ts b/src/modules/explorer/database/__tests__/__mocks__/wa-sqlite-wasm-url.ts index 7a18853..0368045 100644 --- a/src/modules/explorer/database/__tests__/__mocks__/wa-sqlite-wasm-url.ts +++ b/src/modules/explorer/database/__tests__/__mocks__/wa-sqlite-wasm-url.ts @@ -1,10 +1,10 @@ // Mock for virtual:wa-sqlite-wasm-url used in tests -// Returns a file:// URL that works with the fetch polyfill in jest.setup.mjs +// Returns the WASM binary as Uint8Array (same as production build) import { join } from 'path'; -import { pathToFileURL } from 'url'; +import { readFileSync } from 'fs'; const wasmPath = join(process.cwd(), 'node_modules/wa-sqlite/dist/wa-sqlite-async.wasm'); -const wasmUrl = pathToFileURL(wasmPath).href; +const wasmBinary = new Uint8Array(readFileSync(wasmPath)); -export default wasmUrl; +export default wasmBinary; diff --git a/src/modules/explorer/database/waSqliteMemoryDatabase.ts b/src/modules/explorer/database/waSqliteMemoryDatabase.ts index 5b26577..0777cad 100644 --- a/src/modules/explorer/database/waSqliteMemoryDatabase.ts +++ b/src/modules/explorer/database/waSqliteMemoryDatabase.ts @@ -4,7 +4,7 @@ import SQLiteAsyncESMFactory from 'wa-sqlite/dist/wa-sqlite-async.mjs'; import * as SQLite from 'wa-sqlite'; import { MemoryAsyncVFS } from 'wa-sqlite/src/examples/MemoryAsyncVFS.js'; // @ts-ignore - Virtual module from esbuild -import wasmUrl from 'virtual:wa-sqlite-wasm-url'; +import wasmBinary from 'virtual:wa-sqlite-wasm-url'; type ParamsObject = Record; @@ -33,15 +33,7 @@ export class WaSqliteMemoryDatabase { throw new Error('Invalid SQLite database file format'); } - // Initialize wa-sqlite - const asyncModule = await SQLiteAsyncESMFactory({ - locateFile: (file: string) => { - if (file.endsWith('.wasm')) { - return wasmUrl; - } - return file; - } - }); + const asyncModule = await SQLiteAsyncESMFactory({ wasmBinary, locateFile: (file: string) => file }); this.sqlite3 = SQLite.Factory(asyncModule); From 2bb056f61670700ff8e219ca116b80de80d192dc Mon Sep 17 00:00:00 2001 From: Kacper Kula Date: Sun, 3 May 2026 11:24:27 +0100 Subject: [PATCH 2/4] chore: adding changeset --- .changeset/slimy-toys-wear.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/slimy-toys-wear.md diff --git a/.changeset/slimy-toys-wear.md b/.changeset/slimy-toys-wear.md new file mode 100644 index 0000000..7e32348 --- /dev/null +++ b/.changeset/slimy-toys-wear.md @@ -0,0 +1,5 @@ +--- +"sqlseal": patch +--- + +fixing issue with new wa-sqlite on mobile From 8bbe84485867f17bb41e95fe7aae3a815303b5a1 Mon Sep 17 00:00:00 2001 From: Kacper Kula Date: Sun, 3 May 2026 15:27:39 +0100 Subject: [PATCH 3/4] fix: passing wasm between workers to reduce bundle size --- esbuild.config.mjs | 30 ++----------------- .../database/sqlocal/sqlocalDatabaseProxy.ts | 4 ++- .../database/sqlocal/sqlocalWorkerDatabase.ts | 15 ++++++---- 3 files changed, 14 insertions(+), 35 deletions(-) diff --git a/esbuild.config.mjs b/esbuild.config.mjs index b58689d..a53fc52 100644 --- a/esbuild.config.mjs +++ b/esbuild.config.mjs @@ -98,34 +98,8 @@ const workerPlugin = { })); build.onLoad({ filter: /.*/, namespace: 'sqlocal-worker-code' }, async () => { - // Create a plugin for the worker that resolves virtual imports - const workerVirtualPlugin = { - name: 'worker-virtual', - setup(build) { - // Handle virtual WASM URL for wa-sqlite - build.onResolve({ filter: /^virtual:wa-sqlite-wasm-url$/ }, args => ({ - path: args.path, - namespace: 'wa-sqlite-wasm-url', - })); - - build.onLoad({ filter: /.*/, namespace: 'wa-sqlite-wasm-url' }, async () => { - const wasmPath = join(process.cwd(), 'node_modules/wa-sqlite/dist/wa-sqlite-async.wasm'); - const wasmContents = readFileSync(wasmPath); - const wasmBase64 = wasmContents.toString('base64'); - - return { - contents: ` - const wasmBase64 = "${wasmBase64}"; - const wasmBinary = Uint8Array.from(atob(wasmBase64), c => c.charCodeAt(0)); - export default wasmBinary; - `, - loader: 'js', - }; - }); - } - }; - // Build sqlocal worker code + // WASM binary is NOT embedded in the worker — it's passed from the main thread via Comlink const result = await esbuild.build({ entryPoints: ['src/modules/database/sqlocal/sqlocalWorkerDatabase.ts'], bundle: true, @@ -133,7 +107,7 @@ const workerPlugin = { format: 'iife', target: 'es2020', external: ['fs', 'path', 'obsidian'], - plugins: [wasmPlugin, workerVirtualPlugin, polyfillNode({ + plugins: [wasmPlugin, polyfillNode({ })], minify: process.argv[2] === 'production', define: { diff --git a/src/modules/database/sqlocal/sqlocalDatabaseProxy.ts b/src/modules/database/sqlocal/sqlocalDatabaseProxy.ts index 9a8129f..af83b59 100644 --- a/src/modules/database/sqlocal/sqlocalDatabaseProxy.ts +++ b/src/modules/database/sqlocal/sqlocalDatabaseProxy.ts @@ -3,6 +3,8 @@ import * as Comlink from 'comlink'; import { SqlocalWorkerDatabase } from "./sqlocalWorkerDatabase"; import { ColumnDefinition } from "../../../utils/types"; import { sanitise } from "../../../utils/sanitiseColumn"; +// @ts-ignore +import wasmBinary from 'virtual:wa-sqlite-wasm-url'; /** * Main-thread proxy for SqlocalWorkerDatabase. @@ -49,7 +51,7 @@ export class SqlocalDatabaseProxy { const instance = await new DatabaseWrap(this.dbName); - await instance.connect(); + await instance.connect(wasmBinary); this.db = instance; this.isConnected = true; diff --git a/src/modules/database/sqlocal/sqlocalWorkerDatabase.ts b/src/modules/database/sqlocal/sqlocalWorkerDatabase.ts index f7c1085..5b246fc 100644 --- a/src/modules/database/sqlocal/sqlocalWorkerDatabase.ts +++ b/src/modules/database/sqlocal/sqlocalWorkerDatabase.ts @@ -5,10 +5,6 @@ import { IDBBatchAtomicVFS } from 'wa-sqlite/src/examples/IDBBatchAtomicVFS.js'; import { ColumnDefinition } from "../../../utils/types"; import { sanitise } from "../../../utils/sanitiseColumn"; -// Get the WASM URL from the virtual module -// @ts-ignore -import wasmBinary from 'virtual:wa-sqlite-wasm-url'; - /** * Retry an async operation with exponential backoff * @param operation - The async operation to retry @@ -70,6 +66,7 @@ export class SqlocalWorkerDatabase { private isConnected = false; private vfsRegistered = false; private isRecreating = false; + private wasmBinary?: Uint8Array; constructor(private readonly dbName: string) { } @@ -109,8 +106,12 @@ export class SqlocalWorkerDatabase { return this.sqlite3; } + if (!this.wasmBinary) { + throw new Error('SqlocalWorkerDatabase: wasmBinary not provided. Call connect() with the WASM binary.'); + } + try { - const asyncModule = await SQLiteAsyncESMFactory({ wasmBinary, locateFile: (file: string) => file }); + const asyncModule = await SQLiteAsyncESMFactory({ wasmBinary: this.wasmBinary, locateFile: (file: string) => file }); // Use Factory to get the actual sqlite3 API this.sqlite3 = SQLite.Factory(asyncModule); @@ -140,11 +141,13 @@ export class SqlocalWorkerDatabase { } } - async connect() { + async connect(wasmBinary: Uint8Array) { if (this.isConnected) { return Promise.resolve(); } + this.wasmBinary = wasmBinary; + try { // Initialize SQLite await this.initializeSQLite(); From 77a5ed23fc6825628cb73936a5777b7deef15e39 Mon Sep 17 00:00:00 2001 From: Kacper Kula Date: Mon, 4 May 2026 10:50:32 +0100 Subject: [PATCH 4/4] fix: fixing issue with vault names --- src/modules/database/sqlocal/databaseProvider.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modules/database/sqlocal/databaseProvider.ts b/src/modules/database/sqlocal/databaseProvider.ts index b36ed25..142499a 100644 --- a/src/modules/database/sqlocal/databaseProvider.ts +++ b/src/modules/database/sqlocal/databaseProvider.ts @@ -8,8 +8,9 @@ export class DatabaseProvider { constructor(private app: App) { } get prefix() { + const appId = ((this.app as any).appId ?? '').replace(/[^a-zA-Z0-9_-]/g, '_'); const filename = `sqlseal_1__` + - sanitise(this.app.vault.getName()) + "___" + (this.app as any).appId; + sanitise(this.app.vault.getName()) + "___" + appId; return filename; }