Skip to content

Add wasm32-unknown-unknown compilation target support for matrix_sdk_sqlite#6329

Open
NoManColonies wants to merge 22 commits intomatrix-org:mainfrom
NoManColonies:main
Open

Add wasm32-unknown-unknown compilation target support for matrix_sdk_sqlite#6329
NoManColonies wants to merge 22 commits intomatrix-org:mainfrom
NoManColonies:main

Conversation

@NoManColonies
Copy link
Copy Markdown

@NoManColonies NoManColonies commented Mar 20, 2026

Before starting, I apologize for any inconvenience caused by my non-native English.

This PR adds support for compiling matrix_sdk_sqlite to the wasm32-unknown-unknown target, enabling use in browser and similar WASM environments.

Currently, matrix_sdk in WASM is limited to:

  • in-memory state store/event cache, or
  • IndexedDB-backed state store with in-memory event cache

This means persistent event/media caching is not available without a custom implementation.
This PR introduces SQLite-backed persistence for WASM as an additional store option.

Summary of changes

  • Bump rusqlite to 0.38 (adds wasm32-unknown-unknown support via sqlite-wasm-rs)
    • cache feature now required for prepared/cached statements
    • fallible_uint feature required for unsigned integer casting
  • Add wasm32-wasi-vfs feature for WASM targets to enable a browser-compatible VFS
    • Default backend: OPFS
    • Other VFS implementation is split into a separate PR
  • Add web-time dependency for media retention policy serialization
  • Gate Tokio fs feature and deadpool-sync behind non-WASM targets
  • Replace Send with SendOutsideWasm where required for non-Send WASM environments
  • Use #[cfg_attr(...)] instead of unconditional #[async_trait] for target-specific behavior
  • Replace SyncWrapper<T> with RefCell<T> in the WASM deadpool adapter
    • SyncWrapper<T> requires Send bound
    • RefCell<T> provides equivalent interior mutability without Send bound

Notes for reviewers

  • Default VFS backend is OPFS; other VFS implementation is split into a separate PR
  • No public API changes beyond documented feature additions
    • js feature is needed in order to compile to WASM target
  • Changes are largely conditional on target_family = "wasm"

  • I've documented the public API Changes in the appropriate CHANGELOG.md files
  • This PR was made with the help of AI
    • This PR description was machine translated/assisted

Signed-off-by: Geng Kongpop geng@finnomena.com

@NoManColonies NoManColonies changed the title Pull changes from upstream Added wasm32-unknown-unknown compilation support target for matrix_sdk_sqlite Mar 20, 2026
@NoManColonies NoManColonies changed the title Added wasm32-unknown-unknown compilation support target for matrix_sdk_sqlite Added wasm32-unknown-unknown compilation target support for matrix_sdk_sqlite Mar 20, 2026
@codecov
Copy link
Copy Markdown

codecov bot commented Mar 20, 2026

Codecov Report

❌ Patch coverage is 82.35294% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.87%. Comparing base (85b8c83) to head (4bd5f07).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
crates/matrix-sdk-sqlite/src/crypto_store.rs 0.00% 0 Missing and 1 partial ⚠️
crates/matrix-sdk-sqlite/src/state_store.rs 75.00% 0 Missing and 1 partial ⚠️
crates/matrix-sdk-sqlite/src/utils.rs 87.50% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6329      +/-   ##
==========================================
- Coverage   89.88%   89.87%   -0.02%     
==========================================
  Files         376      376              
  Lines      103093   103097       +4     
  Branches   103093   103097       +4     
==========================================
- Hits        92670    92658      -12     
- Misses       6863     6870       +7     
- Partials     3560     3569       +9     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq bot commented Mar 20, 2026

Merging this PR will not alter performance

✅ 50 untouched benchmarks


Comparing NoManColonies:main (4bd5f07) with main (85b8c83)

Open in CodSpeed

@NoManColonies NoManColonies marked this pull request as ready for review March 23, 2026 10:06
@NoManColonies NoManColonies requested a review from a team as a code owner March 23, 2026 10:06
@NoManColonies NoManColonies requested review from poljar and removed request for a team March 23, 2026 10:06
@richvdh richvdh self-requested a review March 25, 2026 12:12
Copy link
Copy Markdown
Member

@richvdh richvdh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks very much for submitting this. We're quite excited by it, as it opens the door to things like being able to use the wasm bindings for matrix-sdk-crypto in node.js (matrix-org/matrix-sdk-crypto-wasm#168), and maybe even dropping support for indexeddb altogether.

