//! Generated by `trust-tasks-codegen` — do not edit by hand.
//!
//! Spec slug: `persona/attribute/put`. Version: `1.0`.
#[allow(unused_imports)]
use serde::{Deserialize, Serialize};
/// Error types.
pub mod error {
/// Error from a `TryFrom` or `FromStr` implementation.
pub struct ConversionError(::std::borrow::Cow<'static, str>);
impl ::std::error::Error for ConversionError {}
impl ::std::fmt::Display for ConversionError {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> Result<(), ::std::fmt::Error> {
::std::fmt::Display::fmt(&self.0, f)
}
}
impl ::std::fmt::Debug for ConversionError {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> Result<(), ::std::fmt::Error> {
::std::fmt::Debug::fmt(&self.0, f)
}
}
impl From<&'static str> for ConversionError {
fn from(value: &'static str) -> Self {
Self(value.into())
}
}
impl From<String> for ConversionError {
fn from(value: String) -> Self {
Self(value.into())
}
}
}
/**
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.*/
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "ClaimType",
/// "description": "\nThe 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.",
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1,
/// "pattern": "^(x:)?[a-z][a-zA-Z0-9]*(\\.[a-z][a-zA-Z0-9]*)*$"
///}
/// ```
/// </details>
#[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())
})
}
}
///Optimistic-concurrency precondition. A positive value requires the record's current `version` to equal it exactly; zero means create-only and applies only when no live record exists at the address.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "ExpectedVersion",
/// "description": "Optimistic-concurrency precondition. A positive value requires the record's current `version` to equal it exactly; zero means create-only and applies only when no live record exists at the address.",
/// "type": "integer",
/// "minimum": 0.0
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(transparent)]
pub struct ExpectedVersion(pub u64);
impl ::std::ops::Deref for ExpectedVersion {
type Target = u64;
fn deref(&self) -> &u64 {
&self.0
}
}
impl ::std::convert::From<ExpectedVersion> for u64 {
fn from(value: ExpectedVersion) -> Self {
value.0
}
}
impl ::std::convert::From<u64> for ExpectedVersion {
fn from(value: u64) -> Self {
Self(value)
}
}
impl ::std::str::FromStr for ExpectedVersion {
type Err = <u64 as ::std::str::FromStr>::Err;
fn from_str(value: &str) -> ::std::result::Result<Self, Self::Err> {
Ok(Self(value.parse()?))
}
}
impl ::std::convert::TryFrom<&str> for ExpectedVersion {
type Error = <u64 as ::std::str::FromStr>::Err;
fn try_from(value: &str) -> ::std::result::Result<Self, Self::Error> {
value.parse()
}
}
impl ::std::convert::TryFrom<String> for ExpectedVersion {
type Error = <u64 as ::std::str::FromStr>::Err;
fn try_from(value: String) -> ::std::result::Result<Self, Self::Error> {
value.parse()
}
}
impl ::std::fmt::Display for ExpectedVersion {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
self.0.fmt(f)
}
}
///Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Ext",
/// "description": "Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.",
/// "type": "object",
/// "minProperties": 1,
/// "additionalProperties": true,
/// "propertyNames": {
/// "pattern": "^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$"
/// }
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(transparent)]
pub struct Ext(pub ::std::collections::HashMap<ExtKey, ::serde_json::Value>);
impl ::std::ops::Deref for Ext {
type Target = ::std::collections::HashMap<ExtKey, ::serde_json::Value>;
fn deref(&self) -> &::std::collections::HashMap<ExtKey, ::serde_json::Value> {
&self.0
}
}
impl ::std::convert::From<Ext> for ::std::collections::HashMap<ExtKey, ::serde_json::Value> {
fn from(value: Ext) -> Self {
value.0
}
}
impl ::std::convert::From<::std::collections::HashMap<ExtKey, ::serde_json::Value>> for Ext {
fn from(value: ::std::collections::HashMap<ExtKey, ::serde_json::Value>) -> Self {
Self(value)
}
}
///`ExtKey`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "pattern": "^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ExtKey(::std::string::String);
impl ::std::ops::Deref for ExtKey {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ExtKey> for ::std::string::String {
fn from(value: ExtKey) -> Self {
value.0
}
}
impl ::std::str::FromStr for ExtKey {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| {
::regress::Regex::new("^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ExtKey {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for ExtKey {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for ExtKey {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for ExtKey {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///Create or replace one attribute in the holder's pool. Omit `attributeId` to create; supply it to replace. `expectedVersion` makes the write conditional.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "$id": "https://trusttasks.org/spec/persona/attribute/put/1.0",
/// "title": "Payload",
/// "description": "Create or replace one attribute in the holder's pool. Omit `attributeId` to create; supply it to replace. `expectedVersion` makes the write conditional.",
/// "type": "object",
/// "required": [
/// "provenance",
/// "type",
/// "value",
/// "valueType"
/// ],
/// "properties": {
/// "attributeId": {
/// "description": "Omit to create — the maintainer assigns one and returns it. Supply to replace an existing attribute, or to make a create idempotent under retry; a supplied id that already exists is a replacement, and a producer that meant to create MUST pair it with `expectedVersion: 0`.",
/// "$ref": "#/definitions/Ulid"
/// },
/// "endorsements": {
/// "description": "Vault identifiers of credentials in which a third party endorses this value. Inventory, not evidence — see the `endorsements` member of the shared Attribute. Replaced whole by each put; omit or send empty for none.",
/// "type": "array",
/// "items": {
/// "type": "string",
/// "minLength": 1
/// },
/// "maxItems": 64,
/// "uniqueItems": true
/// },
/// "expectedVersion": {
/// "description": "Optional precondition. Omit for last-writer-wins. Supply the version a prior read returned to make the write conditional; supply 0 to create only.",
/// "$ref": "#/definitions/ExpectedVersion"
/// },
/// "ext": {
/// "description": "Ecosystem-defined extension members per SPEC.md §4.5.1.",
/// "$ref": "#/definitions/Ext"
/// },
/// "label": {
/// "description": "The holder's own words, for their own picker. Never disclosed to a verifier.",
/// "type": "string",
/// "maxLength": 128
/// },
/// "provenance": {
/// "$ref": "#/definitions/Provenance"
/// },
/// "release": {
/// "description": "What it takes to disclose this value. OPTIONAL, with the same meaning for absence as `sensitivity`.",
/// "$ref": "#/definitions/ReleaseRequirement"
/// },
/// "sensitivity": {
/// "description": "How carefully this value is shown to the holder. OPTIONAL, and its absence is meaningful: it records that the holder made no explicit decision, so a consumer resolves it from the claim-type registry. Sending the resolved value back would freeze it — a later tightening of the registry would then protect new attributes and leave this one exposed.",
/// "$ref": "#/definitions/Sensitivity"
/// },
/// "type": {
/// "$ref": "#/definitions/ClaimType"
/// },
/// "value": {
/// "description": "The fact itself. MUST agree with `valueType`; a maintainer MUST refuse a document where it does not. For a `credentialBacked` provenance this is the initial display cache — the maintainer re-derives it from the credential and MAY overwrite what was supplied."
/// },
/// "valueType": {
/// "$ref": "#/definitions/ValueType"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct Payload {
///Omit to create — the maintainer assigns one and returns it. Supply to replace an existing attribute, or to make a create idempotent under retry; a supplied id that already exists is a replacement, and a producer that meant to create MUST pair it with `expectedVersion: 0`.
#[serde(
rename = "attributeId",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub attribute_id: ::std::option::Option<Ulid>,
///Vault identifiers of credentials in which a third party endorses this value. Inventory, not evidence — see the `endorsements` member of the shared Attribute. Replaced whole by each put; omit or send empty for none.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub endorsements: ::std::option::Option<Vec<PayloadEndorsementsItem>>,
///Optional precondition. Omit for last-writer-wins. Supply the version a prior read returned to make the write conditional; supply 0 to create only.
#[serde(
rename = "expectedVersion",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub expected_version: ::std::option::Option<ExpectedVersion>,
///Ecosystem-defined extension members per SPEC.md §4.5.1.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ext: ::std::option::Option<Ext>,
///The holder's own words, for their own picker. Never disclosed to a verifier.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub label: ::std::option::Option<PayloadLabel>,
pub provenance: Provenance,
///What it takes to disclose this value. OPTIONAL, with the same meaning for absence as `sensitivity`.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub release: ::std::option::Option<ReleaseRequirement>,
///How carefully this value is shown to the holder. OPTIONAL, and its absence is meaningful: it records that the holder made no explicit decision, so a consumer resolves it from the claim-type registry. Sending the resolved value back would freeze it — a later tightening of the registry would then protect new attributes and leave this one exposed.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub sensitivity: ::std::option::Option<Sensitivity>,
#[serde(rename = "type")]
pub type_: ClaimType,
///The fact itself. MUST agree with `valueType`; a maintainer MUST refuse a document where it does not. For a `credentialBacked` provenance this is the initial display cache — the maintainer re-derives it from the credential and MAY overwrite what was supplied.
pub value: ::serde_json::Value,
#[serde(rename = "valueType")]
pub value_type: ValueType,
}
impl Payload {
pub fn builder() -> builder::Payload {
Default::default()
}
}
///`PayloadEndorsementsItem`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PayloadEndorsementsItem(::std::string::String);
impl ::std::ops::Deref for PayloadEndorsementsItem {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PayloadEndorsementsItem> for ::std::string::String {
fn from(value: PayloadEndorsementsItem) -> Self {
value.0
}
}
impl ::std::str::FromStr for PayloadEndorsementsItem {
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 PayloadEndorsementsItem {
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 PayloadEndorsementsItem {
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 PayloadEndorsementsItem {
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 PayloadEndorsementsItem {
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 own words, for their own picker. Never disclosed to a verifier.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "The holder's own words, for their own picker. Never disclosed to a verifier.",
/// "type": "string",
/// "maxLength": 128
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PayloadLabel(::std::string::String);
impl ::std::ops::Deref for PayloadLabel {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PayloadLabel> for ::std::string::String {
fn from(value: PayloadLabel) -> Self {
value.0
}
}
impl ::std::str::FromStr for PayloadLabel {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 128usize {
return Err("longer than 128 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for PayloadLabel {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for PayloadLabel {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for PayloadLabel {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for PayloadLabel {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
/**
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.*/
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "ProofRung",
/// "description": "\nHow 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.",
/// "type": "string",
/// "enum": [
/// "predicate",
/// "derived",
/// "selectiveDisclosure",
/// "whole"
/// ]
///}
/// ```
/// </details>
#[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.*/
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Provenance",
/// "description": "\nWhere 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.",
/// "type": "object",
/// "oneOf": [
/// {
/// "required": [
/// "kind"
/// ],
/// "properties": {
/// "kind": {
/// "const": "selfAsserted"
/// }
/// },
/// "additionalProperties": false
/// },
/// {
/// "required": [
/// "claimPath",
/// "credentialId",
/// "kind"
/// ],
/// "properties": {
/// "claimPath": {
/// "description": "RFC 6901 JSON Pointer to the claim within the credential, e.g. `/credentialSubject/familyName`.",
/// "type": "string",
/// "pattern": "^(/[^/~]*(~[01][^/~]*)*)*$"
/// },
/// "credentialId": {
/// "description": "Vault identifier of the backing credential.",
/// "type": "string",
/// "minLength": 1
/// },
/// "issuerDid": {
/// "description": "Issuer of the backing credential. Advisory: a consumer MUST verify the credential rather than trusting this member.",
/// "type": "string",
/// "minLength": 1
/// },
/// "kind": {
/// "const": "credentialBacked"
/// },
/// "proof": {
/// "description": "The disclosure rung this claim was, or will be, presented at.",
/// "$ref": "#/definitions/ProofRung"
/// }
/// },
/// "additionalProperties": false
/// },
/// {
/// "required": [
/// "generator",
/// "kind"
/// ],
/// "properties": {
/// "generator": {
/// "description": "Names the minting scheme, e.g. `relayEmail`. Maintainer-defined.",
/// "type": "string",
/// "maxLength": 64,
/// "minLength": 1
/// },
/// "kind": {
/// "const": "generated"
/// },
/// "perVerifier": {
/// "description": "When true (the default and the only useful setting), a distinct value is minted for each verifier.",
/// "default": true,
/// "type": "boolean"
/// }
/// },
/// "additionalProperties": false
/// },
/// {
/// "required": [
/// "derivedAt",
/// "kind",
/// "source"
/// ],
/// "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.",
/// "type": "string",
/// "format": "date-time"
/// },
/// "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.",
/// "type": "string",
/// "maxLength": 64,
/// "minLength": 1,
/// "pattern": "^[a-z][A-Za-z0-9.-]*$"
/// }
/// },
/// "additionalProperties": false
/// }
/// ],
/// "required": [
/// "kind"
/// ]
///}
/// ```
/// </details>
#[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`.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "RFC 6901 JSON Pointer to the claim within the credential, e.g. `/credentialSubject/familyName`.",
/// "type": "string",
/// "pattern": "^(/[^/~]*(~[01][^/~]*)*)*$"
///}
/// ```
/// </details>
#[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.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Vault identifier of the backing credential.",
/// "type": "string",
/// "minLength": 1
///}
/// ```
/// </details>
#[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.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Issuer of the backing credential. Advisory: a consumer MUST verify the credential rather than trusting this member.",
/// "type": "string",
/// "minLength": 1
///}
/// ```
/// </details>
#[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.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Names the minting scheme, e.g. `relayEmail`. Maintainer-defined.",
/// "type": "string",
/// "maxLength": 64,
/// "minLength": 1
///}
/// ```
/// </details>
#[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.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "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.",
/// "type": "string",
/// "maxLength": 64,
/// "minLength": 1,
/// "pattern": "^[a-z][A-Za-z0-9.-]*$"
///}
/// ```
/// </details>
#[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())
})
}
}
/**
What it takes to let a value LEAVE. Distinct from `Sensitivity`, which governs showing it to the holder.
`consent` is the ordinary gate: `persona/disclosure/preview` renders what would leave and `persona/disclosure/present` releases it, so a human sees it once.
`stepUp` additionally requires a fresh authentication bound to THAT preview — not to the session. Without the binding, "each time" degrades into "once per login", which is the failure the requirement exists to prevent; the single-use `previewId` the preview already mints is what an implementation binds to. A maintainer MUST refuse `persona/disclosure/present` for a `stepUp` attribute when no such approval accompanies it.
Absent means *not decided by the holder* and resolves from the claim-type registry, which defaults `payment.*` and `gov.*` to `stepUp`.*/
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "ReleaseRequirement",
/// "description": "\nWhat it takes to let a value LEAVE. Distinct from `Sensitivity`, which governs showing it to the holder.\n\n`consent` is the ordinary gate: `persona/disclosure/preview` renders what would leave and `persona/disclosure/present` releases it, so a human sees it once.\n\n`stepUp` additionally requires a fresh authentication bound to THAT preview — not to the session. Without the binding, \"each time\" degrades into \"once per login\", which is the failure the requirement exists to prevent; the single-use `previewId` the preview already mints is what an implementation binds to. A maintainer MUST refuse `persona/disclosure/present` for a `stepUp` attribute when no such approval accompanies it.\n\nAbsent means *not decided by the holder* and resolves from the claim-type registry, which defaults `payment.*` and `gov.*` to `stepUp`.",
/// "type": "string",
/// "enum": [
/// "consent",
/// "stepUp"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum ReleaseRequirement {
#[serde(rename = "consent")]
Consent,
#[serde(rename = "stepUp")]
StepUp,
}
impl ::std::fmt::Display for ReleaseRequirement {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Consent => f.write_str("consent"),
Self::StepUp => f.write_str("stepUp"),
}
}
}
impl ::std::str::FromStr for ReleaseRequirement {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"consent" => Ok(Self::Consent),
"stepUp" => Ok(Self::StepUp),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for ReleaseRequirement {
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 ReleaseRequirement {
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 ReleaseRequirement {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///Success response to persona/attribute/put. Type https://trusttasks.org/spec/persona/attribute/put/1.0#response. A failed precondition is not a success: it is a trust-task-error carrying persona/attribute/put:versionConflict, whose details carry the maintainer's current version and value.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Response",
/// "description": "Success response to persona/attribute/put. Type https://trusttasks.org/spec/persona/attribute/put/1.0#response. A failed precondition is not a success: it is a trust-task-error carrying persona/attribute/put:versionConflict, whose details carry the maintainer's current version and value.",
/// "type": "object",
/// "required": [
/// "attributeId",
/// "created",
/// "updatedAt",
/// "version"
/// ],
/// "properties": {
/// "attributeId": {
/// "$ref": "#/definitions/Ulid"
/// },
/// "correlation": {
/// "description": "Advisory result of the correlation check the maintainer runs over the new value (see persona/correlation/analyze). Returned on the write so a producer's builder can warn at the moment of composition rather than requiring a second round trip. Advisory only: the write has already applied, and a maintainer MUST NOT refuse a write on correlation grounds — the holder decides.",
/// "type": "object",
/// "required": [
/// "severity"
/// ],
/// "properties": {
/// "severity": {
/// "type": "string",
/// "enum": [
/// "none",
/// "low",
/// "high"
/// ]
/// },
/// "sharedWithProfileCount": {
/// "description": "How many other profiles already present this exact value. A count, not identifiers — the identifiers are available from the analyze task, which is where a producer should go to render remedies.",
/// "type": "integer",
/// "minimum": 0.0
/// }
/// },
/// "additionalProperties": false
/// },
/// "created": {
/// "description": "True when this write created the attribute, false when it replaced one. A producer that omitted `attributeId` can still be told which happened, because a retried create with a supplied id is a replacement.",
/// "type": "boolean"
/// },
/// "createdAt": {
/// "type": "string",
/// "format": "date-time"
/// },
/// "ext": {
/// "$ref": "#/definitions/Ext"
/// },
/// "heldByPin": {
/// "description": "Faces that pin this attribute to an earlier version and so did NOT follow the edit — the counterparties that must keep seeing the value they verified. Named so the holder can decide, per face, whether that is still what they want. Absent when no face pins it.",
/// "type": "array",
/// "items": {
/// "type": "object",
/// "required": [
/// "pinVersion",
/// "profileId"
/// ],
/// "properties": {
/// "pinVersion": {
/// "$ref": "#/definitions/Version"
/// },
/// "profileId": {
/// "$ref": "#/definitions/Ulid"
/// }
/// },
/// "additionalProperties": false
/// },
/// "maxItems": 256
/// },
/// "refreshed": {
/// "description": "Every place this write changed what a persona presents: each binding whose projection was re-pushed because a face wearing it shows this attribute live. An edit propagates by design, and a holder told only that it saved cannot tell whether it refreshed one face or nine. Holder-authorized, so identifiers are returned. Absent when nothing was bound to a face showing it.",
/// "type": "array",
/// "items": {
/// "type": "object",
/// "required": [
/// "contextId",
/// "personaDid",
/// "profileId"
/// ],
/// "properties": {
/// "contextId": {
/// "type": "string",
/// "minLength": 1
/// },
/// "personaDid": {
/// "type": "string",
/// "minLength": 1
/// },
/// "profileId": {
/// "$ref": "#/definitions/Ulid"
/// }
/// },
/// "additionalProperties": false
/// },
/// "maxItems": 256
/// },
/// "updatedAt": {
/// "type": "string",
/// "format": "date-time"
/// },
/// "version": {
/// "$ref": "#/definitions/Version"
/// }
/// },
/// "additionalProperties": false,
/// "$anchor": "response"
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct Response {
#[serde(rename = "attributeId")]
pub attribute_id: Ulid,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub correlation: ::std::option::Option<ResponseCorrelation>,
///True when this write created the attribute, false when it replaced one. A producer that omitted `attributeId` can still be told which happened, because a retried create with a supplied id is a replacement.
pub created: bool,
#[serde(
rename = "createdAt",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub created_at: ::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ext: ::std::option::Option<Ext>,
///Faces that pin this attribute to an earlier version and so did NOT follow the edit — the counterparties that must keep seeing the value they verified. Named so the holder can decide, per face, whether that is still what they want. Absent when no face pins it.
#[serde(
rename = "heldByPin",
default,
skip_serializing_if = "::std::vec::Vec::is_empty"
)]
pub held_by_pin: ::std::vec::Vec<ResponseHeldByPinItem>,
///Every place this write changed what a persona presents: each binding whose projection was re-pushed because a face wearing it shows this attribute live. An edit propagates by design, and a holder told only that it saved cannot tell whether it refreshed one face or nine. Holder-authorized, so identifiers are returned. Absent when nothing was bound to a face showing it.
#[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")]
pub refreshed: ::std::vec::Vec<ResponseRefreshedItem>,
#[serde(rename = "updatedAt")]
pub updated_at: ::chrono::DateTime<::chrono::offset::Utc>,
pub version: Version,
}
impl Response {
pub fn builder() -> builder::Response {
Default::default()
}
}
///Advisory result of the correlation check the maintainer runs over the new value (see persona/correlation/analyze). Returned on the write so a producer's builder can warn at the moment of composition rather than requiring a second round trip. Advisory only: the write has already applied, and a maintainer MUST NOT refuse a write on correlation grounds — the holder decides.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Advisory result of the correlation check the maintainer runs over the new value (see persona/correlation/analyze). Returned on the write so a producer's builder can warn at the moment of composition rather than requiring a second round trip. Advisory only: the write has already applied, and a maintainer MUST NOT refuse a write on correlation grounds — the holder decides.",
/// "type": "object",
/// "required": [
/// "severity"
/// ],
/// "properties": {
/// "severity": {
/// "type": "string",
/// "enum": [
/// "none",
/// "low",
/// "high"
/// ]
/// },
/// "sharedWithProfileCount": {
/// "description": "How many other profiles already present this exact value. A count, not identifiers — the identifiers are available from the analyze task, which is where a producer should go to render remedies.",
/// "type": "integer",
/// "minimum": 0.0
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct ResponseCorrelation {
pub severity: ResponseCorrelationSeverity,
///How many other profiles already present this exact value. A count, not identifiers — the identifiers are available from the analyze task, which is where a producer should go to render remedies.
#[serde(
rename = "sharedWithProfileCount",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub shared_with_profile_count: ::std::option::Option<u64>,
}
impl ResponseCorrelation {
pub fn builder() -> builder::ResponseCorrelation {
Default::default()
}
}
///`ResponseCorrelationSeverity`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "enum": [
/// "none",
/// "low",
/// "high"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum ResponseCorrelationSeverity {
#[serde(rename = "none")]
None,
#[serde(rename = "low")]
Low,
#[serde(rename = "high")]
High,
}
impl ::std::fmt::Display for ResponseCorrelationSeverity {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::None => f.write_str("none"),
Self::Low => f.write_str("low"),
Self::High => f.write_str("high"),
}
}
}
impl ::std::str::FromStr for ResponseCorrelationSeverity {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"none" => Ok(Self::None),
"low" => Ok(Self::Low),
"high" => Ok(Self::High),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for ResponseCorrelationSeverity {
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 ResponseCorrelationSeverity {
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 ResponseCorrelationSeverity {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///`ResponseHeldByPinItem`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "object",
/// "required": [
/// "pinVersion",
/// "profileId"
/// ],
/// "properties": {
/// "pinVersion": {
/// "$ref": "#/definitions/Version"
/// },
/// "profileId": {
/// "$ref": "#/definitions/Ulid"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct ResponseHeldByPinItem {
#[serde(rename = "pinVersion")]
pub pin_version: Version,
#[serde(rename = "profileId")]
pub profile_id: Ulid,
}
impl ResponseHeldByPinItem {
pub fn builder() -> builder::ResponseHeldByPinItem {
Default::default()
}
}
///`ResponseRefreshedItem`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "object",
/// "required": [
/// "contextId",
/// "personaDid",
/// "profileId"
/// ],
/// "properties": {
/// "contextId": {
/// "type": "string",
/// "minLength": 1
/// },
/// "personaDid": {
/// "type": "string",
/// "minLength": 1
/// },
/// "profileId": {
/// "$ref": "#/definitions/Ulid"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct ResponseRefreshedItem {
#[serde(rename = "contextId")]
pub context_id: ResponseRefreshedItemContextId,
#[serde(rename = "personaDid")]
pub persona_did: ResponseRefreshedItemPersonaDid,
#[serde(rename = "profileId")]
pub profile_id: Ulid,
}
impl ResponseRefreshedItem {
pub fn builder() -> builder::ResponseRefreshedItem {
Default::default()
}
}
///`ResponseRefreshedItemContextId`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ResponseRefreshedItemContextId(::std::string::String);
impl ::std::ops::Deref for ResponseRefreshedItemContextId {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ResponseRefreshedItemContextId> for ::std::string::String {
fn from(value: ResponseRefreshedItemContextId) -> Self {
value.0
}
}
impl ::std::str::FromStr for ResponseRefreshedItemContextId {
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 ResponseRefreshedItemContextId {
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 ResponseRefreshedItemContextId {
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 ResponseRefreshedItemContextId {
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 ResponseRefreshedItemContextId {
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())
})
}
}
///`ResponseRefreshedItemPersonaDid`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ResponseRefreshedItemPersonaDid(::std::string::String);
impl ::std::ops::Deref for ResponseRefreshedItemPersonaDid {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ResponseRefreshedItemPersonaDid> for ::std::string::String {
fn from(value: ResponseRefreshedItemPersonaDid) -> Self {
value.0
}
}
impl ::std::str::FromStr for ResponseRefreshedItemPersonaDid {
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 ResponseRefreshedItemPersonaDid {
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 ResponseRefreshedItemPersonaDid {
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 ResponseRefreshedItemPersonaDid {
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 ResponseRefreshedItemPersonaDid {
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 carefully a value is shown TO ITS OWN HOLDER. `high` means a consumer masks it by default, reveals it one attribute at a time on a deliberate act, and — the half that is not cosmetic — omits it from a listing that did not ask for sensitive values.
Absent means *not decided by the holder*, not `normal`: a consumer resolves it from the claim-type registry (see CLAIM-TYPES.md §4), which is why this member is optional and why an unregistered token resolves conservatively rather than permissively.
Distinct from how linkable the value is. A payment card is highly sensitive and barely linkable — every card number is unique, so knowing one tells a second verifier nothing about the first. Reading either as a proxy for the other produces a consumer that hides the wrong things.*/
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Sensitivity",
/// "description": "\nHow carefully a value is shown TO ITS OWN HOLDER. `high` means a consumer masks it by default, reveals it one attribute at a time on a deliberate act, and — the half that is not cosmetic — omits it from a listing that did not ask for sensitive values.\n\nAbsent means *not decided by the holder*, not `normal`: a consumer resolves it from the claim-type registry (see CLAIM-TYPES.md §4), which is why this member is optional and why an unregistered token resolves conservatively rather than permissively.\n\nDistinct from how linkable the value is. A payment card is highly sensitive and barely linkable — every card number is unique, so knowing one tells a second verifier nothing about the first. Reading either as a proxy for the other produces a consumer that hides the wrong things.",
/// "type": "string",
/// "enum": [
/// "normal",
/// "high"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum Sensitivity {
#[serde(rename = "normal")]
Normal,
#[serde(rename = "high")]
High,
}
impl ::std::fmt::Display for Sensitivity {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Normal => f.write_str("normal"),
Self::High => f.write_str("high"),
}
}
}
impl ::std::str::FromStr for Sensitivity {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"normal" => Ok(Self::Normal),
"high" => Ok(Self::High),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for Sensitivity {
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 Sensitivity {
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 Sensitivity {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///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.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "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.",
/// "type": "string",
/// "pattern": "^[0-9A-HJKMNP-TV-Z]{26}$"
///}
/// ```
/// </details>
#[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.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "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.",
/// "type": "string",
/// "enum": [
/// "string",
/// "number",
/// "boolean",
/// "date",
/// "object"
/// ]
///}
/// ```
/// </details>
#[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()
}
}
///A value of the store's monotonic write counter. Server-assigned; a producer never chooses one.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Version",
/// "description": "A value of the store's monotonic write counter. Server-assigned; a producer never chooses one.",
/// "type": "integer",
/// "minimum": 1.0
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(transparent)]
pub struct Version(pub ::std::num::NonZeroU64);
impl ::std::ops::Deref for Version {
type Target = ::std::num::NonZeroU64;
fn deref(&self) -> &::std::num::NonZeroU64 {
&self.0
}
}
impl ::std::convert::From<Version> for ::std::num::NonZeroU64 {
fn from(value: Version) -> Self {
value.0
}
}
impl ::std::convert::From<::std::num::NonZeroU64> for Version {
fn from(value: ::std::num::NonZeroU64) -> Self {
Self(value)
}
}
impl ::std::str::FromStr for Version {
type Err = <::std::num::NonZeroU64 as ::std::str::FromStr>::Err;
fn from_str(value: &str) -> ::std::result::Result<Self, Self::Err> {
Ok(Self(value.parse()?))
}
}
impl ::std::convert::TryFrom<&str> for Version {
type Error = <::std::num::NonZeroU64 as ::std::str::FromStr>::Err;
fn try_from(value: &str) -> ::std::result::Result<Self, Self::Error> {
value.parse()
}
}
impl ::std::convert::TryFrom<String> for Version {
type Error = <::std::num::NonZeroU64 as ::std::str::FromStr>::Err;
fn try_from(value: String) -> ::std::result::Result<Self, Self::Error> {
value.parse()
}
}
impl ::std::fmt::Display for Version {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
self.0.fmt(f)
}
}
/// Types for composing complex structures.
pub mod builder {
#[derive(Clone, Debug)]
pub struct Payload {
attribute_id:
::std::result::Result<::std::option::Option<super::Ulid>, ::std::string::String>,
endorsements: ::std::result::Result<
::std::option::Option<Vec<super::PayloadEndorsementsItem>>,
::std::string::String,
>,
expected_version: ::std::result::Result<
::std::option::Option<super::ExpectedVersion>,
::std::string::String,
>,
ext: ::std::result::Result<::std::option::Option<super::Ext>, ::std::string::String>,
label: ::std::result::Result<
::std::option::Option<super::PayloadLabel>,
::std::string::String,
>,
provenance: ::std::result::Result<super::Provenance, ::std::string::String>,
release: ::std::result::Result<
::std::option::Option<super::ReleaseRequirement>,
::std::string::String,
>,
sensitivity:
::std::result::Result<::std::option::Option<super::Sensitivity>, ::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 Payload {
fn default() -> Self {
Self {
attribute_id: Ok(Default::default()),
endorsements: Ok(Default::default()),
expected_version: Ok(Default::default()),
ext: Ok(Default::default()),
label: Ok(Default::default()),
provenance: Err("no value supplied for provenance".to_string()),
release: Ok(Default::default()),
sensitivity: 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 Payload {
pub fn attribute_id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::Ulid>>,
T::Error: ::std::fmt::Display,
{
self.attribute_id = value
.try_into()
.map_err(|e| format!("error converting supplied value for attribute_id: {e}"));
self
}
pub fn endorsements<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<Vec<super::PayloadEndorsementsItem>>>,
T::Error: ::std::fmt::Display,
{
self.endorsements = value
.try_into()
.map_err(|e| format!("error converting supplied value for endorsements: {e}"));
self
}
pub fn expected_version<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::ExpectedVersion>>,
T::Error: ::std::fmt::Display,
{
self.expected_version = value
.try_into()
.map_err(|e| format!("error converting supplied value for expected_version: {e}"));
self
}
pub fn ext<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::Ext>>,
T::Error: ::std::fmt::Display,
{
self.ext = value
.try_into()
.map_err(|e| format!("error converting supplied value for ext: {e}"));
self
}
pub fn label<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::PayloadLabel>>,
T::Error: ::std::fmt::Display,
{
self.label = value
.try_into()
.map_err(|e| format!("error converting supplied value for label: {e}"));
self
}
pub fn provenance<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<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 release<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::ReleaseRequirement>>,
T::Error: ::std::fmt::Display,
{
self.release = value
.try_into()
.map_err(|e| format!("error converting supplied value for release: {e}"));
self
}
pub fn sensitivity<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::Sensitivity>>,
T::Error: ::std::fmt::Display,
{
self.sensitivity = value
.try_into()
.map_err(|e| format!("error converting supplied value for sensitivity: {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<Payload> for super::Payload {
type Error = super::error::ConversionError;
fn try_from(value: Payload) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
attribute_id: value.attribute_id?,
endorsements: value.endorsements?,
expected_version: value.expected_version?,
ext: value.ext?,
label: value.label?,
provenance: value.provenance?,
release: value.release?,
sensitivity: value.sensitivity?,
type_: value.type_?,
value: value.value?,
value_type: value.value_type?,
})
}
}
impl ::std::convert::From<super::Payload> for Payload {
fn from(value: super::Payload) -> Self {
Self {
attribute_id: Ok(value.attribute_id),
endorsements: Ok(value.endorsements),
expected_version: Ok(value.expected_version),
ext: Ok(value.ext),
label: Ok(value.label),
provenance: Ok(value.provenance),
release: Ok(value.release),
sensitivity: Ok(value.sensitivity),
type_: Ok(value.type_),
value: Ok(value.value),
value_type: Ok(value.value_type),
}
}
}
#[derive(Clone, Debug)]
pub struct Response {
attribute_id: ::std::result::Result<super::Ulid, ::std::string::String>,
correlation: ::std::result::Result<
::std::option::Option<super::ResponseCorrelation>,
::std::string::String,
>,
created: ::std::result::Result<bool, ::std::string::String>,
created_at: ::std::result::Result<
::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
::std::string::String,
>,
ext: ::std::result::Result<::std::option::Option<super::Ext>, ::std::string::String>,
held_by_pin: ::std::result::Result<
::std::vec::Vec<super::ResponseHeldByPinItem>,
::std::string::String,
>,
refreshed: ::std::result::Result<
::std::vec::Vec<super::ResponseRefreshedItem>,
::std::string::String,
>,
updated_at:
::std::result::Result<::chrono::DateTime<::chrono::offset::Utc>, ::std::string::String>,
version: ::std::result::Result<super::Version, ::std::string::String>,
}
impl ::std::default::Default for Response {
fn default() -> Self {
Self {
attribute_id: Err("no value supplied for attribute_id".to_string()),
correlation: Ok(Default::default()),
created: Err("no value supplied for created".to_string()),
created_at: Ok(Default::default()),
ext: Ok(Default::default()),
held_by_pin: Ok(Default::default()),
refreshed: Ok(Default::default()),
updated_at: Err("no value supplied for updated_at".to_string()),
version: Err("no value supplied for version".to_string()),
}
}
}
impl Response {
pub fn attribute_id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::Ulid>,
T::Error: ::std::fmt::Display,
{
self.attribute_id = value
.try_into()
.map_err(|e| format!("error converting supplied value for attribute_id: {e}"));
self
}
pub fn correlation<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::ResponseCorrelation>>,
T::Error: ::std::fmt::Display,
{
self.correlation = value
.try_into()
.map_err(|e| format!("error converting supplied value for correlation: {e}"));
self
}
pub fn created<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<bool>,
T::Error: ::std::fmt::Display,
{
self.created = value
.try_into()
.map_err(|e| format!("error converting supplied value for created: {e}"));
self
}
pub fn created_at<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<
::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
>,
T::Error: ::std::fmt::Display,
{
self.created_at = value
.try_into()
.map_err(|e| format!("error converting supplied value for created_at: {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 held_by_pin<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::vec::Vec<super::ResponseHeldByPinItem>>,
T::Error: ::std::fmt::Display,
{
self.held_by_pin = value
.try_into()
.map_err(|e| format!("error converting supplied value for held_by_pin: {e}"));
self
}
pub fn refreshed<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::vec::Vec<super::ResponseRefreshedItem>>,
T::Error: ::std::fmt::Display,
{
self.refreshed = value
.try_into()
.map_err(|e| format!("error converting supplied value for refreshed: {e}"));
self
}
pub fn updated_at<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::chrono::DateTime<::chrono::offset::Utc>>,
T::Error: ::std::fmt::Display,
{
self.updated_at = value
.try_into()
.map_err(|e| format!("error converting supplied value for updated_at: {e}"));
self
}
pub fn version<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::Version>,
T::Error: ::std::fmt::Display,
{
self.version = value
.try_into()
.map_err(|e| format!("error converting supplied value for version: {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 {
attribute_id: value.attribute_id?,
correlation: value.correlation?,
created: value.created?,
created_at: value.created_at?,
ext: value.ext?,
held_by_pin: value.held_by_pin?,
refreshed: value.refreshed?,
updated_at: value.updated_at?,
version: value.version?,
})
}
}
impl ::std::convert::From<super::Response> for Response {
fn from(value: super::Response) -> Self {
Self {
attribute_id: Ok(value.attribute_id),
correlation: Ok(value.correlation),
created: Ok(value.created),
created_at: Ok(value.created_at),
ext: Ok(value.ext),
held_by_pin: Ok(value.held_by_pin),
refreshed: Ok(value.refreshed),
updated_at: Ok(value.updated_at),
version: Ok(value.version),
}
}
}
#[derive(Clone, Debug)]
pub struct ResponseCorrelation {
severity: ::std::result::Result<super::ResponseCorrelationSeverity, ::std::string::String>,
shared_with_profile_count:
::std::result::Result<::std::option::Option<u64>, ::std::string::String>,
}
impl ::std::default::Default for ResponseCorrelation {
fn default() -> Self {
Self {
severity: Err("no value supplied for severity".to_string()),
shared_with_profile_count: Ok(Default::default()),
}
}
}
impl ResponseCorrelation {
pub fn severity<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::ResponseCorrelationSeverity>,
T::Error: ::std::fmt::Display,
{
self.severity = value
.try_into()
.map_err(|e| format!("error converting supplied value for severity: {e}"));
self
}
pub fn shared_with_profile_count<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<u64>>,
T::Error: ::std::fmt::Display,
{
self.shared_with_profile_count = value.try_into().map_err(|e| {
format!("error converting supplied value for shared_with_profile_count: {e}")
});
self
}
}
impl ::std::convert::TryFrom<ResponseCorrelation> for super::ResponseCorrelation {
type Error = super::error::ConversionError;
fn try_from(
value: ResponseCorrelation,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
severity: value.severity?,
shared_with_profile_count: value.shared_with_profile_count?,
})
}
}
impl ::std::convert::From<super::ResponseCorrelation> for ResponseCorrelation {
fn from(value: super::ResponseCorrelation) -> Self {
Self {
severity: Ok(value.severity),
shared_with_profile_count: Ok(value.shared_with_profile_count),
}
}
}
#[derive(Clone, Debug)]
pub struct ResponseHeldByPinItem {
pin_version: ::std::result::Result<super::Version, ::std::string::String>,
profile_id: ::std::result::Result<super::Ulid, ::std::string::String>,
}
impl ::std::default::Default for ResponseHeldByPinItem {
fn default() -> Self {
Self {
pin_version: Err("no value supplied for pin_version".to_string()),
profile_id: Err("no value supplied for profile_id".to_string()),
}
}
}
impl ResponseHeldByPinItem {
pub fn pin_version<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::Version>,
T::Error: ::std::fmt::Display,
{
self.pin_version = value
.try_into()
.map_err(|e| format!("error converting supplied value for pin_version: {e}"));
self
}
pub fn profile_id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::Ulid>,
T::Error: ::std::fmt::Display,
{
self.profile_id = value
.try_into()
.map_err(|e| format!("error converting supplied value for profile_id: {e}"));
self
}
}
impl ::std::convert::TryFrom<ResponseHeldByPinItem> for super::ResponseHeldByPinItem {
type Error = super::error::ConversionError;
fn try_from(
value: ResponseHeldByPinItem,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
pin_version: value.pin_version?,
profile_id: value.profile_id?,
})
}
}
impl ::std::convert::From<super::ResponseHeldByPinItem> for ResponseHeldByPinItem {
fn from(value: super::ResponseHeldByPinItem) -> Self {
Self {
pin_version: Ok(value.pin_version),
profile_id: Ok(value.profile_id),
}
}
}
#[derive(Clone, Debug)]
pub struct ResponseRefreshedItem {
context_id:
::std::result::Result<super::ResponseRefreshedItemContextId, ::std::string::String>,
persona_did:
::std::result::Result<super::ResponseRefreshedItemPersonaDid, ::std::string::String>,
profile_id: ::std::result::Result<super::Ulid, ::std::string::String>,
}
impl ::std::default::Default for ResponseRefreshedItem {
fn default() -> Self {
Self {
context_id: Err("no value supplied for context_id".to_string()),
persona_did: Err("no value supplied for persona_did".to_string()),
profile_id: Err("no value supplied for profile_id".to_string()),
}
}
}
impl ResponseRefreshedItem {
pub fn context_id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::ResponseRefreshedItemContextId>,
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 persona_did<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::ResponseRefreshedItemPersonaDid>,
T::Error: ::std::fmt::Display,
{
self.persona_did = value
.try_into()
.map_err(|e| format!("error converting supplied value for persona_did: {e}"));
self
}
pub fn profile_id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::Ulid>,
T::Error: ::std::fmt::Display,
{
self.profile_id = value
.try_into()
.map_err(|e| format!("error converting supplied value for profile_id: {e}"));
self
}
}
impl ::std::convert::TryFrom<ResponseRefreshedItem> for super::ResponseRefreshedItem {
type Error = super::error::ConversionError;
fn try_from(
value: ResponseRefreshedItem,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
context_id: value.context_id?,
persona_did: value.persona_did?,
profile_id: value.profile_id?,
})
}
}
impl ::std::convert::From<super::ResponseRefreshedItem> for ResponseRefreshedItem {
fn from(value: super::ResponseRefreshedItem) -> Self {
Self {
context_id: Ok(value.context_id),
persona_did: Ok(value.persona_did),
profile_id: Ok(value.profile_id),
}
}
}
}
/// 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/attribute/put/1.0";
const IS_PROOF_REQUIRED: bool = true;
const IS_ISSUED_AT_REQUIRED: bool = true;
const IS_RECIPIENT_REQUIRED: bool = true;
const PAYLOAD_SCHEMA: Option<&'static str> = Some(
"{\n \"$defs\": {\n \"ClaimType\": {\n \"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.\",\n \"maxLength\": 128,\n \"minLength\": 1,\n \"pattern\": \"^(x:)?[a-z][a-zA-Z0-9]*(\\\\.[a-z][a-zA-Z0-9]*)*$\",\n \"title\": \"ClaimType\",\n \"type\": \"string\"\n },\n \"ExpectedVersion\": {\n \"description\": \"Optimistic-concurrency precondition. A positive value requires the record's current `version` to equal it exactly; zero means create-only and applies only when no live record exists at the address.\",\n \"minimum\": 0,\n \"title\": \"ExpectedVersion\",\n \"type\": \"integer\"\n },\n \"Ext\": {\n \"additionalProperties\": true,\n \"description\": \"Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.\",\n \"minProperties\": 1,\n \"propertyNames\": {\n \"pattern\": \"^[a-z][a-z0-9-]*(\\\\.[a-z0-9-]+)+$\"\n },\n \"title\": \"Ext\",\n \"type\": \"object\"\n },\n \"ProofRung\": {\n \"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.\",\n \"enum\": [\n \"predicate\",\n \"derived\",\n \"selectiveDisclosure\",\n \"whole\"\n ],\n \"title\": \"ProofRung\",\n \"type\": \"string\"\n },\n \"Provenance\": {\n \"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.\",\n \"oneOf\": [\n {\n \"additionalProperties\": false,\n \"properties\": {\n \"kind\": {\n \"const\": \"selfAsserted\"\n }\n },\n \"required\": [\n \"kind\"\n ]\n },\n {\n \"additionalProperties\": false,\n \"properties\": {\n \"claimPath\": {\n \"description\": \"RFC 6901 JSON Pointer to the claim within the credential, e.g. `/credentialSubject/familyName`.\",\n \"pattern\": \"^(/[^/~]*(~[01][^/~]*)*)*$\",\n \"type\": \"string\"\n },\n \"credentialId\": {\n \"description\": \"Vault identifier of the backing credential.\",\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"issuerDid\": {\n \"description\": \"Issuer of the backing credential. Advisory: a consumer MUST verify the credential rather than trusting this member.\",\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"kind\": {\n \"const\": \"credentialBacked\"\n },\n \"proof\": {\n \"$ref\": \"#/$defs/ProofRung\",\n \"description\": \"The disclosure rung this claim was, or will be, presented at.\"\n }\n },\n \"required\": [\n \"kind\",\n \"credentialId\",\n \"claimPath\"\n ]\n },\n {\n \"additionalProperties\": false,\n \"properties\": {\n \"generator\": {\n \"description\": \"Names the minting scheme, e.g. `relayEmail`. Maintainer-defined.\",\n \"maxLength\": 64,\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"kind\": {\n \"const\": \"generated\"\n },\n \"perVerifier\": {\n \"default\": true,\n \"description\": \"When true (the default and the only useful setting), a distinct value is minted for each verifier.\",\n \"type\": \"boolean\"\n }\n },\n \"required\": [\n \"kind\",\n \"generator\"\n ]\n },\n {\n \"additionalProperties\": false,\n \"properties\": {\n \"derivedAt\": {\n \"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.\",\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"kind\": {\n \"const\": \"derived\"\n },\n \"source\": {\n \"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.\",\n \"maxLength\": 64,\n \"minLength\": 1,\n \"pattern\": \"^[a-z][A-Za-z0-9.-]*$\",\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"kind\",\n \"source\",\n \"derivedAt\"\n ]\n }\n ],\n \"required\": [\n \"kind\"\n ],\n \"title\": \"Provenance\",\n \"type\": \"object\"\n },\n \"ReleaseRequirement\": {\n \"description\": \"What it takes to let a value LEAVE. Distinct from `Sensitivity`, which governs showing it to the holder.\\n\\n`consent` is the ordinary gate: `persona/disclosure/preview` renders what would leave and `persona/disclosure/present` releases it, so a human sees it once.\\n\\n`stepUp` additionally requires a fresh authentication bound to THAT preview — not to the session. Without the binding, \\\"each time\\\" degrades into \\\"once per login\\\", which is the failure the requirement exists to prevent; the single-use `previewId` the preview already mints is what an implementation binds to. A maintainer MUST refuse `persona/disclosure/present` for a `stepUp` attribute when no such approval accompanies it.\\n\\nAbsent means *not decided by the holder* and resolves from the claim-type registry, which defaults `payment.*` and `gov.*` to `stepUp`.\",\n \"enum\": [\n \"consent\",\n \"stepUp\"\n ],\n \"title\": \"ReleaseRequirement\",\n \"type\": \"string\"\n },\n \"Response\": {\n \"$anchor\": \"response\",\n \"additionalProperties\": false,\n \"description\": \"Success response to persona/attribute/put. Type https://trusttasks.org/spec/persona/attribute/put/1.0#response. A failed precondition is not a success: it is a trust-task-error carrying persona/attribute/put:versionConflict, whose details carry the maintainer's current version and value.\",\n \"properties\": {\n \"attributeId\": {\n \"$ref\": \"#/$defs/Ulid\"\n },\n \"correlation\": {\n \"additionalProperties\": false,\n \"description\": \"Advisory result of the correlation check the maintainer runs over the new value (see persona/correlation/analyze). Returned on the write so a producer's builder can warn at the moment of composition rather than requiring a second round trip. Advisory only: the write has already applied, and a maintainer MUST NOT refuse a write on correlation grounds — the holder decides.\",\n \"properties\": {\n \"severity\": {\n \"enum\": [\n \"none\",\n \"low\",\n \"high\"\n ],\n \"type\": \"string\"\n },\n \"sharedWithProfileCount\": {\n \"description\": \"How many other profiles already present this exact value. A count, not identifiers — the identifiers are available from the analyze task, which is where a producer should go to render remedies.\",\n \"minimum\": 0,\n \"type\": \"integer\"\n }\n },\n \"required\": [\n \"severity\"\n ],\n \"type\": \"object\"\n },\n \"created\": {\n \"description\": \"True when this write created the attribute, false when it replaced one. A producer that omitted `attributeId` can still be told which happened, because a retried create with a supplied id is a replacement.\",\n \"type\": \"boolean\"\n },\n \"createdAt\": {\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\"\n },\n \"heldByPin\": {\n \"description\": \"Faces that pin this attribute to an earlier version and so did NOT follow the edit — the counterparties that must keep seeing the value they verified. Named so the holder can decide, per face, whether that is still what they want. Absent when no face pins it.\",\n \"items\": {\n \"additionalProperties\": false,\n \"properties\": {\n \"pinVersion\": {\n \"$ref\": \"#/$defs/Version\"\n },\n \"profileId\": {\n \"$ref\": \"#/$defs/Ulid\"\n }\n },\n \"required\": [\n \"profileId\",\n \"pinVersion\"\n ],\n \"type\": \"object\"\n },\n \"maxItems\": 256,\n \"type\": \"array\"\n },\n \"refreshed\": {\n \"description\": \"Every place this write changed what a persona presents: each binding whose projection was re-pushed because a face wearing it shows this attribute live. An edit propagates by design, and a holder told only that it saved cannot tell whether it refreshed one face or nine. Holder-authorized, so identifiers are returned. Absent when nothing was bound to a face showing it.\",\n \"items\": {\n \"additionalProperties\": false,\n \"properties\": {\n \"contextId\": {\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"personaDid\": {\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"profileId\": {\n \"$ref\": \"#/$defs/Ulid\"\n }\n },\n \"required\": [\n \"profileId\",\n \"contextId\",\n \"personaDid\"\n ],\n \"type\": \"object\"\n },\n \"maxItems\": 256,\n \"type\": \"array\"\n },\n \"updatedAt\": {\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"version\": {\n \"$ref\": \"#/$defs/Version\"\n }\n },\n \"required\": [\n \"attributeId\",\n \"version\",\n \"created\",\n \"updatedAt\"\n ],\n \"title\": \"Persona Attribute Put — response payload\",\n \"type\": \"object\"\n },\n \"Sensitivity\": {\n \"description\": \"How carefully a value is shown TO ITS OWN HOLDER. `high` means a consumer masks it by default, reveals it one attribute at a time on a deliberate act, and — the half that is not cosmetic — omits it from a listing that did not ask for sensitive values.\\n\\nAbsent means *not decided by the holder*, not `normal`: a consumer resolves it from the claim-type registry (see CLAIM-TYPES.md §4), which is why this member is optional and why an unregistered token resolves conservatively rather than permissively.\\n\\nDistinct from how linkable the value is. A payment card is highly sensitive and barely linkable — every card number is unique, so knowing one tells a second verifier nothing about the first. Reading either as a proxy for the other produces a consumer that hides the wrong things.\",\n \"enum\": [\n \"normal\",\n \"high\"\n ],\n \"title\": \"Sensitivity\",\n \"type\": \"string\"\n },\n \"Ulid\": {\n \"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.\",\n \"pattern\": \"^[0-9A-HJKMNP-TV-Z]{26}$\",\n \"title\": \"Ulid\",\n \"type\": \"string\"\n },\n \"ValueType\": {\n \"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.\",\n \"enum\": [\n \"string\",\n \"number\",\n \"boolean\",\n \"date\",\n \"object\"\n ],\n \"title\": \"ValueType\",\n \"type\": \"string\"\n },\n \"Version\": {\n \"description\": \"A value of the store's monotonic write counter. Server-assigned; a producer never chooses one.\",\n \"minimum\": 1,\n \"title\": \"Version\",\n \"type\": \"integer\"\n }\n },\n \"$id\": \"https://trusttasks.org/spec/persona/attribute/put/1.0\",\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"additionalProperties\": false,\n \"description\": \"Create or replace one attribute in the holder's pool. Omit `attributeId` to create; supply it to replace. `expectedVersion` makes the write conditional.\",\n \"properties\": {\n \"attributeId\": {\n \"$ref\": \"#/$defs/Ulid\",\n \"description\": \"Omit to create — the maintainer assigns one and returns it. Supply to replace an existing attribute, or to make a create idempotent under retry; a supplied id that already exists is a replacement, and a producer that meant to create MUST pair it with `expectedVersion: 0`.\"\n },\n \"endorsements\": {\n \"description\": \"Vault identifiers of credentials in which a third party endorses this value. Inventory, not evidence — see the `endorsements` member of the shared Attribute. Replaced whole by each put; omit or send empty for none.\",\n \"items\": {\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"maxItems\": 64,\n \"type\": \"array\",\n \"uniqueItems\": true\n },\n \"expectedVersion\": {\n \"$ref\": \"#/$defs/ExpectedVersion\",\n \"description\": \"Optional precondition. Omit for last-writer-wins. Supply the version a prior read returned to make the write conditional; supply 0 to create only.\"\n },\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\",\n \"description\": \"Ecosystem-defined extension members per SPEC.md §4.5.1.\"\n },\n \"label\": {\n \"description\": \"The holder's own words, for their own picker. Never disclosed to a verifier.\",\n \"maxLength\": 128,\n \"type\": \"string\"\n },\n \"provenance\": {\n \"$ref\": \"#/$defs/Provenance\"\n },\n \"release\": {\n \"$ref\": \"#/$defs/ReleaseRequirement\",\n \"description\": \"What it takes to disclose this value. OPTIONAL, with the same meaning for absence as `sensitivity`.\"\n },\n \"sensitivity\": {\n \"$ref\": \"#/$defs/Sensitivity\",\n \"description\": \"How carefully this value is shown to the holder. OPTIONAL, and its absence is meaningful: it records that the holder made no explicit decision, so a consumer resolves it from the claim-type registry. Sending the resolved value back would freeze it — a later tightening of the registry would then protect new attributes and leave this one exposed.\"\n },\n \"type\": {\n \"$ref\": \"#/$defs/ClaimType\"\n },\n \"value\": {\n \"description\": \"The fact itself. MUST agree with `valueType`; a maintainer MUST refuse a document where it does not. For a `credentialBacked` provenance this is the initial display cache — the maintainer re-derives it from the credential and MAY overwrite what was supplied.\"\n },\n \"valueType\": {\n \"$ref\": \"#/$defs/ValueType\"\n }\n },\n \"required\": [\n \"type\",\n \"valueType\",\n \"value\",\n \"provenance\"\n ],\n \"title\": \"Persona Attribute Put — payload\",\n \"type\": \"object\"\n}\n",
);
}
impl crate::Payload for Response {
const TYPE_URI: &'static str = "https://trusttasks.org/spec/persona/attribute/put/1.0#response";
const IS_PROOF_REQUIRED: bool = true;
const IS_ISSUED_AT_REQUIRED: bool = true;
const IS_RECIPIENT_REQUIRED: bool = true;
const PAYLOAD_SCHEMA: Option<&'static str> = Some(
"{\n \"$defs\": {\n \"ClaimType\": {\n \"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.\",\n \"maxLength\": 128,\n \"minLength\": 1,\n \"pattern\": \"^(x:)?[a-z][a-zA-Z0-9]*(\\\\.[a-z][a-zA-Z0-9]*)*$\",\n \"title\": \"ClaimType\",\n \"type\": \"string\"\n },\n \"ExpectedVersion\": {\n \"description\": \"Optimistic-concurrency precondition. A positive value requires the record's current `version` to equal it exactly; zero means create-only and applies only when no live record exists at the address.\",\n \"minimum\": 0,\n \"title\": \"ExpectedVersion\",\n \"type\": \"integer\"\n },\n \"Ext\": {\n \"additionalProperties\": true,\n \"description\": \"Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.\",\n \"minProperties\": 1,\n \"propertyNames\": {\n \"pattern\": \"^[a-z][a-z0-9-]*(\\\\.[a-z0-9-]+)+$\"\n },\n \"title\": \"Ext\",\n \"type\": \"object\"\n },\n \"ProofRung\": {\n \"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.\",\n \"enum\": [\n \"predicate\",\n \"derived\",\n \"selectiveDisclosure\",\n \"whole\"\n ],\n \"title\": \"ProofRung\",\n \"type\": \"string\"\n },\n \"Provenance\": {\n \"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.\",\n \"oneOf\": [\n {\n \"additionalProperties\": false,\n \"properties\": {\n \"kind\": {\n \"const\": \"selfAsserted\"\n }\n },\n \"required\": [\n \"kind\"\n ]\n },\n {\n \"additionalProperties\": false,\n \"properties\": {\n \"claimPath\": {\n \"description\": \"RFC 6901 JSON Pointer to the claim within the credential, e.g. `/credentialSubject/familyName`.\",\n \"pattern\": \"^(/[^/~]*(~[01][^/~]*)*)*$\",\n \"type\": \"string\"\n },\n \"credentialId\": {\n \"description\": \"Vault identifier of the backing credential.\",\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"issuerDid\": {\n \"description\": \"Issuer of the backing credential. Advisory: a consumer MUST verify the credential rather than trusting this member.\",\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"kind\": {\n \"const\": \"credentialBacked\"\n },\n \"proof\": {\n \"$ref\": \"#/$defs/ProofRung\",\n \"description\": \"The disclosure rung this claim was, or will be, presented at.\"\n }\n },\n \"required\": [\n \"kind\",\n \"credentialId\",\n \"claimPath\"\n ]\n },\n {\n \"additionalProperties\": false,\n \"properties\": {\n \"generator\": {\n \"description\": \"Names the minting scheme, e.g. `relayEmail`. Maintainer-defined.\",\n \"maxLength\": 64,\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"kind\": {\n \"const\": \"generated\"\n },\n \"perVerifier\": {\n \"default\": true,\n \"description\": \"When true (the default and the only useful setting), a distinct value is minted for each verifier.\",\n \"type\": \"boolean\"\n }\n },\n \"required\": [\n \"kind\",\n \"generator\"\n ]\n },\n {\n \"additionalProperties\": false,\n \"properties\": {\n \"derivedAt\": {\n \"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.\",\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"kind\": {\n \"const\": \"derived\"\n },\n \"source\": {\n \"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.\",\n \"maxLength\": 64,\n \"minLength\": 1,\n \"pattern\": \"^[a-z][A-Za-z0-9.-]*$\",\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"kind\",\n \"source\",\n \"derivedAt\"\n ]\n }\n ],\n \"required\": [\n \"kind\"\n ],\n \"title\": \"Provenance\",\n \"type\": \"object\"\n },\n \"ReleaseRequirement\": {\n \"description\": \"What it takes to let a value LEAVE. Distinct from `Sensitivity`, which governs showing it to the holder.\\n\\n`consent` is the ordinary gate: `persona/disclosure/preview` renders what would leave and `persona/disclosure/present` releases it, so a human sees it once.\\n\\n`stepUp` additionally requires a fresh authentication bound to THAT preview — not to the session. Without the binding, \\\"each time\\\" degrades into \\\"once per login\\\", which is the failure the requirement exists to prevent; the single-use `previewId` the preview already mints is what an implementation binds to. A maintainer MUST refuse `persona/disclosure/present` for a `stepUp` attribute when no such approval accompanies it.\\n\\nAbsent means *not decided by the holder* and resolves from the claim-type registry, which defaults `payment.*` and `gov.*` to `stepUp`.\",\n \"enum\": [\n \"consent\",\n \"stepUp\"\n ],\n \"title\": \"ReleaseRequirement\",\n \"type\": \"string\"\n },\n \"Response\": {\n \"$anchor\": \"response\",\n \"additionalProperties\": false,\n \"description\": \"Success response to persona/attribute/put. Type https://trusttasks.org/spec/persona/attribute/put/1.0#response. A failed precondition is not a success: it is a trust-task-error carrying persona/attribute/put:versionConflict, whose details carry the maintainer's current version and value.\",\n \"properties\": {\n \"attributeId\": {\n \"$ref\": \"#/$defs/Ulid\"\n },\n \"correlation\": {\n \"additionalProperties\": false,\n \"description\": \"Advisory result of the correlation check the maintainer runs over the new value (see persona/correlation/analyze). Returned on the write so a producer's builder can warn at the moment of composition rather than requiring a second round trip. Advisory only: the write has already applied, and a maintainer MUST NOT refuse a write on correlation grounds — the holder decides.\",\n \"properties\": {\n \"severity\": {\n \"enum\": [\n \"none\",\n \"low\",\n \"high\"\n ],\n \"type\": \"string\"\n },\n \"sharedWithProfileCount\": {\n \"description\": \"How many other profiles already present this exact value. A count, not identifiers — the identifiers are available from the analyze task, which is where a producer should go to render remedies.\",\n \"minimum\": 0,\n \"type\": \"integer\"\n }\n },\n \"required\": [\n \"severity\"\n ],\n \"type\": \"object\"\n },\n \"created\": {\n \"description\": \"True when this write created the attribute, false when it replaced one. A producer that omitted `attributeId` can still be told which happened, because a retried create with a supplied id is a replacement.\",\n \"type\": \"boolean\"\n },\n \"createdAt\": {\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\"\n },\n \"heldByPin\": {\n \"description\": \"Faces that pin this attribute to an earlier version and so did NOT follow the edit — the counterparties that must keep seeing the value they verified. Named so the holder can decide, per face, whether that is still what they want. Absent when no face pins it.\",\n \"items\": {\n \"additionalProperties\": false,\n \"properties\": {\n \"pinVersion\": {\n \"$ref\": \"#/$defs/Version\"\n },\n \"profileId\": {\n \"$ref\": \"#/$defs/Ulid\"\n }\n },\n \"required\": [\n \"profileId\",\n \"pinVersion\"\n ],\n \"type\": \"object\"\n },\n \"maxItems\": 256,\n \"type\": \"array\"\n },\n \"refreshed\": {\n \"description\": \"Every place this write changed what a persona presents: each binding whose projection was re-pushed because a face wearing it shows this attribute live. An edit propagates by design, and a holder told only that it saved cannot tell whether it refreshed one face or nine. Holder-authorized, so identifiers are returned. Absent when nothing was bound to a face showing it.\",\n \"items\": {\n \"additionalProperties\": false,\n \"properties\": {\n \"contextId\": {\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"personaDid\": {\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"profileId\": {\n \"$ref\": \"#/$defs/Ulid\"\n }\n },\n \"required\": [\n \"profileId\",\n \"contextId\",\n \"personaDid\"\n ],\n \"type\": \"object\"\n },\n \"maxItems\": 256,\n \"type\": \"array\"\n },\n \"updatedAt\": {\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"version\": {\n \"$ref\": \"#/$defs/Version\"\n }\n },\n \"required\": [\n \"attributeId\",\n \"version\",\n \"created\",\n \"updatedAt\"\n ],\n \"title\": \"Persona Attribute Put — response payload\",\n \"type\": \"object\"\n },\n \"Sensitivity\": {\n \"description\": \"How carefully a value is shown TO ITS OWN HOLDER. `high` means a consumer masks it by default, reveals it one attribute at a time on a deliberate act, and — the half that is not cosmetic — omits it from a listing that did not ask for sensitive values.\\n\\nAbsent means *not decided by the holder*, not `normal`: a consumer resolves it from the claim-type registry (see CLAIM-TYPES.md §4), which is why this member is optional and why an unregistered token resolves conservatively rather than permissively.\\n\\nDistinct from how linkable the value is. A payment card is highly sensitive and barely linkable — every card number is unique, so knowing one tells a second verifier nothing about the first. Reading either as a proxy for the other produces a consumer that hides the wrong things.\",\n \"enum\": [\n \"normal\",\n \"high\"\n ],\n \"title\": \"Sensitivity\",\n \"type\": \"string\"\n },\n \"Ulid\": {\n \"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.\",\n \"pattern\": \"^[0-9A-HJKMNP-TV-Z]{26}$\",\n \"title\": \"Ulid\",\n \"type\": \"string\"\n },\n \"ValueType\": {\n \"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.\",\n \"enum\": [\n \"string\",\n \"number\",\n \"boolean\",\n \"date\",\n \"object\"\n ],\n \"title\": \"ValueType\",\n \"type\": \"string\"\n },\n \"Version\": {\n \"description\": \"A value of the store's monotonic write counter. Server-assigned; a producer never chooses one.\",\n \"minimum\": 1,\n \"title\": \"Version\",\n \"type\": \"integer\"\n }\n },\n \"$ref\": \"#/$defs/Response\",\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\"\n}\n",
);
}
impl crate::RequestPayload for Payload {
type Response = Response;
}
/// The extended error codes this specification declares (SPEC §7.3 item 9,
/// §8.5), in declaration order. Empty when it declares none.
pub const ERROR_CODES: &[crate::DeclaredErrorCode] = &[
error_codes::VERSION_CONFLICT,
error_codes::VALUE_TYPE_MISMATCH,
error_codes::ENDORSEMENT_NOT_FOUND,
error_codes::CREDENTIAL_NOT_FOUND,
];
/// 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/attribute/put:versionConflict`
///
/// The `expectedVersion` precondition failed. The details carry the maintainer's current version and value, so the caller can resolve without a re-read.
///
/// Declared `retryable: false`.
pub const VERSION_CONFLICT: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "persona/attribute/put:versionConflict",
retryable: false,
};
/// `persona/attribute/put:valueTypeMismatch`
///
/// The supplied `value` does not agree with the declared `valueType`.
///
/// Declared `retryable: false`.
pub const VALUE_TYPE_MISMATCH: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "persona/attribute/put:valueTypeMismatch",
retryable: false,
};
/// `persona/attribute/put:endorsementNotFound`
///
/// An `endorsements` entry names a credential the vault does not hold. The details name the identifiers. The attribute is not written — an endorsement the holder cannot produce is not one.
///
/// Declared `retryable: false`.
pub const ENDORSEMENT_NOT_FOUND: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "persona/attribute/put:endorsementNotFound",
retryable: false,
};
/// `persona/attribute/put:credentialNotFound`
///
/// A `credentialBacked` provenance names a credential the vault does not hold, or holds in a state it cannot be derived from. The attribute is not written — an attribute whose backing cannot be resolved at write time would read back stale forever.
///
/// Declared `retryable: false`.
pub const CREDENTIAL_NOT_FOUND: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "persona/attribute/put:credentialNotFound",
retryable: false,
};
}