//! Generated by `trust-tasks-codegen` — do not edit by hand.
//!
//! Spec slug: `vta/webvh/dids/update`. Version: `2.0`.
#[allow(unused_imports)]
use serde::{Deserialize, Serialize};
/// Error types.
pub mod error {
/// Error from a `TryFrom` or `FromStr` implementation.
pub struct ConversionError(::std::borrow::Cow<'static, str>);
impl ::std::error::Error for ConversionError {}
impl ::std::fmt::Display for ConversionError {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> Result<(), ::std::fmt::Error> {
::std::fmt::Display::fmt(&self.0, f)
}
}
impl ::std::fmt::Debug for ConversionError {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> Result<(), ::std::fmt::Error> {
::std::fmt::Debug::fmt(&self.0, f)
}
}
impl From<&'static str> for ConversionError {
fn from(value: &'static str) -> Self {
Self(value.into())
}
}
impl From<String> for ConversionError {
fn from(value: String) -> Self {
Self(value.into())
}
}
}
///`DidDocumentChange`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "DidDocumentChange",
/// "type": "object",
/// "required": [
/// "op",
/// "role"
/// ],
/// "properties": {
/// "keyType": {
/// "$ref": "#/definitions/KeyType"
/// },
/// "op": {
/// "description": "`addKey` — a verification method is added, listed in its role's relationship and in `keyRoles`. `retireKey` — a verification method leaves its relationship, `keyRoles` and the document. `revokeKey` — a verification method leaves its relationship and `keyRoles`, and the compromise is recorded (CONVENTIONS.md §7). `rotateUpdateKey` — the log's update key moves to a committed successor. `setPreRotation` — the number of successors committed changes.",
/// "type": "string",
/// "enum": [
/// "addKey",
/// "retireKey",
/// "revokeKey",
/// "rotateUpdateKey",
/// "setPreRotation"
/// ]
/// },
/// "preRotationCount": {
/// "type": "integer",
/// "minimum": 0.0
/// },
/// "publicKeyMultibase": {
/// "type": "string"
/// },
/// "relationships": {
/// "type": "array",
/// "items": {
/// "$ref": "#/definitions/DidVerificationRelationship"
/// },
/// "uniqueItems": true
/// },
/// "role": {
/// "$ref": "#/definitions/KeyRole"
/// },
/// "verificationMethod": {
/// "type": "string"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct DidDocumentChange {
#[serde(
rename = "keyType",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub key_type: ::std::option::Option<KeyType>,
///`addKey` — a verification method is added, listed in its role's relationship and in `keyRoles`. `retireKey` — a verification method leaves its relationship, `keyRoles` and the document. `revokeKey` — a verification method leaves its relationship and `keyRoles`, and the compromise is recorded (CONVENTIONS.md §7). `rotateUpdateKey` — the log's update key moves to a committed successor. `setPreRotation` — the number of successors committed changes.
pub op: DidDocumentChangeOp,
#[serde(
rename = "preRotationCount",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub pre_rotation_count: ::std::option::Option<u64>,
#[serde(
rename = "publicKeyMultibase",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub public_key_multibase: ::std::option::Option<::std::string::String>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub relationships: ::std::option::Option<Vec<DidVerificationRelationship>>,
pub role: KeyRole,
#[serde(
rename = "verificationMethod",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub verification_method: ::std::option::Option<::std::string::String>,
}
impl DidDocumentChange {
pub fn builder() -> builder::DidDocumentChange {
Default::default()
}
}
///`addKey` — a verification method is added, listed in its role's relationship and in `keyRoles`. `retireKey` — a verification method leaves its relationship, `keyRoles` and the document. `revokeKey` — a verification method leaves its relationship and `keyRoles`, and the compromise is recorded (CONVENTIONS.md §7). `rotateUpdateKey` — the log's update key moves to a committed successor. `setPreRotation` — the number of successors committed changes.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "`addKey` — a verification method is added, listed in its role's relationship and in `keyRoles`. `retireKey` — a verification method leaves its relationship, `keyRoles` and the document. `revokeKey` — a verification method leaves its relationship and `keyRoles`, and the compromise is recorded (CONVENTIONS.md §7). `rotateUpdateKey` — the log's update key moves to a committed successor. `setPreRotation` — the number of successors committed changes.",
/// "type": "string",
/// "enum": [
/// "addKey",
/// "retireKey",
/// "revokeKey",
/// "rotateUpdateKey",
/// "setPreRotation"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum DidDocumentChangeOp {
#[serde(rename = "addKey")]
AddKey,
#[serde(rename = "retireKey")]
RetireKey,
#[serde(rename = "revokeKey")]
RevokeKey,
#[serde(rename = "rotateUpdateKey")]
RotateUpdateKey,
#[serde(rename = "setPreRotation")]
SetPreRotation,
}
impl ::std::fmt::Display for DidDocumentChangeOp {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::AddKey => f.write_str("addKey"),
Self::RetireKey => f.write_str("retireKey"),
Self::RevokeKey => f.write_str("revokeKey"),
Self::RotateUpdateKey => f.write_str("rotateUpdateKey"),
Self::SetPreRotation => f.write_str("setPreRotation"),
}
}
}
impl ::std::str::FromStr for DidDocumentChangeOp {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"addKey" => Ok(Self::AddKey),
"retireKey" => Ok(Self::RetireKey),
"revokeKey" => Ok(Self::RevokeKey),
"rotateUpdateKey" => Ok(Self::RotateUpdateKey),
"setPreRotation" => Ok(Self::SetPreRotation),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for DidDocumentChangeOp {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for DidDocumentChangeOp {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for DidDocumentChangeOp {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///What a change would publish, computed by the VTA by running the handler it would run to apply it, and nothing else (CONVENTIONS.md §3.1). This is what a consent surface renders and what an approval is bound to.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "DidDocumentPreview",
/// "description": "What a change would publish, computed by the VTA by running the handler it would run to apply it, and nothing else (CONVENTIONS.md §3.1). This is what a consent surface renders and what an approval is bound to.",
/// "type": "object",
/// "required": [
/// "baseVersionId",
/// "changes",
/// "document",
/// "expiresAt",
/// "previewId",
/// "updateKeyRotates"
/// ],
/// "properties": {
/// "baseVersionId": {
/// "description": "versionId of the log entry the plan was computed against. The plan is void once the log moves past it.",
/// "type": "string"
/// },
/// "changes": {
/// "description": "Every change the entry would make, including the ones the caller did not ask for — in particular `rotateUpdateKey`, which accompanies every entry appended under pre-rotation.",
/// "type": "array",
/// "items": {
/// "$ref": "#/definitions/DidDocumentChange"
/// }
/// },
/// "document": {
/// "description": "The complete DID document the entry would publish. Public data by construction; no key material beyond public halves.",
/// "type": "object"
/// },
/// "expiresAt": {
/// "type": "string",
/// "format": "date-time"
/// },
/// "previewId": {
/// "description": "Opaque, unguessable identifier for this exact plan. Carried back by the apply request, and the thing every approval is bound to.",
/// "type": "string",
/// "minLength": 16
/// },
/// "updateKeyRotates": {
/// "description": "True when appending this entry also moves the DID's update key to a committed successor. Stated as its own member, not left to be found in `changes`, because it is the consequence a reviewer most often misses.",
/// "type": "boolean"
/// },
/// "warnings": {
/// "description": "Conditions a human should be shown before approving. `preRotationDisabled` — the entry leaves no committed successor, so a later update-key compromise can only end in deactivation. `singleKeyRole` — the role will hold one active key, so its next compromise empties it until replaced. `algorithmNotInAcceptedSet` — a verifier population the VTA knows of does not accept the new key's algorithm. `roleWillHaveNoClassicalKey` — every remaining key is post-quantum, which verifiers without post-quantum support cannot check. `attestationReissuanceRequired` — revoking this `attestation` key obliges the node to re-issue every attestation artefact still in force and re-sign every status list (VTI-KEY-133). `serverless` — the VTA will not publish the entry; the operator must.",
/// "type": "array",
/// "items": {
/// "type": "string",
/// "enum": [
/// "preRotationDisabled",
/// "singleKeyRole",
/// "algorithmNotInAcceptedSet",
/// "roleWillHaveNoClassicalKey",
/// "attestationReissuanceRequired",
/// "serverless"
/// ]
/// },
/// "uniqueItems": true
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct DidDocumentPreview {
///versionId of the log entry the plan was computed against. The plan is void once the log moves past it.
#[serde(rename = "baseVersionId")]
pub base_version_id: ::std::string::String,
///Every change the entry would make, including the ones the caller did not ask for — in particular `rotateUpdateKey`, which accompanies every entry appended under pre-rotation.
pub changes: ::std::vec::Vec<DidDocumentChange>,
///The complete DID document the entry would publish. Public data by construction; no key material beyond public halves.
pub document: ::serde_json::Map<::std::string::String, ::serde_json::Value>,
#[serde(rename = "expiresAt")]
pub expires_at: ::chrono::DateTime<::chrono::offset::Utc>,
///Opaque, unguessable identifier for this exact plan. Carried back by the apply request, and the thing every approval is bound to.
#[serde(rename = "previewId")]
pub preview_id: DidDocumentPreviewPreviewId,
///True when appending this entry also moves the DID's update key to a committed successor. Stated as its own member, not left to be found in `changes`, because it is the consequence a reviewer most often misses.
#[serde(rename = "updateKeyRotates")]
pub update_key_rotates: bool,
///Conditions a human should be shown before approving. `preRotationDisabled` — the entry leaves no committed successor, so a later update-key compromise can only end in deactivation. `singleKeyRole` — the role will hold one active key, so its next compromise empties it until replaced. `algorithmNotInAcceptedSet` — a verifier population the VTA knows of does not accept the new key's algorithm. `roleWillHaveNoClassicalKey` — every remaining key is post-quantum, which verifiers without post-quantum support cannot check. `attestationReissuanceRequired` — revoking this `attestation` key obliges the node to re-issue every attestation artefact still in force and re-sign every status list (VTI-KEY-133). `serverless` — the VTA will not publish the entry; the operator must.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub warnings: ::std::option::Option<Vec<DidDocumentPreviewWarningsItem>>,
}
impl DidDocumentPreview {
pub fn builder() -> builder::DidDocumentPreview {
Default::default()
}
}
///Opaque, unguessable identifier for this exact plan. Carried back by the apply request, and the thing every approval is bound to.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Opaque, unguessable identifier for this exact plan. Carried back by the apply request, and the thing every approval is bound to.",
/// "type": "string",
/// "minLength": 16
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct DidDocumentPreviewPreviewId(::std::string::String);
impl ::std::ops::Deref for DidDocumentPreviewPreviewId {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<DidDocumentPreviewPreviewId> for ::std::string::String {
fn from(value: DidDocumentPreviewPreviewId) -> Self {
value.0
}
}
impl ::std::str::FromStr for DidDocumentPreviewPreviewId {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() < 16usize {
return Err("shorter than 16 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for DidDocumentPreviewPreviewId {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for DidDocumentPreviewPreviewId {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for DidDocumentPreviewPreviewId {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for DidDocumentPreviewPreviewId {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///`DidDocumentPreviewWarningsItem`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "enum": [
/// "preRotationDisabled",
/// "singleKeyRole",
/// "algorithmNotInAcceptedSet",
/// "roleWillHaveNoClassicalKey",
/// "attestationReissuanceRequired",
/// "serverless"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum DidDocumentPreviewWarningsItem {
#[serde(rename = "preRotationDisabled")]
PreRotationDisabled,
#[serde(rename = "singleKeyRole")]
SingleKeyRole,
#[serde(rename = "algorithmNotInAcceptedSet")]
AlgorithmNotInAcceptedSet,
#[serde(rename = "roleWillHaveNoClassicalKey")]
RoleWillHaveNoClassicalKey,
#[serde(rename = "attestationReissuanceRequired")]
AttestationReissuanceRequired,
#[serde(rename = "serverless")]
Serverless,
}
impl ::std::fmt::Display for DidDocumentPreviewWarningsItem {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::PreRotationDisabled => f.write_str("preRotationDisabled"),
Self::SingleKeyRole => f.write_str("singleKeyRole"),
Self::AlgorithmNotInAcceptedSet => f.write_str("algorithmNotInAcceptedSet"),
Self::RoleWillHaveNoClassicalKey => f.write_str("roleWillHaveNoClassicalKey"),
Self::AttestationReissuanceRequired => f.write_str("attestationReissuanceRequired"),
Self::Serverless => f.write_str("serverless"),
}
}
}
impl ::std::str::FromStr for DidDocumentPreviewWarningsItem {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"preRotationDisabled" => Ok(Self::PreRotationDisabled),
"singleKeyRole" => Ok(Self::SingleKeyRole),
"algorithmNotInAcceptedSet" => Ok(Self::AlgorithmNotInAcceptedSet),
"roleWillHaveNoClassicalKey" => Ok(Self::RoleWillHaveNoClassicalKey),
"attestationReissuanceRequired" => Ok(Self::AttestationReissuanceRequired),
"serverless" => Ok(Self::Serverless),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for DidDocumentPreviewWarningsItem {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for DidDocumentPreviewWarningsItem {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for DidDocumentPreviewWarningsItem {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///A DID Core verification relationship.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "DidVerificationRelationship",
/// "description": "A DID Core verification relationship.",
/// "type": "string",
/// "enum": [
/// "authentication",
/// "assertionMethod",
/// "keyAgreement",
/// "capabilityInvocation",
/// "capabilityDelegation"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum DidVerificationRelationship {
#[serde(rename = "authentication")]
Authentication,
#[serde(rename = "assertionMethod")]
AssertionMethod,
#[serde(rename = "keyAgreement")]
KeyAgreement,
#[serde(rename = "capabilityInvocation")]
CapabilityInvocation,
#[serde(rename = "capabilityDelegation")]
CapabilityDelegation,
}
impl ::std::fmt::Display for DidVerificationRelationship {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Authentication => f.write_str("authentication"),
Self::AssertionMethod => f.write_str("assertionMethod"),
Self::KeyAgreement => f.write_str("keyAgreement"),
Self::CapabilityInvocation => f.write_str("capabilityInvocation"),
Self::CapabilityDelegation => f.write_str("capabilityDelegation"),
}
}
}
impl ::std::str::FromStr for DidVerificationRelationship {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"authentication" => Ok(Self::Authentication),
"assertionMethod" => Ok(Self::AssertionMethod),
"keyAgreement" => Ok(Self::KeyAgreement),
"capabilityInvocation" => Ok(Self::CapabilityInvocation),
"capabilityDelegation" => Ok(Self::CapabilityDelegation),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for DidVerificationRelationship {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for DidVerificationRelationship {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for DidVerificationRelationship {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Ext",
/// "description": "Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.",
/// "type": "object",
/// "minProperties": 1,
/// "additionalProperties": true,
/// "propertyNames": {
/// "pattern": "^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$"
/// }
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(transparent)]
pub struct Ext(pub ::std::collections::HashMap<ExtKey, ::serde_json::Value>);
impl ::std::ops::Deref for Ext {
type Target = ::std::collections::HashMap<ExtKey, ::serde_json::Value>;
fn deref(&self) -> &::std::collections::HashMap<ExtKey, ::serde_json::Value> {
&self.0
}
}
impl ::std::convert::From<Ext> for ::std::collections::HashMap<ExtKey, ::serde_json::Value> {
fn from(value: Ext) -> Self {
value.0
}
}
impl ::std::convert::From<::std::collections::HashMap<ExtKey, ::serde_json::Value>> for Ext {
fn from(value: ::std::collections::HashMap<ExtKey, ::serde_json::Value>) -> Self {
Self(value)
}
}
///`ExtKey`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "pattern": "^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ExtKey(::std::string::String);
impl ::std::ops::Deref for ExtKey {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ExtKey> for ::std::string::String {
fn from(value: ExtKey) -> Self {
value.0
}
}
impl ::std::str::FromStr for ExtKey {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| {
::regress::Regex::new("^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ExtKey {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for ExtKey {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for ExtKey {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for ExtKey {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///The named key role a key occupies in the DID (VTI-KEY-070 onward). `attestation` — the only keys in `assertionMethod`; sign the DID's attestation artefacts (membership and role credentials, endorsements, status lists, every other credential the node issues), through the VTA's signing service and nowhere else. Generated inside the VTA, never derived, never exportable, never in a backup. `operational` — the only keys in `authentication`; sign the node's own traffic (Trust Task requests and responses, DIDComm and TSP message signatures, invitations, notices, audit checkpoints) with proof purpose `authentication`. `messaging` — the only keys in `keyAgreement`; sign nothing. `update` — the keys that authorize appending to the DID's log (a did:webvh `updateKeys` entry) and the pre-rotation commitments that authorize the next ones; never a verification method, never in `keyRoles`. Generated inside the VTA, never derived, never exportable, never in a backup. No role permits `capabilityInvocation` or `capabilityDelegation` (VTI-KEY-075); both are reserved for a future role. The mapping is normative and is set out in CONVENTIONS.md §1. The set is an extensible registry and growing it is a MINOR change: a consumer that receives a role it does not implement MUST refuse the document rather than map the key onto a role it does know.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "KeyRole",
/// "description": "The named key role a key occupies in the DID (VTI-KEY-070 onward). `attestation` — the only keys in `assertionMethod`; sign the DID's attestation artefacts (membership and role credentials, endorsements, status lists, every other credential the node issues), through the VTA's signing service and nowhere else. Generated inside the VTA, never derived, never exportable, never in a backup. `operational` — the only keys in `authentication`; sign the node's own traffic (Trust Task requests and responses, DIDComm and TSP message signatures, invitations, notices, audit checkpoints) with proof purpose `authentication`. `messaging` — the only keys in `keyAgreement`; sign nothing. `update` — the keys that authorize appending to the DID's log (a did:webvh `updateKeys` entry) and the pre-rotation commitments that authorize the next ones; never a verification method, never in `keyRoles`. Generated inside the VTA, never derived, never exportable, never in a backup. No role permits `capabilityInvocation` or `capabilityDelegation` (VTI-KEY-075); both are reserved for a future role. The mapping is normative and is set out in CONVENTIONS.md §1. The set is an extensible registry and growing it is a MINOR change: a consumer that receives a role it does not implement MUST refuse the document rather than map the key onto a role it does know.",
/// "type": "string",
/// "enum": [
/// "attestation",
/// "operational",
/// "messaging",
/// "update"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum KeyRole {
#[serde(rename = "attestation")]
Attestation,
#[serde(rename = "operational")]
Operational,
#[serde(rename = "messaging")]
Messaging,
#[serde(rename = "update")]
Update,
}
impl ::std::fmt::Display for KeyRole {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Attestation => f.write_str("attestation"),
Self::Operational => f.write_str("operational"),
Self::Messaging => f.write_str("messaging"),
Self::Update => f.write_str("update"),
}
}
}
impl ::std::str::FromStr for KeyRole {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"attestation" => Ok(Self::Attestation),
"operational" => Ok(Self::Operational),
"messaging" => Ok(Self::Messaging),
"update" => Ok(Self::Update),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for KeyRole {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for KeyRole {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for KeyRole {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///Approval progress of a change the VTA's policy gates on more than one approval (CONVENTIONS.md §3.3).
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "KeyRoleApprovalState",
/// "description": "Approval progress of a change the VTA's policy gates on more than one approval (CONVENTIONS.md §3.3).",
/// "type": "object",
/// "required": [
/// "expiresAt",
/// "received",
/// "required"
/// ],
/// "properties": {
/// "approvers": {
/// "description": "VIDs whose approvals were recorded. Custody projection only; omitted from a response to anyone who is not themselves an eligible approver of this change.",
/// "type": "array",
/// "items": {
/// "type": "string"
/// },
/// "uniqueItems": true
/// },
/// "expiresAt": {
/// "description": "When the preview, and every approval bound to it, stops being usable.",
/// "type": "string",
/// "format": "date-time"
/// },
/// "received": {
/// "description": "Distinct approvals recorded so far, including the initiator's own.",
/// "type": "integer",
/// "minimum": 0.0
/// },
/// "required": {
/// "description": "Distinct approvals the VTA's policy requires.",
/// "type": "integer",
/// "minimum": 1.0
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct KeyRoleApprovalState {
///VIDs whose approvals were recorded. Custody projection only; omitted from a response to anyone who is not themselves an eligible approver of this change.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub approvers: ::std::option::Option<Vec<::std::string::String>>,
///When the preview, and every approval bound to it, stops being usable.
#[serde(rename = "expiresAt")]
pub expires_at: ::chrono::DateTime<::chrono::offset::Utc>,
///Distinct approvals recorded so far, including the initiator's own.
pub received: u64,
///Distinct approvals the VTA's policy requires.
pub required: ::std::num::NonZeroU64,
}
impl KeyRoleApprovalState {
pub fn builder() -> builder::KeyRoleApprovalState {
Default::default()
}
}
///`preview` — nothing was written; the response carries the plan. `applied` — the entry was appended (and published, unless `serverless`). `pendingApproval` — the plan is recorded and awaits further approvals; nothing is published until they arrive (CONVENTIONS.md §3.3).
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "KeyRoleChangeOutcome",
/// "description": "`preview` — nothing was written; the response carries the plan. `applied` — the entry was appended (and published, unless `serverless`). `pendingApproval` — the plan is recorded and awaits further approvals; nothing is published until they arrive (CONVENTIONS.md §3.3).",
/// "type": "string",
/// "enum": [
/// "preview",
/// "applied",
/// "pendingApproval"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum KeyRoleChangeOutcome {
#[serde(rename = "preview")]
Preview,
#[serde(rename = "applied")]
Applied,
#[serde(rename = "pendingApproval")]
PendingApproval,
}
impl ::std::fmt::Display for KeyRoleChangeOutcome {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Preview => f.write_str("preview"),
Self::Applied => f.write_str("applied"),
Self::PendingApproval => f.write_str("pendingApproval"),
}
}
}
impl ::std::str::FromStr for KeyRoleChangeOutcome {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"preview" => Ok(Self::Preview),
"applied" => Ok(Self::Applied),
"pendingApproval" => Ok(Self::PendingApproval),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for KeyRoleChangeOutcome {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for KeyRoleChangeOutcome {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for KeyRoleChangeOutcome {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///Cryptographic algorithm the key material belongs to. `ed25519` signs (EdDSA), `x25519` performs key agreement and never signs, `p256` signs (ES256), and `mldsa44` and `mldsa65` sign with the post-quantum ML-DSA scheme of US NIST FIPS 204. The set is expected to grow as algorithms are standardised, and growing it is a MINOR change under SPEC.md §5.2: `keyType` selects no schema branch, so adding a value relaxes a constraint rather than narrowing one, and the generated libraries mark this enumeration non-exhaustive so that a consumer absorbs a new value rather than failing to compile. Two ML-DSA parameter sets are carried because two specifications require different ones — W3C Quantum-Resistant Cryptosuites defines Data Integrity suites only for ML-DSA-44, while Trust Spanning Protocol Rev 3 §8.1 mandates ML-DSA-65 — so the parameter set is chosen by whatever consumes the key and the two are not redundant. A consumer that does not implement a value it receives MUST refuse the document rather than substitute one it does support.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "KeyType",
/// "description": "Cryptographic algorithm the key material belongs to. `ed25519` signs (EdDSA), `x25519` performs key agreement and never signs, `p256` signs (ES256), and `mldsa44` and `mldsa65` sign with the post-quantum ML-DSA scheme of US NIST FIPS 204. The set is expected to grow as algorithms are standardised, and growing it is a MINOR change under SPEC.md §5.2: `keyType` selects no schema branch, so adding a value relaxes a constraint rather than narrowing one, and the generated libraries mark this enumeration non-exhaustive so that a consumer absorbs a new value rather than failing to compile. Two ML-DSA parameter sets are carried because two specifications require different ones — W3C Quantum-Resistant Cryptosuites defines Data Integrity suites only for ML-DSA-44, while Trust Spanning Protocol Rev 3 §8.1 mandates ML-DSA-65 — so the parameter set is chosen by whatever consumes the key and the two are not redundant. A consumer that does not implement a value it receives MUST refuse the document rather than substitute one it does support.",
/// "type": "string",
/// "enum": [
/// "ed25519",
/// "x25519",
/// "p256",
/// "mldsa44",
/// "mldsa65"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum KeyType {
#[serde(rename = "ed25519")]
Ed25519,
#[serde(rename = "x25519")]
X25519,
#[serde(rename = "p256")]
P256,
#[serde(rename = "mldsa44")]
Mldsa44,
#[serde(rename = "mldsa65")]
Mldsa65,
}
impl ::std::fmt::Display for KeyType {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Ed25519 => f.write_str("ed25519"),
Self::X25519 => f.write_str("x25519"),
Self::P256 => f.write_str("p256"),
Self::Mldsa44 => f.write_str("mldsa44"),
Self::Mldsa65 => f.write_str("mldsa65"),
}
}
}
impl ::std::str::FromStr for KeyType {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"ed25519" => Ok(Self::Ed25519),
"x25519" => Ok(Self::X25519),
"p256" => Ok(Self::P256),
"mldsa44" => Ok(Self::Mldsa44),
"mldsa65" => Ok(Self::Mldsa65),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for KeyType {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for KeyType {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for KeyType {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///Ask a Verifiable Trust Agent to publish a new entry in a did:webvh log it holds the update key for, changing anything but the DID's keys. Keys change only through the key-role tasks (vta/_shared/0.3/CONVENTIONS.md).
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "$id": "https://trusttasks.org/spec/vta/webvh/dids/update/2.0",
/// "title": "Payload",
/// "description": "Ask a Verifiable Trust Agent to publish a new entry in a did:webvh log it holds the update key for, changing anything but the DID's keys. Keys change only through the key-role tasks (vta/_shared/0.3/CONVENTIONS.md).",
/// "type": "object",
/// "required": [
/// "did"
/// ],
/// "properties": {
/// "did": {
/// "description": "The did:webvh being updated. The agent MUST verify it speaks for this subject.",
/// "type": "string",
/// "minLength": 1
/// },
/// "document": {
/// "description": "The new DID document. Omit to leave it unchanged. It MUST carry, unchanged, the current `verificationMethod`, `authentication`, `assertionMethod`, `keyAgreement`, `capabilityInvocation`, `capabilityDelegation` and `keyRoles` members: a change to any of them is refused with `vta/webvh/dids/update:keyMembersManaged`, because keys change only through the key-role tasks. Appending the entry still rotates the DID's update key under pre-rotation, which a consent surface MUST render from the executor's preview, never from this document.",
/// "type": "object"
/// },
/// "dryRun": {
/// "description": "Compute and return the preview without writing anything but the plan (CONVENTIONS.md §3.1). Absent reads as false.",
/// "type": "boolean"
/// },
/// "expectedVersionId": {
/// "description": "Optimistic-concurrency precondition: the versionId the caller based this edit on. The agent MUST refuse the update if the DID's latest entry no longer matches. Without it a `get -> edit -> save` cycle silently overwrites a concurrent edit with a chain that is structurally valid, verifies perfectly, and is based on a stale read. Where a human approves the update the window is minutes wide, so this is a routine race rather than an exotic one. OPTIONAL because a scripted caller with no concurrent writers has nothing to protect against; not optional for anything a person looked at.",
/// "type": "string",
/// "minLength": 1
/// },
/// "ext": {
/// "$ref": "#/definitions/Ext"
/// },
/// "label": {
/// "description": "Operator-facing audit label.",
/// "type": "string",
/// "maxLength": 256
/// },
/// "preRotationCount": {
/// "description": "Number of pre-rotation commitments to publish. Omit to keep the current count. `0` is refused for a durable node identity (`vta/webvh/dids:preRotationRequired`).",
/// "type": "integer",
/// "minimum": 0.0
/// },
/// "previewId": {
/// "description": "Apply exactly the plan a previous dry run of this same request returned; what an approval is bound to (CONVENTIONS.md §3.1–§3.2).",
/// "type": "string",
/// "minLength": 16
/// },
/// "ttl": {
/// "description": "New TTL in seconds. Omit to keep the current value.",
/// "type": "integer",
/// "minimum": 0.0
/// },
/// "watchers": {
/// "description": "New watcher URLs. Omit to keep the current set; an empty array removes them.",
/// "type": "array",
/// "items": {
/// "type": "string"
/// }
/// },
/// "witnesses": {
/// "description": "New witness configuration. Omit to keep the current one."
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct Payload {
///The did:webvh being updated. The agent MUST verify it speaks for this subject.
pub did: PayloadDid,
///The new DID document. Omit to leave it unchanged. It MUST carry, unchanged, the current `verificationMethod`, `authentication`, `assertionMethod`, `keyAgreement`, `capabilityInvocation`, `capabilityDelegation` and `keyRoles` members: a change to any of them is refused with `vta/webvh/dids/update:keyMembersManaged`, because keys change only through the key-role tasks. Appending the entry still rotates the DID's update key under pre-rotation, which a consent surface MUST render from the executor's preview, never from this document.
#[serde(default, skip_serializing_if = "::serde_json::Map::is_empty")]
pub document: ::serde_json::Map<::std::string::String, ::serde_json::Value>,
///Compute and return the preview without writing anything but the plan (CONVENTIONS.md §3.1). Absent reads as false.
#[serde(
rename = "dryRun",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub dry_run: ::std::option::Option<bool>,
///Optimistic-concurrency precondition: the versionId the caller based this edit on. The agent MUST refuse the update if the DID's latest entry no longer matches. Without it a `get -> edit -> save` cycle silently overwrites a concurrent edit with a chain that is structurally valid, verifies perfectly, and is based on a stale read. Where a human approves the update the window is minutes wide, so this is a routine race rather than an exotic one. OPTIONAL because a scripted caller with no concurrent writers has nothing to protect against; not optional for anything a person looked at.
#[serde(
rename = "expectedVersionId",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub expected_version_id: ::std::option::Option<PayloadExpectedVersionId>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ext: ::std::option::Option<Ext>,
///Operator-facing audit label.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub label: ::std::option::Option<PayloadLabel>,
///Number of pre-rotation commitments to publish. Omit to keep the current count. `0` is refused for a durable node identity (`vta/webvh/dids:preRotationRequired`).
#[serde(
rename = "preRotationCount",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub pre_rotation_count: ::std::option::Option<u64>,
///Apply exactly the plan a previous dry run of this same request returned; what an approval is bound to (CONVENTIONS.md §3.1–§3.2).
#[serde(
rename = "previewId",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub preview_id: ::std::option::Option<PayloadPreviewId>,
///New TTL in seconds. Omit to keep the current value.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ttl: ::std::option::Option<u64>,
///New watcher URLs. Omit to keep the current set; an empty array removes them.
#[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")]
pub watchers: ::std::vec::Vec<::std::string::String>,
///New witness configuration. Omit to keep the current one.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub witnesses: ::std::option::Option<::serde_json::Value>,
}
impl Payload {
pub fn builder() -> builder::Payload {
Default::default()
}
}
///The did:webvh being updated. The agent MUST verify it speaks for this subject.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "The did:webvh being updated. The agent MUST verify it speaks for this subject.",
/// "type": "string",
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PayloadDid(::std::string::String);
impl ::std::ops::Deref for PayloadDid {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PayloadDid> for ::std::string::String {
fn from(value: PayloadDid) -> Self {
value.0
}
}
impl ::std::str::FromStr for PayloadDid {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for PayloadDid {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for PayloadDid {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for PayloadDid {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for PayloadDid {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///Optimistic-concurrency precondition: the versionId the caller based this edit on. The agent MUST refuse the update if the DID's latest entry no longer matches. Without it a `get -> edit -> save` cycle silently overwrites a concurrent edit with a chain that is structurally valid, verifies perfectly, and is based on a stale read. Where a human approves the update the window is minutes wide, so this is a routine race rather than an exotic one. OPTIONAL because a scripted caller with no concurrent writers has nothing to protect against; not optional for anything a person looked at.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Optimistic-concurrency precondition: the versionId the caller based this edit on. The agent MUST refuse the update if the DID's latest entry no longer matches. Without it a `get -> edit -> save` cycle silently overwrites a concurrent edit with a chain that is structurally valid, verifies perfectly, and is based on a stale read. Where a human approves the update the window is minutes wide, so this is a routine race rather than an exotic one. OPTIONAL because a scripted caller with no concurrent writers has nothing to protect against; not optional for anything a person looked at.",
/// "type": "string",
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PayloadExpectedVersionId(::std::string::String);
impl ::std::ops::Deref for PayloadExpectedVersionId {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PayloadExpectedVersionId> for ::std::string::String {
fn from(value: PayloadExpectedVersionId) -> Self {
value.0
}
}
impl ::std::str::FromStr for PayloadExpectedVersionId {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for PayloadExpectedVersionId {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for PayloadExpectedVersionId {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for PayloadExpectedVersionId {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for PayloadExpectedVersionId {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///Operator-facing audit label.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Operator-facing audit label.",
/// "type": "string",
/// "maxLength": 256
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PayloadLabel(::std::string::String);
impl ::std::ops::Deref for PayloadLabel {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PayloadLabel> for ::std::string::String {
fn from(value: PayloadLabel) -> Self {
value.0
}
}
impl ::std::str::FromStr for PayloadLabel {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 256usize {
return Err("longer than 256 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for PayloadLabel {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for PayloadLabel {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for PayloadLabel {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for PayloadLabel {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///Apply exactly the plan a previous dry run of this same request returned; what an approval is bound to (CONVENTIONS.md §3.1–§3.2).
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Apply exactly the plan a previous dry run of this same request returned; what an approval is bound to (CONVENTIONS.md §3.1–§3.2).",
/// "type": "string",
/// "minLength": 16
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PayloadPreviewId(::std::string::String);
impl ::std::ops::Deref for PayloadPreviewId {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PayloadPreviewId> for ::std::string::String {
fn from(value: PayloadPreviewId) -> Self {
value.0
}
}
impl ::std::str::FromStr for PayloadPreviewId {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() < 16usize {
return Err("shorter than 16 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for PayloadPreviewId {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for PayloadPreviewId {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for PayloadPreviewId {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for PayloadPreviewId {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///The outcome. `preview` and `pendingApproval` carry the plan; `applied` carries the published entry.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Response",
/// "description": "The outcome. `preview` and `pendingApproval` carry the plan; `applied` carries the published entry.",
/// "type": "object",
/// "required": [
/// "did",
/// "outcome"
/// ],
/// "properties": {
/// "approvals": {
/// "$ref": "#/definitions/KeyRoleApprovalState"
/// },
/// "did": {
/// "type": "string"
/// },
/// "ext": {
/// "$ref": "#/definitions/Ext"
/// },
/// "newLogEntry": {
/// "description": "The appended log entry, as JSON text.",
/// "type": "string"
/// },
/// "newScid": {
/// "type": "string"
/// },
/// "newVersionId": {
/// "description": "versionId of the entry just appended. A caller intending a further edit SHOULD pass this back as the next request's `expectedVersionId`.",
/// "type": "string"
/// },
/// "outcome": {
/// "$ref": "#/definitions/KeyRoleChangeOutcome"
/// },
/// "preRotationKeyCount": {
/// "description": "Pre-rotation commitments published by this entry.",
/// "type": "integer",
/// "minimum": 0.0
/// },
/// "preview": {
/// "$ref": "#/definitions/DidDocumentPreview"
/// },
/// "serverless": {
/// "description": "True when the agent holds the log itself and no hosting server was published to — the operator must fetch and redeploy `did.jsonl`.",
/// "type": "boolean"
/// },
/// "updateKeysCount": {
/// "description": "Update keys authorized AFTER this entry. Where `document` was supplied these are new keys — the previous ones no longer authorize anything.",
/// "type": "integer",
/// "minimum": 0.0
/// }
/// },
/// "additionalProperties": false,
/// "$anchor": "response"
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct Response {
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub approvals: ::std::option::Option<KeyRoleApprovalState>,
pub did: ::std::string::String,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ext: ::std::option::Option<Ext>,
///The appended log entry, as JSON text.
#[serde(
rename = "newLogEntry",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub new_log_entry: ::std::option::Option<::std::string::String>,
#[serde(
rename = "newScid",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub new_scid: ::std::option::Option<::std::string::String>,
///versionId of the entry just appended. A caller intending a further edit SHOULD pass this back as the next request's `expectedVersionId`.
#[serde(
rename = "newVersionId",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub new_version_id: ::std::option::Option<::std::string::String>,
pub outcome: KeyRoleChangeOutcome,
///Pre-rotation commitments published by this entry.
#[serde(
rename = "preRotationKeyCount",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub pre_rotation_key_count: ::std::option::Option<u64>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub preview: ::std::option::Option<DidDocumentPreview>,
///True when the agent holds the log itself and no hosting server was published to — the operator must fetch and redeploy `did.jsonl`.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub serverless: ::std::option::Option<bool>,
///Update keys authorized AFTER this entry. Where `document` was supplied these are new keys — the previous ones no longer authorize anything.
#[serde(
rename = "updateKeysCount",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub update_keys_count: ::std::option::Option<u64>,
}
impl Response {
pub fn builder() -> builder::Response {
Default::default()
}
}
/// Types for composing complex structures.
pub mod builder {
#[derive(Clone, Debug)]
pub struct DidDocumentChange {
key_type:
::std::result::Result<::std::option::Option<super::KeyType>, ::std::string::String>,
op: ::std::result::Result<super::DidDocumentChangeOp, ::std::string::String>,
pre_rotation_count:
::std::result::Result<::std::option::Option<u64>, ::std::string::String>,
public_key_multibase: ::std::result::Result<
::std::option::Option<::std::string::String>,
::std::string::String,
>,
relationships: ::std::result::Result<
::std::option::Option<Vec<super::DidVerificationRelationship>>,
::std::string::String,
>,
role: ::std::result::Result<super::KeyRole, ::std::string::String>,
verification_method: ::std::result::Result<
::std::option::Option<::std::string::String>,
::std::string::String,
>,
}
impl ::std::default::Default for DidDocumentChange {
fn default() -> Self {
Self {
key_type: Ok(Default::default()),
op: Err("no value supplied for op".to_string()),
pre_rotation_count: Ok(Default::default()),
public_key_multibase: Ok(Default::default()),
relationships: Ok(Default::default()),
role: Err("no value supplied for role".to_string()),
verification_method: Ok(Default::default()),
}
}
}
impl DidDocumentChange {
pub fn key_type<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::KeyType>>,
T::Error: ::std::fmt::Display,
{
self.key_type = value
.try_into()
.map_err(|e| format!("error converting supplied value for key_type: {e}"));
self
}
pub fn op<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::DidDocumentChangeOp>,
T::Error: ::std::fmt::Display,
{
self.op = value
.try_into()
.map_err(|e| format!("error converting supplied value for op: {e}"));
self
}
pub fn pre_rotation_count<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<u64>>,
T::Error: ::std::fmt::Display,
{
self.pre_rotation_count = value.try_into().map_err(|e| {
format!("error converting supplied value for pre_rotation_count: {e}")
});
self
}
pub fn public_key_multibase<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>,
T::Error: ::std::fmt::Display,
{
self.public_key_multibase = value.try_into().map_err(|e| {
format!("error converting supplied value for public_key_multibase: {e}")
});
self
}
pub fn relationships<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<
::std::option::Option<Vec<super::DidVerificationRelationship>>,
>,
T::Error: ::std::fmt::Display,
{
self.relationships = value
.try_into()
.map_err(|e| format!("error converting supplied value for relationships: {e}"));
self
}
pub fn role<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::KeyRole>,
T::Error: ::std::fmt::Display,
{
self.role = value
.try_into()
.map_err(|e| format!("error converting supplied value for role: {e}"));
self
}
pub fn verification_method<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>,
T::Error: ::std::fmt::Display,
{
self.verification_method = value.try_into().map_err(|e| {
format!("error converting supplied value for verification_method: {e}")
});
self
}
}
impl ::std::convert::TryFrom<DidDocumentChange> for super::DidDocumentChange {
type Error = super::error::ConversionError;
fn try_from(
value: DidDocumentChange,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
key_type: value.key_type?,
op: value.op?,
pre_rotation_count: value.pre_rotation_count?,
public_key_multibase: value.public_key_multibase?,
relationships: value.relationships?,
role: value.role?,
verification_method: value.verification_method?,
})
}
}
impl ::std::convert::From<super::DidDocumentChange> for DidDocumentChange {
fn from(value: super::DidDocumentChange) -> Self {
Self {
key_type: Ok(value.key_type),
op: Ok(value.op),
pre_rotation_count: Ok(value.pre_rotation_count),
public_key_multibase: Ok(value.public_key_multibase),
relationships: Ok(value.relationships),
role: Ok(value.role),
verification_method: Ok(value.verification_method),
}
}
}
#[derive(Clone, Debug)]
pub struct DidDocumentPreview {
base_version_id: ::std::result::Result<::std::string::String, ::std::string::String>,
changes:
::std::result::Result<::std::vec::Vec<super::DidDocumentChange>, ::std::string::String>,
document: ::std::result::Result<
::serde_json::Map<::std::string::String, ::serde_json::Value>,
::std::string::String,
>,
expires_at:
::std::result::Result<::chrono::DateTime<::chrono::offset::Utc>, ::std::string::String>,
preview_id:
::std::result::Result<super::DidDocumentPreviewPreviewId, ::std::string::String>,
update_key_rotates: ::std::result::Result<bool, ::std::string::String>,
warnings: ::std::result::Result<
::std::option::Option<Vec<super::DidDocumentPreviewWarningsItem>>,
::std::string::String,
>,
}
impl ::std::default::Default for DidDocumentPreview {
fn default() -> Self {
Self {
base_version_id: Err("no value supplied for base_version_id".to_string()),
changes: Err("no value supplied for changes".to_string()),
document: Err("no value supplied for document".to_string()),
expires_at: Err("no value supplied for expires_at".to_string()),
preview_id: Err("no value supplied for preview_id".to_string()),
update_key_rotates: Err("no value supplied for update_key_rotates".to_string()),
warnings: Ok(Default::default()),
}
}
}
impl DidDocumentPreview {
pub fn base_version_id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::string::String>,
T::Error: ::std::fmt::Display,
{
self.base_version_id = value
.try_into()
.map_err(|e| format!("error converting supplied value for base_version_id: {e}"));
self
}
pub fn changes<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::vec::Vec<super::DidDocumentChange>>,
T::Error: ::std::fmt::Display,
{
self.changes = value
.try_into()
.map_err(|e| format!("error converting supplied value for changes: {e}"));
self
}
pub fn document<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<
::serde_json::Map<::std::string::String, ::serde_json::Value>,
>,
T::Error: ::std::fmt::Display,
{
self.document = value
.try_into()
.map_err(|e| format!("error converting supplied value for document: {e}"));
self
}
pub fn expires_at<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::chrono::DateTime<::chrono::offset::Utc>>,
T::Error: ::std::fmt::Display,
{
self.expires_at = value
.try_into()
.map_err(|e| format!("error converting supplied value for expires_at: {e}"));
self
}
pub fn preview_id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::DidDocumentPreviewPreviewId>,
T::Error: ::std::fmt::Display,
{
self.preview_id = value
.try_into()
.map_err(|e| format!("error converting supplied value for preview_id: {e}"));
self
}
pub fn update_key_rotates<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<bool>,
T::Error: ::std::fmt::Display,
{
self.update_key_rotates = value.try_into().map_err(|e| {
format!("error converting supplied value for update_key_rotates: {e}")
});
self
}
pub fn warnings<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<
::std::option::Option<Vec<super::DidDocumentPreviewWarningsItem>>,
>,
T::Error: ::std::fmt::Display,
{
self.warnings = value
.try_into()
.map_err(|e| format!("error converting supplied value for warnings: {e}"));
self
}
}
impl ::std::convert::TryFrom<DidDocumentPreview> for super::DidDocumentPreview {
type Error = super::error::ConversionError;
fn try_from(
value: DidDocumentPreview,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
base_version_id: value.base_version_id?,
changes: value.changes?,
document: value.document?,
expires_at: value.expires_at?,
preview_id: value.preview_id?,
update_key_rotates: value.update_key_rotates?,
warnings: value.warnings?,
})
}
}
impl ::std::convert::From<super::DidDocumentPreview> for DidDocumentPreview {
fn from(value: super::DidDocumentPreview) -> Self {
Self {
base_version_id: Ok(value.base_version_id),
changes: Ok(value.changes),
document: Ok(value.document),
expires_at: Ok(value.expires_at),
preview_id: Ok(value.preview_id),
update_key_rotates: Ok(value.update_key_rotates),
warnings: Ok(value.warnings),
}
}
}
#[derive(Clone, Debug)]
pub struct KeyRoleApprovalState {
approvers: ::std::result::Result<
::std::option::Option<Vec<::std::string::String>>,
::std::string::String,
>,
expires_at:
::std::result::Result<::chrono::DateTime<::chrono::offset::Utc>, ::std::string::String>,
received: ::std::result::Result<u64, ::std::string::String>,
required: ::std::result::Result<::std::num::NonZeroU64, ::std::string::String>,
}
impl ::std::default::Default for KeyRoleApprovalState {
fn default() -> Self {
Self {
approvers: Ok(Default::default()),
expires_at: Err("no value supplied for expires_at".to_string()),
received: Err("no value supplied for received".to_string()),
required: Err("no value supplied for required".to_string()),
}
}
}
impl KeyRoleApprovalState {
pub fn approvers<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<Vec<::std::string::String>>>,
T::Error: ::std::fmt::Display,
{
self.approvers = value
.try_into()
.map_err(|e| format!("error converting supplied value for approvers: {e}"));
self
}
pub fn expires_at<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::chrono::DateTime<::chrono::offset::Utc>>,
T::Error: ::std::fmt::Display,
{
self.expires_at = value
.try_into()
.map_err(|e| format!("error converting supplied value for expires_at: {e}"));
self
}
pub fn received<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<u64>,
T::Error: ::std::fmt::Display,
{
self.received = value
.try_into()
.map_err(|e| format!("error converting supplied value for received: {e}"));
self
}
pub fn required<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::num::NonZeroU64>,
T::Error: ::std::fmt::Display,
{
self.required = value
.try_into()
.map_err(|e| format!("error converting supplied value for required: {e}"));
self
}
}
impl ::std::convert::TryFrom<KeyRoleApprovalState> for super::KeyRoleApprovalState {
type Error = super::error::ConversionError;
fn try_from(
value: KeyRoleApprovalState,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
approvers: value.approvers?,
expires_at: value.expires_at?,
received: value.received?,
required: value.required?,
})
}
}
impl ::std::convert::From<super::KeyRoleApprovalState> for KeyRoleApprovalState {
fn from(value: super::KeyRoleApprovalState) -> Self {
Self {
approvers: Ok(value.approvers),
expires_at: Ok(value.expires_at),
received: Ok(value.received),
required: Ok(value.required),
}
}
}
#[derive(Clone, Debug)]
pub struct Payload {
did: ::std::result::Result<super::PayloadDid, ::std::string::String>,
document: ::std::result::Result<
::serde_json::Map<::std::string::String, ::serde_json::Value>,
::std::string::String,
>,
dry_run: ::std::result::Result<::std::option::Option<bool>, ::std::string::String>,
expected_version_id: ::std::result::Result<
::std::option::Option<super::PayloadExpectedVersionId>,
::std::string::String,
>,
ext: ::std::result::Result<::std::option::Option<super::Ext>, ::std::string::String>,
label: ::std::result::Result<
::std::option::Option<super::PayloadLabel>,
::std::string::String,
>,
pre_rotation_count:
::std::result::Result<::std::option::Option<u64>, ::std::string::String>,
preview_id: ::std::result::Result<
::std::option::Option<super::PayloadPreviewId>,
::std::string::String,
>,
ttl: ::std::result::Result<::std::option::Option<u64>, ::std::string::String>,
watchers:
::std::result::Result<::std::vec::Vec<::std::string::String>, ::std::string::String>,
witnesses: ::std::result::Result<
::std::option::Option<::serde_json::Value>,
::std::string::String,
>,
}
impl ::std::default::Default for Payload {
fn default() -> Self {
Self {
did: Err("no value supplied for did".to_string()),
document: Ok(Default::default()),
dry_run: Ok(Default::default()),
expected_version_id: Ok(Default::default()),
ext: Ok(Default::default()),
label: Ok(Default::default()),
pre_rotation_count: Ok(Default::default()),
preview_id: Ok(Default::default()),
ttl: Ok(Default::default()),
watchers: Ok(Default::default()),
witnesses: Ok(Default::default()),
}
}
}
impl Payload {
pub fn did<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::PayloadDid>,
T::Error: ::std::fmt::Display,
{
self.did = value
.try_into()
.map_err(|e| format!("error converting supplied value for did: {e}"));
self
}
pub fn document<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<
::serde_json::Map<::std::string::String, ::serde_json::Value>,
>,
T::Error: ::std::fmt::Display,
{
self.document = value
.try_into()
.map_err(|e| format!("error converting supplied value for document: {e}"));
self
}
pub fn dry_run<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<bool>>,
T::Error: ::std::fmt::Display,
{
self.dry_run = value
.try_into()
.map_err(|e| format!("error converting supplied value for dry_run: {e}"));
self
}
pub fn expected_version_id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::PayloadExpectedVersionId>>,
T::Error: ::std::fmt::Display,
{
self.expected_version_id = value.try_into().map_err(|e| {
format!("error converting supplied value for expected_version_id: {e}")
});
self
}
pub fn ext<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::Ext>>,
T::Error: ::std::fmt::Display,
{
self.ext = value
.try_into()
.map_err(|e| format!("error converting supplied value for ext: {e}"));
self
}
pub fn label<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::PayloadLabel>>,
T::Error: ::std::fmt::Display,
{
self.label = value
.try_into()
.map_err(|e| format!("error converting supplied value for label: {e}"));
self
}
pub fn pre_rotation_count<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<u64>>,
T::Error: ::std::fmt::Display,
{
self.pre_rotation_count = value.try_into().map_err(|e| {
format!("error converting supplied value for pre_rotation_count: {e}")
});
self
}
pub fn preview_id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::PayloadPreviewId>>,
T::Error: ::std::fmt::Display,
{
self.preview_id = value
.try_into()
.map_err(|e| format!("error converting supplied value for preview_id: {e}"));
self
}
pub fn ttl<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<u64>>,
T::Error: ::std::fmt::Display,
{
self.ttl = value
.try_into()
.map_err(|e| format!("error converting supplied value for ttl: {e}"));
self
}
pub fn watchers<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::vec::Vec<::std::string::String>>,
T::Error: ::std::fmt::Display,
{
self.watchers = value
.try_into()
.map_err(|e| format!("error converting supplied value for watchers: {e}"));
self
}
pub fn witnesses<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<::serde_json::Value>>,
T::Error: ::std::fmt::Display,
{
self.witnesses = value
.try_into()
.map_err(|e| format!("error converting supplied value for witnesses: {e}"));
self
}
}
impl ::std::convert::TryFrom<Payload> for super::Payload {
type Error = super::error::ConversionError;
fn try_from(value: Payload) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
did: value.did?,
document: value.document?,
dry_run: value.dry_run?,
expected_version_id: value.expected_version_id?,
ext: value.ext?,
label: value.label?,
pre_rotation_count: value.pre_rotation_count?,
preview_id: value.preview_id?,
ttl: value.ttl?,
watchers: value.watchers?,
witnesses: value.witnesses?,
})
}
}
impl ::std::convert::From<super::Payload> for Payload {
fn from(value: super::Payload) -> Self {
Self {
did: Ok(value.did),
document: Ok(value.document),
dry_run: Ok(value.dry_run),
expected_version_id: Ok(value.expected_version_id),
ext: Ok(value.ext),
label: Ok(value.label),
pre_rotation_count: Ok(value.pre_rotation_count),
preview_id: Ok(value.preview_id),
ttl: Ok(value.ttl),
watchers: Ok(value.watchers),
witnesses: Ok(value.witnesses),
}
}
}
#[derive(Clone, Debug)]
pub struct Response {
approvals: ::std::result::Result<
::std::option::Option<super::KeyRoleApprovalState>,
::std::string::String,
>,
did: ::std::result::Result<::std::string::String, ::std::string::String>,
ext: ::std::result::Result<::std::option::Option<super::Ext>, ::std::string::String>,
new_log_entry: ::std::result::Result<
::std::option::Option<::std::string::String>,
::std::string::String,
>,
new_scid: ::std::result::Result<
::std::option::Option<::std::string::String>,
::std::string::String,
>,
new_version_id: ::std::result::Result<
::std::option::Option<::std::string::String>,
::std::string::String,
>,
outcome: ::std::result::Result<super::KeyRoleChangeOutcome, ::std::string::String>,
pre_rotation_key_count:
::std::result::Result<::std::option::Option<u64>, ::std::string::String>,
preview: ::std::result::Result<
::std::option::Option<super::DidDocumentPreview>,
::std::string::String,
>,
serverless: ::std::result::Result<::std::option::Option<bool>, ::std::string::String>,
update_keys_count: ::std::result::Result<::std::option::Option<u64>, ::std::string::String>,
}
impl ::std::default::Default for Response {
fn default() -> Self {
Self {
approvals: Ok(Default::default()),
did: Err("no value supplied for did".to_string()),
ext: Ok(Default::default()),
new_log_entry: Ok(Default::default()),
new_scid: Ok(Default::default()),
new_version_id: Ok(Default::default()),
outcome: Err("no value supplied for outcome".to_string()),
pre_rotation_key_count: Ok(Default::default()),
preview: Ok(Default::default()),
serverless: Ok(Default::default()),
update_keys_count: Ok(Default::default()),
}
}
}
impl Response {
pub fn approvals<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::KeyRoleApprovalState>>,
T::Error: ::std::fmt::Display,
{
self.approvals = value
.try_into()
.map_err(|e| format!("error converting supplied value for approvals: {e}"));
self
}
pub fn did<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::string::String>,
T::Error: ::std::fmt::Display,
{
self.did = value
.try_into()
.map_err(|e| format!("error converting supplied value for did: {e}"));
self
}
pub fn ext<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::Ext>>,
T::Error: ::std::fmt::Display,
{
self.ext = value
.try_into()
.map_err(|e| format!("error converting supplied value for ext: {e}"));
self
}
pub fn new_log_entry<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>,
T::Error: ::std::fmt::Display,
{
self.new_log_entry = value
.try_into()
.map_err(|e| format!("error converting supplied value for new_log_entry: {e}"));
self
}
pub fn new_scid<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>,
T::Error: ::std::fmt::Display,
{
self.new_scid = value
.try_into()
.map_err(|e| format!("error converting supplied value for new_scid: {e}"));
self
}
pub fn new_version_id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>,
T::Error: ::std::fmt::Display,
{
self.new_version_id = value
.try_into()
.map_err(|e| format!("error converting supplied value for new_version_id: {e}"));
self
}
pub fn outcome<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::KeyRoleChangeOutcome>,
T::Error: ::std::fmt::Display,
{
self.outcome = value
.try_into()
.map_err(|e| format!("error converting supplied value for outcome: {e}"));
self
}
pub fn pre_rotation_key_count<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<u64>>,
T::Error: ::std::fmt::Display,
{
self.pre_rotation_key_count = value.try_into().map_err(|e| {
format!("error converting supplied value for pre_rotation_key_count: {e}")
});
self
}
pub fn preview<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::DidDocumentPreview>>,
T::Error: ::std::fmt::Display,
{
self.preview = value
.try_into()
.map_err(|e| format!("error converting supplied value for preview: {e}"));
self
}
pub fn serverless<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<bool>>,
T::Error: ::std::fmt::Display,
{
self.serverless = value
.try_into()
.map_err(|e| format!("error converting supplied value for serverless: {e}"));
self
}
pub fn update_keys_count<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<u64>>,
T::Error: ::std::fmt::Display,
{
self.update_keys_count = value
.try_into()
.map_err(|e| format!("error converting supplied value for update_keys_count: {e}"));
self
}
}
impl ::std::convert::TryFrom<Response> for super::Response {
type Error = super::error::ConversionError;
fn try_from(value: Response) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
approvals: value.approvals?,
did: value.did?,
ext: value.ext?,
new_log_entry: value.new_log_entry?,
new_scid: value.new_scid?,
new_version_id: value.new_version_id?,
outcome: value.outcome?,
pre_rotation_key_count: value.pre_rotation_key_count?,
preview: value.preview?,
serverless: value.serverless?,
update_keys_count: value.update_keys_count?,
})
}
}
impl ::std::convert::From<super::Response> for Response {
fn from(value: super::Response) -> Self {
Self {
approvals: Ok(value.approvals),
did: Ok(value.did),
ext: Ok(value.ext),
new_log_entry: Ok(value.new_log_entry),
new_scid: Ok(value.new_scid),
new_version_id: Ok(value.new_version_id),
outcome: Ok(value.outcome),
pre_rotation_key_count: Ok(value.pre_rotation_key_count),
preview: Ok(value.preview),
serverless: Ok(value.serverless),
update_keys_count: Ok(value.update_keys_count),
}
}
}
}
impl crate::Payload for Payload {
const TYPE_URI: &'static str = "https://trusttasks.org/spec/vta/webvh/dids/update/2.0";
const IS_PROOF_REQUIRED: bool = true;
const IS_ISSUED_AT_REQUIRED: bool = true;
const IS_RECIPIENT_REQUIRED: bool = true;
const PAYLOAD_SCHEMA: Option<&'static str> = Some(
"{\n \"$defs\": {\n \"DidDocumentChange\": {\n \"additionalProperties\": false,\n \"properties\": {\n \"keyType\": {\n \"$ref\": \"#/$defs/KeyType\"\n },\n \"op\": {\n \"description\": \"`addKey` — a verification method is added, listed in its role's relationship and in `keyRoles`. `retireKey` — a verification method leaves its relationship, `keyRoles` and the document. `revokeKey` — a verification method leaves its relationship and `keyRoles`, and the compromise is recorded (CONVENTIONS.md §7). `rotateUpdateKey` — the log's update key moves to a committed successor. `setPreRotation` — the number of successors committed changes.\",\n \"enum\": [\n \"addKey\",\n \"retireKey\",\n \"revokeKey\",\n \"rotateUpdateKey\",\n \"setPreRotation\"\n ],\n \"type\": \"string\"\n },\n \"preRotationCount\": {\n \"minimum\": 0,\n \"type\": \"integer\"\n },\n \"publicKeyMultibase\": {\n \"type\": \"string\"\n },\n \"relationships\": {\n \"items\": {\n \"$ref\": \"#/$defs/DidVerificationRelationship\"\n },\n \"type\": \"array\",\n \"uniqueItems\": true\n },\n \"role\": {\n \"$ref\": \"#/$defs/KeyRole\"\n },\n \"verificationMethod\": {\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"op\",\n \"role\"\n ],\n \"title\": \"DidDocumentChange\",\n \"type\": \"object\"\n },\n \"DidDocumentPreview\": {\n \"additionalProperties\": false,\n \"description\": \"What a change would publish, computed by the VTA by running the handler it would run to apply it, and nothing else (CONVENTIONS.md §3.1). This is what a consent surface renders and what an approval is bound to.\",\n \"properties\": {\n \"baseVersionId\": {\n \"description\": \"versionId of the log entry the plan was computed against. The plan is void once the log moves past it.\",\n \"type\": \"string\"\n },\n \"changes\": {\n \"description\": \"Every change the entry would make, including the ones the caller did not ask for — in particular `rotateUpdateKey`, which accompanies every entry appended under pre-rotation.\",\n \"items\": {\n \"$ref\": \"#/$defs/DidDocumentChange\"\n },\n \"type\": \"array\"\n },\n \"document\": {\n \"description\": \"The complete DID document the entry would publish. Public data by construction; no key material beyond public halves.\",\n \"type\": \"object\"\n },\n \"expiresAt\": {\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"previewId\": {\n \"description\": \"Opaque, unguessable identifier for this exact plan. Carried back by the apply request, and the thing every approval is bound to.\",\n \"minLength\": 16,\n \"type\": \"string\"\n },\n \"updateKeyRotates\": {\n \"description\": \"True when appending this entry also moves the DID's update key to a committed successor. Stated as its own member, not left to be found in `changes`, because it is the consequence a reviewer most often misses.\",\n \"type\": \"boolean\"\n },\n \"warnings\": {\n \"description\": \"Conditions a human should be shown before approving. `preRotationDisabled` — the entry leaves no committed successor, so a later update-key compromise can only end in deactivation. `singleKeyRole` — the role will hold one active key, so its next compromise empties it until replaced. `algorithmNotInAcceptedSet` — a verifier population the VTA knows of does not accept the new key's algorithm. `roleWillHaveNoClassicalKey` — every remaining key is post-quantum, which verifiers without post-quantum support cannot check. `attestationReissuanceRequired` — revoking this `attestation` key obliges the node to re-issue every attestation artefact still in force and re-sign every status list (VTI-KEY-133). `serverless` — the VTA will not publish the entry; the operator must.\",\n \"items\": {\n \"enum\": [\n \"preRotationDisabled\",\n \"singleKeyRole\",\n \"algorithmNotInAcceptedSet\",\n \"roleWillHaveNoClassicalKey\",\n \"attestationReissuanceRequired\",\n \"serverless\"\n ],\n \"type\": \"string\"\n },\n \"type\": \"array\",\n \"uniqueItems\": true\n }\n },\n \"required\": [\n \"previewId\",\n \"baseVersionId\",\n \"expiresAt\",\n \"changes\",\n \"document\",\n \"updateKeyRotates\"\n ],\n \"title\": \"DidDocumentPreview\",\n \"type\": \"object\"\n },\n \"DidVerificationRelationship\": {\n \"description\": \"A DID Core verification relationship.\",\n \"enum\": [\n \"authentication\",\n \"assertionMethod\",\n \"keyAgreement\",\n \"capabilityInvocation\",\n \"capabilityDelegation\"\n ],\n \"title\": \"DidVerificationRelationship\",\n \"type\": \"string\"\n },\n \"Ext\": {\n \"additionalProperties\": true,\n \"description\": \"Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.\",\n \"minProperties\": 1,\n \"propertyNames\": {\n \"pattern\": \"^[a-z][a-z0-9-]*(\\\\.[a-z0-9-]+)+$\"\n },\n \"title\": \"Ext\",\n \"type\": \"object\"\n },\n \"KeyRole\": {\n \"description\": \"The named key role a key occupies in the DID (VTI-KEY-070 onward). `attestation` — the only keys in `assertionMethod`; sign the DID's attestation artefacts (membership and role credentials, endorsements, status lists, every other credential the node issues), through the VTA's signing service and nowhere else. Generated inside the VTA, never derived, never exportable, never in a backup. `operational` — the only keys in `authentication`; sign the node's own traffic (Trust Task requests and responses, DIDComm and TSP message signatures, invitations, notices, audit checkpoints) with proof purpose `authentication`. `messaging` — the only keys in `keyAgreement`; sign nothing. `update` — the keys that authorize appending to the DID's log (a did:webvh `updateKeys` entry) and the pre-rotation commitments that authorize the next ones; never a verification method, never in `keyRoles`. Generated inside the VTA, never derived, never exportable, never in a backup. No role permits `capabilityInvocation` or `capabilityDelegation` (VTI-KEY-075); both are reserved for a future role. The mapping is normative and is set out in CONVENTIONS.md §1. The set is an extensible registry and growing it is a MINOR change: a consumer that receives a role it does not implement MUST refuse the document rather than map the key onto a role it does know.\",\n \"enum\": [\n \"attestation\",\n \"operational\",\n \"messaging\",\n \"update\"\n ],\n \"title\": \"KeyRole\",\n \"type\": \"string\"\n },\n \"KeyRoleApprovalState\": {\n \"additionalProperties\": false,\n \"description\": \"Approval progress of a change the VTA's policy gates on more than one approval (CONVENTIONS.md §3.3).\",\n \"properties\": {\n \"approvers\": {\n \"description\": \"VIDs whose approvals were recorded. Custody projection only; omitted from a response to anyone who is not themselves an eligible approver of this change.\",\n \"items\": {\n \"type\": \"string\"\n },\n \"type\": \"array\",\n \"uniqueItems\": true\n },\n \"expiresAt\": {\n \"description\": \"When the preview, and every approval bound to it, stops being usable.\",\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"received\": {\n \"description\": \"Distinct approvals recorded so far, including the initiator's own.\",\n \"minimum\": 0,\n \"type\": \"integer\"\n },\n \"required\": {\n \"description\": \"Distinct approvals the VTA's policy requires.\",\n \"minimum\": 1,\n \"type\": \"integer\"\n }\n },\n \"required\": [\n \"required\",\n \"received\",\n \"expiresAt\"\n ],\n \"title\": \"KeyRoleApprovalState\",\n \"type\": \"object\"\n },\n \"KeyRoleChangeOutcome\": {\n \"description\": \"`preview` — nothing was written; the response carries the plan. `applied` — the entry was appended (and published, unless `serverless`). `pendingApproval` — the plan is recorded and awaits further approvals; nothing is published until they arrive (CONVENTIONS.md §3.3).\",\n \"enum\": [\n \"preview\",\n \"applied\",\n \"pendingApproval\"\n ],\n \"title\": \"KeyRoleChangeOutcome\",\n \"type\": \"string\"\n },\n \"KeyType\": {\n \"description\": \"Cryptographic algorithm the key material belongs to. `ed25519` signs (EdDSA), `x25519` performs key agreement and never signs, `p256` signs (ES256), and `mldsa44` and `mldsa65` sign with the post-quantum ML-DSA scheme of US NIST FIPS 204. The set is expected to grow as algorithms are standardised, and growing it is a MINOR change under SPEC.md §5.2: `keyType` selects no schema branch, so adding a value relaxes a constraint rather than narrowing one, and the generated libraries mark this enumeration non-exhaustive so that a consumer absorbs a new value rather than failing to compile. Two ML-DSA parameter sets are carried because two specifications require different ones — W3C Quantum-Resistant Cryptosuites defines Data Integrity suites only for ML-DSA-44, while Trust Spanning Protocol Rev 3 §8.1 mandates ML-DSA-65 — so the parameter set is chosen by whatever consumes the key and the two are not redundant. A consumer that does not implement a value it receives MUST refuse the document rather than substitute one it does support.\",\n \"enum\": [\n \"ed25519\",\n \"x25519\",\n \"p256\",\n \"mldsa44\",\n \"mldsa65\"\n ],\n \"title\": \"KeyType\",\n \"type\": \"string\"\n },\n \"Response\": {\n \"$anchor\": \"response\",\n \"additionalProperties\": false,\n \"description\": \"The outcome. `preview` and `pendingApproval` carry the plan; `applied` carries the published entry.\",\n \"properties\": {\n \"approvals\": {\n \"$ref\": \"#/$defs/KeyRoleApprovalState\"\n },\n \"did\": {\n \"type\": \"string\"\n },\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\"\n },\n \"newLogEntry\": {\n \"description\": \"The appended log entry, as JSON text.\",\n \"type\": \"string\"\n },\n \"newScid\": {\n \"type\": \"string\"\n },\n \"newVersionId\": {\n \"description\": \"versionId of the entry just appended. A caller intending a further edit SHOULD pass this back as the next request's `expectedVersionId`.\",\n \"type\": \"string\"\n },\n \"outcome\": {\n \"$ref\": \"#/$defs/KeyRoleChangeOutcome\"\n },\n \"preRotationKeyCount\": {\n \"description\": \"Pre-rotation commitments published by this entry.\",\n \"minimum\": 0,\n \"type\": \"integer\"\n },\n \"preview\": {\n \"$ref\": \"#/$defs/DidDocumentPreview\"\n },\n \"serverless\": {\n \"description\": \"True when the agent holds the log itself and no hosting server was published to — the operator must fetch and redeploy `did.jsonl`.\",\n \"type\": \"boolean\"\n },\n \"updateKeysCount\": {\n \"description\": \"Update keys authorized AFTER this entry. Where `document` was supplied these are new keys — the previous ones no longer authorize anything.\",\n \"minimum\": 0,\n \"type\": \"integer\"\n }\n },\n \"required\": [\n \"did\",\n \"outcome\"\n ],\n \"title\": \"WebVH DID Update — response payload\",\n \"type\": \"object\"\n }\n },\n \"$id\": \"https://trusttasks.org/spec/vta/webvh/dids/update/2.0\",\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"additionalProperties\": false,\n \"description\": \"Ask a Verifiable Trust Agent to publish a new entry in a did:webvh log it holds the update key for, changing anything but the DID's keys. Keys change only through the key-role tasks (vta/_shared/0.3/CONVENTIONS.md).\",\n \"properties\": {\n \"did\": {\n \"description\": \"The did:webvh being updated. The agent MUST verify it speaks for this subject.\",\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"document\": {\n \"description\": \"The new DID document. Omit to leave it unchanged. It MUST carry, unchanged, the current `verificationMethod`, `authentication`, `assertionMethod`, `keyAgreement`, `capabilityInvocation`, `capabilityDelegation` and `keyRoles` members: a change to any of them is refused with `vta/webvh/dids/update:keyMembersManaged`, because keys change only through the key-role tasks. Appending the entry still rotates the DID's update key under pre-rotation, which a consent surface MUST render from the executor's preview, never from this document.\",\n \"type\": \"object\"\n },\n \"dryRun\": {\n \"description\": \"Compute and return the preview without writing anything but the plan (CONVENTIONS.md §3.1). Absent reads as false.\",\n \"type\": \"boolean\"\n },\n \"expectedVersionId\": {\n \"description\": \"Optimistic-concurrency precondition: the versionId the caller based this edit on. The agent MUST refuse the update if the DID's latest entry no longer matches. Without it a `get -> edit -> save` cycle silently overwrites a concurrent edit with a chain that is structurally valid, verifies perfectly, and is based on a stale read. Where a human approves the update the window is minutes wide, so this is a routine race rather than an exotic one. OPTIONAL because a scripted caller with no concurrent writers has nothing to protect against; not optional for anything a person looked at.\",\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\"\n },\n \"label\": {\n \"description\": \"Operator-facing audit label.\",\n \"maxLength\": 256,\n \"type\": \"string\"\n },\n \"preRotationCount\": {\n \"description\": \"Number of pre-rotation commitments to publish. Omit to keep the current count. `0` is refused for a durable node identity (`vta/webvh/dids:preRotationRequired`).\",\n \"minimum\": 0,\n \"type\": \"integer\"\n },\n \"previewId\": {\n \"description\": \"Apply exactly the plan a previous dry run of this same request returned; what an approval is bound to (CONVENTIONS.md §3.1–§3.2).\",\n \"minLength\": 16,\n \"type\": \"string\"\n },\n \"ttl\": {\n \"description\": \"New TTL in seconds. Omit to keep the current value.\",\n \"minimum\": 0,\n \"type\": \"integer\"\n },\n \"watchers\": {\n \"description\": \"New watcher URLs. Omit to keep the current set; an empty array removes them.\",\n \"items\": {\n \"type\": \"string\"\n },\n \"type\": \"array\"\n },\n \"witnesses\": {\n \"description\": \"New witness configuration. Omit to keep the current one.\"\n }\n },\n \"required\": [\n \"did\"\n ],\n \"title\": \"WebVH DID Update — payload\",\n \"type\": \"object\"\n}\n",
);
}
impl crate::Payload for Response {
const TYPE_URI: &'static str = "https://trusttasks.org/spec/vta/webvh/dids/update/2.0#response";
const IS_PROOF_REQUIRED: bool = true;
const IS_ISSUED_AT_REQUIRED: bool = true;
const IS_RECIPIENT_REQUIRED: bool = true;
const PAYLOAD_SCHEMA: Option<&'static str> = Some(
"{\n \"$defs\": {\n \"DidDocumentChange\": {\n \"additionalProperties\": false,\n \"properties\": {\n \"keyType\": {\n \"$ref\": \"#/$defs/KeyType\"\n },\n \"op\": {\n \"description\": \"`addKey` — a verification method is added, listed in its role's relationship and in `keyRoles`. `retireKey` — a verification method leaves its relationship, `keyRoles` and the document. `revokeKey` — a verification method leaves its relationship and `keyRoles`, and the compromise is recorded (CONVENTIONS.md §7). `rotateUpdateKey` — the log's update key moves to a committed successor. `setPreRotation` — the number of successors committed changes.\",\n \"enum\": [\n \"addKey\",\n \"retireKey\",\n \"revokeKey\",\n \"rotateUpdateKey\",\n \"setPreRotation\"\n ],\n \"type\": \"string\"\n },\n \"preRotationCount\": {\n \"minimum\": 0,\n \"type\": \"integer\"\n },\n \"publicKeyMultibase\": {\n \"type\": \"string\"\n },\n \"relationships\": {\n \"items\": {\n \"$ref\": \"#/$defs/DidVerificationRelationship\"\n },\n \"type\": \"array\",\n \"uniqueItems\": true\n },\n \"role\": {\n \"$ref\": \"#/$defs/KeyRole\"\n },\n \"verificationMethod\": {\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"op\",\n \"role\"\n ],\n \"title\": \"DidDocumentChange\",\n \"type\": \"object\"\n },\n \"DidDocumentPreview\": {\n \"additionalProperties\": false,\n \"description\": \"What a change would publish, computed by the VTA by running the handler it would run to apply it, and nothing else (CONVENTIONS.md §3.1). This is what a consent surface renders and what an approval is bound to.\",\n \"properties\": {\n \"baseVersionId\": {\n \"description\": \"versionId of the log entry the plan was computed against. The plan is void once the log moves past it.\",\n \"type\": \"string\"\n },\n \"changes\": {\n \"description\": \"Every change the entry would make, including the ones the caller did not ask for — in particular `rotateUpdateKey`, which accompanies every entry appended under pre-rotation.\",\n \"items\": {\n \"$ref\": \"#/$defs/DidDocumentChange\"\n },\n \"type\": \"array\"\n },\n \"document\": {\n \"description\": \"The complete DID document the entry would publish. Public data by construction; no key material beyond public halves.\",\n \"type\": \"object\"\n },\n \"expiresAt\": {\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"previewId\": {\n \"description\": \"Opaque, unguessable identifier for this exact plan. Carried back by the apply request, and the thing every approval is bound to.\",\n \"minLength\": 16,\n \"type\": \"string\"\n },\n \"updateKeyRotates\": {\n \"description\": \"True when appending this entry also moves the DID's update key to a committed successor. Stated as its own member, not left to be found in `changes`, because it is the consequence a reviewer most often misses.\",\n \"type\": \"boolean\"\n },\n \"warnings\": {\n \"description\": \"Conditions a human should be shown before approving. `preRotationDisabled` — the entry leaves no committed successor, so a later update-key compromise can only end in deactivation. `singleKeyRole` — the role will hold one active key, so its next compromise empties it until replaced. `algorithmNotInAcceptedSet` — a verifier population the VTA knows of does not accept the new key's algorithm. `roleWillHaveNoClassicalKey` — every remaining key is post-quantum, which verifiers without post-quantum support cannot check. `attestationReissuanceRequired` — revoking this `attestation` key obliges the node to re-issue every attestation artefact still in force and re-sign every status list (VTI-KEY-133). `serverless` — the VTA will not publish the entry; the operator must.\",\n \"items\": {\n \"enum\": [\n \"preRotationDisabled\",\n \"singleKeyRole\",\n \"algorithmNotInAcceptedSet\",\n \"roleWillHaveNoClassicalKey\",\n \"attestationReissuanceRequired\",\n \"serverless\"\n ],\n \"type\": \"string\"\n },\n \"type\": \"array\",\n \"uniqueItems\": true\n }\n },\n \"required\": [\n \"previewId\",\n \"baseVersionId\",\n \"expiresAt\",\n \"changes\",\n \"document\",\n \"updateKeyRotates\"\n ],\n \"title\": \"DidDocumentPreview\",\n \"type\": \"object\"\n },\n \"DidVerificationRelationship\": {\n \"description\": \"A DID Core verification relationship.\",\n \"enum\": [\n \"authentication\",\n \"assertionMethod\",\n \"keyAgreement\",\n \"capabilityInvocation\",\n \"capabilityDelegation\"\n ],\n \"title\": \"DidVerificationRelationship\",\n \"type\": \"string\"\n },\n \"Ext\": {\n \"additionalProperties\": true,\n \"description\": \"Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.\",\n \"minProperties\": 1,\n \"propertyNames\": {\n \"pattern\": \"^[a-z][a-z0-9-]*(\\\\.[a-z0-9-]+)+$\"\n },\n \"title\": \"Ext\",\n \"type\": \"object\"\n },\n \"KeyRole\": {\n \"description\": \"The named key role a key occupies in the DID (VTI-KEY-070 onward). `attestation` — the only keys in `assertionMethod`; sign the DID's attestation artefacts (membership and role credentials, endorsements, status lists, every other credential the node issues), through the VTA's signing service and nowhere else. Generated inside the VTA, never derived, never exportable, never in a backup. `operational` — the only keys in `authentication`; sign the node's own traffic (Trust Task requests and responses, DIDComm and TSP message signatures, invitations, notices, audit checkpoints) with proof purpose `authentication`. `messaging` — the only keys in `keyAgreement`; sign nothing. `update` — the keys that authorize appending to the DID's log (a did:webvh `updateKeys` entry) and the pre-rotation commitments that authorize the next ones; never a verification method, never in `keyRoles`. Generated inside the VTA, never derived, never exportable, never in a backup. No role permits `capabilityInvocation` or `capabilityDelegation` (VTI-KEY-075); both are reserved for a future role. The mapping is normative and is set out in CONVENTIONS.md §1. The set is an extensible registry and growing it is a MINOR change: a consumer that receives a role it does not implement MUST refuse the document rather than map the key onto a role it does know.\",\n \"enum\": [\n \"attestation\",\n \"operational\",\n \"messaging\",\n \"update\"\n ],\n \"title\": \"KeyRole\",\n \"type\": \"string\"\n },\n \"KeyRoleApprovalState\": {\n \"additionalProperties\": false,\n \"description\": \"Approval progress of a change the VTA's policy gates on more than one approval (CONVENTIONS.md §3.3).\",\n \"properties\": {\n \"approvers\": {\n \"description\": \"VIDs whose approvals were recorded. Custody projection only; omitted from a response to anyone who is not themselves an eligible approver of this change.\",\n \"items\": {\n \"type\": \"string\"\n },\n \"type\": \"array\",\n \"uniqueItems\": true\n },\n \"expiresAt\": {\n \"description\": \"When the preview, and every approval bound to it, stops being usable.\",\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"received\": {\n \"description\": \"Distinct approvals recorded so far, including the initiator's own.\",\n \"minimum\": 0,\n \"type\": \"integer\"\n },\n \"required\": {\n \"description\": \"Distinct approvals the VTA's policy requires.\",\n \"minimum\": 1,\n \"type\": \"integer\"\n }\n },\n \"required\": [\n \"required\",\n \"received\",\n \"expiresAt\"\n ],\n \"title\": \"KeyRoleApprovalState\",\n \"type\": \"object\"\n },\n \"KeyRoleChangeOutcome\": {\n \"description\": \"`preview` — nothing was written; the response carries the plan. `applied` — the entry was appended (and published, unless `serverless`). `pendingApproval` — the plan is recorded and awaits further approvals; nothing is published until they arrive (CONVENTIONS.md §3.3).\",\n \"enum\": [\n \"preview\",\n \"applied\",\n \"pendingApproval\"\n ],\n \"title\": \"KeyRoleChangeOutcome\",\n \"type\": \"string\"\n },\n \"KeyType\": {\n \"description\": \"Cryptographic algorithm the key material belongs to. `ed25519` signs (EdDSA), `x25519` performs key agreement and never signs, `p256` signs (ES256), and `mldsa44` and `mldsa65` sign with the post-quantum ML-DSA scheme of US NIST FIPS 204. The set is expected to grow as algorithms are standardised, and growing it is a MINOR change under SPEC.md §5.2: `keyType` selects no schema branch, so adding a value relaxes a constraint rather than narrowing one, and the generated libraries mark this enumeration non-exhaustive so that a consumer absorbs a new value rather than failing to compile. Two ML-DSA parameter sets are carried because two specifications require different ones — W3C Quantum-Resistant Cryptosuites defines Data Integrity suites only for ML-DSA-44, while Trust Spanning Protocol Rev 3 §8.1 mandates ML-DSA-65 — so the parameter set is chosen by whatever consumes the key and the two are not redundant. A consumer that does not implement a value it receives MUST refuse the document rather than substitute one it does support.\",\n \"enum\": [\n \"ed25519\",\n \"x25519\",\n \"p256\",\n \"mldsa44\",\n \"mldsa65\"\n ],\n \"title\": \"KeyType\",\n \"type\": \"string\"\n },\n \"Response\": {\n \"$anchor\": \"response\",\n \"additionalProperties\": false,\n \"description\": \"The outcome. `preview` and `pendingApproval` carry the plan; `applied` carries the published entry.\",\n \"properties\": {\n \"approvals\": {\n \"$ref\": \"#/$defs/KeyRoleApprovalState\"\n },\n \"did\": {\n \"type\": \"string\"\n },\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\"\n },\n \"newLogEntry\": {\n \"description\": \"The appended log entry, as JSON text.\",\n \"type\": \"string\"\n },\n \"newScid\": {\n \"type\": \"string\"\n },\n \"newVersionId\": {\n \"description\": \"versionId of the entry just appended. A caller intending a further edit SHOULD pass this back as the next request's `expectedVersionId`.\",\n \"type\": \"string\"\n },\n \"outcome\": {\n \"$ref\": \"#/$defs/KeyRoleChangeOutcome\"\n },\n \"preRotationKeyCount\": {\n \"description\": \"Pre-rotation commitments published by this entry.\",\n \"minimum\": 0,\n \"type\": \"integer\"\n },\n \"preview\": {\n \"$ref\": \"#/$defs/DidDocumentPreview\"\n },\n \"serverless\": {\n \"description\": \"True when the agent holds the log itself and no hosting server was published to — the operator must fetch and redeploy `did.jsonl`.\",\n \"type\": \"boolean\"\n },\n \"updateKeysCount\": {\n \"description\": \"Update keys authorized AFTER this entry. Where `document` was supplied these are new keys — the previous ones no longer authorize anything.\",\n \"minimum\": 0,\n \"type\": \"integer\"\n }\n },\n \"required\": [\n \"did\",\n \"outcome\"\n ],\n \"title\": \"WebVH DID Update — response payload\",\n \"type\": \"object\"\n }\n },\n \"$ref\": \"#/$defs/Response\",\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\"\n}\n",
);
}
impl crate::RequestPayload for Payload {
type Response = Response;
}
/// The extended error codes this specification declares (SPEC §7.3 item 9,
/// §8.5), in declaration order. Empty when it declares none.
pub const ERROR_CODES: &[crate::DeclaredErrorCode] = &[
error_codes::NOT_FOUND,
error_codes::VERSION_CONFLICT,
error_codes::INVALID_DOCUMENT,
error_codes::KEY_MEMBERS_MANAGED,
error_codes::PREVIEW_STALE,
error_codes::STEP_UP_REQUIRED,
error_codes::PRE_ROTATION_REQUIRED,
error_codes::NOT_KEY_ROLE_IDENTITY,
];
/// One constant per extended error code this specification declares
/// (SPEC §7.3 item 9), named for its local part.
///
/// Emit these rather than a string literal: the code is read from the
/// specification, so it cannot name a code the specification never
/// declared.
pub mod error_codes {
/// `vta/webvh/dids/update:notFound`
///
/// The agent holds no update key for this DID, or the caller cannot reach its context.
///
/// Declared `retryable: false`.
pub const NOT_FOUND: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "vta/webvh/dids/update:notFound",
retryable: false,
};
/// `vta/webvh/dids/update:versionConflict`
///
/// The DID's latest entry no longer matches `expectedVersionId`. The caller SHOULD re-read and re-apply its edits.
///
/// Declared `retryable: false`.
pub const VERSION_CONFLICT: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "vta/webvh/dids/update:versionConflict",
retryable: false,
};
/// `vta/webvh/dids/update:invalidDocument`
///
/// The document is not a valid DID document for this subject (for example, its `id` does not match `did`).
///
/// Declared `retryable: false`.
pub const INVALID_DOCUMENT: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "vta/webvh/dids/update:invalidDocument",
retryable: false,
};
/// `vta/webvh/dids/update:keyMembersManaged`
///
/// The document changes `verificationMethod`, a verification relationship or `keyRoles`. Keys change only through the key-role tasks; `details.members` names the members that differ.
///
/// Declared `retryable: false`.
pub const KEY_MEMBERS_MANAGED: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "vta/webvh/dids/update:keyMembersManaged",
retryable: false,
};
/// `vta/webvh/dids:previewStale`
///
/// The `previewId` is unknown, expired, already applied, based on an entry the log has moved past, or for a different request.
///
/// Declared `retryable: false`.
pub const PREVIEW_STALE: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "vta/webvh/dids:previewStale",
retryable: false,
};
/// `vta/webvh/dids:stepUpRequired`
///
/// The VTA's policy requires a step-up bound to this change's preview; `details.stepUpRequest` carries it and `details.preview` the plan.
///
/// Declared `retryable: true`.
pub const STEP_UP_REQUIRED: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "vta/webvh/dids:stepUpRequired",
retryable: true,
};
/// `vta/webvh/dids:preRotationRequired`
///
/// The update would leave a durable node identity with no committed successor update key.
///
/// Declared `retryable: false`.
pub const PRE_ROTATION_REQUIRED: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "vta/webvh/dids:preRotationRequired",
retryable: false,
};
/// `vta/webvh/dids:notKeyRoleIdentity`
///
/// The DID was not created with key roles. Create a new identity with key roles instead.
///
/// Declared `retryable: false`.
pub const NOT_KEY_ROLE_IDENTITY: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "vta/webvh/dids:notKeyRoleIdentity",
retryable: false,
};
}
#[cfg(test)]
mod conformance {
//! Round-trip tests harvested from the spec's `spec.md`,
//! plus a `rejects_invalid_examples` test for any fixtures
//! in `payload.invalid-examples.json` (validate feature).
#[test]
fn request_example_1() {
const JSON: &str = "{\n \"id\": \"urn:uuid:2f7c1a90-4b6e-4d21-9a55-1c3e8b7d0f43\",\n \"type\": \"https://trusttasks.org/spec/vta/webvh/dids/update/2.0\",\n \"issuer\": \"did:key:z6MkCallerExample\",\n \"recipient\": \"did:webvh:QmVtaScid:vta.example\",\n \"issuedAt\": \"2026-09-25T10:12:00Z\",\n \"payload\": {\n \"did\": \"did:webvh:QmSCIDExample:example.com:acme\",\n \"document\": {\n \"@context\": [\"https://www.w3.org/ns/did/v1\"],\n \"id\": \"did:webvh:QmSCIDExample:example.com:acme\",\n \"service\": [\n { \"id\": \"#files\", \"type\": \"FileStore\", \"serviceEndpoint\": \"https://files.example.com/acme\" }\n ]\n },\n \"expectedVersionId\": \"3-QmPriorEntryHashExample\",\n \"dryRun\": true,\n \"label\": \"add file store\"\n },\n \"proof\": {\n \"type\": \"DataIntegrityProof\",\n \"cryptosuite\": \"eddsa-jcs-2022\",\n \"created\": \"2026-09-25T10:12:00Z\",\n \"verificationMethod\": \"did:key:z6MkCallerExample#z6MkCallerExample\",\n \"proofPurpose\": \"authentication\",\n \"proofValue\": \"z4Xq7WExampleProofValueForWebvhUpdateRequest\"\n }\n}\n";
let doc: crate::TrustTask<super::Payload> =
serde_json::from_str(JSON).expect("deserialize request example");
let rendered = serde_json::to_value(&doc).expect("re-serialize");
let expected: serde_json::Value = serde_json::from_str(JSON).expect("re-parse expected");
assert_eq!(rendered, expected, "request example failed round-trip");
}
#[test]
fn response_example_1() {
const JSON: &str = "{\n \"id\": \"urn:uuid:8d1b6e34-7f92-4c05-b3a1-6e0d29c4f8b8\",\n \"type\": \"https://trusttasks.org/spec/vta/webvh/dids/update/2.0#response\",\n \"issuer\": \"did:webvh:QmVtaScid:vta.example\",\n \"recipient\": \"did:key:z6MkCallerExample\",\n \"issuedAt\": \"2026-09-25T10:12:01Z\",\n \"payload\": {\n \"did\": \"did:webvh:QmSCIDExample:example.com:acme\",\n \"outcome\": \"preview\",\n \"preview\": {\n \"previewId\": \"pv_5e6f7a8b9c0d1e2f3a4b\",\n \"baseVersionId\": \"3-QmPriorEntryHashExample\",\n \"expiresAt\": \"2026-09-25T10:42:01Z\",\n \"updateKeyRotates\": true,\n \"changes\": [ { \"op\": \"rotateUpdateKey\", \"role\": \"update\" } ],\n \"document\": { \"id\": \"did:webvh:QmSCIDExample:example.com:acme\" }\n }\n }\n}\n";
let doc: crate::TrustTask<super::Response> =
serde_json::from_str(JSON).expect("deserialize response example");
let rendered = serde_json::to_value(&doc).expect("re-serialize");
let expected: serde_json::Value = serde_json::from_str(JSON).expect("re-parse expected");
assert_eq!(rendered, expected, "response example failed round-trip");
}
}