diff --git a/CLAUDE.md b/CLAUDE.md index 8aa580cc53..620b6046e7 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -113,12 +113,17 @@ docker-compose up -d ### SQLite Package -- RivetKit SQLite is native-only: VFS and query execution live in `rivetkit-rust/packages/rivetkit-sqlite/`, core owns lifecycle, and NAPI only marshals JS types. +- Depot client owns native SQLite VFS and query execution in `engine/packages/depot-client/`; core owns lifecycle, and NAPI only marshals JS types. +- SQLite VFS direct tests should record workflow compaction wakes through `CompactionSignaler`, not call legacy `compact_default_batch`. +- SQLite VFS correctness tests should use `DirectStorage`; do not reintroduce mock or envoy transport variants for those tests. +- SQLite VFS `xSync` durability depends on depot's `sqlite_commit` reply waiting for the FDB transaction commit. +- SQLite VFS process-global registrations must be owned by a Drop guard so panics unwind through `sqlite3_vfs_unregister`. +- `NativeDatabase::Drop` must bound dirty-page flushes with a short timeout and return after logging if the commit future never resolves. - Actor2 workflows and envoy actors always use the SQLite v2 storage format; only old actor v1 workflows and pegboard runners use the v1 storage format. ("v2" here refers to the on-disk storage format, not envoy-protocol v2.) - Native SQLite VFS recent-page preload hints are actor-side Rust state surfaced by `NativeDatabase::snapshot_preload_hints()`; persist and consume them through runtime/envoy wiring, not JS APIs. - SQLite VFS file handles must enforce their reader or writer role; reader-owned handles fail closed on mutating callbacks. - Native SQLite single-statement work should route through the native execute path; keep `exec` as the multi-statement compatibility path. -- Pegboard-envoy remote SQL execution should use `rivetkit-sqlite::database::open_database_from_engine` instead of direct `rusqlite` calls so native routing policy stays shared. +- Native SQLite opens should use `depot_client::database::open_database_from_envoy` instead of direct `rusqlite` calls so native routing policy stays shared. - Pegboard-envoy remote SQL executor caches should use `Arc>` values so first-use initialization stays lazy and single-flight per `(actor_id, sqlite_generation)`. - Sent remote SQL requests must fail with `sqlite.remote_indeterminate_result` on WebSocket disconnect; only unsent remote SQL may be sent after reconnect. - Native SQLite manual transactions keep an idle writer open until autocommit returns; route subsequent work through the writer instead of reader classification. diff --git a/Cargo.lock b/Cargo.lock index 6b983ec535..d5362aac24 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1839,6 +1839,38 @@ dependencies = [ "vbare", ] +[[package]] +name = "depot-client" +version = "2.3.0-rc.4" +dependencies = [ + "anyhow", + "async-trait", + "depot", + "depot-client-types", + "futures-util", + "gasoline", + "getrandom 0.2.16", + "libsqlite3-sys", + "moka", + "parking_lot", + "rivet-config", + "rivet-envoy-client", + "rivet-envoy-protocol", + "rivet-pools", + "rivet-test-deps", + "scc", + "sha2", + "tempfile", + "tokio", + "tracing", + "universaldb", + "universalpubsub", +] + +[[package]] +name = "depot-client-types" +version = "2.3.0-rc.4" + [[package]] name = "der" version = "0.6.1" @@ -4192,6 +4224,7 @@ dependencies = [ "async-trait", "bytes", "depot", + "depot-client", "futures-util", "gasoline", "http-body 1.0.1", @@ -4212,7 +4245,6 @@ dependencies = [ "rivet-pools", "rivet-runtime", "rivet-types", - "rivetkit-sqlite", "rusqlite", "scc", "serde", @@ -5969,6 +6001,8 @@ dependencies = [ "anyhow", "base64 0.22.1", "ciborium", + "depot-client", + "depot-client-types", "futures", "getrandom 0.2.16", "http 1.3.1", @@ -5986,8 +6020,6 @@ dependencies = [ "rivetkit-client-protocol", "rivetkit-inspector-protocol", "rivetkit-shared-types", - "rivetkit-sqlite", - "rivetkit-sqlite-types", "scc", "serde", "serde_bare", @@ -6024,6 +6056,7 @@ version = "2.3.0-rc.4" dependencies = [ "anyhow", "async-trait", + "depot-client", "hex", "http 1.3.1", "napi", @@ -6033,7 +6066,6 @@ dependencies = [ "rivet-error", "rivetkit-actor-persist", "rivetkit-core", - "rivetkit-sqlite", "scc", "serde", "serde_json", @@ -6052,38 +6084,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "rivetkit-sqlite" -version = "2.3.0-rc.4" -dependencies = [ - "anyhow", - "async-trait", - "depot", - "futures-util", - "gasoline", - "getrandom 0.2.16", - "libsqlite3-sys", - "moka", - "parking_lot", - "rivet-config", - "rivet-envoy-client", - "rivet-envoy-protocol", - "rivet-pools", - "rivet-test-deps", - "rivetkit-sqlite-types", - "scc", - "sha2", - "tempfile", - "tokio", - "tracing", - "universaldb", - "universalpubsub", -] - -[[package]] -name = "rivetkit-sqlite-types" -version = "2.3.0-rc.4" - [[package]] name = "rivetkit-wasm" version = "2.3.0-rc.4" diff --git a/Cargo.toml b/Cargo.toml index e568ea85fc..22899cb81b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,8 +63,8 @@ members = [ "rivetkit-rust/packages/actor-persist", "rivetkit-rust/packages/rivetkit-core", "rivetkit-rust/packages/shared-types", - "rivetkit-rust/packages/rivetkit-sqlite", - "rivetkit-rust/packages/rivetkit-sqlite-types", + "engine/packages/depot-client", + "engine/packages/depot-client-types", "rivetkit-typescript/packages/rivetkit-napi", "rivetkit-typescript/packages/rivetkit-wasm" ] @@ -558,11 +558,11 @@ members = [ [workspace.dependencies.rivetkit-inspector-protocol] path = "rivetkit-rust/packages/inspector-protocol" - [workspace.dependencies.rivetkit-sqlite] - path = "rivetkit-rust/packages/rivetkit-sqlite" + [workspace.dependencies.depot-client] + path = "engine/packages/depot-client" - [workspace.dependencies.rivetkit-sqlite-types] - path = "rivetkit-rust/packages/rivetkit-sqlite-types" + [workspace.dependencies.depot-client-types] + path = "engine/packages/depot-client-types" [workspace.dependencies.rivetkit-core] path = "rivetkit-rust/packages/rivetkit-core" diff --git a/docs-internal/engine/sqlite-vfs.md b/docs-internal/engine/sqlite-vfs.md index 2a864e1825..4d5e6c3d22 100644 --- a/docs-internal/engine/sqlite-vfs.md +++ b/docs-internal/engine/sqlite-vfs.md @@ -1,30 +1,13 @@ -# SQLite VFS parity +# SQLite VFS -Rules for the SQLite VFS implementations. +Rules for the SQLite VFS implementation. ## Package boundaries -- RivetKit SQLite is native-only. VFS and query execution live in `rivetkit-rust/packages/rivetkit-sqlite/`, core owns lifecycle, and NAPI only marshals JS types. -- RivetKit TypeScript SQLite is exposed through `@rivetkit/rivetkit-napi`, but runtime behavior stays in `rivetkit-rust/packages/rivetkit-sqlite/` and `rivetkit-core`. -- The Rust KV-backed SQLite implementation lives in `rivetkit-rust/packages/rivetkit-sqlite/src/`. When changing its on-disk or KV layout, update the internal data-channel spec in the same change. - -## Native VFS ↔ WASM VFS parity - -**The native Rust VFS and the WASM TypeScript VFS must match 1:1.** This includes: - -- KV key layout and encoding -- Chunk size -- PRAGMA settings -- VFS callback-to-KV-operation mapping -- Delete/truncate strategy (both must use `deleteRange`) -- Journal mode - -When changing any VFS behavior in one implementation, update the other. - -- Native: `rivetkit-rust/packages/rivetkit-sqlite/src/vfs.rs`, `kv.rs` -- WASM: `rivetkit-typescript/packages/sqlite-wasm/src/vfs.ts`, `kv.ts` - -The native VFS uses the same 4 KiB chunk layout and KV key encoding as the WASM VFS. Data is compatible between backends. +- Depot client owns native SQLite VFS and query execution in `engine/packages/depot-client/`. Core owns lifecycle, and NAPI only marshals JS types. +- RivetKit TypeScript SQLite is exposed through `@rivetkit/rivetkit-napi`, but runtime behavior stays in `engine/packages/depot-client/` and `rivetkit-core`. +- The Rust KV-backed SQLite implementation lives in `engine/packages/depot-client/src/`. When changing its on-disk or KV layout, update the internal data-channel spec in the same change. +- The VFS uses a 4 KiB chunk layout for page storage. PRAGMAs are pinned at open: `journal_mode = DELETE`, `locking_mode = EXCLUSIVE`, `auto_vacuum = NONE`. Source: `engine/packages/depot-client/src/vfs.rs`. ## VFS implementation notes diff --git a/docs-internal/engine/sqlite/vfs-brief.md b/docs-internal/engine/sqlite/vfs-brief.md index 7b9c0080ec..3b9081c437 100644 --- a/docs-internal/engine/sqlite/vfs-brief.md +++ b/docs-internal/engine/sqlite/vfs-brief.md @@ -28,4 +28,4 @@ The VFS does not write local SQLite database files. Local files would break the - [SQLite VFS](../sqlite-vfs.md) - [Depot crash course](../depot.md) -- VFS source: `rivetkit-rust/packages/rivetkit-sqlite/src/` +- VFS source: `engine/packages/depot-client/src/` diff --git a/rivetkit-rust/packages/rivetkit-sqlite-types/Cargo.toml b/engine/packages/depot-client-types/Cargo.toml similarity index 64% rename from rivetkit-rust/packages/rivetkit-sqlite-types/Cargo.toml rename to engine/packages/depot-client-types/Cargo.toml index 2b3e19d504..31465b3ff8 100644 --- a/rivetkit-rust/packages/rivetkit-sqlite-types/Cargo.toml +++ b/engine/packages/depot-client-types/Cargo.toml @@ -1,11 +1,11 @@ [package] -name = "rivetkit-sqlite-types" +name = "depot-client-types" version.workspace = true authors.workspace = true license.workspace = true edition.workspace = true workspace = "../../../" -description = "Shared SQLite execution types for RivetKit" +description = "Shared SQLite execution types for depot client" [lib] crate-type = ["lib"] diff --git a/rivetkit-rust/packages/rivetkit-sqlite-types/src/lib.rs b/engine/packages/depot-client-types/src/lib.rs similarity index 96% rename from rivetkit-rust/packages/rivetkit-sqlite-types/src/lib.rs rename to engine/packages/depot-client-types/src/lib.rs index 7e6839dcf5..6db765e2e3 100644 --- a/rivetkit-rust/packages/rivetkit-sqlite-types/src/lib.rs +++ b/engine/packages/depot-client-types/src/lib.rs @@ -1,4 +1,4 @@ -//! Shared SQLite execution types for local and remote RivetKit backends. +//! Shared SQLite execution types for local and remote depot client backends. #[derive(Clone, Debug, PartialEq)] pub enum BindParam { diff --git a/rivetkit-rust/packages/rivetkit-sqlite/Cargo.toml b/engine/packages/depot-client/Cargo.toml similarity index 87% rename from rivetkit-rust/packages/rivetkit-sqlite/Cargo.toml rename to engine/packages/depot-client/Cargo.toml index 58d5606de0..facdbcc850 100644 --- a/rivetkit-rust/packages/rivetkit-sqlite/Cargo.toml +++ b/engine/packages/depot-client/Cargo.toml @@ -1,11 +1,11 @@ [package] -name = "rivetkit-sqlite" +name = "depot-client" version.workspace = true edition.workspace = true authors.workspace = true license.workspace = true workspace = "../../../" -description = "Native SQLite VFS for RivetKit backed by depot" +description = "Depot-backed native SQLite VFS client" [lib] crate-type = ["lib"] @@ -18,7 +18,7 @@ tokio.workspace = true tracing.workspace = true getrandom = "0.2" rivet-envoy-protocol.workspace = true -rivetkit-sqlite-types.workspace = true +depot-client-types.workspace = true moka = { version = "0.12", default-features = false, features = ["sync"] } parking_lot.workspace = true diff --git a/rivetkit-rust/packages/rivetkit-sqlite/src/connection_manager.rs b/engine/packages/depot-client/src/connection_manager.rs similarity index 100% rename from rivetkit-rust/packages/rivetkit-sqlite/src/connection_manager.rs rename to engine/packages/depot-client/src/connection_manager.rs diff --git a/rivetkit-rust/packages/rivetkit-sqlite/src/database.rs b/engine/packages/depot-client/src/database.rs similarity index 100% rename from rivetkit-rust/packages/rivetkit-sqlite/src/database.rs rename to engine/packages/depot-client/src/database.rs diff --git a/rivetkit-rust/packages/rivetkit-sqlite/src/lib.rs b/engine/packages/depot-client/src/lib.rs similarity index 78% rename from rivetkit-rust/packages/rivetkit-sqlite/src/lib.rs rename to engine/packages/depot-client/src/lib.rs index 5b49adb529..c9b1f83789 100644 --- a/rivetkit-rust/packages/rivetkit-sqlite/src/lib.rs +++ b/engine/packages/depot-client/src/lib.rs @@ -1,6 +1,6 @@ -//! SQLite library for RivetKit. +//! Depot-backed SQLite client. //! -//! Provides the native SQLite VFS used by RivetKit actors. +//! Provides the native SQLite VFS used by Rivet actors. //! //! This is a pure Rust library. N-API bindings and transport clients //! live in separate crates that compose this one. @@ -26,7 +26,7 @@ pub mod optimization_flags; /// SQLite query execution helpers. pub mod query; -/// Custom SQLite VFS for actor-side sqlite-storage transport. +pub use depot_client_types as types; -pub use rivetkit_sqlite_types as types; +/// Custom SQLite VFS for actor-side depot transport. pub mod vfs; diff --git a/rivetkit-rust/packages/rivetkit-sqlite/src/optimization_flags.rs b/engine/packages/depot-client/src/optimization_flags.rs similarity index 100% rename from rivetkit-rust/packages/rivetkit-sqlite/src/optimization_flags.rs rename to engine/packages/depot-client/src/optimization_flags.rs diff --git a/rivetkit-rust/packages/rivetkit-sqlite/src/query.rs b/engine/packages/depot-client/src/query.rs similarity index 99% rename from rivetkit-rust/packages/rivetkit-sqlite/src/query.rs rename to engine/packages/depot-client/src/query.rs index 77f1294a82..bcd52bf60c 100644 --- a/rivetkit-rust/packages/rivetkit-sqlite/src/query.rs +++ b/engine/packages/depot-client/src/query.rs @@ -20,7 +20,7 @@ use libsqlite3_sys::{ sqlite3_column_type, sqlite3_errmsg, sqlite3_finalize, sqlite3_last_insert_rowid, sqlite3_prepare_v2, sqlite3_set_authorizer, sqlite3_step, sqlite3_stmt_readonly, }; -pub use rivetkit_sqlite_types::{ +pub use depot_client_types::{ BindParam, ColumnValue, ExecResult, ExecuteResult, ExecuteRoute, QueryResult, }; diff --git a/rivetkit-rust/packages/rivetkit-sqlite/src/vfs.rs b/engine/packages/depot-client/src/vfs.rs similarity index 99% rename from rivetkit-rust/packages/rivetkit-sqlite/src/vfs.rs rename to engine/packages/depot-client/src/vfs.rs index 4d46347ac9..e407a42912 100644 --- a/rivetkit-rust/packages/rivetkit-sqlite/src/vfs.rs +++ b/engine/packages/depot-client/src/vfs.rs @@ -1,6 +1,6 @@ //! Custom SQLite VFS backed by KV operations over the KV channel. //! -//! This crate now owns the KV-backed SQLite behavior used by `rivetkit-napi`. +//! This crate owns the KV-backed SQLite behavior used by `rivetkit-napi`. use std::collections::{BTreeMap, HashMap, HashSet, VecDeque}; use std::ffi::{CStr, CString, c_char, c_int, c_void}; diff --git a/engine/packages/depot-client/tests/inline/fault/AGENTS.md b/engine/packages/depot-client/tests/inline/fault/AGENTS.md new file mode 120000 index 0000000000..681311eb9c --- /dev/null +++ b/engine/packages/depot-client/tests/inline/fault/AGENTS.md @@ -0,0 +1 @@ +CLAUDE.md \ No newline at end of file diff --git a/rivetkit-rust/packages/rivetkit-sqlite/tests/inline/fault/CLAUDE.md b/engine/packages/depot-client/tests/inline/fault/CLAUDE.md similarity index 100% rename from rivetkit-rust/packages/rivetkit-sqlite/tests/inline/fault/CLAUDE.md rename to engine/packages/depot-client/tests/inline/fault/CLAUDE.md diff --git a/rivetkit-rust/packages/rivetkit-sqlite/tests/inline/fault/chaos.rs b/engine/packages/depot-client/tests/inline/fault/chaos.rs similarity index 100% rename from rivetkit-rust/packages/rivetkit-sqlite/tests/inline/fault/chaos.rs rename to engine/packages/depot-client/tests/inline/fault/chaos.rs diff --git a/rivetkit-rust/packages/rivetkit-sqlite/tests/inline/fault/mod.rs b/engine/packages/depot-client/tests/inline/fault/mod.rs similarity index 100% rename from rivetkit-rust/packages/rivetkit-sqlite/tests/inline/fault/mod.rs rename to engine/packages/depot-client/tests/inline/fault/mod.rs diff --git a/rivetkit-rust/packages/rivetkit-sqlite/tests/inline/fault/oracle.rs b/engine/packages/depot-client/tests/inline/fault/oracle.rs similarity index 100% rename from rivetkit-rust/packages/rivetkit-sqlite/tests/inline/fault/oracle.rs rename to engine/packages/depot-client/tests/inline/fault/oracle.rs diff --git a/rivetkit-rust/packages/rivetkit-sqlite/tests/inline/fault/scenario.rs b/engine/packages/depot-client/tests/inline/fault/scenario.rs similarity index 99% rename from rivetkit-rust/packages/rivetkit-sqlite/tests/inline/fault/scenario.rs rename to engine/packages/depot-client/tests/inline/fault/scenario.rs index 86f2200980..385b30cb00 100644 --- a/rivetkit-rust/packages/rivetkit-sqlite/tests/inline/fault/scenario.rs +++ b/engine/packages/depot-client/tests/inline/fault/scenario.rs @@ -893,6 +893,7 @@ fn open_fault_database( actor_id.to_string(), handle.clone(), config, + None, ) .map_err(anyhow::Error::msg)?; diff --git a/rivetkit-rust/packages/rivetkit-sqlite/tests/inline/fault/simple.rs b/engine/packages/depot-client/tests/inline/fault/simple.rs similarity index 100% rename from rivetkit-rust/packages/rivetkit-sqlite/tests/inline/fault/simple.rs rename to engine/packages/depot-client/tests/inline/fault/simple.rs diff --git a/rivetkit-rust/packages/rivetkit-sqlite/tests/inline/fault/verify.rs b/engine/packages/depot-client/tests/inline/fault/verify.rs similarity index 100% rename from rivetkit-rust/packages/rivetkit-sqlite/tests/inline/fault/verify.rs rename to engine/packages/depot-client/tests/inline/fault/verify.rs diff --git a/rivetkit-rust/packages/rivetkit-sqlite/tests/inline/fault/workload.rs b/engine/packages/depot-client/tests/inline/fault/workload.rs similarity index 100% rename from rivetkit-rust/packages/rivetkit-sqlite/tests/inline/fault/workload.rs rename to engine/packages/depot-client/tests/inline/fault/workload.rs diff --git a/rivetkit-rust/packages/rivetkit-sqlite/tests/inline/query.rs b/engine/packages/depot-client/tests/inline/query.rs similarity index 100% rename from rivetkit-rust/packages/rivetkit-sqlite/tests/inline/query.rs rename to engine/packages/depot-client/tests/inline/query.rs diff --git a/rivetkit-rust/packages/rivetkit-sqlite/tests/inline/vfs.rs b/engine/packages/depot-client/tests/inline/vfs.rs similarity index 99% rename from rivetkit-rust/packages/rivetkit-sqlite/tests/inline/vfs.rs rename to engine/packages/depot-client/tests/inline/vfs.rs index bd90e17eaa..8b9a5d7b4b 100644 --- a/rivetkit-rust/packages/rivetkit-sqlite/tests/inline/vfs.rs +++ b/engine/packages/depot-client/tests/inline/vfs.rs @@ -90,6 +90,7 @@ actor_id.to_string(), runtime.handle().clone(), config, + None, ) .expect("v2 vfs should register"); @@ -109,6 +110,7 @@ SqliteTransport::from_direct(engine), VfsConfig::default(), unsafe { std::mem::zeroed() }, + None, ) .expect("vfs context should build") } @@ -1678,7 +1680,8 @@ fn direct_engine_marks_vfs_dead_after_transport_errors() { let runtime = direct_runtime(); let harness = DirectEngineHarness::new(); - let engine = runtime.block_on(harness.open_engine()); let transport = SqliteTransport::from_direct(engine); + let engine = runtime.block_on(harness.open_engine()); + let transport = SqliteTransport::from_direct(engine); let hooks = transport .direct_hooks() .expect("direct transport should expose test hooks"); @@ -1688,6 +1691,7 @@ harness.actor_id.clone(), runtime.handle().clone(), VfsConfig::default(), + None, ) .expect("v2 vfs should register"); let db = open_database(vfs, &harness.actor_id).expect("sqlite database should open"); @@ -1720,7 +1724,8 @@ fn flush_dirty_pages_marks_vfs_dead_after_transport_error() { let runtime = direct_runtime(); let harness = DirectEngineHarness::new(); - let engine = runtime.block_on(harness.open_engine()); let transport = SqliteTransport::from_direct(engine); + let engine = runtime.block_on(harness.open_engine()); + let transport = SqliteTransport::from_direct(engine); let hooks = transport .direct_hooks() .expect("direct transport should expose test hooks"); @@ -1730,6 +1735,7 @@ harness.actor_id.clone(), runtime.handle().clone(), VfsConfig::default(), + None, ) .expect("v2 vfs should register"); let db = open_database(vfs, &harness.actor_id).expect("sqlite database should open"); @@ -1764,7 +1770,8 @@ fn commit_atomic_write_marks_vfs_dead_after_transport_error() { let runtime = direct_runtime(); let harness = DirectEngineHarness::new(); - let engine = runtime.block_on(harness.open_engine()); let transport = SqliteTransport::from_direct(engine); + let engine = runtime.block_on(harness.open_engine()); + let transport = SqliteTransport::from_direct(engine); let hooks = transport .direct_hooks() .expect("direct transport should expose test hooks"); @@ -1774,6 +1781,7 @@ harness.actor_id.clone(), runtime.handle().clone(), VfsConfig::default(), + None, ) .expect("v2 vfs should register"); let db = open_database(vfs, &harness.actor_id).expect("sqlite database should open"); @@ -1818,6 +1826,7 @@ harness.actor_id.clone(), runtime.handle().clone(), VfsConfig::default(), + None, ) .expect("v2 vfs should register"); let db = open_database(vfs, &harness.actor_id).expect("sqlite database should open"); @@ -1861,6 +1870,7 @@ transport, VfsConfig::default(), unsafe { std::mem::zeroed() }, + None, ) .expect("vfs context should build"); @@ -1971,6 +1981,7 @@ harness.actor_id.clone(), runtime.handle().clone(), VfsConfig::default(), + None, ) .expect("v2 vfs should register"); let db = open_database(vfs, &harness.actor_id).expect("sqlite database should open"); @@ -2306,6 +2317,7 @@ harness.actor_id.clone(), runtime.handle().clone(), VfsConfig::default(), + None, ) .expect("v2 vfs should register"); let db = open_database(vfs, &harness.actor_id).expect("sqlite database should open"); @@ -2393,6 +2405,7 @@ harness.actor_id.clone(), runtime.handle().clone(), VfsConfig::default(), + None, ) .expect("v2 vfs should register"); let db = open_database(vfs, &harness.actor_id).expect("sqlite database should open"); @@ -2560,6 +2573,7 @@ harness.actor_id.clone(), runtime.handle().clone(), VfsConfig::default(), + None, ) .expect("vfs should register"); let db = open_database(vfs, &harness.actor_id).expect("db should open"); diff --git a/rivetkit-rust/packages/rivetkit-sqlite/tests/inline/vfs_support.rs b/engine/packages/depot-client/tests/inline/vfs_support.rs similarity index 100% rename from rivetkit-rust/packages/rivetkit-sqlite/tests/inline/vfs_support.rs rename to engine/packages/depot-client/tests/inline/vfs_support.rs diff --git a/rivetkit-rust/packages/rivetkit-sqlite/tests/query_text_nul.rs b/engine/packages/depot-client/tests/query_text_nul.rs similarity index 98% rename from rivetkit-rust/packages/rivetkit-sqlite/tests/query_text_nul.rs rename to engine/packages/depot-client/tests/query_text_nul.rs index 9a6e6ac975..3b95b353c0 100644 --- a/rivetkit-rust/packages/rivetkit-sqlite/tests/query_text_nul.rs +++ b/engine/packages/depot-client/tests/query_text_nul.rs @@ -2,7 +2,7 @@ use std::ffi::CString; use std::ptr; use libsqlite3_sys::{SQLITE_OK, sqlite3, sqlite3_close, sqlite3_open}; -use rivetkit_sqlite::query::{ +use depot_client::query::{ BindParam, ColumnValue, exec_statements, execute_statement, query_statement, }; diff --git a/rivetkit-rust/packages/rivetkit-sqlite/tests/statement_classification.rs b/engine/packages/depot-client/tests/statement_classification.rs similarity index 99% rename from rivetkit-rust/packages/rivetkit-sqlite/tests/statement_classification.rs rename to engine/packages/depot-client/tests/statement_classification.rs index 14a22765ca..cac434378f 100644 --- a/rivetkit-rust/packages/rivetkit-sqlite/tests/statement_classification.rs +++ b/engine/packages/depot-client/tests/statement_classification.rs @@ -2,7 +2,7 @@ use std::ffi::CString; use std::ptr; use libsqlite3_sys::{SQLITE_OK, sqlite3, sqlite3_close, sqlite3_open}; -use rivetkit_sqlite::query::{ +use depot_client::query::{ ExecuteRoute, StatementAuthorizerActionKind, classify_statement, exec_statements, execute_single_statement, install_reader_authorizer, }; diff --git a/engine/packages/depot/CLAUDE.md b/engine/packages/depot/CLAUDE.md index 1ff07a971d..7a24ca1d5f 100644 --- a/engine/packages/depot/CLAUDE.md +++ b/engine/packages/depot/CLAUDE.md @@ -205,7 +205,7 @@ We explicitly do **not** import: - Lease-expiry and time-window tests use `tokio::time::pause()` + `advance()` for determinism. - Use a nil bucket `Db` to exercise branch-scoped hot compaction through public `compact_default_batch`. - Latency tests that depend on `UDB_SIMULATED_LATENCY_MS` must live in a dedicated integration test binary because UDB caches the env var once per process via `OnceLock`. -- SQLite VFS integration and fault-injection tests live in `rivetkit-rust/packages/rivetkit-sqlite/` so they exercise the full VFS. +- SQLite VFS integration and fault-injection tests live in `engine/packages/depot-client/` so they exercise the full VFS. - Depot fault-injection APIs live only behind `depot/test-faults`; enable the feature from dev/test dependencies only. - Production fault-leak checks run through `engine/packages/depot/scripts/check-production-fault-leaks.sh`. - Depot fault-controller tests live in `tests/fault_controller.rs` and run with `cargo test -p depot --features test-faults --test fault_controller`. diff --git a/engine/packages/pegboard-envoy/Cargo.toml b/engine/packages/pegboard-envoy/Cargo.toml index 86d8f64ce2..17d8ff8932 100644 --- a/engine/packages/pegboard-envoy/Cargo.toml +++ b/engine/packages/pegboard-envoy/Cargo.toml @@ -26,7 +26,7 @@ rivet-guard-core.workspace = true rivet-metrics.workspace = true rivet-pools.workspace = true rivet-envoy-protocol.workspace = true -rivetkit-sqlite.workspace = true +depot-client.workspace = true rivet-runtime.workspace = true rivet-types.workspace = true scc.workspace = true diff --git a/engine/packages/pegboard-envoy/tests/support/ws_to_tunnel_task.rs b/engine/packages/pegboard-envoy/tests/support/ws_to_tunnel_task.rs index 0f6d66a909..7a49987d21 100644 --- a/engine/packages/pegboard-envoy/tests/support/ws_to_tunnel_task.rs +++ b/engine/packages/pegboard-envoy/tests/support/ws_to_tunnel_task.rs @@ -90,7 +90,7 @@ use std::{ }; use anyhow::Result; -use rivetkit_sqlite::types::{BindParam, ColumnValue}; +use depot_client::types::{BindParam, ColumnValue}; use sqlite_storage::{engine::SqliteEngine, error::SqliteStorageError, open::OpenConfig}; use tokio::{ sync::{Notify, Semaphore}, diff --git a/rivetkit-rust/packages/rivetkit-core/Cargo.toml b/rivetkit-rust/packages/rivetkit-core/Cargo.toml index 1f8904144c..f79ba7883a 100644 --- a/rivetkit-rust/packages/rivetkit-core/Cargo.toml +++ b/rivetkit-rust/packages/rivetkit-core/Cargo.toml @@ -17,7 +17,7 @@ native-runtime = [ ] wasm-runtime = ["rivet-envoy-client/wasm-transport"] sqlite = ["sqlite-local"] -sqlite-local = ["native-runtime", "dep:rivetkit-sqlite"] +sqlite-local = ["native-runtime", "dep:depot-client"] sqlite-remote = [] [dependencies] @@ -38,8 +38,8 @@ rivetkit-shared-types.workspace = true rivetkit-actor-persist.workspace = true rivetkit-client-protocol.workspace = true rivetkit-inspector-protocol.workspace = true -rivetkit-sqlite-types.workspace = true -rivetkit-sqlite = { workspace = true, optional = true } +depot-client-types.workspace = true +depot-client = { workspace = true, optional = true } scc.workspace = true serde.workspace = true serde_json.workspace = true diff --git a/rivetkit-rust/packages/rivetkit-core/src/actor/metrics.rs b/rivetkit-rust/packages/rivetkit-core/src/actor/metrics.rs index 93d2d0440b..885adf8395 100644 --- a/rivetkit-rust/packages/rivetkit-core/src/actor/metrics.rs +++ b/rivetkit-rust/packages/rivetkit-core/src/actor/metrics.rs @@ -762,7 +762,7 @@ impl ActorMetrics { } #[cfg(feature = "sqlite-local")] -impl rivetkit_sqlite::vfs::SqliteVfsMetrics for ActorMetrics { +impl depot_client::vfs::SqliteVfsMetrics for ActorMetrics { fn record_resolve_pages(&self, requested_pages: u64) { let Some(inner) = self.inner.as_ref().as_ref() else { return; diff --git a/rivetkit-rust/packages/rivetkit-core/src/actor/sqlite.rs b/rivetkit-rust/packages/rivetkit-core/src/actor/sqlite.rs index 840a99c6c0..3bd384fcfb 100644 --- a/rivetkit-rust/packages/rivetkit-core/src/actor/sqlite.rs +++ b/rivetkit-rust/packages/rivetkit-core/src/actor/sqlite.rs @@ -12,7 +12,7 @@ use rivet_envoy_client::protocol; use rivet_envoy_client::{ handle::EnvoyHandle, utils::RemoteSqliteIndeterminateResultError, }; -pub use rivetkit_sqlite_types::{ +pub use depot_client_types::{ BindParam, ColumnValue, ExecResult, ExecuteResult, ExecuteRoute, QueryResult, }; use serde::Serialize; @@ -29,7 +29,7 @@ use tracing::Instrument; use crate::error::SqliteRuntimeError; #[cfg(feature = "sqlite-local")] -use rivetkit_sqlite::{ +use depot_client::{ database::{NativeDatabaseHandle, open_database_from_envoy}, optimization_flags::sqlite_optimization_flags, vfs::{SqliteVfsMetrics, SqliteVfsMetricsSnapshot, VfsPreloadHintSnapshot}, diff --git a/rivetkit-rust/packages/rivetkit-core/tests/metrics.rs b/rivetkit-rust/packages/rivetkit-core/tests/metrics.rs index b59d9504b7..0e0c1eee27 100644 --- a/rivetkit-rust/packages/rivetkit-core/tests/metrics.rs +++ b/rivetkit-rust/packages/rivetkit-core/tests/metrics.rs @@ -38,7 +38,7 @@ mod moved_tests { #[cfg(feature = "sqlite-local")] #[test] fn sqlite_read_pool_metrics_render() { - use rivetkit_sqlite::vfs::SqliteVfsMetrics; + use depot_client::vfs::SqliteVfsMetrics; let metrics = ActorMetrics::new("actor-1", "test"); metrics.set_read_pool_active_readers(2); diff --git a/rivetkit-rust/packages/rivetkit-sqlite/tests/remote_execution_parity.rs b/rivetkit-rust/packages/rivetkit-sqlite/tests/remote_execution_parity.rs deleted file mode 100644 index c5e9339662..0000000000 --- a/rivetkit-rust/packages/rivetkit-sqlite/tests/remote_execution_parity.rs +++ /dev/null @@ -1,261 +0,0 @@ -use std::sync::Arc; -use std::time::{SystemTime, UNIX_EPOCH}; - -use anyhow::Result; -use rivetkit_sqlite::database::{NativeDatabaseHandle, open_database_from_engine}; -use rivetkit_sqlite::types::{BindParam, ColumnValue, ExecuteRoute}; -use sqlite_storage::engine::SqliteEngine; -use sqlite_storage::open::OpenConfig; -use tempfile::TempDir; -use universaldb::Subspace; -use universaldb::driver::RocksDbDatabaseDriver; - -struct RemoteDbHarness { - _db_dir: TempDir, - engine: Arc, - actor_id: String, - generation: u64, - db: NativeDatabaseHandle, -} - -impl RemoteDbHarness { - async fn open(prefix: &str, now_ms: i64) -> Result { - let actor_id = unique_actor_id(prefix); - let db_dir = tempfile::tempdir()?; - let driver = RocksDbDatabaseDriver::new(db_dir.path().to_path_buf()).await?; - let db = universaldb::Database::new(Arc::new(driver)); - let (engine, _compaction_rx) = - SqliteEngine::new(db, Subspace::new(&(prefix, &actor_id))); - let engine = Arc::new(engine); - let opened = engine.open(&actor_id, OpenConfig::new(now_ms)).await?; - let db = open_database_from_engine( - Arc::clone(&engine), - actor_id.clone(), - opened.generation, - tokio::runtime::Handle::current(), - None, - ) - .await?; - - Ok(Self { - _db_dir: db_dir, - engine, - actor_id, - generation: opened.generation, - db, - }) - } - - async fn reopen(&mut self, now_ms: i64) -> Result<()> { - self.db.close().await?; - self.engine.close(&self.actor_id, self.generation).await?; - let opened = self.engine.open(&self.actor_id, OpenConfig::new(now_ms)).await?; - self.generation = opened.generation; - self.db = open_database_from_engine( - Arc::clone(&self.engine), - self.actor_id.clone(), - opened.generation, - tokio::runtime::Handle::current(), - None, - ) - .await?; - Ok(()) - } - - async fn close(self) -> Result<()> { - self.db.close().await?; - self.engine.close(&self.actor_id, self.generation).await?; - Ok(()) - } -} - -#[tokio::test] -async fn remote_migration_order_persists_across_reopen() -> Result<()> { - let mut harness = RemoteDbHarness::open("remote-migration-order", 1).await?; - - harness - .db - .execute_write( - "CREATE TABLE __rivet_migrations(id INTEGER PRIMARY KEY, name TEXT NOT NULL);" - .to_string(), - None, - ) - .await?; - harness - .db - .execute_write( - "CREATE TABLE items(id INTEGER PRIMARY KEY, value TEXT NOT NULL);".to_string(), - None, - ) - .await?; - harness - .db - .execute_write( - "INSERT INTO __rivet_migrations(id, name) VALUES (?, ?);".to_string(), - Some(vec![ - BindParam::Integer(1), - BindParam::Text("create-items".to_string()), - ]), - ) - .await?; - - let before_reopen = harness - .db - .execute( - "SELECT name FROM __rivet_migrations ORDER BY id;".to_string(), - None, - ) - .await?; - assert_eq!( - before_reopen.rows, - vec![vec![ColumnValue::Text("create-items".to_string())]] - ); - - harness.reopen(2).await?; - let after_reopen = harness - .db - .execute( - "SELECT name FROM __rivet_migrations ORDER BY id;".to_string(), - None, - ) - .await?; - assert_eq!( - after_reopen.rows, - vec![vec![ColumnValue::Text("create-items".to_string())]] - ); - - let table_check = harness - .db - .execute( - "SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'items';" - .to_string(), - None, - ) - .await?; - assert_eq!( - table_check.rows, - vec![vec![ColumnValue::Text("items".to_string())]] - ); - - harness.close().await -} - -#[tokio::test] -async fn remote_execute_write_forces_writer_for_readonly_sql() -> Result<()> { - let harness = RemoteDbHarness::open("remote-execute-write", 1).await?; - harness - .db - .execute_write( - "CREATE TABLE force_writer(id INTEGER PRIMARY KEY);".to_string(), - None, - ) - .await?; - - let result = harness - .db - .execute_write("SELECT COUNT(*) FROM force_writer;".to_string(), None) - .await?; - - assert_eq!(result.route, ExecuteRoute::Write); - assert_eq!(result.rows, vec![vec![ColumnValue::Integer(0)]]); - - harness.close().await -} - -#[tokio::test] -async fn remote_manual_transactions_stay_on_writer_until_commit_or_rollback() -> Result<()> { - let harness = RemoteDbHarness::open("remote-manual-transactions", 1).await?; - harness - .db - .execute_write( - "CREATE TABLE tx_items(id INTEGER PRIMARY KEY, value TEXT NOT NULL);".to_string(), - None, - ) - .await?; - - harness.db.execute("BEGIN".to_string(), None).await?; - harness - .db - .execute( - "INSERT INTO tx_items(id, value) VALUES (1, 'committed');".to_string(), - None, - ) - .await?; - let in_tx_read = harness - .db - .execute( - "SELECT COUNT(*) FROM tx_items WHERE value = 'committed';".to_string(), - None, - ) - .await?; - assert_eq!(in_tx_read.route, ExecuteRoute::WriteFallback); - assert_eq!(in_tx_read.rows, vec![vec![ColumnValue::Integer(1)]]); - harness.db.execute("COMMIT".to_string(), None).await?; - - harness.db.execute("BEGIN".to_string(), None).await?; - harness - .db - .execute( - "INSERT INTO tx_items(id, value) VALUES (2, 'rolled-back');".to_string(), - None, - ) - .await?; - harness.db.execute("ROLLBACK".to_string(), None).await?; - - harness.db.execute("BEGIN".to_string(), None).await?; - harness - .db - .execute( - "INSERT INTO tx_items(id, value) VALUES (3, 'savepoint-base');".to_string(), - None, - ) - .await?; - harness - .db - .execute("SAVEPOINT patch".to_string(), None) - .await?; - harness - .db - .execute( - "UPDATE tx_items SET value = 'patched' WHERE id = 3;".to_string(), - None, - ) - .await?; - harness - .db - .execute("ROLLBACK TO patch".to_string(), None) - .await?; - harness - .db - .execute("RELEASE patch".to_string(), None) - .await?; - harness.db.execute("COMMIT".to_string(), None).await?; - - let rows = harness - .db - .execute("SELECT id, value FROM tx_items ORDER BY id;".to_string(), None) - .await?; - assert_eq!( - rows.rows, - vec![ - vec![ - ColumnValue::Integer(1), - ColumnValue::Text("committed".to_string()) - ], - vec![ - ColumnValue::Integer(3), - ColumnValue::Text("savepoint-base".to_string()) - ], - ] - ); - - harness.close().await -} - -fn unique_actor_id(prefix: &str) -> String { - let nanos = SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("system time should be after epoch") - .as_nanos(); - format!("{prefix}-{nanos}") -} diff --git a/rivetkit-typescript/packages/rivetkit-napi/Cargo.toml b/rivetkit-typescript/packages/rivetkit-napi/Cargo.toml index 3ac1d3b9b8..a91abd06e7 100644 --- a/rivetkit-typescript/packages/rivetkit-napi/Cargo.toml +++ b/rivetkit-typescript/packages/rivetkit-napi/Cargo.toml @@ -13,7 +13,7 @@ crate-type = ["cdylib"] napi = { version = "2", default-features = false, features = ["napi6", "async", "serde-json", "dyn-symbols"] } napi-derive = "2" async-trait.workspace = true -rivetkit-sqlite.workspace = true +depot-client.workspace = true tokio.workspace = true tokio-util.workspace = true anyhow.workspace = true diff --git a/scripts/cargo/check-rivetkit-core-wasm.sh b/scripts/cargo/check-rivetkit-core-wasm.sh index e39b56a19f..5c94ba55dd 100755 --- a/scripts/cargo/check-rivetkit-core-wasm.sh +++ b/scripts/cargo/check-rivetkit-core-wasm.sh @@ -5,7 +5,7 @@ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" TARGET="wasm32-unknown-unknown" CORE_FEATURES="wasm-runtime,sqlite-remote" BANNED_CRATES=( - "rivetkit-sqlite" + "depot-client" "libsqlite3-sys" "tokio-tungstenite" "mio"