Skip to main content

salamander/
lib.rs

1//! SalamanderDB — an embedded event-sourcing engine with instant recovery.
2//!
3//! The append-only log is the only durable structure; everything else is a
4//! rebuildable projection. Losing a catalog, index, projection, snapshot, or
5//! sidecar may change performance, but never answers.
6//!
7//! The engine is generic over its payload type: [`Salamander<B>`] frames,
8//! orders, and persists bodies of any [`Body`] type but never interprets
9//! them (P1 — "general engine underneath, agent memory as a labeled
10//! beachhead"). The agent vocabulary — [`agent::EventBody`],
11//! [`agent::SessionProjection`], `session_view`, `fork` — is a *provided
12//! module* over that engine, in [`agent`]. Agent users open an
13//! [`AgentDb`] and never see the type parameter.
14//!
15//! The crate also provides named streams, atomic batches, optimistic
16//! concurrency, idempotent retries, branches, streaming replay, verified
17//! snapshots, and a committed-batch feed. See the repository README and
18//! roadmap for guides, operational boundaries, and planned work.
19//!
20//! # Custom payloads
21//!
22//! Any serde-serializable, `Clone`, `'static` type is a valid payload —
23//! the agent vocabulary is just one choice. Define your own events and
24//! project them however you like:
25//!
26//! ```
27//! use salamander::{Event, Salamander};
28//! use serde::{Deserialize, Serialize};
29//!
30//! #[derive(Clone, Serialize, Deserialize)]
31//! enum Metric {
32//!     Cpu(f64),
33//!     Mem(u64),
34//! }
35//!
36//! # fn main() -> salamander::Result<()> {
37//! let dir = tempfile::tempdir().unwrap();
38//!
39//! let mut db: Salamander<Metric> = Salamander::open(dir.path())?;
40//! db.append("host-1", Metric::Cpu(0.7))?;
41//! db.append("host-1", Metric::Mem(2048))?;
42//! db.commit()?;
43//! drop(db); // release the single-writer lock before reopening
44//!
45//! // Reopen from disk and read the custom payloads straight back out.
46//! let db: Salamander<Metric> = Salamander::open(dir.path())?;
47//! let mut count = 0;
48//! db.replay("host-1", 0..db.head(), |_e: &Event<Metric>| count += 1)?;
49//! assert_eq!(count, 2);
50//! # Ok(())
51//! # }
52//! ```
53
54#![warn(missing_docs)]
55
56mod branch;
57mod commit;
58mod error;
59mod event;
60mod facade;
61mod log;
62mod migration;
63mod projection;
64mod retention;
65mod snapshot;
66mod stream;
67
68pub mod agent;
69/// Low-level engine framing and codec types. Most users need only the
70/// types re-exported at the crate root (`BranchId`, `StreamId`,
71/// `EventType`, `CodecId`, …); the framing internals here are not a stable
72/// API.
73#[doc(hidden)]
74pub mod format;
75pub mod json;
76pub mod view;
77
78mod db;
79mod introspect;
80
81pub use branch::{BranchInfo, BranchName, BranchStatus, DEFAULT_BRANCH_NAME, MAX_LINEAGE_DEPTH};
82pub use commit::CommitPolicy;
83pub use error::{Result, SalamanderError};
84pub use event::{Body, Event};
85// The non-generic engine facade: the language-neutral boundary the
86// language bindings bind to, and the current home of the committed-batch
87// feed. Reachable (examples and `salamander-py` use these root paths) but
88// hidden from the documented surface — it is an advanced/plumbing layer,
89// not the stable typed Rust API, which is `Salamander`/`AgentDb`/`JsonDb`.
90#[doc(hidden)]
91pub use facade::{
92    AppendBatch as EngineAppendBatch, AppendReceiptDto as EngineAppendReceipt, BranchDto,
93    CommittedBatch, DiffDto, DiffRequestDto, DiffSideDto, DurabilityDto, Engine, EngineError,
94    EngineOptions, ErrorCategory, EventData, ExpectedRevisionDto, FeedBootstrapDescriptor,
95    FeedFilter, FeedHandle, FeedPage, FeedRequest, InputType, PartitionScheme, PartitionStatus,
96    PayloadCodec, ProjectionCursor, ProjectionDescriptor, ProjectionFailure, ProjectionRuntime,
97    ProjectionScope, ProjectionStatus, QueryConsistency, QueryDefinition, QueryHandle,
98    QueryOperation, QueryResult, ReaderHandle, RecordDto, ReplayPage, ReplayRequest,
99    RetentionConsumerStatus, RetentionStatus, StaleReason, MAX_FACADE_BATCH_BYTES,
100    MAX_FACADE_PAYLOAD_BYTES, MAX_REPLAY_PAGE_BYTES, MAX_REPLAY_PAGE_EVENTS,
101};
102pub use format::{
103    BatchId, BincodeCodec, BranchId, CodecId, DatabaseId, EventId, EventType, FormatLimits,
104    FrameKind, JsonCodec, Metadata, OwnedStoredRecord, RecordEnvelopeV2, StoredRecord, StreamId,
105    StreamRevision, TypedCodec,
106};
107#[doc(hidden)]
108pub use log::partition_of;
109pub use log::{LogReader, RecordReader, ReplayEnd, ReplayPlan, StreamSelector, VerificationMode};
110pub use projection::{NamespaceScoped, Projection};
111pub use view::{Change, IndexKey, IndexedView, View};
112
113pub use agent::AgentDb;
114pub use db::{
115    DiffRequest, DiffSide, RetentionApplyResult, RetentionBlocker, RetentionCleanupStatus,
116    RetentionPlan, RetentionPolicy, RetentionPolicyPreview, RetentionSegment, Salamander,
117    TimelineDiff,
118};
119pub use json::{Json, JsonDb};
120pub use migration::{migrate_legacy_branches, migrate_v1, BranchMigrationReport, MigrationReport};
121pub use retention::{
122    RetentionAnchorInfo, RetentionBranchBootstrap, RetentionConsumerBootstrap, RetentionFeedScope,
123    RetentionProjectionCoverage, MAX_BOOTSTRAP_BYTES,
124};
125// Snapshot descriptors are surfaced only through the engine facade
126// (snapshot management is not on the typed `Salamander` API — instant
127// recovery uses snapshots internally). Reachable for bindings, hidden from
128// the documented surface.
129#[doc(hidden)]
130pub use snapshot::{SnapshotInfo, SnapshotManifest, MAX_SNAPSHOT_STATE_BYTES};
131pub use stream::{
132    AppendReceipt, AppendRequest, Durability, ExpectedRevision, IdempotencyKey, NewEvent,
133    ReceiptDurability, StreamName,
134};