98 Commits

Author SHA1 Message Date
osmaczko
37ae88bfa7
chore: remove the unused PrivateV1 conversation stack (#176)
PrivateV1 was the legacy prekey-handshake 1:1 protocol, superseded by
DirectV1 over InboxV2. Remove it and everything that existed only to
serve it.

- Delete PrivateV1Convo and its v1 inbox bootstrap: the Inbox,
  Introduction, and InboxHandshake types, plus the support code only they
  used (the crate::crypto module, EncryptionError, timestamp_millis, the
  PrivateV1Domain HKDF domain, and the ServiceContext test doubles).
- Drop the public entry points that exposed it: Core::create_intro_bundle,
  create_private_convo_v1, dispatch_to_inbox, and the matching
  ChatClient::create_intro_bundle / create_conversation.
- Remove ConversationKind::PrivateV1 and its "private_v1" mapping, the
  from_kind arm, and the orphaned inbox-v1 proto re-exports.
- Migrate the chat-cli /intro and /connect commands and the
  message-exchange example to create_direct_conversation.
- Delete the PrivateV1 integration test; move the sqlite conversation
  roundtrip test to GroupV1.

InboxOutcome, PayloadOutcome::Inbox, and ConversationClass::Private stay:
InboxV2 (DirectV1 and GroupV1 invites) still produces them.

Follow-ups, out of scope here:
- logos-chat-module still calls create_intro_bundle / create_conversation
  and needs a companion change.
- remote_convo_id and EphemeralKeyStore are now vestigial (only PrivateV1
  used them); dropping them is a storage-schema change for a later PR.
2026-07-16 10:40:23 +02:00
osmaczko
b0de532199
feat: surface a roster-changed event when group membership changes (#177)
A group's roster changed silently. An add merges on the steward's commit-inactivity timer, and the members that receive its commit apply it, but neither surfaced any observation: Core::wakeup returned () and the client worker discarded it, and GroupV2Convo mapped only chat messages into a ConvoOutcome, so a commit produced an empty outcome. An app could learn a group grew only by re-selecting the conversation, a manual refresh, or a later message from the new member.

de-mls already reports the change: CommitApplied (adds and removes) and WelcomeReady (adds) both fire, on every member, when a commit merges. Drain them into the observation and emit a new event.

- ConvoOutcome gains members_changed, set by GroupV2Convo when a poll cycle's drained de-mls events include CommitApplied or WelcomeReady. It rides alongside content, the same way a protocol-only frame already yields content: None.
- Convo::wakeup returns a ConvoOutcome instead of (), mirroring handle_frame, so the steward's own timer-driven commit is observable. Kinds with no timers return ConvoOutcome::empty; Core::wakeup and the worker translate it through the same events_from_inbound path inbound payloads use.
- New Event::ConversationMembersChanged { convo_id }: the app re-fetches group_members. Fires on every member a commit reaches, so the inviter sees its own add land and existing members see later joins.
2026-07-15 17:21:23 +02:00
Jazz Turner-Baggs
f5e877b6e1
Use random port for Logos-Delivery (#180)
* Cleanup logging

* Randomize port to avoid conlicts
2026-07-14 14:04:31 -07:00
Jazz Turner-Baggs
225b0fab14
Isolate delivery library (#178)
* Isolate logos-delivery

* Update cargo.toml + fixups

* clippy fixes

* fix: topic

* remove tcp prefix from port
2026-07-13 08:51:17 -07:00
Jazz Turner-Baggs
c089144dc9
Add group description (#161)
Update config

Update constructor calls

Enable groupContext for GV2

Remove test group type

Add test

temporary dep; waiting for upstream

Remove owner

Doc MLS extension type

Add ConvoMetaInfoVersion

Update infallable function docs

strongly typed metadata

Cleanup tests

Pin de-mls revision

full remove owner
2026-07-10 23:26:05 -07:00
Ekaterina Broslavskaia
8da9e4da18
feat: inject the GroupV2 time source and timing config (#168)
* add WallClock into groupv2

* switch to main branch, remove custom type

---------

Co-authored-by: Jazz Turner-Baggs <473256+jazzz@users.noreply.github.com>
2026-07-10 16:08:51 -07:00
osmaczko
e7e122b0cc
feat: GroupV2 through the threaded client, group roster, registry retry (#167)
* feat: expose GroupV2 through the threaded client

GroupV2 (de-mls) conversations were reachable only from Core, and every
conversation ran the hardcoded millisecond timer profile in group_v2.rs
(20-150 ms freeze/consensus windows), which cannot survive real network
latency. Make them reachable through ChatClient (as DirectV1 already is), with
timing that holds up over a real network.

- ChatClient::create_group_conversation(accounts) and
  add_group_members(convo_id, accounts): resolve each account address to
  its endorsed signer ids through the client-held directory, the same
  resolution create_direct_conversation uses, and drive
  Core::create_group_convo / group_add_member.
- GroupV2 timing/policy is injectable: ServiceContext carries a
  de_mls::ConversationConfig (re-exported as GroupV2Config) defaulting
  to the de-mls library defaults; Core::set_group_v2_config and the
  builder's group_v2_config setter override it. The creator's phase
  durations reach joiners inside the welcome's ConversationSync, so the
  group runs the creator's phase timing.
- GroupV2Convo::add_member validates every member's key package before
  proposing any add, skips members de-mls would silently not propose
  (self, already in the group) instead of stranding a pending invite,
  and flushes opened proposals even on a mid-batch failure, so a failed
  batch cannot invite members behind the caller's back.
- The millisecond test profile moves into the test harnesses
  (integration_tests_core's TestHarness, crates/client/tests/group_v2.rs).
- New client-level tests: three accounts on the in-process transport
  create a group, a non-creator adds the third member, and messages fan
  out with directory-verified senders; a batch containing a member with
  no key package fails without inviting anyone.

* fix: class inbound DirectV1 joins as Private, not Group

The joiner of a DirectV1 (pairwise) conversation received it classed as
Group, because dispatch_to_inbox2 hardcoded ConversationClass::Group for
every InboxV2 join. DirectV1 welcomes (InviteType::GroupV1) and GroupV2
welcomes (InviteType::GroupV2) both arrive over InboxV2, so a plain 1:1
invite surfaced to the display layer as a group. ConversationClass is
documented as stable across protocol versions of the same conversation
shape, and DirectV1 is the pairwise shape, so its joiner must see Private.

- InboxV2::handle_frame returns the class alongside the convo:
  InviteType::GroupV1 (the DirectV1 welcome carrier) yields Private,
  InviteType::GroupV2 yields Group.
- dispatch_to_inbox2 propagates that class instead of hardcoding Group.
- direct_v1_by_account_address asserts the joiner sees Private.

* feat: expose a group's roster, deduped to one entry per account

The display layer needs a group's membership, but nothing exposed it:
de-mls holds the authoritative roster (MLS group state) with no public
accessor, and members added by other members stay invisible until they
send a message. Rebuilding the roster from observed messages would fork
state the crypto layer owns and be wrong exactly when a group grows.

- GroupConvo::members() returns each member's hex-encoded MLS
  leaf-credential content, self included. GroupV2Convo delegates to
  de-mls and guarantees self-inclusion; GroupV1Convo reads its openmls
  leaves.
- Core::group_members(convo_id) mirrors group_add_member's dispatch: a
  cached group yields its members, a direct conversation is an
  UnsupportedFunction, otherwise the group is loaded.
- ChatClient::group_members returns Vec<GroupMember>, resolving each
  member's account claim through the directory. A member whose account
  claim is unconfirmable is listed by device with account None rather
  than dropped: it is cryptographically in the group, only the account
  claim is unproven. The credential parsing decode_sender did is
  factored into parse_credential and shared by both, leaving
  decode_sender's stricter drop semantics for message senders unchanged.
- Because resolve_device_ids fans an account out to every endorsed
  device, an account whose devices all join surfaced once per device;
  group_members dedups by account, keeping the first-seen device as the
  account's representative. Members with no confirmed account stay
  individual, keyed by their unique device key.
- Unit tests cover the tolerant-vs-drop split and the per-account dedup;
  the three-member group integration test asserts the roster converges
  after create and after each add, and a solo group lists only its
  creator.

* feat: retry the registry on transient 5xx with backoff and jitter

The keypackage/account registry is reliable request-by-request but sheds concurrent bursts with a 5xx, so several instances registering at once each hard-failed on init. HttpRegistry's four calls now retry network errors and 5xx/429 with exponential backoff and full jitter (the jitter decorrelates concurrent publishers so their retries don't re-collide); 4xx and success return immediately. The total retry window is bounded to a few seconds.

* fix: mark InboxV2 key package last-resort so members can join multiple groups

A key package's init key is one-time-use: openmls deletes it after the first
welcome that consumes it. Each installation registers a single key package, so a
second group inviting the same member found no matching key package and rejected
the welcome with "welcome not addressed to this member", the flaky group add.

Mark the InboxV2 key package as last-resort (and advertise the extension in the
leaf capabilities, which key-package validation requires) so openmls retains the
init key, letting one key package admit an installation to any number of groups.

This reuses one init key for every join, trading per-join forward secrecy for
membership that just works. A TODO at the publish site tracks the intended
one-time key-package pool (the registry pops one per fetch, the client
replenishes) with last-resort as the exhaustion fallback (#169).

Add regression tests: a member joining two groups (core harness) and two peers
invited to several groups over the threaded client.

* fix: dedup list_conversations across the store and the in-memory cache

A DirectV1 join persists its conversation to the store and also caches it in
memory, so list_conversations saw it twice. It deduped with Vec::dedup, which
only drops consecutive repeats, over cached_convos' nondeterministic HashMap
order, so the duplicate survived whenever another cached conversation fell
between the two copies. list_conversations then intermittently returned a
conversation twice, and a consumer counting conversations (e.g. checking that a
peer joined a group while a direct chat already existed) saw a flaky count.

Dedup through a set so a conversation held in both stores is listed once
regardless of iteration order.

Add a DirectV1-then-GroupV2 regression test, which also covers key-package reuse
across conversation types.

* fix: dedup the GroupV2 add batch to avoid redundant fetches and duplicate invites

Both create_group_convo_v2 and group_add_member funnel through
GroupV2Convo::add_member, so a duplicate signer (an account that resolves
to the same signer twice, or a repeated account) cost a redundant
key-package fetch and a second Add proposal. The existing guard skipped
only self and already-committed members, which a within-batch duplicate
escapes because add_member opens a proposal the committed roster does not
yet reflect, stranding a pending_invite that can later fire a spurious
duplicate welcome.

Dedup the requested signers before fetching, and guard the add loop with a
membership set seeded from the roster and self, hoisting the per-iteration
members() call out of the loop.

* docs: correct the retry-budget and group-add doc comments

The retry-budget comment claimed the ~20s init IPC budget held even at the
worst-case sum, but that only holds on the load-shed path where each retry
returns fast; a fully unreachable registry costs up to MAX_RETRIES times
the reqwest timeout, which no retry budget can rescue. State both.

Reword add_group_members to name the proposal, commit, and welcome flow
rather than the unexplained "once the add commits".

* chore: allow clippy::question_mark in LocalBroadcaster::poll (Rust 1.97 FP)

Stable rolled to 1.97, whose clippy question_mark flags poll()'s match on
`self.shared.borrow().read(next)`. Its suggested `read(next)?` would drop the
RefCell Ref guard and dangle the returned reference, so the lint is a false
positive here. CI tracks floating stable (`rustup update stable`), so this is
pre-existing code newly flagged; suppress it to keep the branch green.
2026-07-09 20:02:04 +02:00
kaichao
939a63e8bc
feat: separate embedded logos client (#166)
* feat: separate embedded p2p delievery to its own crate

* feat: separate p2p config in its own crate

* chore: split embed module

* chore: refactor registry config

* feat: split logos chat crate

* chore: refactor
2026-07-09 15:12:58 +08:00
Jazz Turner-Baggs
b19d0c6e67
fix: lock xeddsa to 1.0.2 to above breaking change (#174) 2026-07-08 12:57:37 -07:00
kaichao
b6fe452ea7
feat: add config for logos chat client (#163)
* feat: add config for logos chat client

* chore: fix mock registry log message

* chore: set custom fields in logos config
2026-07-04 11:59:44 +08:00
osmaczko
c09459c0a0
fix: signer-scoped DirectV1 routing (#162)
Core is no longer account-aware: the client resolves an account address
to signer ids via the account directory, and the signer's verifying-key
hex serves as registry key, inbox subscription, and Welcome routing
target end to end. The MLS credential stays the full id().

- GroupV2 reads the de-mls member id from the fetched key package and
  maps it to the signer id the welcome is delivered to.
- All account machinery (directory trait, bundle codec, resolution)
  moves out of core into logos-account; the RegistrationService
  supertrait and Core::account_directory() are gone, and the client
  holds its own directory handle.
- The account exposes functionality, never a signer: add_delegate_signer
  does the lamport upsert and signs internally.
- Every client acts for an account (ChatClientBuilder::new(account)).
  DelegateSigner is a pure keypair; the client composes the wire
  credential from the signer and the account, so the association is
  client state. addr() is the account address.
- resolve_device_ids fails fast (NotAnAccountKey / NoDeviceBundle /
  Directory) instead of falling back to treating an unresolved address
  as a signer id. LogosChatClient::open and chat-cli mint and publish a
  dev account each launch.
- EphemeralRegistry keys key packages by hex pubkey like HttpRegistry.

Supersedes #155 (routing_id).
2026-07-03 23:18:10 +02:00
kaichao
d131a69583
feat: default transport for logos chat client (#159)
* chore: gate logos-delivery transport on cargo feature, not env-dependent cfg

* chore: fix clippy

* feat: logos chat client use logos delivery as default
2026-07-03 02:17:45 +08:00
Ekaterina Broslavskaia
6897281826
update Cargo.lock (#160) 2026-07-02 10:47:18 -07:00
kaichao
943ba2973f
chore: gate embed p2p transport on cargo feature (#157)
* chore: gate logos-delivery transport on cargo feature, not env-dependent cfg

* chore: fix clippy
2026-07-03 01:13:53 +08:00
Jazz Turner-Baggs
098612ba8b
Update demls for external group configuration (#156) 2026-07-01 15:45:40 -07:00
kaichao
d2cb3017e9
feat: default value for logos chat client (#151)
* feat: add logos default client

* feat: chat cli use logos chat client config
2026-07-01 09:56:25 +08:00
Ekaterina Broslavskaia
ebae3317d6
bump de-mls and adapt group_v2 to its new API (#153) 2026-06-29 15:54:26 +03:00
Jazz Turner-Baggs
97eacc01a7
Componentize logos delivery (#148)
* Move logos_delivery to components

Rename components

update deps

WIP

Remove requirement for build.rs in chat-cli

fix imports

update linux flake

Linter fixes

fix build in linux

* Update docs

* Blankspace fix
2026-06-26 10:05:28 -07:00
kaichao
0d38dd80b7
feat: update nixpkgs locked version to avoid override nixpkgs in ci. (#150)
Co-authored-by: Jazz Turner-Baggs <473256+jazzz@users.noreply.github.com>
2026-06-24 08:04:44 -07:00
Jazz Turner-Baggs
7f3da1288a
Remove keypkg generation in GroupV2 (#147)
Remove GroupV2Convo::new_pending

Flatten types
2026-06-24 07:34:52 -07: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
Ekaterina Broslavskaya
e1921b944d
remove outdated factories and inline providers from de-mls 2026-06-23 18:08:25 +03: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
Jazz Turner-Baggs
1c984f442c
Add client path for DirectConvo (#140)
* Add PrivateV2Convo

* Rename to DirectV1

* Update DirectV1 to support multiple members

* Add client path for DirectConvo
2026-06-20 09:44:27 -07:00
Jazz Turner-Baggs
7612b233c9
Add 1:1 Chats using Groups (#139)
* Add Identified Trait for convo

* Add PrivateV2Convo

* Rename to DirectV1

* Rename ConvoTypeOwned variant

* Update DirectV1 to support multiple members

* Apply suggestion from @kaichaosun

Co-authored-by: kaichao <kaichaosuna@gmail.com>

---------

Co-authored-by: kaichao <kaichaosuna@gmail.com>
2026-06-19 12:01:17 -07:00
Jazz Turner-Baggs
c5b264c827
Add Identified Trait for convo (#138)
* Add Identified Trait for convo
2026-06-19 08:43:55 -07:00
Jazz Turner-Baggs
e163980715
Move Ephemeral registry to submodule (#136) 2026-06-17 08:27:39 -07:00
Jazz Turner-Baggs
960d0bc119
DeMLS Integration (#134)
* Add WakeupService

* Move Id to trait

* Add GroupV2

* Add convo cache

* Add TestHarness

* Instrument call paths

* Downgrade Ciphersuite

* Update imports

* cleanups

* Add Wakeups to Client

* fix: protoc dependency for ci

* fix: nix hash

* Remove save_conversation for v2

* PR comments
2026-06-15 13:15:18 -07:00
osmaczko
9d9a691fe3
refactor: remove client-ffi and legacy nim bindings (#133)
closes: #77

The C consumer story lives downstream now: logos-chat-module wraps the
client crate and exposes its own C API. The in-tree client-ffi crate has
no consumers left, and the nim bindings still target the removed
Context-based C API.

- delete crates/client-ffi (including the message-exchange C example)
  and nim-bindings
- drop core/conversations' unused safer-ffi dependency plus the leftover
  C artifact crate-types: staticlib on core/conversations, cdylib on
  double-ratchets (neither crate has extern "C" exports)
- flake.nix: drop the default package (it built libclient_ffi.a plus its
  header); keep the logos-delivery package and the dev shell
- ci.yml: drop the C FFI smoketest steps (valgrind included), the rustup
  install the smoketest no longer needs, and the nix-build job that
  built the removed default package
- ADR 0001: point the FFI-compatibility driver at the downstream C API
  boundary instead of crates/client-ffi
2026-06-15 17:55:58 +02:00
kaichao
78d6b6c47a
chore: fix ci failure steps of nix build (#132)
* chore: fix ci failure steps of nix build

* chore: update comments
2026-06-12 08:52:13 +08:00
kaichao
f41fb40c2f
feat: extend the http registry to store account's installations (#129)
* feat: account to device store

* feat: accout traits and codec

* feat: integrate accounts abstraction

* chore: clean docs and naming

* remove account public key from payload

* chore: fix clippy

* feat: lamport check before update account store

* chore: rebase to core

* chore: register account in new core

* chore: rebase changes and use account pub for index account store

* chore: move chat store outside of libchat

* chore: use account pub for registry
2026-06-11 21:07:11 +08: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
Jazz Turner-Baggs
a610117e81
Update Context to accept External Identity Provider. (#127)
* rename .account_id() to .id()

* Create logos-traits crate

* Remove AccountId references

* external IdentityProvider for Context

* Fix compile errors from merge

* Update logos-traits to shared-traits

* format fixes

* warnings cleanup

* clippy fix

* Remove rebase artifact
2026-06-10 06:59:04 -07:00
osmaczko
0e72fdf483
refactor(core): replace Rc-based Context with a synchronous, Send-able Core (#123)
Make the conversations core Send so the threaded client can own it behind an
Arc<Mutex<Core>>: a background worker polls the transport and handles inbound
payloads while the application thread issues outbound calls (send, create
conversation). Sharing the core across those two threads means moving it into
the spawned worker, which is only legal if it is Send. Access stays serialized
by the client's Mutex (one thread at a time), so the core needs Send but not
Sync and carries no lock of its own. See
docs/adr/0001-client-event-system.md for the background-poller design.

The Rc<RefCell> service-sharing is what made the core !Send. Context is de-Rc'd
and renamed to Core, owning its services outright and driving the inbox and
conversation primitives with plain &mut self.

- Services (identity, delivery, store, registry, MLS context, causal history)
  are bundled into a ServiceContext<S> behind an ExternalServices trait, with
  S = (DS, RS, CS). Constructors live on the (DS, RS, CS) form because S cannot
  be inferred backwards through S::DS.
- Inbox, InboxV2, PrivateV1Convo, and GroupV1Convo become non-generic and
  receive the ServiceContext bundle as a &mut/& parameter; no Rc or
  RefCell-as-shared-state remains, so Core is Send whenever its injected
  services are.
- Dispatch branches on ConversationKind in one place: Core rebuilds the target
  as a Convo<S>/GroupConvo<S> trait object bound to the service bundle, so
  conversations never escape the orchestrator.
- CausalHistoryStore drops its Rc, keeping a plain RefCell.
2026-06-08 21:55:33 +02:00
kaichao
cd7dd6a330
feat: http server based key package registry (#124)
* feat: http server based key package registry

* chore: instructions on running the registration service

* chore: remove duplicate post param

* chore: revert out sourced account id for multi devices support

* feat: signature on account id and key packages

* chore: include http registry in contact registry module

* refactor: use device id for retrieve key package

* chore: use string for device id

* feat: server verification on the register

* chore: doc the smoke test

* chore: fix data folder non exist

* chore: use payload for register and retrieve

* chore: fix clippy
2026-06-04 10:09:29 +08:00
Jazz Turner-Baggs
6f5838af51
Add crate logos-accounts (#103)
Update InboxV2 to use IdentProvider

Create Full featured Provider

Introduce MlsIdentityProvider

Flatten MLSContext

Cleanup warnings until future integration PR

remove duplicate

Update account_id comments
2026-06-02 15:21:21 -07:00
kaichao
4df23aad63
Include sender information on missing messages (#120)
* feat: prefix sender id

* chore: add message struct for sender info

* chore: refactor struct name for frontier

* chore: reuse duplicate test

* chore: fix clippy

* feat: use sender_id in wire

* chore: remove result

* chore: fix nix build

* chore: bump chat_proto version
2026-06-02 21:55:19 +08:00
Jazz Turner-Baggs
2d3ad27d51
Add cron job for ci (#122) 2026-06-01 22:12:12 -07: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
kaichao
279477cdeb
feat: causal history notify missing messages (#105)
* feat: causal history notify missing messages

* chore: fix test

* chore: fix clippy

* chore: update domain seprator
2026-05-25 11:54:52 +08:00
Jazz Turner-Baggs
fa68714e2f
Add crate logos-accounts (#102) 2026-05-20 14:11:02 -07:00
Jazz Turner-Baggs
65e103ab1d
Remove naming conflict with Signatures (#101) 2026-05-20 13:41:12 -07: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
d972741157
chore: add adr for client-event-system (#99) 2026-05-19 21:26:09 +02:00
Jazz Turner-Baggs
3245498438
Add GroupV1 + InboxV2 (#92)
* Add GroupV1

* Clean warnings

* Remove dead test

* Re-use components in integration tests

* Remove deadcode

* undo import fixes

* tidy

* Update Accounts + service_traits

* Remove ClientCtx

* Remove duplicate test_utils

* Wrap constructor in result

* Warning fixups

* Appease clippy

* Update comments

* Update todo

* Clean up warnings

* Avoid panic

* Fix libchat import in chat-cli

* Add InboxV2 comment

* Add comments to GroupV1Convo

* Update doc comments

* reduce visibility

* Doc Integration tests

* Hashlen update

* remove type alias for ProtocolParams

* Remove stray printlines

* Review fixes

* PR review changes

* Add trait comments

* chat_proto import paths

* PR Feedback fixes

* Update CliClient

* Update CLI DeliveryService impls
2026-05-19 11:54:54 -07:00
osmaczko
1e373226ae
chore(chat-cli): switch transport at runtime via --transport flag (#95)
Both file and logos-delivery transports are now compiled into a single
binary and selected at runtime (default: logos-delivery), replacing the
env-var-driven build-time cfg.
2026-05-12 15:33:50 +02:00
Jazz Turner-Baggs
39bf267564
Add Account Struct (#94)
* Add Account Struct

* Quell Warnings

* Update core/conversations/src/account.rs

Co-authored-by: osmaczko <33099791+osmaczko@users.noreply.github.com>

* Add clarity to todo

* Update test account constructor docs

* Add removal todo

* Resolve cargo.lock conflict

* remove warnings

---------

Co-authored-by: osmaczko <33099791+osmaczko@users.noreply.github.com>
2026-04-28 07:47:57 -07:00
Jazz Turner-Baggs
25debdc051
Add Signature + Verifying key types (#93) 2026-04-27 13:35:20 -07:00