1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
// SPDX-License-Identifier: MIT OR Apache-2.0
//! p2panda's high-level Node API is an opinionated, out-of-the-box peer-to-peer stack which
//! orchestrates all individual [p2panda] modules.
//!
//! ```rust
//! # #[tokio::main]
//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
//! # let topic = p2panda::Topic::random();
//! let node = p2panda::spawn().await?;
//! let (tx, rx) = node.stream(topic).await?;
//! # tx.publish(b"Hello!".to_vec()).await?;
//! # Ok(())
//! # }
//! ```
//!
//! It provides peer-to-peer networking, discovery, bootstrap, local-first sync, event streaming,
//! causal ordering, storage, and more in one easy-to-use API.
//!
//! ## Features
//!
//! - High-level p2panda Node API for building decentralised p2p and [local-first] applications with
//! minimal setup
//! - Unified orchestration of p2p networking, node discovery, mDNS, bootstrap, [eventually
//! consistent] sync, event streaming, causal ordering, pruning and persistence
//! - Topic-based [Publish & Subscribe] model with partial replication - sync only the data relevant
//! to a topic
//! - Transport-agnostic event delivery architecture supporting Internet p2p today (QUIC/iroh) and
//! future mesh/radio transports such as BLE and LoRa
//! - Built on single-writer append-only, fork-tolerant CRDT operation logs with pruning,
//! multi-writer causal ordering, and efficient sync
//! - Persistent local SQLite storage for operations, sync state, address books, stream cursors, and
//! soon encryption/access-control state
//! - Event-stream-inspired consumer model with acknowledgements, replay support, at-least-once
//! delivery semantics and crash recovery
//! - Atomic transactional processing pipeline for resilience against crashes and corrupted database
//! state
//! - Observable system state, events, and metrics
//!
//! ## Walkaway Stack
//!
//! The Node API is designed around a separation between the event delivery and event processing
//! layers. Applications built with p2panda should not need to care abot _where_ messages originate
//! from, but rather _how_ they are processed.
//!
//! The stack confidentially discovers nodes interested in the same topic, synchronises missed
//! messages and delivers them to the processing layer.
//!
//! Today this is implemented over the Internet using [iroh] for direct peer-to-peer connections
//! but the abstraction is designed to support additional transports such as LoRa or BLE, including
//! delay-tolerant and store-and-forward mesh network topologies in the future.
//!
//! Application developers primarily interact with the API to monitor networking and sync activity,
//! configure transports and manage access control, while the stack handles message delivery,
//! synchronisation and persistence.
//!
//! This allows applications to remain portable across different network infrastructures - what we
//! refer to as a ["Walkaway Stack"].
//!
//! ### Append-only log operations
//!
//! Application messages are transported using p2panda's `Operation` data type: a single-writer
//! append-only log with pruning support and fork resistance. Multiple logs can coexist
//! independently or form causally-ordered graphs when arranged in multi-writer streams over a
//! topic.
//!
//! Append-only logs are also well-suited for radio-based meshes, where synchronisation needs to
//! remain bandwidth-efficient. State vectors can be exchanged in constant size and work naturally
//! in broadcast-oriented networks.
//!
//! Operations can be thought of as carriers for application data, similar to how IP datagrams
//! transport arbitrary payloads over the Internet.
//!
//! ### Composable event processors
//!
//! Additional system-level functionality can be layered on top of Operations by extending their
//! headers with metadata for pruning, tombstones, causal ordering, group encryption and other
//! behaviours.
//!
//! The design also allows integration with external processors, CRDTs, key agreement solutions,
//! databases, schemas or capability systems such as Willow's [Meadowcap] or [UCAN] for permission
//! checks and delegated access control.
//!
//! ### Multicast by nature
//!
//! Applications generate a Topic (random bytes) and publish messages into it while subscribing to
//! receive messages from other nodes. This follows a [Publish & Subscribe] (PubSub) model.
//!
//! Topics provide a way to group related data. A topic might represent a text document, a chess
//! game session or a chat room for example.
//!
//! ### SQLite database
//!
//! The Node API persists synchronised Operations in a local SQLite database, together with
//! additional state such as address books, causal ordering buffers, topic mappings and stream
//! cursors.
//!
//! Future versions may also store encryption state, secret key material and access control
//! metadata.
//!
//! ### Event streaming and state materialisation
//!
//! Once data is available locally, the stack processes and delivers it to the application layer
//! using concepts inspired by event-streaming systems such as NATS JetStream or Kafka - adapted for
//! decentralised and autonomous p2p networks.
//!
//! Subscribing to a topic creates a stateful stream consumer.
//!
//! Each operation first passes through an internal _system-level_ processing layer where the system
//! validates log integrity, applies pruning rules, performs causal ordering and, in the future,
//! handles decryption.
//!
//! The processed operation is then forwarded to the _application-level_ together with metadata and
//! debugging information.
//!
//! Applications can then apply their own domain-specific processing logic, such as updating a
//! document title, processing a chat message, applying a text CRDT operation or handling a chess
//! move.
//!
//! ### Crash resilience & acknowledgements
//!
//! Operations can be acknowledged after successful processing. Once acknowledged, they are
//! internally marked as processed and will not be delivered again when re-subscribing to the same
//! stream.
//!
//! By default acknowledgements are handled automatically, though manual control is also possible
//! for advanced use cases.
//!
//! This becomes important in scenarios where an application crashes or is terminated during
//! processing - for example on mobile devices. Unacknowledged operations are replayed on the next
//! startup, allowing applications to maintain at-least-once processing guarantees.
//!
//! Internally, processing and state updates are performed atomically using transactions to minimise
//! the risk of corruption during unexpected shutdowns. Combined with acknowledgements and replay
//! support, this provides a resilient foundation for long-running p2p applications.
//!
//! Replay functionality can also be used to rebuild application state after schema changes, logic
//! updates or recovery scenarios.
//!
//! ### Local-first publishing
//!
//! Publishing a message appends a new operation to the right log for the given topic, signs it,
//! persists it locally and forwards it to the networking layer.
//!
//! If nodes are currently connected, operations may be propagated eagerly in real time. Otherwise,
//! missed operations are synchronised automatically the next time nodes are online again.
//!
//! ## Examples
//!
//! ### Topic stream
//!
//! ```rust,no_run
//! # use futures_util::StreamExt;
//! # use p2panda::Topic;
//! # use p2panda::streams::StreamEvent;
//! #
//! # #[tokio::main]
//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
//! // Spawn default, in-memory node with mdns discovery.
//! let node = p2panda::spawn().await?;
//!
//! // Generate random topic.
//! let chat_id = Topic::random();
//!
//! // Publish and subscribe topic stream with sync.
//! let (tx, mut rx) = node.stream(chat_id).await?;
//! tx.publish("Hello, Panda!".to_string()).await?;
//!
//! while let Some(event) = rx.next().await {
//! // React to system events.
//! if let StreamEvent::SyncStarted {
//! remote_node_id,
//! incoming_bytes,
//! ..
//! } = event {
//! println!("syncing {} bytes from {}", incoming_bytes, remote_node_id);
//! }
//!
//! // Handle application messages.
//! if let StreamEvent::Processed { operation, .. } = event {
//! println!(
//! "[{}]: received {} from {}",
//! operation.timestamp(),
//! operation.message(),
//! operation.author(),
//! );
//! }
//! }
//! #
//! # Ok(())
//! # }
//! ```
//!
//! ### Node configuration
//!
//! ```rust,no_run
//! # use p2panda::RelayUrl;
//! #
//! # #[tokio::main]
//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
//! // Public key of node helping to bootstrap the network for any topic.
//! let bootstrap_id = "1021253b4ccdfba6cac196d2b9fa6ebb605b747bcd502d6bf1d46887f04ec913".parse()?;
//!
//! // URL of iroh relay to establish a direct connection over the Internet.
//! let relay_url: RelayUrl = "https://my.relay.link".parse()?;
//!
//! // Persist SQLite database under given file path.
//! let database_url = "db.sqlite";
//!
//! // Check the builder docs for more information on configuration options.
//! let node = p2panda::builder()
//! .database_url(database_url)
//! .bootstrap(bootstrap_id, relay_url.clone())
//! .relay_url(relay_url)
//! .spawn()
//! .await?;
//! #
//! # Ok(())
//! # }
//! ```
//!
//! ### Application messages
//!
//! ```rust
//! # use p2panda::Topic;
//! # use serde::{Serialize, Deserialize};
//! #
//! # #[tokio::main]
//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
//! // This will automatically serialise to CBOR.
//! #[derive(Serialize, Deserialize)]
//! enum CalendarMessage {
//! Update { title: String },
//! Delete,
//! }
//!
//! let node = p2panda::spawn().await?;
//! let topic = Topic::random();
//! let (tx, rx) = node.stream::<CalendarMessage>(topic).await?;
//! # Ok(())
//! # }
//! ```
//!
//! ["Walkaway Stack"]: https://fosdem.org/2026/schedule/event/J3FLC3-walkaway-stack/
//! [Meadowcap]: https://willowprotocol.org/specs/meadowcap/index.html
//! [Publish & Subscribe]: https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern
//! [UCAN]: https://ucan.xyz/
//! [eventually consistent]: https://en.wikipedia.org/wiki/Eventual_consistency
//! [iroh]: https://www.iroh.computer/
//! [local-first]: https://www.inkandswitch.com/local-first-software/
//! [p2panda]: https://p2panda.org
// Useful external types we want to re-export for convenience.
pub use ;
pub use ;
pub use ;
pub use NodeBuilder;
pub use Node;
/// Spawns a `Node` using default configuration parameters.
pub async
/// Returns the builder for a `Node`.