Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
51bbf0a
feat: drop in sqlite-wasm replacement
TheUltDev Oct 17, 2025
18e7206
enable encryption wasm (wip)
TheUltDev Oct 17, 2025
7245d6a
fix: add coop headers
TheUltDev Oct 18, 2025
f209b82
feat: disk encryption on web, add encryptionKey option
TheUltDev Oct 18, 2025
a264d15
Format file
steida Oct 25, 2025
7c24e51
Merge branch 'owners-api' into sqlite-wasm-cipher
TheUltDev Oct 26, 2025
680ec85
chore: reapply changes
TheUltDev Oct 26, 2025
fbb0182
feat: webauthn provided owner -> encryptionKey
TheUltDev Oct 26, 2025
a6163c9
chore: ocd
TheUltDev Oct 26, 2025
4c92054
fix: opfs directory namespace when encrypted
TheUltDev Oct 27, 2025
7510a66
fix: lint
TheUltDev Oct 27, 2025
0475444
feat: pass encryption key to op-sqlite
TheUltDev Oct 27, 2025
682a4a8
feat: pass encryption key to expo-sqlite
TheUltDev Oct 27, 2025
f26101c
chore: use hex representation
TheUltDev Oct 27, 2025
928e179
chore: enable sqlcipher in expo-sqlite
TheUltDev Oct 27, 2025
35a96c2
chore: add suggested expo metro headers
TheUltDev Oct 27, 2025
b2dd8e6
chore: hex for wasm as well
TheUltDev Oct 27, 2025
0399898
Merge remote-tracking branch 'upstream/owners-api' into sqlite-wasm-c…
TheUltDev Oct 28, 2025
904bdc5
chore: update lockfile
TheUltDev Oct 28, 2025
bf7bb5b
fix: lint
TheUltDev Oct 28, 2025
a44cc14
fix: monorepo-lint
TheUltDev Oct 28, 2025
d57b005
chore: update sqlite web package name
TheUltDev Oct 28, 2025
eefc5f2
chore: update lockfile
TheUltDev Oct 28, 2025
b1f2695
Merge branch 'owners-api' into sqlite-wasm-cipher
steida Oct 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions examples/react-electron/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ export default defineConfig({
path.resolve(__dirname, "../../packages/web/dist"),
path.resolve(
__dirname,
"../../node_modules/@sqlite.org/sqlite-wasm/sqlite-wasm/jswasm",
"../../node_modules/@evolu/sqlite-wasm/sqlite-wasm/jswasm",
),
],
},
},
optimizeDeps: {
exclude: ["@sqlite.org/sqlite-wasm", "kysely", "@evolu/react-web"],
exclude: ["@evolu/sqlite-wasm", "kysely", "@evolu/react-web"],
},
assetsInclude: ["**/*.wasm"],
});
6 changes: 5 additions & 1 deletion examples/react-expo/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,11 @@
"backgroundColor": "#ffffff"
}
],
"expo-sqlite"
[
"expo-sqlite", {
"useSqlCipher": true
}
]
],
"experiments": {
"typedRoutes": true,
Expand Down
12 changes: 12 additions & 0 deletions examples/react-expo/metro.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,16 @@ const { getDefaultConfig } = require("expo/metro-config");
/** @type {import("expo/metro-config").MetroConfig} */
const config = getDefaultConfig(__dirname);

// Add wasm asset support
config.resolver.assetExts.push('wasm');

// Add COEP and COOP headers to support SharedArrayBuffer
config.server.enhanceMiddleware = (middleware) => {
return (req, res, next) => {
res.setHeader('Cross-Origin-Embedder-Policy', 'credentialless');
res.setHeader('Cross-Origin-Opener-Policy', 'same-origin');
middleware(req, res, next);
};
};

module.exports = config;
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ const evolu = Evolu.createEvolu(evoluReactWebDeps)(Schema, {
name: Evolu.SimpleName.orThrow(
`${service}-${authResult?.owner?.id ?? "guest"}`,
),
externalAppOwner: authResult?.owner,
reloadUrl: "/",

encryptionKey: authResult?.owner?.encryptionKey,
externalAppOwner: authResult?.owner,
...(process.env.NODE_ENV === "development" && {
transports: [{ type: "WebSocket", url: "ws://localhost:4000" }],
}),
Expand Down
12 changes: 11 additions & 1 deletion examples/react-vite-pwa/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { VitePWA } from "vite-plugin-pwa";
export default defineConfig({
cacheDir: ".vite",
optimizeDeps: {
exclude: ["@sqlite.org/sqlite-wasm", "kysely", "@evolu/react-web"],
exclude: ["@evolu/sqlite-wasm", "kysely", "@evolu/react-web"],
},
plugins: [
tailwindcss(),
Expand Down Expand Up @@ -41,5 +41,15 @@ export default defineConfig({
type: "module",
},
}),
{
name: "configure-response-headers",
configureServer: (server) => {
server.middlewares.use((_req, res, next) => {
res.setHeader("Cross-Origin-Embedder-Policy", "require-corp");
res.setHeader("Cross-Origin-Opener-Policy", "same-origin");
next();
});
},
},
],
});
2 changes: 1 addition & 1 deletion examples/svelte-vite-pwa/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ export default defineConfig({
],
optimizeDeps: {
// A workaround for Vite bug: https://github.com/vitejs/vite/issues/13314#issuecomment-1560745780
exclude: ["@sqlite.org/sqlite-wasm", "kysely", "@evolu/react-web"],
exclude: ["@evolu/sqlite-wasm", "kysely", "@evolu/react-web"],
},
});
3 changes: 3 additions & 0 deletions packages/common/src/Evolu/Db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
import { ConsoleConfig, ConsoleDep } from "../Console.js";
import {
createSymmetricCrypto,
EncryptionKey,
RandomBytesDep,
SymmetricCryptoDecryptError,
} from "../Crypto.js";
Expand Down Expand Up @@ -174,6 +175,7 @@ export interface DbConfig extends ConsoleConfig, TimestampConfig {
* The default value is: `false`.
*/
readonly inMemory?: boolean;
readonly encryptionKey?: EncryptionKey;
}

export const defaultDbConfig: DbConfig = {
Expand Down Expand Up @@ -339,6 +341,7 @@ const createDbWorkerDeps =
initMessage.config.name,
{
memory: initMessage.config.inMemory ?? false,
encryptionKey: initMessage.config.encryptionKey ?? undefined,
},
);
if (!sqliteResult.ok) {
Expand Down
2 changes: 2 additions & 0 deletions packages/common/src/Sqlite.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Brand } from "./Brand.js";
import { ConsoleDep } from "./Console.js";
import { EncryptionKey } from "./Crypto.js";
import { createTransferableError, TransferableError } from "./Error.js";
import { err, ok, Result, tryAsync, trySync } from "./Result.js";
import { Null, Number, SimpleName, String, Uint8Array, union } from "./Type.js";
Expand All @@ -25,6 +26,7 @@ export interface CreateSqliteDriverDep {

export interface SqliteDriverOptions {
memory?: boolean;
encryptionKey?: EncryptionKey | undefined;
}

/**
Expand Down
8 changes: 8 additions & 0 deletions packages/react-native/src/providers/ExpoSqliteDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
CreateSqliteDriver,
SqliteDriver,
SqliteRow,
bytesToHex,
} from "@evolu/common";

import { openDatabaseSync, SQLiteStatement } from "expo-sqlite";
Expand All @@ -11,6 +12,13 @@ export const createExpoSqliteDriver: CreateSqliteDriver = (name, options) => {
const db = openDatabaseSync(
options?.memory ? ":memory:" : `evolu1-${name}.db`,
);
if (options?.encryptionKey) {
db.execSync(`
PRAGMA cipher = 'sqlcipher';
PRAGMA legacy = 4;
PRAGMA key = "x'${bytesToHex(options.encryptionKey)}'";
`);
}
let isDisposed = false;

const cache = createPreparedStatementsCache<SQLiteStatement>(
Expand Down
8 changes: 7 additions & 1 deletion packages/react-native/src/providers/OpSqliteDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
CreateSqliteDriver,
SqliteDriver,
SqliteRow,
bytesToHex,
} from "@evolu/common";

import { open, PreparedStatement } from "@op-engineering/op-sqlite";
Expand All @@ -14,7 +15,12 @@ export const createOpSqliteDriver: CreateSqliteDriver = (name, options) => {
const db = open(
options?.memory
? { name: `inMemoryDb`, location: ":memory:" }
: { name: `evolu1-${name}.db` },
: {
name: `evolu1-${name}.db`,
...(options?.encryptionKey && {
encryptionKey: `x'${bytesToHex(options.encryptionKey)}'`,
}),
}
);
let isDisposed = false;

Expand Down
4 changes: 2 additions & 2 deletions packages/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@
"format": "prettier --write \"src/*.{ts,tsx,md}\""
},
"dependencies": {
"@sqlite.org/sqlite-wasm": "3.50.4-build1",
"idb-keyval": "^6.2.2"
"idb-keyval": "^6.2.2",
"@evolu/sqlite-wasm": "2.2.4"
},
"devDependencies": {
"@evolu/common": "workspace:*",
Expand Down
33 changes: 27 additions & 6 deletions packages/web/src/WasmSqliteDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@ import {
CreateSqliteDriver,
SqliteDriver,
SqliteRow,
bytesToHex,
} from "@evolu/common";
import sqlite3InitModule, { PreparedStatement } from "@sqlite.org/sqlite-wasm";
import sqlite3InitModule, {
PreparedStatement,
Database,
} from "@evolu/sqlite-wasm";

// TODO: Do we still need that?
// https://github.com/sqlite/sqlite-wasm/issues/62
Expand All @@ -22,12 +26,29 @@ export const createWasmSqliteDriver: CreateSqliteDriver = async (
options,
) => {
const sqlite3 = await sqlite3Promise;
// This is used to make OPFS default vfs for multipleciphers
// @ts-expect-error Missing types (update @evolu/sqlite-wasm types)
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
sqlite3.capi.sqlite3mc_vfs_create("opfs", 1);

let db: Database;
if (options?.memory) {
db = new sqlite3.oo1.DB(":memory:");
} else if (options?.encryptionKey) {
const pool = await sqlite3.installOpfsSAHPoolVfs({ directory: `.${name}` });
db = new pool.OpfsSAHPoolDb(
"file:evolu1.db?vfs=multipleciphers-opfs-sahpool",
);
db.exec(`
PRAGMA cipher = 'sqlcipher';
PRAGMA legacy = 4;
PRAGMA key = "x'${bytesToHex(options.encryptionKey)}'";
`);
} else {
const pool = await sqlite3.installOpfsSAHPoolVfs({ name });
db = new pool.OpfsSAHPoolDb("file:evolu1.db");
}

const db = options?.memory
? new sqlite3.oo1.DB(":memory:")
: new (await sqlite3.installOpfsSAHPoolVfs({ name })).OpfsSAHPoolDb(
"/evolu1.db",
);
let isDisposed = false;

const cache = createPreparedStatementsCache<PreparedStatement>(
Expand Down
24 changes: 12 additions & 12 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading