9 Commits

Author SHA1 Message Date
osmaczko
9fb2ae741c
fix: deliver DirectV1 Welcome to account-associated invitees (routing_id)
DirectV1 over a shared key-package registry (HttpRegistry) could not deliver
the MLS Welcome to an account-associated invitee. Key-package resolution
requires the shared address to be the account key (the account directory
resolves it to the device key HttpRegistry stores the package under), but the
Welcome was routed to, and the invitee's InboxV2 subscribed and gated on, the
credential id (hex of the DelegateCredential TLV). The two strings never
matched, so the Welcome fell through the dispatch gate to PayloadOutcome::Empty
and the invitee never joined. EphemeralRegistry hid this by keying key-packages
on the credential id, collapsing both halves onto one string.

Decouple the 1:1 routing identity from the credential identity:

- Add a defaulted IdentityProvider::routing_id() -> IdentId (defaults to id()).
- DelegateSigner derives routing_id() and account_addr() from its own
  credential: once associated, the account address is read from the
  DelegateCredential TLV; otherwise routing_id() falls back to the credential
  id. The association is stored only in the credential, never in a separate field.
- Core::assemble feeds InboxV2 routing_id() instead of id(); the MLS credential,
  member id, sender id, and decode_sender keep reading id(), so MLS membership
  and sender attribution are unchanged.

Add a regression test (direct_v1_associated_invitee_receives_welcome) over a
DeviceKeyedRegistry that keys key-packages by the device verifying key, as the
deployed HttpRegistry does; it fails without routing_id and passes with it.
2026-06-30 22:33:17 +02:00
kaichao
3b422d01c3
feat: bubble up message sender to applications (#146)
* feat: bubble up message sender to applications

* chore: enrich error types

* chore: code fmt

* feat: make sender always exist in received message
2026-06-24 11:48:50 +08:00
Jazz Turner-Baggs
a5abefa314
ChatClient migration (#145)
* Simplify client

* Fixups

* Update Cli-Client to use builder

* undeprecate legacy convos

* Allow Storage config in builder

* bug fixes

* Clippy fix

* fixes
2026-06-23 12:02:01 -07:00
kaichao
aec902d796
feat: sender check with account store (#142) 2026-06-23 13:40:19 +08:00
Jazz Turner-Baggs
d02689c764
Add Delegate Signer and wire into Client (#143)
* Add encoded_credential to CovnoOutcome

* Add DelegateSigner

* Add test for DirectV1

* Add support for undecodable credentials

* Add docs

* Clean + fixes

* clippy fixes

* Add unit tests

* Update trait bounds
2026-06-22 10:38:17 -07:00
osmaczko
7838d43b30
feat(client): add threaded transport polling (#125)
The client, not the app, now drives the transport; events are delivered
asynchronously, per ADR 0001.

- ChatClient owns Arc<Mutex<Core>> + a worker thread.
- The worker select!s over the inbound and shutdown channels; Drop joins it.
  Outbound runs on the caller's thread.
- A single Transport (DeliveryService + inbound()) owns both directions of the
  boundary, so the client takes one transport rather than a (delivery, inbound)
  pair. InProcessDelivery::new, CDelivery, and chat-cli's transports implement it.
- FFI replaces client_receive with client_push_inbound + client_poll_events.
- chat-cli drains Receiver<Event>; inbound and event channels are both crossbeam.
- Corrects ADR 0001's inbound sequence to push — the worker parks on select!,
  it never polls.
2026-06-11 10:08:07 +02:00
osmaczko
c677cc9334
feat: introduce client event system (#106)
* chore(flake): accept extra system attr; add perl for openssl-sys build

forAllSystems calls the lambda with {system, pkgs}; strict
destructuring requires `..` to ignore the system attribute.

`pkgs.perl` is needed because openssl-sys is pulled vendored via
libsqlite3-sys / rusqlite / chat-sqlite, and its `perl Configure`
step needs FindBin.pm, which Fedora's system perl doesn't ship.

* feat: introduce client event system

- Core processing yields a `PayloadOutcome` enum — `Empty`, `Convo`, or
  `Inbox`. `ConvoOutcome` carries a conversation id and an optional
  decrypted `Content`; `InboxOutcome` adds a `NewConversation`
  (id + `ConversationClass`) for a peer-initiated conversation.
- Client translates `PayloadOutcome` into app-facing `Vec<Event>`
  (`ConversationStarted`, `MessageReceived`) at the boundary, so the
  application loop sees discrete events rather than core types.
- MLS group welcomes produce a `ConversationStarted` event with no
  initial content, fixing the silent-group-join case where the inbox
  layer dropped the observation.
- C FFI exposes an `EventList` opaque type with indexed accessors and
  an `Invalid` sentinel for out-of-bounds / non-applicable reads.
- Symmetric `Inbox` / `InboxV2` handlers: both return
  `Result<InboxOutcome, _>` and own the persistence + ephemeral-key
  cleanup for the conversations they create.
- Updated and simplified `docs/adr/0001-client-event-system.md`.

* chore(flake): bump nixpkgs to nixos-unstable-small

Temporary. The two crates.io UA fixes (NixOS/nixpkgs#512735 for
fetchCargoVendor's python-requests UA, NixOS/nixpkgs#524985 for
importCargoLock's curl UA) haven't propagated to nixos-unstable yet.
Switch to nixos-unstable-small and force logos-delivery to follow so
the smoketest gets the same fix. Revert once nixos-unstable catches up.

Refs:
- https://github.com/rust-lang/crates.io/issues/13482
- https://github.com/rust-lang/crates.io/issues/13783
- https://crates.io/data-access
2026-05-28 23:51:15 +02:00
Jazz Turner-Baggs
b7888c1a70
Dependency cleanup (#100)
* Sort all Cargo.toml deps for less conflicts

* Move relative path deps to workspace

* Standardize workspace imports

* Rename ‘client’ to ‘logos-chat’

* Cleanups
2026-05-20 13:18:25 -07:00
osmaczko
d68c0cb275
feat: implement Client crate and C FFI bindings (#73)
Implement a `client` crate that wraps the `libchat` context behind a
simple `ChatClient<D>` API. The delivery strategy is pluggable via a
`DeliveryService` trait, with two implementations provided:

- `InProcessDelivery` — shared `MessageBus` for single-process tests
- `CDelivery` — C function-pointer callback for the FFI layer

Add a `client-ffi` crate that exposes the client as a C API via
`safer-ffi`. A `generate-headers` binary produces the companion C
header.

Include two runnable examples:
- `examples/in-process` — Alice/Bob exchange using in-process delivery
- `examples/c-ffi` — same exchange written entirely in C; smoketested
under valgrind (to catch memory leaks) in CI

iterates: #71
2026-04-08 23:15:48 +02:00