//! Generated by `trust-tasks-codegen` — do not edit by hand.
//!
//! Spec slug: `persona/contact/put`. Version: `1.2`.
/// Why this specification version is deprecated (SPEC "Superseded and
/// Withdrawn Versions"), or `None` while it is current.
pub const DEPRECATION: Option<&str> = None;
#[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())
}
}
}
/**
The vocabulary token naming what a value IS — `name.legal`, `phone.mobile`, `address.postal`, `person.birthDate`. Dotted, most-general segment first, so that a consumer with no knowledge of the specific token can still group by its prefix.
The token is the maintainer's own; no external vocabulary is primary. External vocabularies (vCard/jCard, OIDC standard claims, schema.org) are mappings applied at PRESENTATION by a renderer, not at rest, so that a query written in any of them can be matched without the store having to live inside any one of them.
The `x:` prefix is an open extension namespace and is not decoration. The closest prior art — Windows CardSpace's self-issued card — supported exactly fifteen predefined claim types with no extensibility, and that is the specific way it failed the requirement a holder actually has. An `x:` attribute stores, composes, binds and discloses exactly like a known one; it renders generically and matches only an explicit query.*/
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ClaimType(::std::string::String);
impl ::std::ops::Deref for ClaimType {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ClaimType> for ::std::string::String {
fn from(value: ClaimType) -> Self {
value.0
}
}
impl ::std::str::FromStr for ClaimType {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 128usize {
return Err("longer than 128 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| {
::regress::Regex::new("^(x:)?[a-z][a-zA-Z0-9]*(\\.[a-z][a-zA-Z0-9]*)*$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err(
"doesn't match pattern \"^(x:)?[a-z][a-zA-Z0-9]*(\\.[a-z][a-zA-Z0-9]*)*$\"".into(),
);
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ClaimType {
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 ClaimType {
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 ClaimType {
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 ClaimType {
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())
})
}
}
///What a peer disclosed, as received. Structurally the same claim set a holder composes and presents — a profile and a contact card are one schema seen from two sides — which is why a maintainer validates both with the same code and a consumer renders both with the same view.
///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct ContactDocument {
///The publisher's own monotonic counter, if they supplied one. Advisory: it orders the publisher's revisions relative to each other and MUST NOT be trusted to order them against anything else.
#[serde(
rename = "cardVersion",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub card_version: ::std::option::Option<::std::num::NonZeroU64>,
pub claims: ::std::vec::Vec<ContactDocumentClaimsItem>,
///The DID that published the document, as it appeared. Normally a pairwise identifier, so it names the relationship rather than the person.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub publisher: ::std::option::Option<ContactDocumentPublisher>,
}
impl ContactDocument {
pub fn builder() -> builder::ContactDocument {
Default::default()
}
}
///`ContactDocumentClaimsItem`
///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct ContactDocumentClaimsItem {
///As asserted by the publisher. A recipient MUST NOT treat a claimed credentialBacked provenance as verified — it is a statement about what the publisher says backs the claim, and verification is a separate act against the credential itself.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub provenance: ::std::option::Option<Provenance>,
#[serde(rename = "type")]
pub type_: ClaimType,
pub value: ::serde_json::Value,
#[serde(rename = "valueType")]
pub value_type: ValueType,
}
impl ContactDocumentClaimsItem {
pub fn builder() -> builder::ContactDocumentClaimsItem {
Default::default()
}
}
///The DID that published the document, as it appeared. Normally a pairwise identifier, so it names the relationship rather than the person.
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ContactDocumentPublisher(::std::string::String);
impl ::std::ops::Deref for ContactDocumentPublisher {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ContactDocumentPublisher> for ::std::string::String {
fn from(value: ContactDocumentPublisher) -> Self {
value.0
}
}
impl ::std::str::FromStr for ContactDocumentPublisher {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 2048usize {
return Err("longer than 2048 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ContactDocumentPublisher {
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 ContactDocumentPublisher {
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 ContactDocumentPublisher {
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 ContactDocumentPublisher {
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())
})
}
}
///A community directory entry's identifier, exactly as that community's directory returned it. Opaque and community-scoped: the agent stores and compares it as a string, never parses it, and never treats the same value under two communities as the same entry.
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct DirectoryEntryId(::std::string::String);
impl ::std::ops::Deref for DirectoryEntryId {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<DirectoryEntryId> for ::std::string::String {
fn from(value: DirectoryEntryId) -> Self {
value.0
}
}
impl ::std::str::FromStr for DirectoryEntryId {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 128usize {
return Err("longer than 128 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| ::regress::Regex::new("^[A-Za-z0-9_-]+$").unwrap());
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[A-Za-z0-9_-]+$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for DirectoryEntryId {
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 DirectoryEntryId {
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 DirectoryEntryId {
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 DirectoryEntryId {
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())
})
}
}
///Links a contact to the entry in a community's member directory it corresponds to, so the holder's own client can join that community's directory with the holder's address book — showing a star or a petname beside an entry — without either side telling the other. The community never learns the link exists; the contact never learns it either. A contact has at most one.
///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct DirectoryRef {
///The entry, as that community's directory identifies it.
#[serde(rename = "entryId")]
pub entry_id: DirectoryEntryId,
///The DID of the community whose directory holds the entry.
#[serde(rename = "vtcDid")]
pub vtc_did: DirectoryRefVtcDid,
}
impl DirectoryRef {
pub fn builder() -> builder::DirectoryRef {
Default::default()
}
}
///The DID of the community whose directory holds the entry.
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct DirectoryRefVtcDid(::std::string::String);
impl ::std::ops::Deref for DirectoryRefVtcDid {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<DirectoryRefVtcDid> for ::std::string::String {
fn from(value: DirectoryRefVtcDid) -> Self {
value.0
}
}
impl ::std::str::FromStr for DirectoryRefVtcDid {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 2048usize {
return Err("longer than 2048 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| ::regress::Regex::new("^did:[a-z0-9]+:").unwrap());
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^did:[a-z0-9]+:\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for DirectoryRefVtcDid {
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 DirectoryRefVtcDid {
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 DirectoryRefVtcDid {
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 DirectoryRefVtcDid {
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())
})
}
}
///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.
///
#[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`
///
#[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())
})
}
}
///Identifier of one of the holder's contact lists: a ULID in Crockford base32, uppercase, assigned by the agent when the list is created. Meaningful only inside the context that holds the list; it is never sent to anyone but the holder's own clients.
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ListId(::std::string::String);
impl ::std::ops::Deref for ListId {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ListId> for ::std::string::String {
fn from(value: ListId) -> Self {
value.0
}
}
impl ::std::str::FromStr for ListId {
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("^[0-9A-HJKMNP-TV-Z]{26}$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[0-9A-HJKMNP-TV-Z]{26}$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ListId {
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 ListId {
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 ListId {
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 ListId {
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 lists a contact is on, as a set: order carries no meaning. A contact on no list has no `lists` member, never an empty array, so there is one way to say "none".
///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(transparent)]
pub struct ListIds(pub Vec<ListId>);
impl ::std::ops::Deref for ListIds {
type Target = Vec<ListId>;
fn deref(&self) -> &Vec<ListId> {
&self.0
}
}
impl ::std::convert::From<ListIds> for Vec<ListId> {
fn from(value: ListIds) -> Self {
value.0
}
}
impl ::std::convert::From<Vec<ListId>> for ListIds {
fn from(value: Vec<ListId>) -> Self {
Self(value)
}
}
///File what a peer disclosed, or change the holder's own annotations on a contact, or both. Three forms. FILING (`subjectDid`, `knownByPersona`, `document`; no `contactId`) appends a revision, never overwrites, so a changed value is visible as a change rather than arriving silently — exactly as 1.0. ANNOTATING (`contactId`; no `subjectDid`, `knownByPersona`, `document` or `credentialRefs`) changes the holder's star, petname, lists, directory link or notes on an existing contact and appends no revision. LINKING (`directoryRef`, `knownByPersona`; no `contactId`, `subjectDid`, `document` or `credentialRefs`) keeps annotations on a member of a community's directory whose DID the holder has not been shown: it finds, or makes, the contact for that entry and persona, and appends no revision. In every form each annotation given replaces the stored one, each `removeX` removes one, and each annotation absent is unchanged. The outer document members are owned by the framework — SPEC §6.3.
///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct Payload {
///Annotating form only: the existing contact whose annotations change. A filing never names one — the agent keys a filing on (contextId, subjectDid, knownByPersona) as in 1.0.
#[serde(
rename = "contactId",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub contact_id: ::std::option::Option<Ulid>,
#[serde(rename = "contextId")]
pub context_id: PayloadContextId,
///Filing form only. Vault identifiers of credentials the peer presented alongside the document. The credentials themselves belong in the credential vault and the contact holds references.
#[serde(
rename = "credentialRefs",
default,
skip_serializing_if = "::std::vec::Vec::is_empty"
)]
pub credential_refs: ::std::vec::Vec<PayloadCredentialRefsItem>,
///Link the contact to a community directory entry, replacing any link it had. Absent: unchanged.
#[serde(
rename = "directoryRef",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub directory_ref: ::std::option::Option<DirectoryRef>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub document: ::std::option::Option<ContactDocument>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ext: ::std::option::Option<Ext>,
///Filing and linking forms. Which of the holder's personas knows this contact. A contact belongs to the relationship, not to the holder at large — the same peer met through two personas is two contacts, and collapsing them would correlate the holder's own personas in their own address book.
#[serde(
rename = "knownByPersona",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub known_by_persona: ::std::option::Option<PayloadKnownByPersona>,
///The lists the contact is on, replacing the whole set. Every identifier MUST name a list in this context. Absent: unchanged. Take the contact off every list with `removeLists`.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub lists: ::std::option::Option<ListIds>,
///The holder's private note about this contact, replacing any they had. Absent: unchanged. Never disclosed to anyone, including the contact.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub notes: ::std::option::Option<PayloadNotes>,
///The holder's private name for the contact, replacing any they had. Absent: unchanged.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub petname: ::std::option::Option<Petname>,
///Remove the contact's directory link. Only `true` is accepted.
#[serde(
rename = "removeDirectoryRef",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub remove_directory_ref: ::std::option::Option<bool>,
///Take the contact off every list. Only `true` is accepted.
#[serde(
rename = "removeLists",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub remove_lists: ::std::option::Option<bool>,
///Remove the note. Only `true` is accepted.
#[serde(
rename = "removeNotes",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub remove_notes: ::std::option::Option<bool>,
///Remove the petname. Only `true` is meaningful, so only `true` is accepted. A separate member rather than `petname: null`, because a nullable optional member makes "unchanged" and "remove" the same value in libraries that map both to one absent option.
#[serde(
rename = "removePetname",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub remove_petname: ::std::option::Option<bool>,
///Star or unstar the contact. Absent: unchanged. A boolean rather than a remove member because `false` is a value the holder chose, not an absence.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub starred: ::std::option::Option<bool>,
///Filing form only. The DID the document is about, as disclosed. Normally pairwise, so it names this relationship and not the person across all of theirs.
#[serde(
rename = "subjectDid",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub subject_did: ::std::option::Option<PayloadSubjectDid>,
}
impl Payload {
pub fn builder() -> builder::Payload {
Default::default()
}
}
///`PayloadContextId`
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PayloadContextId(::std::string::String);
impl ::std::ops::Deref for PayloadContextId {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PayloadContextId> for ::std::string::String {
fn from(value: PayloadContextId) -> Self {
value.0
}
}
impl ::std::str::FromStr for PayloadContextId {
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 PayloadContextId {
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 PayloadContextId {
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 PayloadContextId {
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 PayloadContextId {
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())
})
}
}
///`PayloadCredentialRefsItem`
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PayloadCredentialRefsItem(::std::string::String);
impl ::std::ops::Deref for PayloadCredentialRefsItem {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PayloadCredentialRefsItem> for ::std::string::String {
fn from(value: PayloadCredentialRefsItem) -> Self {
value.0
}
}
impl ::std::str::FromStr for PayloadCredentialRefsItem {
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 PayloadCredentialRefsItem {
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 PayloadCredentialRefsItem {
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 PayloadCredentialRefsItem {
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 PayloadCredentialRefsItem {
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())
})
}
}
///Filing and linking forms. Which of the holder's personas knows this contact. A contact belongs to the relationship, not to the holder at large — the same peer met through two personas is two contacts, and collapsing them would correlate the holder's own personas in their own address book.
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PayloadKnownByPersona(::std::string::String);
impl ::std::ops::Deref for PayloadKnownByPersona {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PayloadKnownByPersona> for ::std::string::String {
fn from(value: PayloadKnownByPersona) -> Self {
value.0
}
}
impl ::std::str::FromStr for PayloadKnownByPersona {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 2048usize {
return Err("longer than 2048 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for PayloadKnownByPersona {
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 PayloadKnownByPersona {
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 PayloadKnownByPersona {
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 PayloadKnownByPersona {
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 holder's private note about this contact, replacing any they had. Absent: unchanged. Never disclosed to anyone, including the contact.
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PayloadNotes(::std::string::String);
impl ::std::ops::Deref for PayloadNotes {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PayloadNotes> for ::std::string::String {
fn from(value: PayloadNotes) -> Self {
value.0
}
}
impl ::std::str::FromStr for PayloadNotes {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 4096usize {
return Err("longer than 4096 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for PayloadNotes {
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 PayloadNotes {
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 PayloadNotes {
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 PayloadNotes {
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())
})
}
}
///Filing form only. The DID the document is about, as disclosed. Normally pairwise, so it names this relationship and not the person across all of theirs.
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PayloadSubjectDid(::std::string::String);
impl ::std::ops::Deref for PayloadSubjectDid {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PayloadSubjectDid> for ::std::string::String {
fn from(value: PayloadSubjectDid) -> Self {
value.0
}
}
impl ::std::str::FromStr for PayloadSubjectDid {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 2048usize {
return Err("longer than 2048 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for PayloadSubjectDid {
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 PayloadSubjectDid {
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 PayloadSubjectDid {
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 PayloadSubjectDid {
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 holder's private name for a contact, on one line: no control characters, line breaks included. A petname in Zooko's sense — chosen by the holder, meaningful to the holder, and unforgeable by anyone else, because nobody else can write it. Distinct from the contact's own disclosed `nickname` or display name, which the contact chose and may change. Compared exactly, as a string: an agent does not case-fold or normalise it.
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct Petname(::std::string::String);
impl ::std::ops::Deref for Petname {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<Petname> for ::std::string::String {
fn from(value: Petname) -> Self {
value.0
}
}
impl ::std::str::FromStr for Petname {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 64usize {
return Err("longer than 64 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| {
::regress::Regex::new("^[^\\u0000-\\u001F\\u007F]+$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[^\\u0000-\\u001F\\u007F]+$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for Petname {
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 Petname {
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 Petname {
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 Petname {
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())
})
}
}
/**
How strongly a credential-backed claim is hidden when presented, ordered most private first. `predicate` proves a statement over a claim without disclosing the claim. `derived` discloses exactly the claims needed via an unlinkable derived proof, so two presentations cannot be joined. `selectiveDisclosure` discloses exactly the claims needed but carries the issuer's signature unchanged, so two presentations ARE linkable. `whole` discloses the entire credential.
The distinction between the first two and the last two is of kind, not degree: only `predicate` and `derived` avoid handing two verifiers a join key. A maintainer MUST default to the highest rung the credential's format supports, and MUST NOT silently fall to a lower one — a request that cannot be satisfied at the rung a producer asked for is refused, because a silent privacy downgrade discloses material the holder believed was hidden.*/
///
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum ProofRung {
#[serde(rename = "predicate")]
Predicate,
#[serde(rename = "derived")]
Derived,
#[serde(rename = "selectiveDisclosure")]
SelectiveDisclosure,
#[serde(rename = "whole")]
Whole,
}
impl ::std::fmt::Display for ProofRung {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Predicate => f.write_str("predicate"),
Self::Derived => f.write_str("derived"),
Self::SelectiveDisclosure => f.write_str("selectiveDisclosure"),
Self::Whole => f.write_str("whole"),
}
}
}
impl ::std::str::FromStr for ProofRung {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"predicate" => Ok(Self::Predicate),
"derived" => Ok(Self::Derived),
"selectiveDisclosure" => Ok(Self::SelectiveDisclosure),
"whole" => Ok(Self::Whole),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for ProofRung {
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 ProofRung {
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 ProofRung {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
/**
Where a value comes from, and the member that makes this family worth building on a trust stack rather than in an address book. It survives to the verifier, so a recipient can tell — per field — what the holder typed from what an issuer attested.
`selfAsserted` — the holder supplied it.
`credentialBacked` — the value is derived from a credential in the vault at `claimPath`. The stored value is a CACHE FOR DISPLAY; the credential is the truth. A maintainer MUST re-derive it on read and MUST fail closed (never presenting a stale value) when the credential has been revoked, has expired, or has been archived or deleted.
`generated` — the value is minted per verifier at disclosure time and recorded against that verifier, so every relying party receives a different one that routes back to the holder. This is the shape of the most widely adopted consumer privacy feature in this space; a maintainer need not operate a relay to conform, but the shape must exist, because retrofitting per-verifier values into a pool-of-values model is a migration rather than an addition.
`derived` — the value was taken from a source the holder connected or supplied — a code-hosting profile, an uploaded CV — rather than typed by them or attested by an issuer. Nobody signed it: it is the holder's claim that the source said so, and a consumer MUST NOT present it as attested. It exists as its own kind because a derived value is neither of the others — the holder did not author it, and no one vouches for it — and a holder deciding whether to disclose deserves to know which of their values they typed.
For how strongly a disclosed value identifies the holder, the kinds rank `credentialBacked` above `derived` above `selfAsserted`; `generated` values are per-verifier and do not correlate.*/
///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(untagged, deny_unknown_fields)]
#[non_exhaustive]
pub enum Provenance {
Variant0 {
kind: ::serde_json::Value,
},
Variant1 {
///RFC 6901 JSON Pointer to the claim within the credential, e.g. `/credentialSubject/familyName`.
#[serde(rename = "claimPath")]
claim_path: ProvenanceVariant1ClaimPath,
///Vault identifier of the backing credential.
#[serde(rename = "credentialId")]
credential_id: ProvenanceVariant1CredentialId,
///Issuer of the backing credential. Advisory: a consumer MUST verify the credential rather than trusting this member.
#[serde(
rename = "issuerDid",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
issuer_did: ::std::option::Option<ProvenanceVariant1IssuerDid>,
kind: ::serde_json::Value,
///The disclosure rung this claim was, or will be, presented at.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
proof: ::std::option::Option<ProofRung>,
},
Variant2 {
///Names the minting scheme, e.g. `relayEmail`. Maintainer-defined.
generator: ProvenanceVariant2Generator,
kind: ::serde_json::Value,
///When true (the default and the only useful setting), a distinct value is minted for each verifier.
#[serde(rename = "perVerifier", default = "defaults::default_bool::<true>")]
per_verifier: bool,
},
Variant3 {
///When the value was taken from the source. A derived value is a snapshot: the source may have changed since, and nothing re-derives it.
#[serde(rename = "derivedAt")]
derived_at: ::chrono::DateTime<::chrono::offset::Utc>,
kind: ::serde_json::Value,
///The KIND of source the value was taken from — `github`, `cvUpload`, `linkedIn` — never an account, handle or URL. Provenance survives to the verifier, so this member is disclosed with the claim; a handle here would disclose an identifier the holder never chose to share.
source: ProvenanceVariant3Source,
},
}
///RFC 6901 JSON Pointer to the claim within the credential, e.g. `/credentialSubject/familyName`.
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ProvenanceVariant1ClaimPath(::std::string::String);
impl ::std::ops::Deref for ProvenanceVariant1ClaimPath {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ProvenanceVariant1ClaimPath> for ::std::string::String {
fn from(value: ProvenanceVariant1ClaimPath) -> Self {
value.0
}
}
impl ::std::str::FromStr for ProvenanceVariant1ClaimPath {
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("^(/[^/~]*(~[01][^/~]*)*)*$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^(/[^/~]*(~[01][^/~]*)*)*$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ProvenanceVariant1ClaimPath {
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 ProvenanceVariant1ClaimPath {
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 ProvenanceVariant1ClaimPath {
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 ProvenanceVariant1ClaimPath {
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())
})
}
}
///Vault identifier of the backing credential.
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ProvenanceVariant1CredentialId(::std::string::String);
impl ::std::ops::Deref for ProvenanceVariant1CredentialId {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ProvenanceVariant1CredentialId> for ::std::string::String {
fn from(value: ProvenanceVariant1CredentialId) -> Self {
value.0
}
}
impl ::std::str::FromStr for ProvenanceVariant1CredentialId {
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 ProvenanceVariant1CredentialId {
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 ProvenanceVariant1CredentialId {
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 ProvenanceVariant1CredentialId {
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 ProvenanceVariant1CredentialId {
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())
})
}
}
///Issuer of the backing credential. Advisory: a consumer MUST verify the credential rather than trusting this member.
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ProvenanceVariant1IssuerDid(::std::string::String);
impl ::std::ops::Deref for ProvenanceVariant1IssuerDid {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ProvenanceVariant1IssuerDid> for ::std::string::String {
fn from(value: ProvenanceVariant1IssuerDid) -> Self {
value.0
}
}
impl ::std::str::FromStr for ProvenanceVariant1IssuerDid {
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 ProvenanceVariant1IssuerDid {
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 ProvenanceVariant1IssuerDid {
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 ProvenanceVariant1IssuerDid {
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 ProvenanceVariant1IssuerDid {
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())
})
}
}
///Names the minting scheme, e.g. `relayEmail`. Maintainer-defined.
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ProvenanceVariant2Generator(::std::string::String);
impl ::std::ops::Deref for ProvenanceVariant2Generator {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ProvenanceVariant2Generator> for ::std::string::String {
fn from(value: ProvenanceVariant2Generator) -> Self {
value.0
}
}
impl ::std::str::FromStr for ProvenanceVariant2Generator {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 64usize {
return Err("longer than 64 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ProvenanceVariant2Generator {
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 ProvenanceVariant2Generator {
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 ProvenanceVariant2Generator {
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 ProvenanceVariant2Generator {
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 KIND of source the value was taken from — `github`, `cvUpload`, `linkedIn` — never an account, handle or URL. Provenance survives to the verifier, so this member is disclosed with the claim; a handle here would disclose an identifier the holder never chose to share.
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ProvenanceVariant3Source(::std::string::String);
impl ::std::ops::Deref for ProvenanceVariant3Source {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ProvenanceVariant3Source> for ::std::string::String {
fn from(value: ProvenanceVariant3Source) -> Self {
value.0
}
}
impl ::std::str::FromStr for ProvenanceVariant3Source {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 64usize {
return Err("longer than 64 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| ::regress::Regex::new("^[a-z][A-Za-z0-9.-]*$").unwrap());
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[a-z][A-Za-z0-9.-]*$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ProvenanceVariant3Source {
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 ProvenanceVariant3Source {
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 ProvenanceVariant3Source {
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 ProvenanceVariant3Source {
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())
})
}
}
///Success response to persona/contact/put. Type https://trusttasks.org/spec/persona/contact/put/1.2#response. Identifiers, the current revision and what changed; no claim value and no annotation text is echoed.
///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct Response {
///True when any annotation now differs from what was stored. False when every annotation given already matched and every one named for removal was already absent — including a filing that named none.
#[serde(rename = "annotationsChanged")]
pub annotations_changed: bool,
///Claim types whose value differs from the previous revision. Present only on a filing that updated an existing contact.
#[serde(
rename = "changedClaims",
default,
skip_serializing_if = "::std::vec::Vec::is_empty"
)]
pub changed_claims: ::std::vec::Vec<ClaimType>,
#[serde(rename = "contactId")]
pub contact_id: Ulid,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ext: ::std::option::Option<Ext>,
///The contact's current revision: the one a filing just appended, or, for an annotating request, the revision that was already current. Annotations never move it.
pub rev: ::std::num::NonZeroU64,
///True when this is the first revision for the subject. Always false for an annotating request.
#[serde(rename = "wasCreated")]
pub was_created: bool,
}
impl Response {
pub fn builder() -> builder::Response {
Default::default()
}
}
///A ULID in Crockford base32, uppercase. Used for `attributeId` and `profileId`. Chosen over a UUID because the leading 48 bits are a timestamp, so a key-ordered scan of the store is also creation-ordered and a `list` needs no secondary sort. Server-assigned on create; a producer MAY supply one to make a create idempotent, and a maintainer MUST reject a supplied value that already exists rather than silently overwriting.
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct Ulid(::std::string::String);
impl ::std::ops::Deref for Ulid {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<Ulid> for ::std::string::String {
fn from(value: Ulid) -> Self {
value.0
}
}
impl ::std::str::FromStr for Ulid {
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("^[0-9A-HJKMNP-TV-Z]{26}$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[0-9A-HJKMNP-TV-Z]{26}$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for Ulid {
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 Ulid {
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 Ulid {
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 Ulid {
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 JSON shape of `value`, declared so that a consumer can render and compare without guessing. The maintainer validates that `value` agrees with this member and does nothing further: it does NOT validate a phone number against a phone-number grammar. That is a producer's affordance, and a store that grows opinions about the contents of its records eventually blocks its consumer's release.
///
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum ValueType {
#[serde(rename = "string")]
String,
#[serde(rename = "number")]
Number,
#[serde(rename = "boolean")]
Boolean,
#[serde(rename = "date")]
Date,
#[serde(rename = "object")]
Object,
}
impl ::std::fmt::Display for ValueType {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::String => f.write_str("string"),
Self::Number => f.write_str("number"),
Self::Boolean => f.write_str("boolean"),
Self::Date => f.write_str("date"),
Self::Object => f.write_str("object"),
}
}
}
impl ::std::str::FromStr for ValueType {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"string" => Ok(Self::String),
"number" => Ok(Self::Number),
"boolean" => Ok(Self::Boolean),
"date" => Ok(Self::Date),
"object" => Ok(Self::Object),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for ValueType {
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 ValueType {
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 ValueType {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
/// Types for composing complex structures.
pub mod builder {
#[derive(Clone, Debug)]
pub struct ContactDocument {
card_version: ::std::result::Result<
::std::option::Option<::std::num::NonZeroU64>,
::std::string::String,
>,
claims: ::std::result::Result<
::std::vec::Vec<super::ContactDocumentClaimsItem>,
::std::string::String,
>,
publisher: ::std::result::Result<
::std::option::Option<super::ContactDocumentPublisher>,
::std::string::String,
>,
}
impl ::std::default::Default for ContactDocument {
fn default() -> Self {
Self {
card_version: Ok(Default::default()),
claims: Err("no value supplied for claims".to_string()),
publisher: Ok(Default::default()),
}
}
}
impl ContactDocument {
pub fn card_version<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<::std::num::NonZeroU64>>,
T::Error: ::std::fmt::Display,
{
self.card_version = value
.try_into()
.map_err(|e| format!("error converting supplied value for card_version: {e}"));
self
}
pub fn claims<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::vec::Vec<super::ContactDocumentClaimsItem>>,
T::Error: ::std::fmt::Display,
{
self.claims = value
.try_into()
.map_err(|e| format!("error converting supplied value for claims: {e}"));
self
}
pub fn publisher<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::ContactDocumentPublisher>>,
T::Error: ::std::fmt::Display,
{
self.publisher = value
.try_into()
.map_err(|e| format!("error converting supplied value for publisher: {e}"));
self
}
}
impl ::std::convert::TryFrom<ContactDocument> for super::ContactDocument {
type Error = super::error::ConversionError;
fn try_from(
value: ContactDocument,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
card_version: value.card_version?,
claims: value.claims?,
publisher: value.publisher?,
})
}
}
impl ::std::convert::From<super::ContactDocument> for ContactDocument {
fn from(value: super::ContactDocument) -> Self {
Self {
card_version: Ok(value.card_version),
claims: Ok(value.claims),
publisher: Ok(value.publisher),
}
}
}
#[derive(Clone, Debug)]
pub struct ContactDocumentClaimsItem {
provenance:
::std::result::Result<::std::option::Option<super::Provenance>, ::std::string::String>,
type_: ::std::result::Result<super::ClaimType, ::std::string::String>,
value: ::std::result::Result<::serde_json::Value, ::std::string::String>,
value_type: ::std::result::Result<super::ValueType, ::std::string::String>,
}
impl ::std::default::Default for ContactDocumentClaimsItem {
fn default() -> Self {
Self {
provenance: Ok(Default::default()),
type_: Err("no value supplied for type_".to_string()),
value: Err("no value supplied for value".to_string()),
value_type: Err("no value supplied for value_type".to_string()),
}
}
}
impl ContactDocumentClaimsItem {
pub fn provenance<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::Provenance>>,
T::Error: ::std::fmt::Display,
{
self.provenance = value
.try_into()
.map_err(|e| format!("error converting supplied value for provenance: {e}"));
self
}
pub fn type_<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::ClaimType>,
T::Error: ::std::fmt::Display,
{
self.type_ = value
.try_into()
.map_err(|e| format!("error converting supplied value for type_: {e}"));
self
}
pub fn value<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::serde_json::Value>,
T::Error: ::std::fmt::Display,
{
self.value = value
.try_into()
.map_err(|e| format!("error converting supplied value for value: {e}"));
self
}
pub fn value_type<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::ValueType>,
T::Error: ::std::fmt::Display,
{
self.value_type = value
.try_into()
.map_err(|e| format!("error converting supplied value for value_type: {e}"));
self
}
}
impl ::std::convert::TryFrom<ContactDocumentClaimsItem> for super::ContactDocumentClaimsItem {
type Error = super::error::ConversionError;
fn try_from(
value: ContactDocumentClaimsItem,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
provenance: value.provenance?,
type_: value.type_?,
value: value.value?,
value_type: value.value_type?,
})
}
}
impl ::std::convert::From<super::ContactDocumentClaimsItem> for ContactDocumentClaimsItem {
fn from(value: super::ContactDocumentClaimsItem) -> Self {
Self {
provenance: Ok(value.provenance),
type_: Ok(value.type_),
value: Ok(value.value),
value_type: Ok(value.value_type),
}
}
}
#[derive(Clone, Debug)]
pub struct DirectoryRef {
entry_id: ::std::result::Result<super::DirectoryEntryId, ::std::string::String>,
vtc_did: ::std::result::Result<super::DirectoryRefVtcDid, ::std::string::String>,
}
impl ::std::default::Default for DirectoryRef {
fn default() -> Self {
Self {
entry_id: Err("no value supplied for entry_id".to_string()),
vtc_did: Err("no value supplied for vtc_did".to_string()),
}
}
}
impl DirectoryRef {
pub fn entry_id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::DirectoryEntryId>,
T::Error: ::std::fmt::Display,
{
self.entry_id = value
.try_into()
.map_err(|e| format!("error converting supplied value for entry_id: {e}"));
self
}
pub fn vtc_did<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::DirectoryRefVtcDid>,
T::Error: ::std::fmt::Display,
{
self.vtc_did = value
.try_into()
.map_err(|e| format!("error converting supplied value for vtc_did: {e}"));
self
}
}
impl ::std::convert::TryFrom<DirectoryRef> for super::DirectoryRef {
type Error = super::error::ConversionError;
fn try_from(
value: DirectoryRef,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
entry_id: value.entry_id?,
vtc_did: value.vtc_did?,
})
}
}
impl ::std::convert::From<super::DirectoryRef> for DirectoryRef {
fn from(value: super::DirectoryRef) -> Self {
Self {
entry_id: Ok(value.entry_id),
vtc_did: Ok(value.vtc_did),
}
}
}
#[derive(Clone, Debug)]
pub struct Payload {
contact_id:
::std::result::Result<::std::option::Option<super::Ulid>, ::std::string::String>,
context_id: ::std::result::Result<super::PayloadContextId, ::std::string::String>,
credential_refs: ::std::result::Result<
::std::vec::Vec<super::PayloadCredentialRefsItem>,
::std::string::String,
>,
directory_ref: ::std::result::Result<
::std::option::Option<super::DirectoryRef>,
::std::string::String,
>,
document: ::std::result::Result<
::std::option::Option<super::ContactDocument>,
::std::string::String,
>,
ext: ::std::result::Result<::std::option::Option<super::Ext>, ::std::string::String>,
known_by_persona: ::std::result::Result<
::std::option::Option<super::PayloadKnownByPersona>,
::std::string::String,
>,
lists: ::std::result::Result<::std::option::Option<super::ListIds>, ::std::string::String>,
notes: ::std::result::Result<
::std::option::Option<super::PayloadNotes>,
::std::string::String,
>,
petname:
::std::result::Result<::std::option::Option<super::Petname>, ::std::string::String>,
remove_directory_ref:
::std::result::Result<::std::option::Option<bool>, ::std::string::String>,
remove_lists: ::std::result::Result<::std::option::Option<bool>, ::std::string::String>,
remove_notes: ::std::result::Result<::std::option::Option<bool>, ::std::string::String>,
remove_petname: ::std::result::Result<::std::option::Option<bool>, ::std::string::String>,
starred: ::std::result::Result<::std::option::Option<bool>, ::std::string::String>,
subject_did: ::std::result::Result<
::std::option::Option<super::PayloadSubjectDid>,
::std::string::String,
>,
}
impl ::std::default::Default for Payload {
fn default() -> Self {
Self {
contact_id: Ok(Default::default()),
context_id: Err("no value supplied for context_id".to_string()),
credential_refs: Ok(Default::default()),
directory_ref: Ok(Default::default()),
document: Ok(Default::default()),
ext: Ok(Default::default()),
known_by_persona: Ok(Default::default()),
lists: Ok(Default::default()),
notes: Ok(Default::default()),
petname: Ok(Default::default()),
remove_directory_ref: Ok(Default::default()),
remove_lists: Ok(Default::default()),
remove_notes: Ok(Default::default()),
remove_petname: Ok(Default::default()),
starred: Ok(Default::default()),
subject_did: Ok(Default::default()),
}
}
}
impl Payload {
pub fn contact_id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::Ulid>>,
T::Error: ::std::fmt::Display,
{
self.contact_id = value
.try_into()
.map_err(|e| format!("error converting supplied value for contact_id: {e}"));
self
}
pub fn context_id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::PayloadContextId>,
T::Error: ::std::fmt::Display,
{
self.context_id = value
.try_into()
.map_err(|e| format!("error converting supplied value for context_id: {e}"));
self
}
pub fn credential_refs<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::vec::Vec<super::PayloadCredentialRefsItem>>,
T::Error: ::std::fmt::Display,
{
self.credential_refs = value
.try_into()
.map_err(|e| format!("error converting supplied value for credential_refs: {e}"));
self
}
pub fn directory_ref<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::DirectoryRef>>,
T::Error: ::std::fmt::Display,
{
self.directory_ref = value
.try_into()
.map_err(|e| format!("error converting supplied value for directory_ref: {e}"));
self
}
pub fn document<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::ContactDocument>>,
T::Error: ::std::fmt::Display,
{
self.document = value
.try_into()
.map_err(|e| format!("error converting supplied value for document: {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 known_by_persona<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::PayloadKnownByPersona>>,
T::Error: ::std::fmt::Display,
{
self.known_by_persona = value
.try_into()
.map_err(|e| format!("error converting supplied value for known_by_persona: {e}"));
self
}
pub fn lists<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::ListIds>>,
T::Error: ::std::fmt::Display,
{
self.lists = value
.try_into()
.map_err(|e| format!("error converting supplied value for lists: {e}"));
self
}
pub fn notes<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::PayloadNotes>>,
T::Error: ::std::fmt::Display,
{
self.notes = value
.try_into()
.map_err(|e| format!("error converting supplied value for notes: {e}"));
self
}
pub fn petname<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::Petname>>,
T::Error: ::std::fmt::Display,
{
self.petname = value
.try_into()
.map_err(|e| format!("error converting supplied value for petname: {e}"));
self
}
pub fn remove_directory_ref<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<bool>>,
T::Error: ::std::fmt::Display,
{
self.remove_directory_ref = value.try_into().map_err(|e| {
format!("error converting supplied value for remove_directory_ref: {e}")
});
self
}
pub fn remove_lists<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<bool>>,
T::Error: ::std::fmt::Display,
{
self.remove_lists = value
.try_into()
.map_err(|e| format!("error converting supplied value for remove_lists: {e}"));
self
}
pub fn remove_notes<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<bool>>,
T::Error: ::std::fmt::Display,
{
self.remove_notes = value
.try_into()
.map_err(|e| format!("error converting supplied value for remove_notes: {e}"));
self
}
pub fn remove_petname<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<bool>>,
T::Error: ::std::fmt::Display,
{
self.remove_petname = value
.try_into()
.map_err(|e| format!("error converting supplied value for remove_petname: {e}"));
self
}
pub fn starred<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<bool>>,
T::Error: ::std::fmt::Display,
{
self.starred = value
.try_into()
.map_err(|e| format!("error converting supplied value for starred: {e}"));
self
}
pub fn subject_did<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::PayloadSubjectDid>>,
T::Error: ::std::fmt::Display,
{
self.subject_did = value
.try_into()
.map_err(|e| format!("error converting supplied value for subject_did: {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 {
contact_id: value.contact_id?,
context_id: value.context_id?,
credential_refs: value.credential_refs?,
directory_ref: value.directory_ref?,
document: value.document?,
ext: value.ext?,
known_by_persona: value.known_by_persona?,
lists: value.lists?,
notes: value.notes?,
petname: value.petname?,
remove_directory_ref: value.remove_directory_ref?,
remove_lists: value.remove_lists?,
remove_notes: value.remove_notes?,
remove_petname: value.remove_petname?,
starred: value.starred?,
subject_did: value.subject_did?,
})
}
}
impl ::std::convert::From<super::Payload> for Payload {
fn from(value: super::Payload) -> Self {
Self {
contact_id: Ok(value.contact_id),
context_id: Ok(value.context_id),
credential_refs: Ok(value.credential_refs),
directory_ref: Ok(value.directory_ref),
document: Ok(value.document),
ext: Ok(value.ext),
known_by_persona: Ok(value.known_by_persona),
lists: Ok(value.lists),
notes: Ok(value.notes),
petname: Ok(value.petname),
remove_directory_ref: Ok(value.remove_directory_ref),
remove_lists: Ok(value.remove_lists),
remove_notes: Ok(value.remove_notes),
remove_petname: Ok(value.remove_petname),
starred: Ok(value.starred),
subject_did: Ok(value.subject_did),
}
}
}
#[derive(Clone, Debug)]
pub struct Response {
annotations_changed: ::std::result::Result<bool, ::std::string::String>,
changed_claims:
::std::result::Result<::std::vec::Vec<super::ClaimType>, ::std::string::String>,
contact_id: ::std::result::Result<super::Ulid, ::std::string::String>,
ext: ::std::result::Result<::std::option::Option<super::Ext>, ::std::string::String>,
rev: ::std::result::Result<::std::num::NonZeroU64, ::std::string::String>,
was_created: ::std::result::Result<bool, ::std::string::String>,
}
impl ::std::default::Default for Response {
fn default() -> Self {
Self {
annotations_changed: Err("no value supplied for annotations_changed".to_string()),
changed_claims: Ok(Default::default()),
contact_id: Err("no value supplied for contact_id".to_string()),
ext: Ok(Default::default()),
rev: Err("no value supplied for rev".to_string()),
was_created: Err("no value supplied for was_created".to_string()),
}
}
}
impl Response {
pub fn annotations_changed<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<bool>,
T::Error: ::std::fmt::Display,
{
self.annotations_changed = value.try_into().map_err(|e| {
format!("error converting supplied value for annotations_changed: {e}")
});
self
}
pub fn changed_claims<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::vec::Vec<super::ClaimType>>,
T::Error: ::std::fmt::Display,
{
self.changed_claims = value
.try_into()
.map_err(|e| format!("error converting supplied value for changed_claims: {e}"));
self
}
pub fn contact_id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::Ulid>,
T::Error: ::std::fmt::Display,
{
self.contact_id = value
.try_into()
.map_err(|e| format!("error converting supplied value for contact_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 rev<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::num::NonZeroU64>,
T::Error: ::std::fmt::Display,
{
self.rev = value
.try_into()
.map_err(|e| format!("error converting supplied value for rev: {e}"));
self
}
pub fn was_created<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<bool>,
T::Error: ::std::fmt::Display,
{
self.was_created = value
.try_into()
.map_err(|e| format!("error converting supplied value for was_created: {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 {
annotations_changed: value.annotations_changed?,
changed_claims: value.changed_claims?,
contact_id: value.contact_id?,
ext: value.ext?,
rev: value.rev?,
was_created: value.was_created?,
})
}
}
impl ::std::convert::From<super::Response> for Response {
fn from(value: super::Response) -> Self {
Self {
annotations_changed: Ok(value.annotations_changed),
changed_claims: Ok(value.changed_claims),
contact_id: Ok(value.contact_id),
ext: Ok(value.ext),
rev: Ok(value.rev),
was_created: Ok(value.was_created),
}
}
}
}
/// Generation of default values for serde.
pub mod defaults {
pub(super) fn default_bool<const V: bool>() -> bool {
V
}
}
impl crate::Payload for Payload {
const TYPE_URI: &'static str = "https://trusttasks.org/spec/persona/contact/put/1.2";
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(
"{\"$defs\":{\"ClaimType\":{\"description\":\"The vocabulary token naming what a value IS — `name.legal`, `phone.mobile`, `address.postal`, `person.birthDate`. Dotted, most-general segment first, so that a consumer with no knowledge of the specific token can still group by its prefix.\\n\\nThe token is the maintainer's own; no external vocabulary is primary. External vocabularies (vCard/jCard, OIDC standard claims, schema.org) are mappings applied at PRESENTATION by a renderer, not at rest, so that a query written in any of them can be matched without the store having to live inside any one of them.\\n\\nThe `x:` prefix is an open extension namespace and is not decoration. The closest prior art — Windows CardSpace's self-issued card — supported exactly fifteen predefined claim types with no extensibility, and that is the specific way it failed the requirement a holder actually has. An `x:` attribute stores, composes, binds and discloses exactly like a known one; it renders generically and matches only an explicit query.\",\"maxLength\":128,\"minLength\":1,\"pattern\":\"^(x:)?[a-z][a-zA-Z0-9]*(\\\\.[a-z][a-zA-Z0-9]*)*$\",\"title\":\"ClaimType\",\"type\":\"string\"},\"ContactDocument\":{\"additionalProperties\":false,\"description\":\"What a peer disclosed, as received. Structurally the same claim set a holder composes and presents — a profile and a contact card are one schema seen from two sides — which is why a maintainer validates both with the same code and a consumer renders both with the same view.\",\"properties\":{\"cardVersion\":{\"description\":\"The publisher's own monotonic counter, if they supplied one. Advisory: it orders the publisher's revisions relative to each other and MUST NOT be trusted to order them against anything else.\",\"minimum\":1,\"type\":\"integer\"},\"claims\":{\"items\":{\"additionalProperties\":false,\"properties\":{\"provenance\":{\"$ref\":\"#/$defs/Provenance\",\"description\":\"As asserted by the publisher. A recipient MUST NOT treat a claimed credentialBacked provenance as verified — it is a statement about what the publisher says backs the claim, and verification is a separate act against the credential itself.\"},\"type\":{\"$ref\":\"#/$defs/ClaimType\"},\"value\":{},\"valueType\":{\"$ref\":\"#/$defs/ValueType\"}},\"required\":[\"type\",\"valueType\",\"value\"],\"type\":\"object\"},\"maxItems\":256,\"type\":\"array\"},\"publisher\":{\"description\":\"The DID that published the document, as it appeared. Normally a pairwise identifier, so it names the relationship rather than the person.\",\"maxLength\":2048,\"type\":\"string\"}},\"required\":[\"claims\"],\"title\":\"ContactDocument\",\"type\":\"object\"},\"DirectoryEntryId\":{\"description\":\"A community directory entry's identifier, exactly as that community's directory returned it. Opaque and community-scoped: the agent stores and compares it as a string, never parses it, and never treats the same value under two communities as the same entry.\",\"maxLength\":128,\"minLength\":1,\"pattern\":\"^[A-Za-z0-9_-]+$\",\"title\":\"DirectoryEntryId\",\"type\":\"string\"},\"DirectoryRef\":{\"additionalProperties\":false,\"description\":\"Links a contact to the entry in a community's member directory it corresponds to, so the holder's own client can join that community's directory with the holder's address book — showing a star or a petname beside an entry — without either side telling the other. The community never learns the link exists; the contact never learns it either. A contact has at most one.\",\"properties\":{\"entryId\":{\"$ref\":\"#/$defs/DirectoryEntryId\",\"description\":\"The entry, as that community's directory identifies it.\"},\"vtcDid\":{\"description\":\"The DID of the community whose directory holds the entry.\",\"maxLength\":2048,\"minLength\":1,\"pattern\":\"^did:[a-z0-9]+:\",\"type\":\"string\"}},\"required\":[\"vtcDid\",\"entryId\"],\"title\":\"DirectoryRef\",\"type\":\"object\"},\"Ext\":{\"additionalProperties\":true,\"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.\",\"minProperties\":1,\"propertyNames\":{\"pattern\":\"^[a-z][a-z0-9-]*(\\\\.[a-z0-9-]+)+$\"},\"title\":\"Ext\",\"type\":\"object\"},\"ListId\":{\"description\":\"Identifier of one of the holder's contact lists: a ULID in Crockford base32, uppercase, assigned by the agent when the list is created. Meaningful only inside the context that holds the list; it is never sent to anyone but the holder's own clients.\",\"pattern\":\"^[0-9A-HJKMNP-TV-Z]{26}$\",\"title\":\"ListId\",\"type\":\"string\"},\"ListIds\":{\"description\":\"The lists a contact is on, as a set: order carries no meaning. A contact on no list has no `lists` member, never an empty array, so there is one way to say \\\"none\\\".\",\"items\":{\"$ref\":\"#/$defs/ListId\"},\"maxItems\":64,\"minItems\":1,\"title\":\"ListIds\",\"type\":\"array\",\"uniqueItems\":true},\"Petname\":{\"description\":\"The holder's private name for a contact, on one line: no control characters, line breaks included. A petname in Zooko's sense — chosen by the holder, meaningful to the holder, and unforgeable by anyone else, because nobody else can write it. Distinct from the contact's own disclosed `nickname` or display name, which the contact chose and may change. Compared exactly, as a string: an agent does not case-fold or normalise it.\",\"maxLength\":64,\"minLength\":1,\"pattern\":\"^[^\\\\u0000-\\\\u001F\\\\u007F]+$\",\"title\":\"Petname\",\"type\":\"string\"},\"ProofRung\":{\"description\":\"How strongly a credential-backed claim is hidden when presented, ordered most private first. `predicate` proves a statement over a claim without disclosing the claim. `derived` discloses exactly the claims needed via an unlinkable derived proof, so two presentations cannot be joined. `selectiveDisclosure` discloses exactly the claims needed but carries the issuer's signature unchanged, so two presentations ARE linkable. `whole` discloses the entire credential.\\n\\nThe distinction between the first two and the last two is of kind, not degree: only `predicate` and `derived` avoid handing two verifiers a join key. A maintainer MUST default to the highest rung the credential's format supports, and MUST NOT silently fall to a lower one — a request that cannot be satisfied at the rung a producer asked for is refused, because a silent privacy downgrade discloses material the holder believed was hidden.\",\"enum\":[\"predicate\",\"derived\",\"selectiveDisclosure\",\"whole\"],\"title\":\"ProofRung\",\"type\":\"string\"},\"Provenance\":{\"description\":\"Where a value comes from, and the member that makes this family worth building on a trust stack rather than in an address book. It survives to the verifier, so a recipient can tell — per field — what the holder typed from what an issuer attested.\\n\\n`selfAsserted` — the holder supplied it.\\n\\n`credentialBacked` — the value is derived from a credential in the vault at `claimPath`. The stored value is a CACHE FOR DISPLAY; the credential is the truth. A maintainer MUST re-derive it on read and MUST fail closed (never presenting a stale value) when the credential has been revoked, has expired, or has been archived or deleted.\\n\\n`generated` — the value is minted per verifier at disclosure time and recorded against that verifier, so every relying party receives a different one that routes back to the holder. This is the shape of the most widely adopted consumer privacy feature in this space; a maintainer need not operate a relay to conform, but the shape must exist, because retrofitting per-verifier values into a pool-of-values model is a migration rather than an addition.\\n\\n`derived` — the value was taken from a source the holder connected or supplied — a code-hosting profile, an uploaded CV — rather than typed by them or attested by an issuer. Nobody signed it: it is the holder's claim that the source said so, and a consumer MUST NOT present it as attested. It exists as its own kind because a derived value is neither of the others — the holder did not author it, and no one vouches for it — and a holder deciding whether to disclose deserves to know which of their values they typed.\\n\\nFor how strongly a disclosed value identifies the holder, the kinds rank `credentialBacked` above `derived` above `selfAsserted`; `generated` values are per-verifier and do not correlate.\",\"oneOf\":[{\"additionalProperties\":false,\"properties\":{\"kind\":{\"const\":\"selfAsserted\"}},\"required\":[\"kind\"]},{\"additionalProperties\":false,\"properties\":{\"claimPath\":{\"description\":\"RFC 6901 JSON Pointer to the claim within the credential, e.g. `/credentialSubject/familyName`.\",\"pattern\":\"^(/[^/~]*(~[01][^/~]*)*)*$\",\"type\":\"string\"},\"credentialId\":{\"description\":\"Vault identifier of the backing credential.\",\"minLength\":1,\"type\":\"string\"},\"issuerDid\":{\"description\":\"Issuer of the backing credential. Advisory: a consumer MUST verify the credential rather than trusting this member.\",\"minLength\":1,\"type\":\"string\"},\"kind\":{\"const\":\"credentialBacked\"},\"proof\":{\"$ref\":\"#/$defs/ProofRung\",\"description\":\"The disclosure rung this claim was, or will be, presented at.\"}},\"required\":[\"kind\",\"credentialId\",\"claimPath\"]},{\"additionalProperties\":false,\"properties\":{\"generator\":{\"description\":\"Names the minting scheme, e.g. `relayEmail`. Maintainer-defined.\",\"maxLength\":64,\"minLength\":1,\"type\":\"string\"},\"kind\":{\"const\":\"generated\"},\"perVerifier\":{\"default\":true,\"description\":\"When true (the default and the only useful setting), a distinct value is minted for each verifier.\",\"type\":\"boolean\"}},\"required\":[\"kind\",\"generator\"]},{\"additionalProperties\":false,\"properties\":{\"derivedAt\":{\"description\":\"When the value was taken from the source. A derived value is a snapshot: the source may have changed since, and nothing re-derives it.\",\"format\":\"date-time\",\"type\":\"string\"},\"kind\":{\"const\":\"derived\"},\"source\":{\"description\":\"The KIND of source the value was taken from — `github`, `cvUpload`, `linkedIn` — never an account, handle or URL. Provenance survives to the verifier, so this member is disclosed with the claim; a handle here would disclose an identifier the holder never chose to share.\",\"maxLength\":64,\"minLength\":1,\"pattern\":\"^[a-z][A-Za-z0-9.-]*$\",\"type\":\"string\"}},\"required\":[\"kind\",\"source\",\"derivedAt\"]}],\"required\":[\"kind\"],\"title\":\"Provenance\",\"type\":\"object\"},\"Response\":{\"$anchor\":\"response\",\"additionalProperties\":false,\"description\":\"Success response to persona/contact/put. Type https://trusttasks.org/spec/persona/contact/put/1.2#response. Identifiers, the current revision and what changed; no claim value and no annotation text is echoed.\",\"properties\":{\"annotationsChanged\":{\"description\":\"True when any annotation now differs from what was stored. False when every annotation given already matched and every one named for removal was already absent — including a filing that named none.\",\"type\":\"boolean\"},\"changedClaims\":{\"description\":\"Claim types whose value differs from the previous revision. Present only on a filing that updated an existing contact.\",\"items\":{\"$ref\":\"#/$defs/ClaimType\"},\"maxItems\":256,\"type\":\"array\"},\"contactId\":{\"$ref\":\"#/$defs/Ulid\"},\"ext\":{\"$ref\":\"#/$defs/Ext\"},\"rev\":{\"description\":\"The contact's current revision: the one a filing just appended, or, for an annotating request, the revision that was already current. Annotations never move it.\",\"minimum\":1,\"type\":\"integer\"},\"wasCreated\":{\"description\":\"True when this is the first revision for the subject. Always false for an annotating request.\",\"type\":\"boolean\"}},\"required\":[\"contactId\",\"rev\",\"wasCreated\",\"annotationsChanged\"],\"title\":\"Persona Contact Put — response payload\",\"type\":\"object\"},\"Ulid\":{\"description\":\"A ULID in Crockford base32, uppercase. Used for `attributeId` and `profileId`. Chosen over a UUID because the leading 48 bits are a timestamp, so a key-ordered scan of the store is also creation-ordered and a `list` needs no secondary sort. Server-assigned on create; a producer MAY supply one to make a create idempotent, and a maintainer MUST reject a supplied value that already exists rather than silently overwriting.\",\"pattern\":\"^[0-9A-HJKMNP-TV-Z]{26}$\",\"title\":\"Ulid\",\"type\":\"string\"},\"ValueType\":{\"description\":\"The JSON shape of `value`, declared so that a consumer can render and compare without guessing. The maintainer validates that `value` agrees with this member and does nothing further: it does NOT validate a phone number against a phone-number grammar. That is a producer's affordance, and a store that grows opinions about the contents of its records eventually blocks its consumer's release.\",\"enum\":[\"string\",\"number\",\"boolean\",\"date\",\"object\"],\"title\":\"ValueType\",\"type\":\"string\"}},\"$id\":\"https://trusttasks.org/spec/persona/contact/put/1.2\",\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"additionalProperties\":false,\"dependentSchemas\":{\"removeDirectoryRef\":{\"not\":{\"required\":[\"directoryRef\"]}},\"removeLists\":{\"not\":{\"required\":[\"lists\"]}},\"removeNotes\":{\"not\":{\"required\":[\"notes\"]}},\"removePetname\":{\"not\":{\"required\":[\"petname\"]}}},\"description\":\"File what a peer disclosed, or change the holder's own annotations on a contact, or both. Three forms. FILING (`subjectDid`, `knownByPersona`, `document`; no `contactId`) appends a revision, never overwrites, so a changed value is visible as a change rather than arriving silently — exactly as 1.0. ANNOTATING (`contactId`; no `subjectDid`, `knownByPersona`, `document` or `credentialRefs`) changes the holder's star, petname, lists, directory link or notes on an existing contact and appends no revision. LINKING (`directoryRef`, `knownByPersona`; no `contactId`, `subjectDid`, `document` or `credentialRefs`) keeps annotations on a member of a community's directory whose DID the holder has not been shown: it finds, or makes, the contact for that entry and persona, and appends no revision. In every form each annotation given replaces the stored one, each `removeX` removes one, and each annotation absent is unchanged. The outer document members are owned by the framework — SPEC §6.3.\",\"oneOf\":[{\"not\":{\"required\":[\"contactId\"]},\"required\":[\"subjectDid\",\"knownByPersona\",\"document\"]},{\"anyOf\":[{\"required\":[\"starred\"]},{\"required\":[\"petname\"]},{\"required\":[\"removePetname\"]},{\"required\":[\"lists\"]},{\"required\":[\"removeLists\"]},{\"required\":[\"directoryRef\"]},{\"required\":[\"removeDirectoryRef\"]},{\"required\":[\"notes\"]},{\"required\":[\"removeNotes\"]}],\"not\":{\"anyOf\":[{\"required\":[\"subjectDid\"]},{\"required\":[\"knownByPersona\"]},{\"required\":[\"document\"]},{\"required\":[\"credentialRefs\"]}]},\"required\":[\"contactId\"]},{\"not\":{\"anyOf\":[{\"required\":[\"contactId\"]},{\"required\":[\"subjectDid\"]},{\"required\":[\"document\"]},{\"required\":[\"credentialRefs\"]}]},\"required\":[\"directoryRef\",\"knownByPersona\"]}],\"properties\":{\"contactId\":{\"$ref\":\"#/$defs/Ulid\",\"description\":\"Annotating form only: the existing contact whose annotations change. A filing never names one — the agent keys a filing on (contextId, subjectDid, knownByPersona) as in 1.0.\"},\"contextId\":{\"minLength\":1,\"type\":\"string\"},\"credentialRefs\":{\"description\":\"Filing form only. Vault identifiers of credentials the peer presented alongside the document. The credentials themselves belong in the credential vault and the contact holds references.\",\"items\":{\"minLength\":1,\"type\":\"string\"},\"maxItems\":256,\"type\":\"array\"},\"directoryRef\":{\"$ref\":\"#/$defs/DirectoryRef\",\"description\":\"Link the contact to a community directory entry, replacing any link it had. Absent: unchanged.\"},\"document\":{\"$ref\":\"#/$defs/ContactDocument\"},\"ext\":{\"$ref\":\"#/$defs/Ext\"},\"knownByPersona\":{\"description\":\"Filing and linking forms. Which of the holder's personas knows this contact. A contact belongs to the relationship, not to the holder at large — the same peer met through two personas is two contacts, and collapsing them would correlate the holder's own personas in their own address book.\",\"maxLength\":2048,\"minLength\":1,\"type\":\"string\"},\"lists\":{\"$ref\":\"#/$defs/ListIds\",\"description\":\"The lists the contact is on, replacing the whole set. Every identifier MUST name a list in this context. Absent: unchanged. Take the contact off every list with `removeLists`.\"},\"notes\":{\"description\":\"The holder's private note about this contact, replacing any they had. Absent: unchanged. Never disclosed to anyone, including the contact.\",\"maxLength\":4096,\"minLength\":1,\"type\":\"string\"},\"petname\":{\"$ref\":\"#/$defs/Petname\",\"description\":\"The holder's private name for the contact, replacing any they had. Absent: unchanged.\"},\"removeDirectoryRef\":{\"const\":true,\"description\":\"Remove the contact's directory link. Only `true` is accepted.\",\"type\":\"boolean\"},\"removeLists\":{\"const\":true,\"description\":\"Take the contact off every list. Only `true` is accepted.\",\"type\":\"boolean\"},\"removeNotes\":{\"const\":true,\"description\":\"Remove the note. Only `true` is accepted.\",\"type\":\"boolean\"},\"removePetname\":{\"const\":true,\"description\":\"Remove the petname. Only `true` is meaningful, so only `true` is accepted. A separate member rather than `petname: null`, because a nullable optional member makes \\\"unchanged\\\" and \\\"remove\\\" the same value in libraries that map both to one absent option.\",\"type\":\"boolean\"},\"starred\":{\"description\":\"Star or unstar the contact. Absent: unchanged. A boolean rather than a remove member because `false` is a value the holder chose, not an absence.\",\"type\":\"boolean\"},\"subjectDid\":{\"description\":\"Filing form only. The DID the document is about, as disclosed. Normally pairwise, so it names this relationship and not the person across all of theirs.\",\"maxLength\":2048,\"minLength\":1,\"type\":\"string\"}},\"required\":[\"contextId\"],\"title\":\"Persona Contact Put — payload\",\"type\":\"object\"}\n",
);
}
impl crate::Payload for Response {
const TYPE_URI: &'static str = "https://trusttasks.org/spec/persona/contact/put/1.2#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(
"{\"$defs\":{\"ClaimType\":{\"description\":\"The vocabulary token naming what a value IS — `name.legal`, `phone.mobile`, `address.postal`, `person.birthDate`. Dotted, most-general segment first, so that a consumer with no knowledge of the specific token can still group by its prefix.\\n\\nThe token is the maintainer's own; no external vocabulary is primary. External vocabularies (vCard/jCard, OIDC standard claims, schema.org) are mappings applied at PRESENTATION by a renderer, not at rest, so that a query written in any of them can be matched without the store having to live inside any one of them.\\n\\nThe `x:` prefix is an open extension namespace and is not decoration. The closest prior art — Windows CardSpace's self-issued card — supported exactly fifteen predefined claim types with no extensibility, and that is the specific way it failed the requirement a holder actually has. An `x:` attribute stores, composes, binds and discloses exactly like a known one; it renders generically and matches only an explicit query.\",\"maxLength\":128,\"minLength\":1,\"pattern\":\"^(x:)?[a-z][a-zA-Z0-9]*(\\\\.[a-z][a-zA-Z0-9]*)*$\",\"title\":\"ClaimType\",\"type\":\"string\"},\"ContactDocument\":{\"additionalProperties\":false,\"description\":\"What a peer disclosed, as received. Structurally the same claim set a holder composes and presents — a profile and a contact card are one schema seen from two sides — which is why a maintainer validates both with the same code and a consumer renders both with the same view.\",\"properties\":{\"cardVersion\":{\"description\":\"The publisher's own monotonic counter, if they supplied one. Advisory: it orders the publisher's revisions relative to each other and MUST NOT be trusted to order them against anything else.\",\"minimum\":1,\"type\":\"integer\"},\"claims\":{\"items\":{\"additionalProperties\":false,\"properties\":{\"provenance\":{\"$ref\":\"#/$defs/Provenance\",\"description\":\"As asserted by the publisher. A recipient MUST NOT treat a claimed credentialBacked provenance as verified — it is a statement about what the publisher says backs the claim, and verification is a separate act against the credential itself.\"},\"type\":{\"$ref\":\"#/$defs/ClaimType\"},\"value\":{},\"valueType\":{\"$ref\":\"#/$defs/ValueType\"}},\"required\":[\"type\",\"valueType\",\"value\"],\"type\":\"object\"},\"maxItems\":256,\"type\":\"array\"},\"publisher\":{\"description\":\"The DID that published the document, as it appeared. Normally a pairwise identifier, so it names the relationship rather than the person.\",\"maxLength\":2048,\"type\":\"string\"}},\"required\":[\"claims\"],\"title\":\"ContactDocument\",\"type\":\"object\"},\"DirectoryEntryId\":{\"description\":\"A community directory entry's identifier, exactly as that community's directory returned it. Opaque and community-scoped: the agent stores and compares it as a string, never parses it, and never treats the same value under two communities as the same entry.\",\"maxLength\":128,\"minLength\":1,\"pattern\":\"^[A-Za-z0-9_-]+$\",\"title\":\"DirectoryEntryId\",\"type\":\"string\"},\"DirectoryRef\":{\"additionalProperties\":false,\"description\":\"Links a contact to the entry in a community's member directory it corresponds to, so the holder's own client can join that community's directory with the holder's address book — showing a star or a petname beside an entry — without either side telling the other. The community never learns the link exists; the contact never learns it either. A contact has at most one.\",\"properties\":{\"entryId\":{\"$ref\":\"#/$defs/DirectoryEntryId\",\"description\":\"The entry, as that community's directory identifies it.\"},\"vtcDid\":{\"description\":\"The DID of the community whose directory holds the entry.\",\"maxLength\":2048,\"minLength\":1,\"pattern\":\"^did:[a-z0-9]+:\",\"type\":\"string\"}},\"required\":[\"vtcDid\",\"entryId\"],\"title\":\"DirectoryRef\",\"type\":\"object\"},\"Ext\":{\"additionalProperties\":true,\"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.\",\"minProperties\":1,\"propertyNames\":{\"pattern\":\"^[a-z][a-z0-9-]*(\\\\.[a-z0-9-]+)+$\"},\"title\":\"Ext\",\"type\":\"object\"},\"ListId\":{\"description\":\"Identifier of one of the holder's contact lists: a ULID in Crockford base32, uppercase, assigned by the agent when the list is created. Meaningful only inside the context that holds the list; it is never sent to anyone but the holder's own clients.\",\"pattern\":\"^[0-9A-HJKMNP-TV-Z]{26}$\",\"title\":\"ListId\",\"type\":\"string\"},\"ListIds\":{\"description\":\"The lists a contact is on, as a set: order carries no meaning. A contact on no list has no `lists` member, never an empty array, so there is one way to say \\\"none\\\".\",\"items\":{\"$ref\":\"#/$defs/ListId\"},\"maxItems\":64,\"minItems\":1,\"title\":\"ListIds\",\"type\":\"array\",\"uniqueItems\":true},\"Petname\":{\"description\":\"The holder's private name for a contact, on one line: no control characters, line breaks included. A petname in Zooko's sense — chosen by the holder, meaningful to the holder, and unforgeable by anyone else, because nobody else can write it. Distinct from the contact's own disclosed `nickname` or display name, which the contact chose and may change. Compared exactly, as a string: an agent does not case-fold or normalise it.\",\"maxLength\":64,\"minLength\":1,\"pattern\":\"^[^\\\\u0000-\\\\u001F\\\\u007F]+$\",\"title\":\"Petname\",\"type\":\"string\"},\"ProofRung\":{\"description\":\"How strongly a credential-backed claim is hidden when presented, ordered most private first. `predicate` proves a statement over a claim without disclosing the claim. `derived` discloses exactly the claims needed via an unlinkable derived proof, so two presentations cannot be joined. `selectiveDisclosure` discloses exactly the claims needed but carries the issuer's signature unchanged, so two presentations ARE linkable. `whole` discloses the entire credential.\\n\\nThe distinction between the first two and the last two is of kind, not degree: only `predicate` and `derived` avoid handing two verifiers a join key. A maintainer MUST default to the highest rung the credential's format supports, and MUST NOT silently fall to a lower one — a request that cannot be satisfied at the rung a producer asked for is refused, because a silent privacy downgrade discloses material the holder believed was hidden.\",\"enum\":[\"predicate\",\"derived\",\"selectiveDisclosure\",\"whole\"],\"title\":\"ProofRung\",\"type\":\"string\"},\"Provenance\":{\"description\":\"Where a value comes from, and the member that makes this family worth building on a trust stack rather than in an address book. It survives to the verifier, so a recipient can tell — per field — what the holder typed from what an issuer attested.\\n\\n`selfAsserted` — the holder supplied it.\\n\\n`credentialBacked` — the value is derived from a credential in the vault at `claimPath`. The stored value is a CACHE FOR DISPLAY; the credential is the truth. A maintainer MUST re-derive it on read and MUST fail closed (never presenting a stale value) when the credential has been revoked, has expired, or has been archived or deleted.\\n\\n`generated` — the value is minted per verifier at disclosure time and recorded against that verifier, so every relying party receives a different one that routes back to the holder. This is the shape of the most widely adopted consumer privacy feature in this space; a maintainer need not operate a relay to conform, but the shape must exist, because retrofitting per-verifier values into a pool-of-values model is a migration rather than an addition.\\n\\n`derived` — the value was taken from a source the holder connected or supplied — a code-hosting profile, an uploaded CV — rather than typed by them or attested by an issuer. Nobody signed it: it is the holder's claim that the source said so, and a consumer MUST NOT present it as attested. It exists as its own kind because a derived value is neither of the others — the holder did not author it, and no one vouches for it — and a holder deciding whether to disclose deserves to know which of their values they typed.\\n\\nFor how strongly a disclosed value identifies the holder, the kinds rank `credentialBacked` above `derived` above `selfAsserted`; `generated` values are per-verifier and do not correlate.\",\"oneOf\":[{\"additionalProperties\":false,\"properties\":{\"kind\":{\"const\":\"selfAsserted\"}},\"required\":[\"kind\"]},{\"additionalProperties\":false,\"properties\":{\"claimPath\":{\"description\":\"RFC 6901 JSON Pointer to the claim within the credential, e.g. `/credentialSubject/familyName`.\",\"pattern\":\"^(/[^/~]*(~[01][^/~]*)*)*$\",\"type\":\"string\"},\"credentialId\":{\"description\":\"Vault identifier of the backing credential.\",\"minLength\":1,\"type\":\"string\"},\"issuerDid\":{\"description\":\"Issuer of the backing credential. Advisory: a consumer MUST verify the credential rather than trusting this member.\",\"minLength\":1,\"type\":\"string\"},\"kind\":{\"const\":\"credentialBacked\"},\"proof\":{\"$ref\":\"#/$defs/ProofRung\",\"description\":\"The disclosure rung this claim was, or will be, presented at.\"}},\"required\":[\"kind\",\"credentialId\",\"claimPath\"]},{\"additionalProperties\":false,\"properties\":{\"generator\":{\"description\":\"Names the minting scheme, e.g. `relayEmail`. Maintainer-defined.\",\"maxLength\":64,\"minLength\":1,\"type\":\"string\"},\"kind\":{\"const\":\"generated\"},\"perVerifier\":{\"default\":true,\"description\":\"When true (the default and the only useful setting), a distinct value is minted for each verifier.\",\"type\":\"boolean\"}},\"required\":[\"kind\",\"generator\"]},{\"additionalProperties\":false,\"properties\":{\"derivedAt\":{\"description\":\"When the value was taken from the source. A derived value is a snapshot: the source may have changed since, and nothing re-derives it.\",\"format\":\"date-time\",\"type\":\"string\"},\"kind\":{\"const\":\"derived\"},\"source\":{\"description\":\"The KIND of source the value was taken from — `github`, `cvUpload`, `linkedIn` — never an account, handle or URL. Provenance survives to the verifier, so this member is disclosed with the claim; a handle here would disclose an identifier the holder never chose to share.\",\"maxLength\":64,\"minLength\":1,\"pattern\":\"^[a-z][A-Za-z0-9.-]*$\",\"type\":\"string\"}},\"required\":[\"kind\",\"source\",\"derivedAt\"]}],\"required\":[\"kind\"],\"title\":\"Provenance\",\"type\":\"object\"},\"Response\":{\"$anchor\":\"response\",\"additionalProperties\":false,\"description\":\"Success response to persona/contact/put. Type https://trusttasks.org/spec/persona/contact/put/1.2#response. Identifiers, the current revision and what changed; no claim value and no annotation text is echoed.\",\"properties\":{\"annotationsChanged\":{\"description\":\"True when any annotation now differs from what was stored. False when every annotation given already matched and every one named for removal was already absent — including a filing that named none.\",\"type\":\"boolean\"},\"changedClaims\":{\"description\":\"Claim types whose value differs from the previous revision. Present only on a filing that updated an existing contact.\",\"items\":{\"$ref\":\"#/$defs/ClaimType\"},\"maxItems\":256,\"type\":\"array\"},\"contactId\":{\"$ref\":\"#/$defs/Ulid\"},\"ext\":{\"$ref\":\"#/$defs/Ext\"},\"rev\":{\"description\":\"The contact's current revision: the one a filing just appended, or, for an annotating request, the revision that was already current. Annotations never move it.\",\"minimum\":1,\"type\":\"integer\"},\"wasCreated\":{\"description\":\"True when this is the first revision for the subject. Always false for an annotating request.\",\"type\":\"boolean\"}},\"required\":[\"contactId\",\"rev\",\"wasCreated\",\"annotationsChanged\"],\"title\":\"Persona Contact Put — response payload\",\"type\":\"object\"},\"Ulid\":{\"description\":\"A ULID in Crockford base32, uppercase. Used for `attributeId` and `profileId`. Chosen over a UUID because the leading 48 bits are a timestamp, so a key-ordered scan of the store is also creation-ordered and a `list` needs no secondary sort. Server-assigned on create; a producer MAY supply one to make a create idempotent, and a maintainer MUST reject a supplied value that already exists rather than silently overwriting.\",\"pattern\":\"^[0-9A-HJKMNP-TV-Z]{26}$\",\"title\":\"Ulid\",\"type\":\"string\"},\"ValueType\":{\"description\":\"The JSON shape of `value`, declared so that a consumer can render and compare without guessing. The maintainer validates that `value` agrees with this member and does nothing further: it does NOT validate a phone number against a phone-number grammar. That is a producer's affordance, and a store that grows opinions about the contents of its records eventually blocks its consumer's release.\",\"enum\":[\"string\",\"number\",\"boolean\",\"date\",\"object\"],\"title\":\"ValueType\",\"type\":\"string\"}},\"$ref\":\"#/$defs/Response\",\"$schema\":\"https://json-schema.org/draft/2020-12/schema\"}\n",
);
}
impl crate::RequestPayload for Payload {
type Response = Response;
}
/// The earlier `MAJOR.MINOR` of this slug that this version declares it
/// extends (front matter `extends`, SPEC §5.2 "Declared extension"), or
/// `None`. Only the direct declaration; walk a chain with
/// [`crate::extension::extends_for`].
pub const EXTENDS: Option<&str> = None;
/// 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::DOCUMENT_TOO_LARGE,
error_codes::NOT_FOUND,
error_codes::LIST_UNKNOWN,
];
/// 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 {
/// `persona/contact/put:documentTooLarge`
///
/// The document exceeds the maintainer's stated per-record cap. The cap and the actual size are both returned, so a producer can tell how far over it is rather than guessing.
///
/// Declared `retryable: false`.
pub const DOCUMENT_TOO_LARGE: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "persona/contact/put:documentTooLarge",
retryable: false,
details_schema: ::core::option::Option::None,
};
/// `persona/contact/put:notFound`
///
/// Annotating form only — no contact exists at `contactId` in this context. Answered the same whether the identifier was never assigned or belongs to another context.
///
/// Declared `retryable: false`.
pub const NOT_FOUND: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "persona/contact/put:notFound",
retryable: false,
details_schema: ::core::option::Option::None,
};
/// `persona/contact/put:listUnknown`
///
/// An identifier in `lists` names no list in this context. Nothing is changed. A producer creates the list with persona/contact/lists/put first.
///
/// Declared `retryable: false`.
/// Declares a `detailsSchema` for the error's `details` member.
pub const LIST_UNKNOWN: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "persona/contact/put:listUnknown",
retryable: false,
details_schema: ::core::option::Option::Some(
"{\"additionalProperties\":false,\"properties\":{\"listIds\":{\"items\":{\"pattern\":\"^[0-9A-HJKMNP-TV-Z]{26}$\",\"type\":\"string\"},\"maxItems\":64,\"minItems\":1,\"type\":\"array\"}},\"required\":[\"listIds\"],\"type\":\"object\"}",
),
};
}