Skip to main content

RegistryServer

Struct RegistryServer 

Source
pub struct RegistryServer<S: RegistryStore, L: RateLimiter = NoopRateLimiter> { /* private fields */ }
Expand description

Logical registry handler over an arbitrary RegistryStore.

L is the rate-limiting policy (RFC-ACDP-0008 §4.3). The default NoopRateLimiter accepts every publish; operators that need a real limiter construct via Self::with_rate_limiter.

Implementations§

Source§

impl<S: RegistryStore> RegistryServer<S, NoopRateLimiter>

Source

pub fn try_new( store: S, caps: CapabilitiesDocument, authority: impl Into<String>, ) -> Result<Self, AcdpError>

Production constructor.

Validates that authority is a bare lowercase DNS hostname, validates capabilities against RFC-ACDP-0007 §3, and enforces that caps.registry_did equals did:web:<authority> (per RFC-ACDP-0006 §4.1 step 3 — the registry’s DID document binds it to the authority it claims).

A host:port, scheme-prefixed, or uppercase authority is rejected: the server uses authority to mint ctx_id (acdp://<authority>/…) and origin_registry, and a colon or slash there violates the acdp:// URI authority rule (RFC-ACDP-0002 §3.1). For host:port test setups use Self::try_new_for_test_authority.

Source§

impl<S: RegistryStore, L: RateLimiter> RegistryServer<S, L>

Source

pub fn with_rate_limiter<L2: RateLimiter>( self, limiter: L2, ) -> RegistryServer<S, L2>

Replace the rate-limiting policy (RFC-ACDP-0008 §4.3).

Source

pub fn with_receipt_signer( self, signer: ReceiptSigner, ) -> Result<Self, AcdpError>

Configure receipt minting (ACDP 0.2, RFC-ACDP-0010). Every subsequent verified publish mints a registry-signed receipt atomically with persistence, returns it in the publish response, and serves it on retrieval.

Also advertises the acdp-registry-receipts profile — a registry without a signing key MUST NOT advertise it, so the profile is bound to this call rather than to raw capabilities input. Fails if the signer’s registry_did does not match caps.registry_did (a receipt minted under a foreign DID would fail every consumer’s serving-authority cross-check).

Note: Self::publish_unverified_for_tests never mints — the producer key is not resolved on that path, so a fingerprint attestation would be false.

Source

pub fn store(&self) -> &S

Borrow the underlying store. Useful for tests that want to inspect side-effects directly.

Source

pub fn capabilities(&self) -> &CapabilitiesDocument

GET /.well-known/acdp.json.

Source

pub fn publish_verified_did_key( &self, req: &PublishRequest, idempotency_key: Option<&str>, ) -> Result<PublishResponse, AcdpError>

RFC-conformant publish for did:key producers — no resolver.

Runs the same RFC-ACDP-0003 §2.1 pipeline as [Self::publish_verified], but performs steps 7–8 via the pure did:key verifier (acdp_verify::verify_publish_request_signature_offline), so it is available without the client feature. Rejects did:web (and any other method) producers with key_resolution_failed — those need the resolver-backed [Self::publish_verified].

The capabilities gate still applies: the request is refused unless supported_did_methods includes "did:key".

Source

pub fn publish_verified_did_key_in_tenant( &self, req: &PublishRequest, idempotency_key: Option<&str>, tenant: Option<&str>, ) -> Result<PublishResponse, AcdpError>

Like Self::publish_verified_did_key but binds the publish to a tenant so a multi-tenant store persists tenant_id atomically with the context row — the same contract as [Self::publish_verified_in_tenant]. tenant = None is identical to Self::publish_verified_did_key.

Source

pub fn retrieve( &self, ctx_id: &CtxId, requester: Option<&AgentDid>, ) -> Result<Option<FullContext>, AcdpError>

GET /contexts/{ctx_id}.

Applies the RFC-ACDP-0008 §4.5 disclosure rules:

VisibilityAuthorized requester for retrieval
publicanyone (when caps.anonymous_public_reads is true)
restrictedproducer (agent_id) or any DID in audience
privateproducer (agent_id) or any DID in audience

Returns Ok(None) (not Err) for unauthorized callers — prevents existence leakage via error codes.

Source

pub fn retrieve_body( &self, ctx_id: &CtxId, requester: Option<&AgentDid>, ) -> Result<Option<Body>, AcdpError>

GET /contexts/{ctx_id}/body. See Self::retrieve for visibility rules.

Source

pub fn lineage( &self, lineage_id: &LineageId, requester: Option<&AgentDid>, ) -> Result<Vec<FullContext>, AcdpError>

GET /lineages/{lineage_id}.

BUG-03: applies the same visibility filter as retrieve. A caller who knows or guesses a lineage_id must not be able to surface restricted or private bodies through the lineage endpoint when retrieve(ctx_id, requester) would deny them.

Source

pub fn current( &self, lineage_id: &LineageId, requester: Option<&AgentDid>, ) -> Result<Option<FullContext>, AcdpError>

GET /lineages/{lineage_id}/current.

BUG-03 + BUG-04: returns the newest non-Superseded version visible to the requester. None when the lineage is unknown, when every version is superseded (RFC-ACDP-0004 §5), or when no visible version exists.

Source

pub fn search( &self, params: &SearchParams, requester: Option<&AgentDid>, ) -> Result<SearchResponse, AcdpError>

GET /contexts/search.

Applies the RFC-ACDP-0008 §4.5 search disclosure rules (note the asymmetry vs retrieval): private contexts surface in search only to their producer (audience members must already know the ctx_id).

When caps.anonymous_public_reads is false, an anonymous search request is rejected outright with AcdpError::NotAuthorized (HTTP 403) rather than returning an empty 200. An empty result set would still leak the registry’s existence and confirm that the keyword query ran; the required response is not_authorized (RFC-ACDP-0005 §2.5.5, RFC-ACDP-0008 §6.3, fixture vis-009).

Auto Trait Implementations§

§

impl<S, L> Freeze for RegistryServer<S, L>
where S: Freeze, L: Freeze,

§

impl<S, L> RefUnwindSafe for RegistryServer<S, L>

§

impl<S, L> Send for RegistryServer<S, L>

§

impl<S, L> Sync for RegistryServer<S, L>

§

impl<S, L> Unpin for RegistryServer<S, L>
where S: Unpin, L: Unpin,

§

impl<S, L> UnsafeUnpin for RegistryServer<S, L>
where S: UnsafeUnpin, L: UnsafeUnpin,

§

impl<S, L> UnwindSafe for RegistryServer<S, L>
where S: UnwindSafe, L: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.