Skip to main content

solid_pod_rs/
lib.rs

1//! Framework-agnostic Rust library for serving Solid Protocol 0.11 pods.
2//!
3//! `solid-pod-rs` provides LDP resource and container semantics, Web Access
4//! Control (WAC 1.x + 2.0), WebID profile documents, Solid-OIDC 0.1,
5//! NIP-98 HTTP auth, and Solid Notifications 0.2 -- all without coupling
6//! to a specific HTTP framework. Wire it into actix-web, axum, hyper, or
7//! anything else; the crate never mounts routes itself.
8//!
9//! For a turnkey binary, use the sibling crate
10//! [`solid-pod-rs-server`](https://docs.rs/solid-pod-rs-server).
11//!
12//! ## Feature flags
13//!
14//! | Flag | Default | Purpose |
15//! |-------------------------|:-------:|-----------------------------------------------|
16//! | `core` | off | Pure-logic surfaces only — wasm32 / CF Workers. |
17//! | `std` | on | std lib (always; reserved for future no_std).  |
18//! | `tokio-runtime` | on | Tokio + tokio-tungstenite + futures-util.       |
19//! | `notifications` | on | WebSocketChannel2023 + WebhookChannel2023.      |
20//! | `fs-backend` | on | POSIX filesystem storage. |
21//! | `memory-backend` | on | In-process `HashMap` storage (tests/demos). |
22//! | `s3-backend` | off | AWS S3 / S3-compatible object stores. |
23//! | `oidc` | off | Solid-OIDC 0.1 + DPoP. |
24//! | `dpop-replay-cache` | off | DPoP `jti` replay cache (pulls `oidc`). |
25//! | `nip98-schnorr` | off | BIP-340 signature verification for NIP-98. |
26//! | `acl-origin` | off | WAC `acl:origin` enforcement. |
27//! | `security-primitives` | off | SSRF guard + dotfile allowlist. |
28//! | `legacy-notifications` | off | `solid-0.1` WebSocket adapter (SolidOS). |
29//! | `config-loader` | off | Layered config loader with `JSS_*` env vars. |
30//! | `webhook-signing` | off | RFC 9421 Ed25519 webhook signing. |
31//! | `did-nostr-types` | off | Canonical did:nostr types (wasm32-safe). |
32//! | `did-nostr` | off | did:nostr resolver in `interop`. |
33//! | `rate-limit` | off | Sliding-window LRU rate limiter. |
34//! | `quota` | off | Per-pod `.quota.json` sidecar (atomic writes). |
35//! | `mrc20` | off | BIP-341 taproot key chaining for MRC20 tokens. |
36//! | `lws-cid` | off | LWS 1.0 CID self-signed JWT verifier (ES256K). |
37//! | `lws-cid-p256` | off | LWS-CID + ES256 (P-256) algorithm. |
38//! | `lws-cid-eddsa` | off | LWS-CID + EdDSA (Ed25519) algorithm. |
39//! | `lws-cid-full` | off | LWS-CID with all algorithms. |
40//!
41//! `core` consumers wire the crate via `default-features = false,
42//! features = ["core"]` and get only the pure-logic surfaces (no
43//! tokio, no reqwest, no DNS resolver, no filesystem). See
44//! `RELEASE_NOTES.md` v0.4.0-alpha.3 for the absorbed surfaces map.
45//!
46//! ## Module overview
47//!
48//! | Module | Responsibility |
49//! |-----------------|--------------------------------------------------------------|
50//! | [`storage`] | `Storage` trait + FS / Memory / S3 backends. |
51//! | [`ldp`] | Resources, containers, content negotiation, PATCH, `Prefer`. |
52//! | [`wac`] | Access control evaluator + WAC 2.0 conditions framework. |
53//! | [`webid`] | WebID profile documents (emits `solid:oidcIssuer` + CID). |
54//! | [`mashlib`] | SolidOS data-browser HTML wrapper + data-island embed.    |
55//! | [`auth`] | NIP-98 HTTP auth + LWS-CID self-signed JWT verifier. |
56//! | [`payments`] | HTTP 402, Web Ledgers, multi-chain TXO, payment store. |
57//! | [`mrc20`] | MRC20 state chains, JCS, BIP-341 key chaining.       |
58//! | [`provenance`] | git-mark / block-trail provenance primitives + PROV-O.  |
59//! | [`trading`] | Peer-to-peer order book + AMM constant-product pool.  |
60//! | [`notifications`] | WebSocket, Webhook (RFC 9421 signed), legacy adapter. |
61//! | [`error`] | Crate-wide [`PodError`] error type. |
62//! | [`config`] | Layered configuration schema. |
63//! | [`security`] | SSRF guard, dotfile allowlist, CORS, rate limiter. |
64//! | [`quota`] | Per-pod byte-quota enforcement. |
65//! | [`multitenant`] | `PodResolver` trait; path + subdomain modes. |
66//! | [`interop`] | `.well-known/solid`, WebFinger, NodeInfo, did:nostr. |
67//! | [`did_nostr_types`] | Canonical `did:nostr` types (wasm32-safe, `core`). |
68//! | [`provision`] | Pod bootstrap (WebID + containers + type indexes + ACL). |
69//!
70//! ## Quick start
71//!
72//! ```rust,no_run
73//! use solid_pod_rs::storage::memory::MemoryBackend;
74//! use solid_pod_rs::{Storage, evaluate_access, AccessMode};
75//! use bytes::Bytes;
76//! use std::sync::Arc;
77//!
78//! # tokio::runtime::Runtime::new().unwrap().block_on(async {
79//! // 1. Create a storage backend.
80//! let store = Arc::new(MemoryBackend::new());
81//!
82//! // 2. PUT a resource.
83//! store.put("/hello.txt", Bytes::from("world"), "text/plain").await.unwrap();
84//!
85//! // 3. GET it back.
86//! let (body, meta) = store.get("/hello.txt").await.unwrap();
87//! assert_eq!(&body[..], b"world");
88//! assert_eq!(meta.content_type, "text/plain");
89//!
90//! // 4. WAC evaluation (no ACL document = deny by default).
91//! let allowed = evaluate_access(None, Some("https://alice.example/profile/card#me"),
92//!     "/hello.txt", AccessMode::Read, None);
93//! assert!(!allowed);
94//! # });
95//! ```
96//!
97//! ## Attribution
98//!
99//! Rust port of JavaScriptSolidServer. See NOTICE for provenance.
100
101#![doc = include_str!("../README.md")]
102#![deny(unsafe_code)]
103#![warn(rust_2018_idioms)]
104
105// ---------------------------------------------------------------------------
106// Always-compiled (`core`) modules.
107//
108// Pure-logic surfaces: parsers, validators, type definitions. None of
109// these reach for tokio, reqwest, or notify directly. Wasm32 / CF
110// Workers consumers wire these via
111// `default-features = false, features = ["core"]`.
112// ---------------------------------------------------------------------------
113pub mod auth;
114/// Bitcoin taproot transaction building (block-trail write-side). The module's
115/// own inner `#![cfg(all(feature = "mrc20", not(target_arch = "wasm32")))]`
116/// gates it: it compiles to nothing on wasm or without the `mrc20` feature, so
117/// the tx-building never leaks into the wasm `core` surface (ADR-059 D4).
118pub mod bitcoin_tx;
119pub mod config;
120pub mod error;
121pub mod interop;
122pub mod ldp;
123pub mod mashlib;
124pub mod metrics;
125pub mod mrc20;
126pub mod multitenant;
127pub mod payments;
128pub mod provenance;
129pub mod security;
130pub mod trading;
131pub mod wac;
132pub mod webid;
133
134// ---------------------------------------------------------------------------
135// `did-nostr-types`-gated module.
136//
137// Canonical did:nostr types (NostrPubkey, DID-Doc renderers, ServiceEntry)
138// behind a lightweight feature flag. No runtime deps — wasm32 / CF Workers
139// consumers get these via `core`.
140// ---------------------------------------------------------------------------
141#[cfg(feature = "did-nostr-types")]
142pub mod did_nostr_types;
143
144// ---------------------------------------------------------------------------
145// `tokio-runtime`-gated modules.
146//
147// These pull tokio (mpsc, fs, broadcast) or reqwest (HTTP client) and
148// are unavailable to `core` consumers. They are wired in by the
149// `default` feature set so the existing surface from 0.4.0-alpha.2 is
150// preserved bit-for-bit on native builds.
151// ---------------------------------------------------------------------------
152#[cfg(feature = "notifications")]
153pub mod notifications;
154#[cfg(feature = "tokio-runtime")]
155pub mod provision;
156#[cfg(feature = "tokio-runtime")]
157pub mod quota;
158#[cfg(feature = "tokio-runtime")]
159pub mod storage;
160
161#[cfg(feature = "oidc")]
162pub mod oidc;
163
164// ---------------------------------------------------------------------------
165// JSS v0.0.190 Phase 1 port (issue #437) — scaffolds.
166//
167// Parity row 198. Default-off; function body is `todo!()`. Type
168// surface is stable for downstream consumers (NRF,
169// dreamlab-ai-website).
170// ---------------------------------------------------------------------------
171#[cfg(feature = "export-jsonld")]
172pub mod export;
173
174/// Transport-agnostic HTTP / WebSocket handler drivers. Consumers wire
175/// these into their HTTP framework of choice. Feature-gated; present
176/// only when at least one handler is enabled. Respects the F7
177/// library-server boundary — this crate never mounts routes itself.
178#[cfg(feature = "legacy-notifications")]
179pub mod handlers;
180
181// ---------------------------------------------------------------------------
182// `core` re-exports — always available.
183// ---------------------------------------------------------------------------
184pub use auth::nip98::Nip98Verifier;
185pub use auth::self_signed::{
186    CidVerifier, ProofEnvelope, SelfSignedError, SelfSignedVerifier, VerifiedSubject,
187};
188pub use error::PodError;
189pub use interop::{
190    dev_session, nip05_document, verify_nip05, webfinger_response, well_known_solid, DevSession,
191    Nip05Document, SolidWellKnown, WebFingerJrd, WebFingerLink,
192};
193pub use ldp::{
194    apply_json_patch, apply_n3_patch, apply_patch_to_absent, apply_sparql_patch, cache_control_for,
195    evaluate_preconditions, is_rdf_content_type, link_headers, negotiate_format, not_found_headers,
196    options_for, parse_range_header, parse_range_header_v2, patch_dialect_from_mime,
197    server_managed_triples, slice_range, vary_header, ByteRange, ConditionalOutcome,
198    ContainerRepresentation, Graph, OptionsResponse, PatchCreateOutcome, PatchDialect,
199    PatchOutcome, PreferHeader, RangeOutcome, RdfFormat, Term, Triple, ACCEPT_PATCH, ACCEPT_POST,
200    CACHE_CONTROL_RDF, SPARQL_UPDATE_MAX_BYTES,
201};
202pub use mashlib::{MashlibConfig, MashlibMode, DATA_ISLAND_MAX_BYTES};
203pub use metrics::SecurityMetrics;
204pub use multitenant::{PathResolver, PodResolver, ResolvedPath, SubdomainResolver};
205pub use provenance::{
206    prov_ttl, AnchorPolicy, BlockAnchorer, BlockTrailAnchor, ClosedEpoch, EpochAccumulator, GitMark,
207    GitMarker, MerkleProof, ProvenanceError, ProvenanceLog, ProvenanceMark, WriteRecord,
208};
209pub use security::{is_path_allowed, DotfileAllowlist, DotfileError, DotfilePathError};
210pub use wac::{
211    check_origin, evaluate_access, evaluate_access_with_groups, extract_origin_patterns,
212    method_to_mode, mode_name, parse_turtle_acl, serialize_turtle_acl, wac_allow_header,
213    AccessMode, AclDocument, GroupMembership, Origin, OriginDecision, OriginPattern,
214    StaticGroupMembership,
215};
216pub use webid::{
217    extract_nostr_pubkey, extract_oidc_issuer, generate_webid_html,
218    generate_webid_html_with_issuer, validate_webid_html,
219};
220
221// ---------------------------------------------------------------------------
222// `tokio-runtime`-gated re-exports.
223// ---------------------------------------------------------------------------
224#[cfg(feature = "tokio-runtime")]
225pub use provision::{
226    check_admin_override, provision_pod, AdminOverride, ProvisionOutcome, ProvisionPlan,
227    QuotaTracker,
228};
229#[cfg(feature = "quota")]
230pub use quota::FsQuotaStore;
231#[cfg(feature = "tokio-runtime")]
232pub use quota::{QuotaExceeded, QuotaPolicy, QuotaUsage};
233#[cfg(feature = "tokio-runtime")]
234pub use security::{is_safe_url, resolve_and_check, IpClass, SsrfError, SsrfPolicy};
235#[cfg(feature = "tokio-runtime")]
236pub use storage::{ResourceMeta, Storage, StorageEvent};
237
238// ---------------------------------------------------------------------------
239// JSS v0.0.190 Phase 1 port — re-exports (scaffolds).
240// ---------------------------------------------------------------------------
241#[cfg(feature = "export-jsonld")]
242pub use export::{
243    export_pod_jsonld, ExportOptions, PodExportBundle, PodExportEntry, EXPORT_CONTENT_TYPE,
244    EXPORT_JSONLD_CONTEXT,
245};
246
247// ---------------------------------------------------------------------------
248// Embedded documentation tree (feature = "embedded-docs")
249// ---------------------------------------------------------------------------
250
251/// Re-exported so dependants can name `include_dir::Dir` without taking a
252/// direct dependency on the embedding crate.
253#[cfg(feature = "embedded-docs")]
254pub use include_dir;
255
256/// The crate's Diataxis `docs/` tree, embedded at compile time. It lives
257/// here — inside the owning crate's package root — so dependants (notably
258/// `solid-pod-rs-server`'s MCP `list_docs`/`read_docs` tools) serve it from
259/// a self-contained binary even when built from the registry tarball, where
260/// a `../solid-pod-rs/docs` path escape does not exist.
261#[cfg(feature = "embedded-docs")]
262pub static DOCS_DIR: include_dir::Dir<'static> =
263    include_dir::include_dir!("$CARGO_MANIFEST_DIR/docs");