Folio #
A local-first database for AT Protocol data. Embed Folio on any client (native or web) to get a local database that functions offline, syncs optimistically, and creates a fast, low-friction user experience.
The public repository API loads collections on first read, then reads and edits locally. Synchronization refreshes only loaded collections and publishes edits:
let client = folio::Client::new(did, store, transport);
let mut repo = client.get_pub_repo();
let record = repo.get(&key).await?; // first read loads this collection
let records = repo.list(&key.collection).await?; // uses the local cache
repo.put(&key, updated_record.clone()).await?;
assert_eq!(repo.get(&key).await?, Some(updated_record));
repo.sync().await?;
Authentication belongs to the supplied transport. The current memory store is not durable, and synchronization trusts the PDS rather than verifying repository signatures and Merkle proofs.
folio-transport-http provides a native
authenticated HTTP transport. Construction and repository selection are synchronous
operations. The client discovers the account's PDS when needed;
the transport authenticates on its first request. Session refresh remains with
the host application.
client.get_priv_repo(space_uri)? selects the account's repository in a Space.
Space reads, edits, and sync are not implemented yet.
The runnable E2E example shows login, lazy loading, local reads and edits, sync, and deletion using only Folio's public APIs:
cargo run -p folio --example e2e --locked
It uses the same root .env credentials and creates, updates, and deletes one
uniquely keyed public record.
The live E2E test uses ATPROTO_HANDLE, ATPROTO_DID, and ATPROTO_PASSWORD from
the ignored root .env. It creates one uniquely keyed record in the account's
existing public repository, checks local reads and remote writes, and deletes
the record through Folio before finishing:
cargo test -p folio --test e2e --locked -- --nocapture
Browser packages #
Enter devenv shell for Rust (including wasm32-unknown-unknown), Bun,
wasm-pack, and cargo-make. Alternatively install those tools yourself and add the
Wasm target with rustup target add wasm32-unknown-unknown.
cargo make build # wasm-pack --target web, frozen Bun install, JS + declarations
cargo make test # build, TypeScript check, Bun integration tests using real Wasm
cargo make rust-test # Rust library tests; excludes the opt-in live-account test
cargo make pack # installable tarballs in target/packages
The Bun workspace contains @folio/client and
@folio/react-query.
Generated Wasm and JavaScript are ignored; rebuilding is required after a fresh
checkout. The installable client includes its Wasm loader, binary, and TypeScript
declarations. cargo make defaults to the test workflow. No task publishes a
package or contacts a live ATProto account.
The React Query adapter provides connectFolio, folioListOptions, and
folioRecordOptions. Connect before mounting queries, save through Folio with
useMutation({ networkMode: "always", retry: false, mutationFn: ... }), and call
folio.sync() separately to publish. Query invalidation reads cached data.
- Rust 79%
- TypeScript 20%
- Makefile <1%
- Nix <1%