Some questions, other than those below:

  • How were you able to test/build this? I tried things like cargo check -p matrix-sdk-sqlite --target wasm32-unknown-unknown and wasm-pack test --chrome --headless crates/matrix-sdk-sqlite, and got build errors.

    Would you be able to add support to cargo xtask ci for checking and testing matrix-sdk-sqlite with the wasm target? I think you'll need to add a new entry to WasmFeatureSet.

  • Would you be able to break the changes down into smaller commits, to make them easier to review?

@richvdh richvdh changed the title Added wasm32-unknown-unknown compilation target support for matrix_sdk_sqlite Add wasm32-unknown-unknown compilation target support for matrix_sdk_sqlite Mar 25, 2026
@NoManColonies NoManColonies requested a review from a team as a code owner March 26, 2026 04:20
@richvdh
Copy link
Copy Markdown
Member

richvdh commented Mar 26, 2026

@NoManColonies I assume you're still working on this. Once it's ready for review, please rebase your changes on main and ping me.

@NoManColonies
Copy link
Copy Markdown
Author

NoManColonies commented Mar 28, 2026

@richvdh

Thanks very much for submitting this. We're quite excited by it, as it opens the door to things like being able to use the wasm bindings for matrix-sdk-crypto in node.js (matrix-org/matrix-sdk-crypto-wasm#168), and maybe even dropping support for indexeddb altogether.

Some questions, other than those below:

  • How were you able to test/build this? I tried things like cargo check -p matrix-sdk-sqlite --target wasm32-unknown-unknown and wasm-pack test --chrome --headless crates/matrix-sdk-sqlite, and got build errors.
    Would you be able to add support to cargo xtask ci for checking and testing matrix-sdk-sqlite with the wasm target? I think you'll need to add a new entry to WasmFeatureSet.
  • Would you be able to break the changes down into smaller commits, to make them easier to review?

Thank you very much for taking your time to review this PR and apologize for the late reply.
To address your questions:

  • How were you able to test/build this? I tried things like cargo check -p matrix-sdk-sqlite --target wasm32-unknown-unknown and wasm-pack test --chrome --headless crates/matrix-sdk-sqlite, and got build errors.

I initially tested the prototype in a temporary downstream project and I seem to have forgotten to properly configure the feature requirements in the upstream crate, my apologies. You should be able to build and test with the following commands:

  • Cargo check: cargo check -p matrix-sdk-sqlite --target wasm32-unknown-unknown --features js
  • Wasm-pack test: wasm-pack test --chrome --headless crates/matrix-sdk-sqlite --features js --release
    • Currently, the OPFS backend has a harmless debug assertion that triggers at the end of test. So you may need to run the test under release profile

Would you be able to add support to cargo xtask ci for checking and testing matrix-sdk-sqlite with the wasm target? I think you'll need to add a new entry to WasmFeatureSet.

I’ve added tests as requested, but current VFS backend (OPFS) require dedicated worker context and is therefore not supported in a Node.js environment without polyfill. I have made a separate PR adding alternative backends that should be usable in Node.js.

  • Would you be able to break the changes down into smaller commits, to make them easier to review?

Apologies for the large initial commit, it was initially composed of many small commit that didn’t compile. I saw a note in CONTRIBUTING.md that requires all commits to compile successfully, and all initial changes were required in order to compile under WASM targets. If you'd prefer, I can break the initial commit down into a smaller one.

Since your previous comments, I have made the following changes:

  • I have refactored associated type of Manager trait in src/connection.rs to use a wrapper type around RefCell<T> and keeping the interface similar to SyncWrapper<T> in order to avoid most of conditional compilation. If you prefer a WASM connection manager entirely in a separate module, please let me know. I initially did not go this route, as it requires a lot of duplicate code in the connection manager that is largely the same as non-WASM targets WASM specific connection manager implementation has also been moved to a separate module.
  • I have created a utility function setup_db_fs in src/utils.rs for setting up filesystem under different compilation targets in order to avoid duplicate code in each module.
  • I have added tests for cargo xtask ci to cover the matrix-sdk-sqlite crate when compiled for wasm targets.
    • The provided test vector isn’t compatible with SQLite compiled for wasm, so I dumped the database contents and converted them using online tool. The wasm tests now use this test vector instead of the previously provided one.
  • I have refactored VFS registration to avoid global installation which is harder to test and could limit downstream usage of SQLite.

If you have additional requests, please let know.

@NoManColonies NoManColonies marked this pull request as ready for review March 28, 2026 17:18
@richvdh richvdh self-requested a review March 30, 2026 10:23
Geng Kongpop added 6 commits March 31, 2026 00:54
chore: address breaking changes from rusqlite

