atagen

macltok

public
Star0
Watch0
d5d8097c3afd94c250affd252a3e9ea63ecec8a5
3
ssh://brewery@pls.lobotomise.me:33/atagen/macltok.git

Blame: README.md

96fdf90aacd6atagen2026-09-08 08:24 UTC1
# macltok
96fdf90aacd6atagen2026-09-08 08:24 UTC2
96fdf90aacd6atagen2026-09-08 08:24 UTC3
`macltok` is a compact Rust application backend built above `matrix-sdk` and
96fdf90aacd6atagen2026-09-08 08:24 UTC4
`matrix-sdk-ui`. It aims to provide the stateful behavior needed by a useful
96fdf90aacd6atagen2026-09-08 08:24 UTC5
Matrix client without depending on a GUI toolkit or inventing another protocol
96fdf90aacd6atagen2026-09-08 08:24 UTC6
SDK.
96fdf90aacd6atagen2026-09-08 08:24 UTC7
96fdf90aacd6atagen2026-09-08 08:24 UTC8
The crate currently provides
96fdf90aacd6atagen2026-09-08 08:24 UTC9
96fdf90aacd6atagen2026-09-08 08:24 UTC10
- typed commands, owned UI-safe events and bounded per-client transport
96fdf90aacd6atagen2026-09-08 08:24 UTC11
- Sliding Sync with normalized connection and room-list state
96fdf90aacd6atagen2026-09-08 08:24 UTC12
- independently retained live room timelines and backwards pagination
96fdf90aacd6atagen2026-09-08 08:24 UTC13
- text, emote, reply, edit, redaction, reaction, receipt and typing operations
96fdf90aacd6atagen2026-09-08 08:24 UTC14
- raw encrypted or unencrypted media acquisition with configurable byte limits
96fdf90aacd6atagen2026-09-08 08:24 UTC15
- encryption state, recovery-key import and SAS verification
62fe32759529atagen2026-09-26 08:50 UTC16
- password login and session restoration with caller-owned encrypted SQLite or
62fe32759529atagen2026-09-26 08:50 UTC17
  IndexedDB stores
96fdf90aacd6atagen2026-09-08 08:24 UTC18
96fdf90aacd6atagen2026-09-08 08:24 UTC19
Matrix room, event, user, device and transaction identifiers remain strongly
96fdf90aacd6atagen2026-09-08 08:24 UTC20
typed. A toolkit timeline identity covers local echoes without pretending they
96fdf90aacd6atagen2026-09-08 08:24 UTC21
already have remote event IDs.
96fdf90aacd6atagen2026-09-08 08:24 UTC22
96fdf90aacd6atagen2026-09-08 08:24 UTC23
## Consuming the engine
96fdf90aacd6atagen2026-09-08 08:24 UTC24
31ce2453c82fatagen2026-09-24 13:07 UTC25
spawn `Engine::run`, drain the `EventStream` from its own task, and talk to the
31ce2453c82fatagen2026-09-24 13:07 UTC26
engine through `ClientHandle`. every command answers once, awaited
31ce2453c82fatagen2026-09-24 13:07 UTC27
(`handle.send_message(..).await?`) or as a `Pending` you can await later or
31ce2453c82fatagen2026-09-24 13:07 UTC28
drop. a sent message answers when the sdk send queue has it, delivery shows up
31ce2453c82fatagen2026-09-24 13:07 UTC29
as the timeline item's send state. reads like `rooms`, `members` and `media`
31ce2453c82fatagen2026-09-24 13:07 UTC30
go straight to the sdk. the stream only carries state
31ce2453c82fatagen2026-09-24 13:07 UTC31
d5d8097c3afdatagen2026-09-26 09:33 UTC32
start a timeline from `TimelineReset`, then apply each `TimelineChanged` whole
d5d8097c3afdatagen2026-09-26 09:33 UTC33
with `TimelineDiff::try_apply_all`. snapshots are `imbl::Vector`s, re-exported
d5d8097c3afdatagen2026-09-26 09:33 UTC34
as `macltok::imbl`, so a copy costs nothing. when a batch doesn't fit none of it
d5d8097c3afdatagen2026-09-26 09:33 UTC35
lands. stop applying, call `resync`, and pick up from the next `TimelineReset`
96fdf90aacd6atagen2026-09-08 08:24 UTC36
62fe32759529atagen2026-09-26 08:50 UTC37
With `sqlite` or `indexeddb`, persist the initial `Session::record()`
62fe32759529atagen2026-09-26 08:50 UTC38
separately from its encrypted store. On `SessionTokensChanged`, obtain a new record from
96fdf90aacd6atagen2026-09-08 08:24 UTC39
`ClientHandle::session_record()` and replace the saved record atomically in
62fe32759529atagen2026-09-26 08:50 UTC40
protected storage. Restore with the same store location and passphrase.
fa9114fcf75fatagen2026-09-24 12:51 UTC41
fe4133dbcd47atagen2026-09-26 09:05 UTC42
`Engine::run` resolves to a `Termination` saying why it stopped, and
fe4133dbcd47atagen2026-09-26 09:05 UTC43
`Termination::retain` says what to do about it. after `LoggedOut` or
fe4133dbcd47atagen2026-09-26 09:05 UTC44
`AccessRevoked` the record and the store are dead, bin them. `SoftLoggedOut`
fe4133dbcd47atagen2026-09-26 09:05 UTC45
wants the store kept and a fresh login with `PasswordLogin::device_id` set to the
fe4133dbcd47atagen2026-09-26 09:05 UTC46
device it carries, or the e2ee keys go with it. `ShutDown` and `HandlesDropped`
fe4133dbcd47atagen2026-09-26 09:05 UTC47
keep everything. an `Err` is a real failure and kills nothing. one store
fe4133dbcd47atagen2026-09-26 09:05 UTC48
directory per login, the sdk won't share a crypto store between devices.
fa9114fcf75fatagen2026-09-24 12:51 UTC49
The headless example is
96fdf90aacd6atagen2026-09-08 08:24 UTC50
login-only; it does not persist sessions across runs.
96fdf90aacd6atagen2026-09-08 08:24 UTC51
62fe32759529atagen2026-09-26 08:50 UTC52
## wasm
62fe32759529atagen2026-09-26 08:50 UTC53
62fe32759529atagen2026-09-26 08:50 UTC54
macltok builds for `wasm32-unknown-unknown`. the `indexeddb` feature gives you
62fe32759529atagen2026-09-26 08:50 UTC55
`StoreConfig::indexeddb` in place of `StoreConfig::sqlite`, and asking for either
62fe32759529atagen2026-09-26 08:50 UTC56
on the wrong target won't compile. `Engine::run` hands back a `LocalBoxFuture`
62fe32759529atagen2026-09-26 08:50 UTC57
there, so spawn it with `wasm_bindgen_futures::spawn_local`
62fe32759529atagen2026-09-26 08:50 UTC58
62fe32759529atagen2026-09-26 08:50 UTC59
getrandom picks its browser backend from a cfg flag, and `.cargo/config.toml`
62fe32759529atagen2026-09-26 08:50 UTC60
only reaches this crate's own builds. every cdylib that pulls macltok in needs
62fe32759529atagen2026-09-26 08:50 UTC61
it too
62fe32759529atagen2026-09-26 08:50 UTC62
62fe32759529atagen2026-09-26 08:50 UTC63
```toml
62fe32759529atagen2026-09-26 08:50 UTC64
[target.wasm32-unknown-unknown]
62fe32759529atagen2026-09-26 08:50 UTC65
rustflags = ["--cfg", "getrandom_backend=\"wasm_js\""]
62fe32759529atagen2026-09-26 08:50 UTC66
```
62fe32759529atagen2026-09-26 08:50 UTC67
62fe32759529atagen2026-09-26 08:50 UTC68
what's different in a browser
62fe32759529atagen2026-09-26 08:50 UTC69
62fe32759529atagen2026-09-26 08:50 UTC70
- a panic aborts the whole instance. natively a panicking command costs its
62fe32759529atagen2026-09-26 08:50 UTC71
  caller an `Interrupted`, here it takes the engine and everything else with it
