Skip to content

calternal_collab::session

Public Note links cannot submit room updates (DESIGN §54, #981). Live Note rooms materialize edits as Markdown. Rooms flush after 750 ms of quiet, at the latest MAX_FLUSH_WAIT, or when the last client leaves. With history enabled, authored updates become durable before file saves; startup resumes their Yrs lineage and recognizes either hash of an unfinished save intent. External file edits become forward changes. Without history, startup validates the cached room against Markdown (DESIGN §§31, 61, #975).

Room epochs (see crate::stored): every connection first receives the room’s epoch as a custom y-protocols message (MESSAGE_ROOM_EPOCH). A client that names another epoch (?epoch=) is closed before any sync, and a client without one is closed when its SyncStep1 shows a document from another lineage. A clean unload and Hub::shutdown store the room’s Yrs state, so the next load continues the same epoch.

Daily notes use the same stable Note identity as every other Markdown file. Their [tz=<zone>] Log metadata is restored by the Notes writer after the shared bridge escapes it, while room flushes and Journal writes keep the same checked-replace lock (DESIGN §§9, 31; #606).

History (#975, DESIGN §61): integration installs one shared HistoryStore. Notes, guest sessions and agent turns all capture updates before broadcast. The same document-neutral writer is available to Canvas rooms. Client IDs bind to a connection, independent of client-supplied awareness names.

Hostile clients (adversarial round 2): a room accepts only updates after which the document still converts to Markdown. Any other update is rolled back and its sender is disconnected, so no client can make every later flush fail. Awareness clocks near u32::MAX are refused because the disconnect cleanup increments them. Canvas rooms accept element events, not client structs. The same author-bound validator serves HTTP and WebSocket edits; clean rooms never write (§60, #976).

Source: crates/calternal-collab/src/session.rs

pub struct AgentTurn

One named agent turn. Call apply once with the turn’s completed Markdown and finish to clear presence and persist. Each apply is one Yrs transaction.

Implements: Drop

pub async fn apply(&self, markdown: &str) -> Result<(), String>

Parse the completed agent text and merge it against the turn base (#907). After parsing succeeds, this turn permits only one apply attempt, even if shutdown or the merge fails. A successful merge marks the room dirty, broadcasts its update, and schedules persistence (DESIGN §27). Apply one verified agent turn. History admission precedes mutation and the server-issued turn ID is captured before broadcast (#975).

pub async fn finish(mut self) -> Result<(), String>

Clear agent presence, flush the room, and unload it when idle (#907). A notification failure is logged after persistence and does not undo the completed turn (DESIGN §27).

Source: crates/calternal-collab/src/session.rs:2272

pub struct Hub

Single collaboration writer for live Notes, with an optional shared history adapter installed by the Phase 2 integration (#975, DESIGN §60–61).

Implements: Clone, crate::history::HistoryMutations

pub fn new(
root: Root,
db: Db,
origin: String,
user_data_directory: PathBuf,
) -> Result<Self, notify::Error>

Start the shared room map and invalidation watchers. Watcher clones use the same history slot, installed before rooms open (#975, DESIGN §61).

pub async fn with_history(
self,
store: Arc<dyn HistoryStore>,
limits: WriteLimits,
) -> crate::history::Result<Self>

Install the shared store and durable budget. The integration job supplies slice A; this slice does not create a second history store (#975).

pub fn router(self) -> Router

No doc comment.

pub async fn live_clients(&self, user: &str, id: &str) -> Option<usize>

Connected client count of a loaded room, or None when no room is loaded for this Note. Used by tests and diagnostics.

pub fn with_shared_notes(mut self, access: Arc<dyn SharedNoteAccess>) -> Self

Install the Files Share authority after its security-state model lands.

pub fn with_trusted_proxies(mut self, trusted_proxies: Vec<ipnet::IpNet>) -> Self

Use the instance’s trusted-proxy rule for per-IP connection limits (§54, #981).

pub async fn shutdown(&self)

Save every loaded room and store its state, for a graceful stop (SIGTERM). Tabs that stay open then resync with the same epoch after the restart. Call it after the listener has stopped.

pub async fn notify_external_change(&self, owner: &str, path: &str)

Apply a Notes invalidation immediately after another server write.

pub async fn notify_external_change_as(&self, owner: &str, path: &str, author: Author)

Server-side parity routes preserve their verified author when they reconcile a file write. This adds no public write endpoint (#975).

pub async fn begin_agent(
&self,
user: &str,
id: &str,
name: &str,
color: &str,
) -> Result<AgentTurn, String>

Start an agent turn with visible awareness. Only one agent may edit a given live Note at a time; the AI plugin queues turns above this API.

Source: crates/calternal-collab/src/session.rs:879

pub enum SharedNotePermission

No doc comment.

Variants

  • Denied
  • Viewer
  • Editor

Implements: Clone, Copy, Debug, Eq, PartialEq

Source: crates/calternal-collab/src/session.rs:831

pub trait SharedNoteAccess: Send + Sync

The Files plugin must verify an editor Share against immutable item identity. Without that security-state adapter, cross-home access fails closed.

fn access<'a>(
&'a self,
recipient: &'a str,
owner: &'a str,
note_id: &'a str,
) -> Pin<Box<dyn Future<Output = SharedNotePermission> + Send + 'a>>;

No doc comment.

fn canvas_access<'a>(
&'a self,
_author: &'a str,
_owner: &'a str,
_path: &'a str,
) -> Pin<Box<dyn Future<Output = SharedNotePermission> + Send + 'a>>

Authorize a linked Note/Task by its current path and Files item identity. Canvas owner authority must never stand in for the editing User (#977).

fn note_saved<'a>(
&'a self,
_owner: &'a str,
_path: &'a str,
_before: FileFingerprint,
) -> Pin<Box<dyn Future<Output = Result<(), String>> + Send + 'a>>

Refresh Files’ fingerprint after this room’s authorized atomic write. A failure leaves the Share unavailable until the refresh succeeds.

Source: crates/calternal-collab/src/session.rs:753

pub fn openapi() -> utoipa::openapi::OpenApi

OpenAPI fragment for both live Note WebSocket handshakes.

Source: crates/calternal-collab/src/session.rs:2989

pub const MAX_FLUSH_WAIT: Duration

Longest time an edit waits for its save while clients keep typing.

Source: crates/calternal-collab/src/session.rs:507

pub const MAX_MESSAGE_BYTES: usize

Largest y-sync message a client may send. The Notes REST body limit is 10 MiB; the margin covers Yjs encoding overhead of a full-document sync.

Source: crates/calternal-collab/src/session.rs:515

pub const MESSAGE_ROOM_EPOCH: u8

Custom y-protocols message type of the room epoch frame. Payload: the epoch as a UTF-8 byte string (y-protocols writeVarUint8Array). Types 0 to 3 are taken by y-protocols; clients ignore unknown types.

Source: crates/calternal-collab/src/session.rs:519

pub const SHUTDOWN_FLUSH_WAIT: Duration

Time Hub::shutdown may spend saving rooms before the process exits.

Source: crates/calternal-collab/src/session.rs:527