From 1dd003d21332cd3c6f5a061c859a681884add3b9 Mon Sep 17 00:00:00 2001 From: Marcus Pousette Date: Sun, 12 Jul 2026 20:09:47 +0200 Subject: [PATCH] fix(wa-sqlite): allow long OPFS paths --- .changeset/wa-sqlite-opfs-path-capacity.md | 5 +++++ .../treecrdt-wa-sqlite/e2e/tests/lifecycle.spec.ts | 4 +++- packages/treecrdt-wa-sqlite/src/opfs.ts | 14 ++++++++++++-- 3 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 .changeset/wa-sqlite-opfs-path-capacity.md diff --git a/.changeset/wa-sqlite-opfs-path-capacity.md b/.changeset/wa-sqlite-opfs-path-capacity.md new file mode 100644 index 00000000..01de743d --- /dev/null +++ b/.changeset/wa-sqlite-opfs-path-capacity.md @@ -0,0 +1,5 @@ +--- +'@treecrdt/wa-sqlite': patch +--- + +Allow OPFS database paths longer than wa-sqlite's 64-byte VFS default. diff --git a/packages/treecrdt-wa-sqlite/e2e/tests/lifecycle.spec.ts b/packages/treecrdt-wa-sqlite/e2e/tests/lifecycle.spec.ts index 16f8ca06..52cd9fc7 100644 --- a/packages/treecrdt-wa-sqlite/e2e/tests/lifecycle.spec.ts +++ b/packages/treecrdt-wa-sqlite/e2e/tests/lifecycle.spec.ts @@ -107,9 +107,11 @@ test.describe('browser OPFS lifecycle', () => { page.on('console', (msg) => console.log(`[page][${msg.type()}] ${msg.text()}`)); const suffix = `${Date.now().toString(36)}-${Math.random().toString(16).slice(2, 8)}`; + const filename = `/lifecycle-${'p'.repeat(48)}-${scenario.runtime}-${suffix}.db`; + expect(new TextEncoder().encode(`${filename}-journal`).byteLength).toBeGreaterThan(64); const opts = { docId: `lifecycle-${scenario.runtime}-${suffix}`, - filename: `/lifecycle-${scenario.runtime}-${suffix}.db`, + filename, runtime: scenario.runtime, }; diff --git a/packages/treecrdt-wa-sqlite/src/opfs.ts b/packages/treecrdt-wa-sqlite/src/opfs.ts index a561adb3..ebe81ac6 100644 --- a/packages/treecrdt-wa-sqlite/src/opfs.ts +++ b/packages/treecrdt-wa-sqlite/src/opfs.ts @@ -124,6 +124,14 @@ export type OpfsVfsOptions = { kind?: OpfsVfsKind; }; +const OPFS_MAX_PATHNAME = 512; + +function withOpfsPathCapacity(vfs: any): any { + // SQLite appends sidecar suffixes such as "-journal" after checking this capacity. + vfs.mxPathname = Math.max(vfs.mxPathname ?? 0, OPFS_MAX_PATHNAME); + return vfs; +} + /** * Create an OPFS VFS bound to the provided wa-sqlite Module. * Uses local copies of wa-sqlite's example VFS implementations to avoid reaching into vendor paths. @@ -133,12 +141,14 @@ export async function createOpfsVfs(module: any, opts: OpfsVfsOptions = {}): Pro if (opts.kind === 'any-context') { // @ts-ignore vendored module lacks type declarations const { OPFSAnyContextVFS } = await import('./vendor/OPFSAnyContextVFS.js'); - return OPFSAnyContextVFS.create(name, module, { lockPolicy: 'exclusive' }); + return withOpfsPathCapacity( + await OPFSAnyContextVFS.create(name, module, { lockPolicy: 'exclusive' }), + ); } // @ts-ignore vendored module lacks type declarations const { OPFSCoopSyncVFS } = await import('./vendor/OPFSCoopSyncVFS.js'); - return OPFSCoopSyncVFS.create(name, module); + return withOpfsPathCapacity(await OPFSCoopSyncVFS.create(name, module)); } export type OpenOptions = {