feat: support alternative v/fs for wasm environment

feat: support non-send future for wasm environment

fix: solve incorrect error transformation

feat: WIP support connection pool in wasm environment

fix: use full-path method call for wasm environment + other fixes for
wasm

fix: more wasm related fixes

feat: use RefCell to simulate interior-mutability in wasm environment

fix: use implicit borrow instead of explicit call to `as_ref()`

fix: more wasm related fixes

fix: resolve ambiguity between lock guard and ref cell implicit
reference + more wasm fixes

fix: resolve wasm related lifetime issues

chore: turn on serde feature for web time when compiled as wasm32 target

chore: ran cargo check to verify Cargo.lock file

chore: fix comment formatting
Copy link
Copy Markdown
Member

@richvdh richvdh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks very much for the updates. I've taken a more detailed look. Generally it looks great, but I have some comments.

// See the License for the specific language governing permissions and
// limitations under the License.

//! An implementation of `deadpool` for `rusqlite` for usage
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't really implement the whole of deadpool, it's just a manager.

Suggested change
//! An implementation of `deadpool` for `rusqlite` for usage
//! An implementation of `deadpool::managed::Manager` for `rusqlite` for usage

// limitations under the License.

//! An implementation of `deadpool` for `rusqlite` for usage
//! in WASM environment.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
//! in WASM environment.
//! in WASM environments.

Comment on lines +18 to +21
//! Similar to the one implemented in `crate::connection::default`,
//! we do not implement connection recycling here. Mostly due to
//! [`managed::Manager`] trait expecting a future output with `Send`
//! bound which is not available in WASM environment.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really understand this comment. What does "do not implement connection recycling" mean? In what sense does Manager expect a future with Send?

Comment on lines +31 to +43
/// The default runtime used by `matrix-sdk-sqlite` for `deadpool`.
pub const RUNTIME: Runtime = Runtime::Tokio1;

deadpool::managed_reexports!(
"matrix-sdk-sqlite",
Manager,
managed::Object<Manager>,
rusqlite::Error,
Infallible
);

/// Type representing a connection to SQLite from the [`Pool`].
pub type Connection = Object;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is the same in both implementations, maybe it could live in mod.rs?`

}
.await
}
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should probably live in connection::wasm

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(and it probably needs a clearer name. I think probably just ConnectionWrapper would be fine, given it will be inside the connection::wasm module)

Comment on lines +508 to +520
if let Some(WasmFeatureSet::Sqlite) = cmd {
// Current VFS backend is not supported in Node.JS just yet.
// We force them to run in browser only for now.
run_wasm_pack_tests(Some(WasmFeatureSet::SqliteAllFeatures), WasmTestRunner::Chrome)?;
run_wasm_pack_tests(Some(WasmFeatureSet::SqliteAllFeatures), WasmTestRunner::Firefox)?;
run_wasm_pack_tests(Some(WasmFeatureSet::SqliteCache), WasmTestRunner::Chrome)?;
run_wasm_pack_tests(Some(WasmFeatureSet::SqliteCache), WasmTestRunner::Firefox)?;
run_wasm_pack_tests(Some(WasmFeatureSet::SqliteState), WasmTestRunner::Chrome)?;
run_wasm_pack_tests(Some(WasmFeatureSet::SqliteState), WasmTestRunner::Firefox)?;
run_wasm_pack_tests(Some(WasmFeatureSet::SqliteCrypto), WasmTestRunner::Chrome)?;
run_wasm_pack_tests(Some(WasmFeatureSet::SqliteCrypto), WasmTestRunner::Firefox)?;
return Ok(());
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you put this next to the indexeddb equivalent?

Comment on lines +252 to +253
# [m]-sqlite is not supported on Node.js yet, due to
# dedicated worker requirement for OPFS
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this matters here.

Suggested change
# [m]-sqlite is not supported on Node.js yet, due to
# dedicated worker requirement for OPFS

Comment on lines +553 to +556
// SQLite WASM test suites has to be ran in release mode due to
// a harmless debug assertion when closing database.
//
// Ref: https://github.com/Spxg/sqlite-wasm-rs/blob/master/crates/sqlite-wasm-vfs/src/sahpool.rs#L672
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why does this happen? The assertion is "close without open", but doesn't the database file get opened?

Comment on lines +281 to +287
# Required in order to compile SQLite to WebAssembly
- name: Install emscripten toolchains
run: |
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
./emsdk install latest
./emsdk activate latest
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't seem to be necessary when I run this locally. Are you sure it's needed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants