From c256c38ffb1c3ce392919c08047eefb1a39c7684 Mon Sep 17 00:00:00 2001 From: Christian Nennemann Date: Mon, 9 Mar 2026 20:46:54 +0100 Subject: [PATCH] docs: add crate-level documentation and public API doc comments - Expand crate-level docs for quicprochat-rpc (architecture, wire format, module map) and quicprochat-sdk (connection lifecycle, event subscription, module descriptions). - Add /// doc comments to all undocumented pub fn/struct/enum items in server domain services (keys, channels, devices, users, account, p2p, blobs) and domain types. - Fix rustdoc broken intra-doc links in plugin-api (HookResult, qpc_plugin_init), federation/mod.rs (Store), and client main.rs (unescaped brackets). --- crates/quicprochat-client/src/main.rs | 2 +- crates/quicprochat-plugin-api/src/lib.rs | 10 +-- crates/quicprochat-rpc/src/lib.rs | 42 ++++++++++-- crates/quicprochat-sdk/src/lib.rs | 41 +++++++++++- .../quicprochat-server/src/domain/account.rs | 1 + crates/quicprochat-server/src/domain/blobs.rs | 4 ++ .../quicprochat-server/src/domain/channels.rs | 4 ++ .../quicprochat-server/src/domain/devices.rs | 3 + crates/quicprochat-server/src/domain/keys.rs | 5 ++ crates/quicprochat-server/src/domain/p2p.rs | 3 + crates/quicprochat-server/src/domain/types.rs | 65 +++++++++++++++++++ crates/quicprochat-server/src/domain/users.rs | 2 + .../quicprochat-server/src/federation/mod.rs | 2 +- 13 files changed, 171 insertions(+), 13 deletions(-) diff --git a/crates/quicprochat-client/src/main.rs b/crates/quicprochat-client/src/main.rs index c2a4b73..a929307 100644 --- a/crates/quicprochat-client/src/main.rs +++ b/crates/quicprochat-client/src/main.rs @@ -505,7 +505,7 @@ enum Command { password: Option, }, - /// Interactive 1:1 chat: type to send, incoming messages printed as [peer] . Ctrl+D to exit. + /// Interactive 1:1 chat: type to send, incoming messages printed as \[peer\] msg. Ctrl+D to exit. /// In a two-person group, peer is chosen automatically; use --peer-key only with 3+ members. Chat { #[arg( diff --git a/crates/quicprochat-plugin-api/src/lib.rs b/crates/quicprochat-plugin-api/src/lib.rs index 1cf6995..ab04d99 100644 --- a/crates/quicprochat-plugin-api/src/lib.rs +++ b/crates/quicprochat-plugin-api/src/lib.rs @@ -8,7 +8,7 @@ //! extern "C" int32_t qpc_plugin_init(HookVTable *vtable); //! ``` //! -//! The server passes a zeroed [`HookVTable`] to `qpc_plugin_init`. The plugin +//! The server passes a zeroed [`HookVTable`] to the init function. The plugin //! fills in whichever function pointers it cares about and returns `0` on //! success or a negative error code on failure. Unused slots remain null and //! the server treats them as no-ops. @@ -27,9 +27,9 @@ //! //! # Return values //! -//! Hooks that can reject an operation return [`HookResult`]. The server maps -//! `HOOK_CONTINUE` to `HookAction::Continue` and any other value to -//! `HookAction::Reject` with the reason string from [`HookVTable::error_message`]. +//! Hooks that can reject an operation return an `i32` result code. The server maps +//! [`HOOK_CONTINUE`] to allow and any other value to reject, reading the reason +//! string from [`HookVTable::error_message`]. #![no_std] @@ -105,7 +105,7 @@ pub struct CFetchEvent { // ── HookVTable ──────────────────────────────────────────────────────────────── -/// C-ABI function-pointer table filled by [`qpc_plugin_init`]. +/// C-ABI function-pointer table filled by the plugin's `qpc_plugin_init` export. /// /// All fields default to null (no-op). The server only calls a slot when its /// pointer is non-null. The `user_data` field is passed as the first argument diff --git a/crates/quicprochat-rpc/src/lib.rs b/crates/quicprochat-rpc/src/lib.rs index 4d5860f..fbdd88f 100644 --- a/crates/quicprochat-rpc/src/lib.rs +++ b/crates/quicprochat-rpc/src/lib.rs @@ -1,9 +1,43 @@ //! QUIC RPC framework for quicprochat v2. //! -//! Wire format per QUIC stream: -//! - Request: `[method_id: u16][request_id: u32][payload_len: u32][protobuf bytes]` -//! - Response: `[status: u8][request_id: u32][payload_len: u32][protobuf bytes]` -//! - Push: `[event_type: u16][payload_len: u32][protobuf bytes]` (uni-stream) +//! This crate implements a lightweight, binary-framed RPC protocol over QUIC. +//! Each RPC call opens a new QUIC bi-directional stream, sends a request frame, +//! and reads a response frame. Server-initiated push events use uni-streams. +//! +//! # Wire format +//! +//! All integers are big-endian. +//! +//! **Request** (client → server, bi-stream): +//! ```text +//! [method_id: u16][request_id: u32][payload_len: u32][protobuf bytes] +//! ``` +//! +//! **Response** (server → client, same bi-stream): +//! ```text +//! [status: u8][request_id: u32][payload_len: u32][protobuf bytes] +//! ``` +//! +//! **Push** (server → client, uni-stream): +//! ```text +//! [event_type: u16][payload_len: u32][protobuf bytes] +//! ``` +//! +//! # Architecture +//! +//! - [`framing`] — frame types ([`framing::RequestFrame`], [`framing::ResponseFrame`], +//! [`framing::PushFrame`]) and encode/decode logic. +//! - [`method`] — [`method::MethodRegistry`] maps `u16` method IDs to async handler +//! functions with optional per-method timeouts. +//! - [`server`] — [`server::RpcServer`] binds a QUIC endpoint, performs an auth +//! handshake on each connection, then dispatches RPC streams to registered handlers. +//! - [`client`] — [`client::RpcClient`] connects to the server with TLS, supports +//! auto-reconnect with exponential backoff, and multiplexes concurrent RPCs. +//! - [`push`] — [`push::PushBroker`] manages per-identity push connections and +//! fan-out to channel members. +//! - [`middleware`] — session validation, rate limiting, and structured audit logging. +//! - [`auth_handshake`] — initial session-token exchange on the first bi-stream. +//! - [`error`] — [`error::RpcError`] and [`error::RpcStatus`] types. pub mod auth_handshake; pub mod framing; diff --git a/crates/quicprochat-sdk/src/lib.rs b/crates/quicprochat-sdk/src/lib.rs index 870cf7e..02648f7 100644 --- a/crates/quicprochat-sdk/src/lib.rs +++ b/crates/quicprochat-sdk/src/lib.rs @@ -1,7 +1,44 @@ //! Client SDK for quicprochat v2. //! -//! Provides `QpqClient` — a single entry point for connecting, authenticating, -//! sending/receiving messages, and subscribing to real-time events. +//! Provides [`QpqClient`](client::QpqClient) — a single entry point for +//! connecting to a quicprochat server, authenticating via OPAQUE, managing +//! conversations, and subscribing to real-time events. +//! +//! # Connection lifecycle +//! +//! 1. Create a [`QpqClient`](client::QpqClient) with a [`ClientConfig`](config::ClientConfig). +//! 2. Call [`connect()`](client::QpqClient::connect) to establish a QUIC connection +//! and open the local SQLCipher conversation store. +//! 3. [`register()`](client::QpqClient::register) or +//! [`login()`](client::QpqClient::login) via OPAQUE to authenticate. +//! 4. Optionally call [`start_heartbeat()`](client::QpqClient::start_heartbeat) +//! to enable proactive dead-connection detection. +//! 5. Use messaging, group, key, and device APIs through the client. +//! 6. Call [`disconnect()`](client::QpqClient::disconnect) to shut down gracefully. +//! +//! # Event subscription +//! +//! Call [`subscribe()`](client::QpqClient::subscribe) to get a +//! `tokio::sync::broadcast::Receiver` that emits connection state +//! changes, authentication events, and incoming message notifications. +//! +//! # Modules +//! +//! - [`client`] — [`QpqClient`](client::QpqClient) and connection management. +//! - [`auth`] — OPAQUE registration and login flows. +//! - [`config`] — [`ClientConfig`](config::ClientConfig) with server address, TLS, DB path. +//! - [`conversation`] — [`ConversationStore`](conversation::ConversationStore) for local +//! message persistence and user blocking. +//! - [`events`] — [`ClientEvent`](events::ClientEvent) enum for the event bus. +//! - [`groups`] — group membership management. +//! - [`keys`] — MLS KeyPackage and hybrid (PQ) key upload/fetch. +//! - [`messaging`] — send and receive encrypted messages. +//! - [`devices`] — multi-device registration, listing, and revocation. +//! - [`recovery`] — account recovery bundle upload/fetch. +//! - [`outbox`] — offline message queue with retry. +//! - [`state`] — client state persistence (identity key, session token). +//! - [`transcript`] — conversation transcript export. +//! - [`users`] — username/identity resolution. pub mod auth; pub mod client; diff --git a/crates/quicprochat-server/src/domain/account.rs b/crates/quicprochat-server/src/domain/account.rs index ecfc964..b9f0af3 100644 --- a/crates/quicprochat-server/src/domain/account.rs +++ b/crates/quicprochat-server/src/domain/account.rs @@ -15,6 +15,7 @@ pub struct AccountService { } impl AccountService { + /// Delete an account and append a KT tombstone entry for auditability. pub fn delete_account(&self, caller_identity_key: &[u8]) -> Result<(), DomainError> { self.store.delete_account(caller_identity_key)?; diff --git a/crates/quicprochat-server/src/domain/blobs.rs b/crates/quicprochat-server/src/domain/blobs.rs index 21866b1..0f1c824 100644 --- a/crates/quicprochat-server/src/domain/blobs.rs +++ b/crates/quicprochat-server/src/domain/blobs.rs @@ -31,6 +31,9 @@ impl BlobService { self.data_dir.join("blobs") } + /// Upload a blob chunk. Chunks are written at the given offset. When the + /// final chunk completes the upload, the SHA-256 hash is verified and the + /// blob is finalized. Already-complete blobs return immediately. pub fn upload_blob( &self, req: UploadBlobReq, @@ -136,6 +139,7 @@ impl BlobService { }) } + /// Download a chunk of a stored blob. Reads at most 256 KB per call. pub fn download_blob( &self, req: DownloadBlobReq, diff --git a/crates/quicprochat-server/src/domain/channels.rs b/crates/quicprochat-server/src/domain/channels.rs index 57ef9d4..7a957d4 100644 --- a/crates/quicprochat-server/src/domain/channels.rs +++ b/crates/quicprochat-server/src/domain/channels.rs @@ -12,6 +12,10 @@ pub struct ChannelService { } impl ChannelService { + /// Create or look up a 1:1 DM channel between caller and peer. + /// + /// The channel ID is deterministic and symmetric — `create(A, B)` returns + /// the same ID as `create(B, A)`. Returns `was_new = true` on first creation. pub fn create_channel( &self, req: CreateChannelReq, diff --git a/crates/quicprochat-server/src/domain/devices.rs b/crates/quicprochat-server/src/domain/devices.rs index ac06794..6c18ca6 100644 --- a/crates/quicprochat-server/src/domain/devices.rs +++ b/crates/quicprochat-server/src/domain/devices.rs @@ -14,6 +14,7 @@ pub struct DeviceService { } impl DeviceService { + /// Register a new device for the caller's identity. Enforces a per-identity device limit. pub fn register_device( &self, req: RegisterDeviceReq, @@ -37,6 +38,7 @@ impl DeviceService { Ok(RegisterDeviceResp { success }) } + /// List all registered devices for the caller's identity. pub fn list_devices( &self, caller_identity_key: &[u8], @@ -53,6 +55,7 @@ impl DeviceService { Ok(ListDevicesResp { devices }) } + /// Revoke (remove) a registered device. Returns an error if the device is not found. pub fn revoke_device( &self, req: RevokeDeviceReq, diff --git a/crates/quicprochat-server/src/domain/keys.rs b/crates/quicprochat-server/src/domain/keys.rs index b757b80..24035c5 100644 --- a/crates/quicprochat-server/src/domain/keys.rs +++ b/crates/quicprochat-server/src/domain/keys.rs @@ -16,6 +16,7 @@ pub struct KeyService { } impl KeyService { + /// Upload an MLS KeyPackage for the given identity. Returns a SHA-256 fingerprint. pub fn upload_key_package( &self, req: UploadKeyPackageReq, @@ -40,6 +41,7 @@ impl KeyService { Ok(UploadKeyPackageResp { fingerprint }) } + /// Fetch the stored MLS KeyPackage for an identity. Returns empty if none exists. pub fn fetch_key_package( &self, req: FetchKeyPackageReq, @@ -53,6 +55,7 @@ impl KeyService { }) } + /// Upload a hybrid (ML-KEM-768) public key for post-quantum key exchange. pub fn upload_hybrid_key( &self, req: UploadHybridKeyReq, @@ -70,6 +73,7 @@ impl KeyService { Ok(()) } + /// Fetch the hybrid public key for a single identity. Returns empty if none exists. pub fn fetch_hybrid_key( &self, req: FetchHybridKeyReq, @@ -82,6 +86,7 @@ impl KeyService { Ok(FetchHybridKeyResp { hybrid_public_key }) } + /// Batch-fetch hybrid public keys for multiple identities. Missing keys return empty. pub fn fetch_hybrid_keys( &self, req: FetchHybridKeysReq, diff --git a/crates/quicprochat-server/src/domain/p2p.rs b/crates/quicprochat-server/src/domain/p2p.rs index 033fb99..642cbb2 100644 --- a/crates/quicprochat-server/src/domain/p2p.rs +++ b/crates/quicprochat-server/src/domain/p2p.rs @@ -12,6 +12,7 @@ pub struct P2pService { } impl P2pService { + /// Publish a P2P endpoint (iroh node address) for the caller's identity. pub fn publish_endpoint( &self, req: PublishEndpointReq, @@ -26,6 +27,7 @@ impl P2pService { Ok(()) } + /// Resolve a P2P endpoint for an identity key. Returns empty if none published. pub fn resolve_endpoint( &self, req: ResolveEndpointReq, @@ -42,6 +44,7 @@ impl P2pService { Ok(ResolveEndpointResp { node_addr }) } + /// Return a health-check response (always "ok"). pub fn health() -> HealthResp { HealthResp { status: "ok".into(), diff --git a/crates/quicprochat-server/src/domain/types.rs b/crates/quicprochat-server/src/domain/types.rs index fd5b358..e3e9c9b 100644 --- a/crates/quicprochat-server/src/domain/types.rs +++ b/crates/quicprochat-server/src/domain/types.rs @@ -74,6 +74,7 @@ pub struct RegisterStartReq { pub request_bytes: Vec, } +/// OPAQUE registration start response. pub struct RegisterStartResp { pub response_bytes: Vec, } @@ -85,6 +86,7 @@ pub struct RegisterFinishReq { pub identity_key: Vec, } +/// OPAQUE registration finish response. pub struct RegisterFinishResp { pub success: bool, } @@ -95,6 +97,7 @@ pub struct LoginStartReq { pub request_bytes: Vec, } +/// OPAQUE login start response. pub struct LoginStartResp { pub response_bytes: Vec, } @@ -106,6 +109,7 @@ pub struct LoginFinishReq { pub identity_key: Vec, } +/// OPAQUE login finish response containing the session token. pub struct LoginFinishResp { pub session_token: Vec, } @@ -119,6 +123,7 @@ pub struct Envelope { pub data: Vec, } +/// Request to enqueue a message for delivery to a recipient. pub struct EnqueueReq { pub recipient_key: Vec, pub payload: Vec, @@ -126,37 +131,44 @@ pub struct EnqueueReq { pub ttl_secs: u32, } +/// Response from enqueue with the assigned sequence number. pub struct EnqueueResp { pub seq: u64, pub delivery_proof: Vec, } +/// Request to fetch (and drain) queued messages. pub struct FetchReq { pub recipient_key: Vec, pub channel_id: Vec, pub limit: u32, } +/// Response containing fetched message envelopes. pub struct FetchResp { pub payloads: Vec, } +/// Request to peek at queued messages without draining. pub struct PeekReq { pub recipient_key: Vec, pub channel_id: Vec, pub limit: u32, } +/// Response containing peeked message envelopes. pub struct PeekResp { pub payloads: Vec, } +/// Request to acknowledge messages up to a sequence number. pub struct AckReq { pub recipient_key: Vec, pub channel_id: Vec, pub seq_up_to: u64, } +/// Request to enqueue a message to multiple recipients at once. pub struct BatchEnqueueReq { pub recipient_keys: Vec>, pub payload: Vec, @@ -164,83 +176,100 @@ pub struct BatchEnqueueReq { pub ttl_secs: u32, } +/// Response from batch enqueue with one sequence number per recipient. pub struct BatchEnqueueResp { pub seqs: Vec, } // ── Keys ───────────────────────────────────────────────────────────────────── +/// Request to upload an MLS KeyPackage. pub struct UploadKeyPackageReq { pub identity_key: Vec, pub package: Vec, } +/// Response containing the SHA-256 fingerprint of the uploaded KeyPackage. #[derive(Debug)] pub struct UploadKeyPackageResp { pub fingerprint: Vec, } +/// Request to fetch a stored MLS KeyPackage. pub struct FetchKeyPackageReq { pub identity_key: Vec, } +/// Response containing the MLS KeyPackage (empty if not found). pub struct FetchKeyPackageResp { pub package: Vec, } +/// Request to upload a hybrid (ML-KEM-768) public key. pub struct UploadHybridKeyReq { pub identity_key: Vec, pub hybrid_public_key: Vec, } +/// Request to fetch a single hybrid public key. pub struct FetchHybridKeyReq { pub identity_key: Vec, } +/// Response containing a hybrid public key (empty if not found). pub struct FetchHybridKeyResp { pub hybrid_public_key: Vec, } +/// Request to batch-fetch hybrid public keys for multiple identities. pub struct FetchHybridKeysReq { pub identity_keys: Vec>, } +/// Response containing hybrid keys in the same order as the request. pub struct FetchHybridKeysResp { pub keys: Vec>, } // ── Key Transparency / Revocation ──────────────────────────────────── +/// Request to revoke an identity key in the Key Transparency log. pub struct RevokeKeyReq { pub identity_key: Vec, pub reason: String, } +/// Response from key revocation with the leaf index in the KT log. pub struct RevokeKeyResp { pub success: bool, pub leaf_index: u64, } +/// Request to check if an identity key has been revoked. pub struct CheckRevocationReq { pub identity_key: Vec, } +/// Response with revocation status, reason, and timestamp. pub struct CheckRevocationResp { pub revoked: bool, pub reason: String, pub timestamp_ms: u64, } +/// Request for a range of Key Transparency audit log entries. pub struct AuditKeyTransparencyReq { pub start: u64, pub end: u64, } +/// A single entry in the KT audit log. pub struct AuditLogEntry { pub index: u64, pub leaf_hash: Vec, } +/// Response containing KT audit log entries, tree size, and root hash. pub struct AuditKeyTransparencyResp { pub entries: Vec, pub tree_size: u64, @@ -249,10 +278,12 @@ pub struct AuditKeyTransparencyResp { // ── Channel ────────────────────────────────────────────────────────────────── +/// Request to create a 1:1 DM channel with a peer. pub struct CreateChannelReq { pub peer_key: Vec, } +/// Response with the channel ID and whether it was newly created. #[derive(Debug)] pub struct CreateChannelResp { pub channel_id: Vec, @@ -261,25 +292,30 @@ pub struct CreateChannelResp { // ── User ───────────────────────────────────────────────────────────────────── +/// Request to resolve a username to an identity key. pub struct ResolveUserReq { pub username: String, } +/// Response with the identity key and KT inclusion proof. pub struct ResolveUserResp { pub identity_key: Vec, pub inclusion_proof: Vec, } +/// Request to reverse-resolve an identity key to a username. pub struct ResolveIdentityReq { pub identity_key: Vec, } +/// Response with the resolved username (empty if unknown). pub struct ResolveIdentityResp { pub username: String, } // ── Blob ───────────────────────────────────────────────────────────────────── +/// Request to upload a blob chunk. The blob is identified by its SHA-256 hash. pub struct UploadBlobReq { pub blob_hash: Vec, pub chunk: Vec, @@ -288,16 +324,19 @@ pub struct UploadBlobReq { pub mime_type: String, } +/// Response from blob upload containing the blob ID (same as hash). pub struct UploadBlobResp { pub blob_id: Vec, } +/// Request to download a chunk of a stored blob. pub struct DownloadBlobReq { pub blob_id: Vec, pub offset: u64, pub length: u32, } +/// Response containing the requested blob chunk and metadata. pub struct DownloadBlobResp { pub chunk: Vec, pub total_size: u64, @@ -306,35 +345,42 @@ pub struct DownloadBlobResp { // ── Device ─────────────────────────────────────────────────────────────────── +/// Request to register a new device for the caller's identity. pub struct RegisterDeviceReq { pub device_id: Vec, pub device_name: String, } +/// Response from device registration. pub struct RegisterDeviceResp { pub success: bool, } +/// Metadata about a registered device. pub struct DeviceInfo { pub device_id: Vec, pub device_name: String, pub registered_at: u64, } +/// Response listing all registered devices. pub struct ListDevicesResp { pub devices: Vec, } +/// Request to revoke (remove) a registered device. pub struct RevokeDeviceReq { pub device_id: Vec, } +/// Response from device revocation. pub struct RevokeDeviceResp { pub success: bool, } // ── Group metadata ─────────────────────────────────────────────────── +/// Server-side group metadata. pub struct GroupMetadata { pub group_id: Vec, pub name: String, @@ -344,6 +390,7 @@ pub struct GroupMetadata { pub created_at: u64, } +/// Request to update group metadata (name, description, avatar). pub struct UpdateGroupMetadataReq { pub group_id: Vec, pub name: String, @@ -351,55 +398,66 @@ pub struct UpdateGroupMetadataReq { pub avatar_hash: Vec, } +/// Request to list members of a group. pub struct ListGroupMembersReq { pub group_id: Vec, } +/// A group member with resolved username. pub struct GroupMemberInfo { pub identity_key: Vec, pub username: String, pub joined_at: u64, } +/// Response listing group members. pub struct ListGroupMembersResp { pub members: Vec, } // ── Moderation ─────────────────────────────────────────────────────────────── +/// Request to submit an encrypted abuse report. pub struct ReportMessageReq { pub encrypted_report: Vec, pub conversation_id: Vec, pub reporter_identity: Vec, } +/// Response from report submission. pub struct ReportMessageResp { pub accepted: bool, } +/// Request to ban a user. `duration_secs = 0` means permanent. pub struct BanUserReq { pub identity_key: Vec, pub reason: String, pub duration_secs: u64, } +/// Response from ban operation. pub struct BanUserResp { pub success: bool, } +/// Request to unban a user. pub struct UnbanUserReq { pub identity_key: Vec, } +/// Response from unban operation. pub struct UnbanUserResp { pub success: bool, } +/// Request to list abuse reports with pagination. pub struct ListReportsReq { pub limit: u32, pub offset: u32, } +/// A stored abuse report entry. pub struct ReportEntry { pub id: u64, pub encrypted_report: Vec, @@ -408,10 +466,12 @@ pub struct ReportEntry { pub timestamp: u64, } +/// Response containing paginated abuse reports. pub struct ListReportsResp { pub reports: Vec, } +/// A banned user entry with expiration info. pub struct BannedUserEntry { pub identity_key: Vec, pub reason: String, @@ -419,25 +479,30 @@ pub struct BannedUserEntry { pub expires_at: u64, } +/// Response listing all currently banned users. pub struct ListBannedResp { pub users: Vec, } // ── P2P ────────────────────────────────────────────────────────────────────── +/// Request to publish a P2P endpoint (iroh node address). pub struct PublishEndpointReq { pub identity_key: Vec, pub node_addr: Vec, } +/// Request to resolve a P2P endpoint for an identity. pub struct ResolveEndpointReq { pub identity_key: Vec, } +/// Response with the resolved P2P node address (empty if not published). pub struct ResolveEndpointResp { pub node_addr: Vec, } +/// Health-check response. pub struct HealthResp { pub status: String, } diff --git a/crates/quicprochat-server/src/domain/users.rs b/crates/quicprochat-server/src/domain/users.rs index 983086a..b674330 100644 --- a/crates/quicprochat-server/src/domain/users.rs +++ b/crates/quicprochat-server/src/domain/users.rs @@ -16,6 +16,7 @@ pub struct UserService { } impl UserService { + /// Resolve a username to its identity key, with a KT inclusion proof if available. pub fn resolve_user(&self, req: ResolveUserReq) -> Result { if req.username.is_empty() { return Err(DomainError::EmptyUsername); @@ -46,6 +47,7 @@ impl UserService { }) } + /// Reverse-resolve an identity key to its username. pub fn resolve_identity( &self, req: ResolveIdentityReq, diff --git a/crates/quicprochat-server/src/federation/mod.rs b/crates/quicprochat-server/src/federation/mod.rs index 60cf361..a5060f1 100644 --- a/crates/quicprochat-server/src/federation/mod.rs +++ b/crates/quicprochat-server/src/federation/mod.rs @@ -3,7 +3,7 @@ //! When federation is enabled, the server binds a second QUIC endpoint on a //! dedicated port (default 7001) that only accepts connections from known peers //! authenticated via mTLS. Inbound requests are handled by [`service::FederationServiceImpl`], -//! which delegates to the local [`Store`]. Outbound relay uses [`client::FederationClient`]. +//! which delegates to the local store. Outbound relay uses [`client::FederationClient`]. pub mod address; pub mod client;