Atex.PLC
(atex v0.9.1)
View Source
Client for the did:plc directory server HTTP API.
did:plc is a self-authenticating DID method that is strongly-consistent,
recoverable, and supports key rotation. The directory server receives and
persists self-signed operation logs for each DID, starting with a genesis
operation that defines the DID identifier itself.
The API is permissionless, but only correctly-signed operations are accepted.
The default server is https://plc.directory, but a custom host can be
supplied via the :host option available on all functions.
Options
All functions accept an optional opts keyword list. Supported keys:
:host- Base URL of the PLC directory server. Defaults toAtex.Config.directory_url/0.
Error returns
Functions return {:error, reason} on failure. Common reasons:
:not_found- The DID is not registered (HTTP 404).:tombstoned- The DID has been permanently deactivated (HTTP 410).:invalid_document- The server returned a body that could not be parsed into anAtex.DID.Document.{:invalid_operation, message}- The submitted operation was rejected by the server, with an explanatory message (HTTP 400).:invalid_operation- The submitted operation was rejected without a message (HTTP 400).%{status: status, body: body}- An unexpected HTTP response.- Any transport-level error from
Req.
Summary
Functions
Submits a new signed PLC operation for the given DID.
Bulk-fetches PLC operations across all DIDs.
Returns the full audit log for the given DID.
Returns the current PLC data for the given DID.
Returns the most recent operation in the operation chain for the given DID.
Returns the current operation chain for the given DID.
Resolves the DID Document for the given did:plc identifier.
Types
Functions
@spec create_op(String.t(), map(), keyword()) :: {:ok, any()} | create_op_error()
Submits a new signed PLC operation for the given DID.
The operation map must be a fully-formed, self-signed PLC operation. The
server validates the signature and the operation's position in the chain
before accepting it.
Supported operation types:
"plc_operation"- A standard update or genesis operation. Required fields:type,rotationKeys,verificationMethods,alsoKnownAs,services,prev,sig."plc_tombstone"- Permanently deactivates the DID. Required fields:type,prev,sig."create"- Legacy genesis operation format (still supported for historical resolution).
Parameters
did- Adid:plcidentifier string.operation- A map representing the signed PLC operation.opts- Optional keyword list. See module docs for supported keys.
Examples
iex> op = %{
...> "type" => "plc_operation",
...> "rotationKeys" => ["did:key:..."],
...> "verificationMethods" => %{"atproto" => "did:key:..."},
...> "alsoKnownAs" => ["at://handle.bsky.social"],
...> "services" => %{"atproto_pds" => %{"type" => "AtprotoPersonalDataServer", "endpoint" => "https://bsky.social"}},
...> "prev" => "bafyreid6awsb6lzc54zxaq2roijyvpbjp5d6mii2xyztn55yli7htyjgqy",
...> "sig" => "..."
...> }
iex> Atex.PLC.create_op("did:plc:ewvi7nxzyoun6zhxrhs64oiz", op)
{:ok, nil}
iex> Atex.PLC.create_op("did:plc:ewvi7nxzyoun6zhxrhs64oiz", %{"sig" => "bad"})
{:error, {:invalid_operation, "Invalid Signature"}}
Bulk-fetches PLC operations across all DIDs.
Results are paginated and returned as a list of log entry maps. Each entry
contains the DID, the operation, its CID hash, a nullified flag, and the
server-assigned createdAt timestamp.
Parameters
opts- Optional keyword list. Supported keys::host- Base URL of the PLC directory server.:count- Number of records to return (default:10, max:1000).:after- ISO 8601 datetime string; return only operations indexed after this timestamp. Useful for cursor-based pagination.
Examples
iex> Atex.PLC.export(count: 2)
{:ok, [%{"did" => "did:plc:...", "nullified" => false, ...}, ...]}
iex> Atex.PLC.export(count: 100, after: "2024-01-01T00:00:00Z")
{:ok, [...]}
Returns the full audit log for the given DID.
Includes every operation ever submitted for the DID, including those that
have been nullified (overridden by a recovery or conflicting operation). Each
entry is a log entry map containing the operation, its CID hash, a
nullified flag, and the timestamp at which the directory received it.
Parameters
did- Adid:plcidentifier string.opts- Optional keyword list. See module docs for supported keys.
Examples
iex> Atex.PLC.get_audit_log("did:plc:ewvi7nxzyoun6zhxrhs64oiz")
{:ok, [%{"did" => "did:plc:ewvi7nxzyoun6zhxrhs64oiz", "nullified" => false, ...}]}
Returns the current PLC data for the given DID.
The response is similar to an operation map but may omit some fields. It reflects the effective state derived from the current operation chain.
Parameters
did- Adid:plcidentifier string.opts- Optional keyword list. See module docs for supported keys.
Examples
iex> Atex.PLC.get_data("did:plc:ewvi7nxzyoun6zhxrhs64oiz")
{:ok, %{"rotationKeys" => [...], "verificationMethods" => %{}, ...}}
Returns the most recent operation in the operation chain for the given DID.
Useful for obtaining the prev CID reference required when constructing a
new signed operation.
Parameters
did- Adid:plcidentifier string.opts- Optional keyword list. See module docs for supported keys.
Examples
iex> Atex.PLC.get_last_op("did:plc:ewvi7nxzyoun6zhxrhs64oiz")
{:ok, %{"type" => "plc_operation", "prev" => nil, ...}}
Returns the current operation chain for the given DID.
This is the authoritative, ordered sequence of operations that make up the DID's history. Unlike the audit log, nullified (overridden) operations are not included.
Parameters
did- Adid:plcidentifier string.opts- Optional keyword list. See module docs for supported keys.
Examples
iex> Atex.PLC.get_op_log("did:plc:ewvi7nxzyoun6zhxrhs64oiz")
{:ok, [%{"type" => "plc_operation", ...}]}
@spec resolve_did( String.t(), keyword() ) :: {:ok, Atex.DID.Document.t()} | error()
Resolves the DID Document for the given did:plc identifier.
Fetches the current DID Document from the directory server and parses it into
an Atex.DID.Document struct.
Parameters
did- Adid:plcidentifier string.opts- Optional keyword list. See module docs for supported keys.
Examples
iex> Atex.PLC.resolve_did("did:plc:ewvi7nxzyoun6zhxrhs64oiz")
{:ok, %Atex.DID.Document{...}}
iex> Atex.PLC.resolve_did("did:plc:doesnotexist")
{:error, :not_found}