62fe32759529atagen2026-09-26 08:50 UTC72
- `MediaUploadProgress` only ever reports completion, the sdk's wasm http path
62fe32759529atagen2026-09-26 08:50 UTC73
  has no upload progress
62fe32759529atagen2026-09-26 08:50 UTC74
- the sdk doesn't retry requests or time them out individually. sync still
62fe32759529atagen2026-09-26 08:50 UTC75
  restarts itself with backoff, that part is ours
62fe32759529atagen2026-09-26 08:50 UTC76
- two tabs or workers on one store each need `StoreConfig::with_lock_holder`
62fe32759529atagen2026-09-26 08:50 UTC77
  with a name of their own, or they both think they hold the crypto store
62fe32759529atagen2026-09-26 08:50 UTC78
96fdf90aacd6atagen2026-09-08 08:24 UTC79
## Dependency policy
96fdf90aacd6atagen2026-09-08 08:24 UTC80
96fdf90aacd6atagen2026-09-08 08:24 UTC81
UI frameworks, image decoders, application-directory discovery and logging
96fdf90aacd6atagen2026-09-08 08:24 UTC82
subscribers do not belong in this crate. SQLite remains optional through the
62fe32759529atagen2026-09-26 08:50 UTC83
`sqlite` and `bundled-sqlite` features, IndexedDB through `indexeddb`. Media
62fe32759529atagen2026-09-26 08:50 UTC84
decoding belongs to the consumer.
96fdf90aacd6atagen2026-09-08 08:24 UTC85
96fdf90aacd6atagen2026-09-08 08:24 UTC86
## Verification
96fdf90aacd6atagen2026-09-08 08:24 UTC87
96fdf90aacd6atagen2026-09-08 08:24 UTC88
```sh
96fdf90aacd6atagen2026-09-08 08:24 UTC89
nix develop --command cargo fmt -- --check
96fdf90aacd6atagen2026-09-08 08:24 UTC90
nix develop --command cargo test --all-targets
96fdf90aacd6atagen2026-09-08 08:24 UTC91
nix develop --command cargo test --all-targets --features sqlite
96fdf90aacd6atagen2026-09-08 08:24 UTC92
nix develop --command cargo clippy --all-targets -- -D warnings
96fdf90aacd6atagen2026-09-08 08:24 UTC93
nix develop --command cargo clippy --all-targets --features sqlite -- -D warnings
96fdf90aacd6atagen2026-09-08 08:24 UTC94
nix flake check
96fdf90aacd6atagen2026-09-08 08:24 UTC95
```