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>
impl<S: RegistryStore> RegistryServer<S, NoopRateLimiter>
Sourcepub fn try_new(
store: S,
caps: CapabilitiesDocument,
authority: impl Into<String>,
) -> Result<Self, AcdpError>
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>
impl<S: RegistryStore, L: RateLimiter> RegistryServer<S, L>
Sourcepub fn with_rate_limiter<L2: RateLimiter>(
self,
limiter: L2,
) -> RegistryServer<S, L2>
pub fn with_rate_limiter<L2: RateLimiter>( self, limiter: L2, ) -> RegistryServer<S, L2>
Replace the rate-limiting policy (RFC-ACDP-0008 §4.3).
Sourcepub fn with_receipt_signer(
self,
signer: ReceiptSigner,
) -> Result<Self, AcdpError>
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.
Sourcepub fn with_lineage_head_receipts(self) -> Result<Self, AcdpError>
pub fn with_lineage_head_receipts(self) -> Result<Self, AcdpError>
Enable lineage-head receipt minting (ACDP 0.3, RFC-ACDP-0011).
Every subsequent Self::current response carries a freshly
minted head receipt (as_of = the registry clock at response
time, ms-truncated), signed with the RFC-ACDP-0010 receipt
signing key — head receipts introduce no new key role (§5, §8).
Also advertises the acdp-registry-head-receipts profile. The
profile’s prerequisite is acdp-registry-receipts (§9): this
method fails unless Self::with_receipt_signer was configured
first — a registry with no receipt key has nothing to sign head
receipts with, and MUST NOT advertise the profile (§6: no
degraded mode on /current). Registries advertising the profile
MUST advertise acdp_version >= 0.3.0 (§9).
Sourcepub fn with_lifecycle(self) -> Result<Self, AcdpError>
pub fn with_lifecycle(self) -> Result<Self, AcdpError>
Enable lifecycle events & retraction (ACDP 0.3, RFC-ACDP-0013).
Advertises the acdp-registry-lifecycle profile (prerequisite:
acdp-registry-core) and activates the
[Self::retract_verified] / [Self::republish_verified]
operation surface, the §7 status derivation (retracted
dominating superseded and expired), the §8.2 default-search
exclusion, and the §8.3 /current head exclusion.
Registries advertising the profile MUST advertise acdp_version
≥ 0.3.0 (§10). The paired RegistryStore must implement
RegistryStore::commit_lifecycle_event — the default trait
impl fails with not_implemented, so a mispaired backend fails
loudly on the first lifecycle write rather than silently
dropping a retraction.
Sourcepub fn store(&self) -> &S
pub fn store(&self) -> &S
Borrow the underlying store. Useful for tests that want to inspect side-effects directly.
Sourcepub fn capabilities(&self) -> &CapabilitiesDocument
pub fn capabilities(&self) -> &CapabilitiesDocument
GET /.well-known/acdp.json.
Sourcepub fn publish_verified_did_key(
&self,
req: &PublishRequest,
idempotency_key: Option<&str>,
) -> Result<PublishResponse, AcdpError>
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".
Sourcepub fn publish_verified_did_key_in_tenant(
&self,
req: &PublishRequest,
idempotency_key: Option<&str>,
tenant: Option<&str>,
) -> Result<PublishResponse, AcdpError>
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.
Sourcepub fn retrieve(
&self,
ctx_id: &CtxId,
requester: Option<&AgentDid>,
) -> Result<Option<FullContext>, AcdpError>
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:
| Visibility | Authorized requester for retrieval |
|---|---|
public | anyone (when caps.anonymous_public_reads is true) |
restricted | producer (agent_id) or any DID in audience |
private | producer (agent_id) or any DID in audience |
Returns Ok(None) (not Err) for unauthorized callers — prevents
existence leakage via error codes.
Sourcepub fn retrieve_body(
&self,
ctx_id: &CtxId,
requester: Option<&AgentDid>,
) -> Result<Option<Body>, AcdpError>
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.
Sourcepub fn lineage(
&self,
lineage_id: &LineageId,
requester: Option<&AgentDid>,
) -> Result<Vec<FullContext>, AcdpError>
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.
Sourcepub fn current(
&self,
lineage_id: &LineageId,
requester: Option<&AgentDid>,
) -> Result<Option<FullContext>, AcdpError>
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 version visible to the
requester that is neither Superseded nor Retracted (a
retracted version is NEVER a head — RFC-ACDP-0013 §8.3, fixture
lc-003; contrast Expired, which remains a servable head).
None when the lineage is unknown, when every version is
superseded or retracted (RFC-ACDP-0004 §5 as amended), or when
no visible version exists. Because head selection excludes
retracted versions, a lineage-head receipt can never name a
retracted head (RFC-ACDP-0011 §4 as amended; the signer’s mint
refusal is the backstop).
When the registry advertises acdp-registry-head-receipts
(Self::with_lineage_head_receipts), the response carries a
freshly minted lineage-head receipt (RFC-ACDP-0011 §6 rule 1:
REQUIRED on /current, no degraded mode). Because the head is
resolved after visibility filtering, the receipt attests the
head as visible to this requester (§4: never an existence leak).
Sourcepub fn search(
&self,
params: &SearchParams,
requester: Option<&AgentDid>,
) -> Result<SearchResponse, AcdpError>
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).
Sourcepub fn retract_verified_did_key(
&self,
event: &LifecycleEvent,
requester: Option<&AgentDid>,
) -> Result<FullContext, AcdpError>
pub fn retract_verified_did_key( &self, event: &LifecycleEvent, requester: Option<&AgentDid>, ) -> Result<FullContext, AcdpError>
[Self::retract_verified] for did:key producers — the §5
signature verification is pure (the DID is the key), so this is
available without the client feature. Rejects did:web (and
any other method) actors with key_resolution_failed.
Sourcepub fn republish_verified_did_key(
&self,
event: &LifecycleEvent,
requester: Option<&AgentDid>,
) -> Result<FullContext, AcdpError>
pub fn republish_verified_did_key( &self, event: &LifecycleEvent, requester: Option<&AgentDid>, ) -> Result<FullContext, AcdpError>
[Self::republish_verified] for did:key producers.
Sourcepub fn record_registry_lifecycle_event(
&self,
event: &LifecycleEvent,
) -> Result<FullContext, AcdpError>
pub fn record_registry_lifecycle_event( &self, event: &LifecycleEvent, ) -> Result<FullContext, AcdpError>
Record a registry-initiated lifecycle event (RFC-ACDP-0013
§6: deployment policy, legal compulsion). Does NOT use the
producer endpoints or their actor rule: actor MUST equal the
registry’s own DID (capabilities.registry_did). Subject to the
same append-only, uniqueness, transition, and shape rules; the
event SHOULD be signed under a key in the registry’s DID
document (a registry advertising acdp-registry-receipts MUST
sign — enforced here when a receipt signer is configured, per
the §5 same-key precedent). This is the protocol-visible form of
“removed by policy”: the body stays served, the withdrawal is
explicit and attributed.