reliar-core 0.3.0

Pure envelope/message model shared by every Reliar crate — no storage or transport dependency.
Documentation
//! `reliar-core` is the pure envelope/message model every Reliar crate builds on: identity
//! newtypes, the [`Message`] contract, a validated [`Headers`] map, typed [`Metadata`], and the
//! [`Envelope`]/[`SerializedEnvelope`] pair that carries them. It has no storage or transport
//! dependency of its own — no sqlx, no broker client, no routing concept (a Kafka partition key,
//! a `RabbitMQ` exchange, a NATS subject) — so it is useful standalone, as the shared vocabulary
//! two independent Reliar crates (say an outbox and a transport) use to talk to each other, or as
//! a typed envelope model for an application that does not use the rest of Reliar at all.
//!
//! # The types you touch
//!
//! - [`Message`] — implement this on your own type to give it a stable, renaming-proof identity
//!   (`TYPE` + `VERSION`), never derived from `std::any::type_name::<T>()` or a module path.
//! - [`Envelope<T>`] / [`SerializedEnvelope`] — the same generic type on both sides of
//!   serialization: an `Envelope<YourType>` on the way in, `Envelope<bytes::Bytes>` once a
//!   [`Serializer`] has turned the body to bytes. Build one with [`Envelope::builder`].
//! - [`Metadata`] — canonical, typed framework metadata (correlation, trace, routing, delivery,
//!   tenant). One source of truth: a value here is never duplicated into [`Headers`], and Reliar
//!   never reads a framework value back out of headers.
//! - [`Headers`] — your own custom, application-defined metadata. A validating newtype, not a
//!   bare map: it rejects the entire `reliar-` prefix case-insensitively, so a custom header can
//!   never collide with — or be mistaken for — a framework one.
//! - [`Serializer`] (default impl: [`JsonSerializer`], behind the default `json` feature) —
//!   converts a typed body to and from bytes.
//! - [`Publisher`] — the trait a transport implements to send an envelope; paired with
//!   [`Classify`]/[`FailureKind`] so a caller can tell a retryable failure from a permanent one
//!   without inspecting transport internals.
//!
//! # End to end
//!
//! `JsonSerializer` ships behind the default `json` feature; without it this block still shows
//! the shape but is not compiled (`cargo test --doc --no-default-features` would not see
//! `JsonSerializer`/`JsonError`).
#![cfg_attr(not(feature = "json"), doc = "```ignore")]
#![cfg_attr(feature = "json", doc = "```")]
//! use reliar_core::{Envelope, JsonSerializer, Message, Serializer};
//!
//! #[derive(serde::Serialize, serde::Deserialize)]
//! struct OrderCreated {
//!     order_id: u64,
//! }
//!
//! impl Message for OrderCreated {
//!     const TYPE: &'static str = "orders.created";
//!     const VERSION: u16 = 1;
//! }
//!
//! // Build a typed envelope; `message_type` and the conversation root are derived, not chosen.
//! let envelope = Envelope::builder(OrderCreated { order_id: 42 })
//!     .tenant("acme")
//!     .build();
//! assert_eq!(envelope.message_type.to_string(), "orders.created.v1");
//!
//! // Serialize the body; the serialized envelope is what storage/transport crates see.
//! let serializer = JsonSerializer;
//! let bytes = serializer.serialize(&envelope.body)?;
//! let serialized = envelope.map_body(|_| bytes);
//! assert_eq!(serialized.metadata.tenant_id.as_deref(), Some("acme"));
//! # Ok::<(), reliar_core::JsonError>(())
//! ```
//!
//! Every public error is a hand-rolled, `#[non_exhaustive]` enum with a wired
//! [`std::error::Error::source`] — no `thiserror`, no `anyhow`. `Debug` on payload-bearing types
//! elides the bytes; no `Display` here ever prints a payload, a header value, or a credential.

#![cfg_attr(docsrs, feature(doc_cfg))]
#![forbid(unsafe_code)]
#![warn(missing_docs)]

mod content_type;
mod envelope;
mod failure;
mod headers;
mod ids;
mod mapper;
mod message;
mod metadata;
mod publisher;
mod serializer;
mod settings;

pub use content_type::{ContentType, ContentTypeError};
pub use envelope::{Envelope, EnvelopeBuilder, SerializedEnvelope};
pub use failure::{Classify, FailureKind};
pub use headers::{HeaderError, Headers};
pub use ids::{ConversationId, CorrelationId, IdError, MessageId, RequestId};
pub use mapper::EnvelopeMapper;
pub use message::{Message, MessageType};
pub use metadata::{
    CorrelationMetadata, DeliveryMetadata, EndpointAddress, Metadata, RoutingMetadata, TraceContext,
};
pub use publisher::Publisher;
pub use serializer::Serializer;
pub use settings::SettingsError;

#[cfg(feature = "json")]
#[cfg_attr(docsrs, doc(cfg(feature = "json")))]
pub use serializer::{JsonError, JsonSerializer};

// The crate README's only fenced Rust block is the `JsonSerializer` quickstart; gate the whole
// module on `json` rather than editing static markdown to carry a per-block cfg_attr.
#[cfg(all(doctest, feature = "json"))]
mod readme_doctests;