//! Generated by `trust-tasks-codegen` — do not edit by hand.
//!
//! Spec slug: `vtc/join-requests/manifest`. Version: `0.3`.
#![allow(deprecated)]
/// Why this specification version is deprecated (SPEC "Superseded and
/// Withdrawn Versions"), or `None` while it is current.
pub const DEPRECATION: Option<&str> = Some("superseded by vtc/join-requests/manifest/0.4");
#[allow(unused_imports)]
use serde::{Deserialize, Serialize};
/// Error types.
pub mod error {
/// Error from a `TryFrom` or `FromStr` implementation.
pub struct ConversionError(::std::borrow::Cow<'static, str>);
impl ::std::error::Error for ConversionError {}
impl ::std::fmt::Display for ConversionError {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> Result<(), ::std::fmt::Error> {
::std::fmt::Display::fmt(&self.0, f)
}
}
impl ::std::fmt::Debug for ConversionError {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> Result<(), ::std::fmt::Error> {
::std::fmt::Debug::fmt(&self.0, f)
}
}
impl From<&'static str> for ConversionError {
fn from(value: &'static str) -> Self {
Self(value.into())
}
}
impl From<String> for ConversionError {
fn from(value: String) -> Self {
Self(value.into())
}
}
}
/**
The vocabulary token naming what a value IS — `name.legal`, `phone.mobile`, `address.postal`, `person.birthDate`. Dotted, most-general segment first, so that a consumer with no knowledge of the specific token can still group by its prefix.
The token is the maintainer's own; no external vocabulary is primary. External vocabularies (vCard/jCard, OIDC standard claims, schema.org) are mappings applied at PRESENTATION by a renderer, not at rest, so that a query written in any of them can be matched without the store having to live inside any one of them.
The `x:` prefix is an open extension namespace and is not decoration. The closest prior art — Windows CardSpace's self-issued card — supported exactly fifteen predefined claim types with no extensibility, and that is the specific way it failed the requirement a holder actually has. An `x:` attribute stores, composes, binds and discloses exactly like a known one; it renders generically and matches only an explicit query.*/
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ClaimType(::std::string::String);
impl ::std::ops::Deref for ClaimType {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ClaimType> for ::std::string::String {
fn from(value: ClaimType) -> Self {
value.0
}
}
impl ::std::str::FromStr for ClaimType {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 128usize {
return Err("longer than 128 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| {
::regress::Regex::new("^(x:)?[a-z][a-zA-Z0-9]*(\\.[a-z][a-zA-Z0-9]*)*$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err(
"doesn't match pattern \"^(x:)?[a-z][a-zA-Z0-9]*(\\.[a-z][a-zA-Z0-9]*)*$\"".into(),
);
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ClaimType {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for ClaimType {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for ClaimType {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for ClaimType {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///OPTIONAL. How the community asks to be shown to a prospective applicant: a name, an accent colour and a logo. Presentation only, self-asserted and unverified — `communityDid` identifies the community, never `branding`. Not part of any criterion, so not covered by a `requirementsDigest`. Every member is optional.
///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct CommunityBranding {
///An sRGB colour as `#rrggbb`, compared case-insensitively. A community SHOULD write it in lower case.
#[serde(
rename = "accentColor",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub accent_color: ::std::option::Option<CommunityBrandingAccentColor>,
///The community's name as it asks to be shown.
#[serde(
rename = "displayName",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub display_name: ::std::option::Option<CommunityBrandingDisplayName>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ext: ::std::option::Option<Ext>,
///An https URL of the community's logo. Fetched by the client, so an untrusted image from wherever it points.
#[serde(
rename = "logoUrl",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub logo_url: ::std::option::Option<::std::string::String>,
}
impl ::std::default::Default for CommunityBranding {
fn default() -> Self {
Self {
accent_color: Default::default(),
display_name: Default::default(),
ext: Default::default(),
logo_url: Default::default(),
}
}
}
impl CommunityBranding {
pub fn builder() -> builder::CommunityBranding {
Default::default()
}
}
///An sRGB colour as `#rrggbb`, compared case-insensitively. A community SHOULD write it in lower case.
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct CommunityBrandingAccentColor(::std::string::String);
impl ::std::ops::Deref for CommunityBrandingAccentColor {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<CommunityBrandingAccentColor> for ::std::string::String {
fn from(value: CommunityBrandingAccentColor) -> Self {
value.0
}
}
impl ::std::str::FromStr for CommunityBrandingAccentColor {
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-fA-F]{6}$").unwrap());
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^#[0-9a-fA-F]{6}$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for CommunityBrandingAccentColor {
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 CommunityBrandingAccentColor {
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 CommunityBrandingAccentColor {
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 CommunityBrandingAccentColor {
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 community's name as it asks to be shown.
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct CommunityBrandingDisplayName(::std::string::String);
impl ::std::ops::Deref for CommunityBrandingDisplayName {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<CommunityBrandingDisplayName> for ::std::string::String {
fn from(value: CommunityBrandingDisplayName) -> Self {
value.0
}
}
impl ::std::str::FromStr for CommunityBrandingDisplayName {
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());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for CommunityBrandingDisplayName {
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 CommunityBrandingDisplayName {
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 CommunityBrandingDisplayName {
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 CommunityBrandingDisplayName {
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())
})
}
}
///`Criterion`
///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct Criterion {
///How the community decides a submission that meets this criterion. `automatic`: it admits the applicant without a person deciding. `review`: it refers the submission to an administrator, who decides.
pub admission: CriterionAdmission,
///Whose credentials meet `presentationDefinition`: `community` (this community's own), `recognised` (this community's, or a community it recognises), or `any` (any issuer whose credential verifies). Present exactly when `presentationDefinition` is.
#[serde(
rename = "credentialIssuers",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub credential_issuers: ::std::option::Option<CriterionCredentialIssuers>,
///Plain-language summary of the criterion, authored by the community and shown to prospective applicants. Informative: where it and `vetting` disagree, `vetting` governs.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub description: ::std::option::Option<CriterionDescription>,
pub id: CriterionId,
///True: the criterion is met only by a submission carrying a valid, unconsumed invitation this community issued to the applicant.
#[serde(
rename = "invitationRequired",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub invitation_required: ::std::option::Option<bool>,
///The credentials an applicant must present for this criterion (opaque here). Absent: the criterion requires no credential.
#[serde(
rename = "presentationDefinition",
default,
skip_serializing_if = "::serde_json::Map::is_empty"
)]
pub presentation_definition: ::serde_json::Map<::std::string::String, ::serde_json::Value>,
///Digest over the RFC 8785 (JCS) canonicalization of this criterion object with the `requirementsDigest` member removed, as a multibase-encoded multihash (SHA-256 and base58btc RECOMMENDED). Names one version of the criterion: an applicant records it when starting an application and echoes it to vetters and at submission.
#[serde(rename = "requirementsDigest")]
pub requirements_digest: DigestMultibase,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub vetting: ::std::option::Option<VettingRequirements>,
}
impl Criterion {
pub fn builder() -> builder::Criterion {
Default::default()
}
}
///How the community decides a submission that meets this criterion. `automatic`: it admits the applicant without a person deciding. `review`: it refers the submission to an administrator, who decides.
///
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum CriterionAdmission {
#[serde(rename = "automatic")]
Automatic,
#[serde(rename = "review")]
Review,
}
impl ::std::fmt::Display for CriterionAdmission {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Automatic => f.write_str("automatic"),
Self::Review => f.write_str("review"),
}
}
}
impl ::std::str::FromStr for CriterionAdmission {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"automatic" => Ok(Self::Automatic),
"review" => Ok(Self::Review),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for CriterionAdmission {
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 CriterionAdmission {
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 CriterionAdmission {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///Whose credentials meet `presentationDefinition`: `community` (this community's own), `recognised` (this community's, or a community it recognises), or `any` (any issuer whose credential verifies). Present exactly when `presentationDefinition` is.
///
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum CriterionCredentialIssuers {
#[serde(rename = "any")]
Any,
#[serde(rename = "community")]
Community,
#[serde(rename = "recognised")]
Recognised,
}
impl ::std::fmt::Display for CriterionCredentialIssuers {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Any => f.write_str("any"),
Self::Community => f.write_str("community"),
Self::Recognised => f.write_str("recognised"),
}
}
}
impl ::std::str::FromStr for CriterionCredentialIssuers {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"any" => Ok(Self::Any),
"community" => Ok(Self::Community),
"recognised" => Ok(Self::Recognised),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for CriterionCredentialIssuers {
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 CriterionCredentialIssuers {
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 CriterionCredentialIssuers {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///Plain-language summary of the criterion, authored by the community and shown to prospective applicants. Informative: where it and `vetting` disagree, `vetting` governs.
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct CriterionDescription(::std::string::String);
impl ::std::ops::Deref for CriterionDescription {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<CriterionDescription> for ::std::string::String {
fn from(value: CriterionDescription) -> Self {
value.0
}
}
impl ::std::str::FromStr for CriterionDescription {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 1024usize {
return Err("longer than 1024 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for CriterionDescription {
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 CriterionDescription {
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 CriterionDescription {
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 CriterionDescription {
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())
})
}
}
///`CriterionId`
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct CriterionId(::std::string::String);
impl ::std::ops::Deref for CriterionId {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<CriterionId> for ::std::string::String {
fn from(value: CriterionId) -> Self {
value.0
}
}
impl ::std::str::FromStr for CriterionId {
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());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for CriterionId {
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 CriterionId {
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 CriterionId {
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 CriterionId {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
/**
A cryptographic digest as a multibase-encoded multihash — the encoding the W3C Verifiable Credentials Data Model 2.0 defines for `digestMultibase`, and the one `did:webvh` uses for its SCID and entry hashes.
Multihash carries the hash algorithm in-band, so the value is self-describing and the wire format survives an algorithm change without a schema revision; multibase does the same for the base encoding, so a verifier never infers base58 from base64url by context. A bare hex string or a `sha-256:`-style prefix hard-codes one algorithm into the wire contract and is non-conforming here.
This definition constrains the *encoding only*. What the digest is computed over is stated by each referencing field, because it differs legitimately: a digest over a JSON document is taken over its RFC 8785 (JCS) canonicalization, while a digest over an opaque artifact is taken over its bytes. A field whose input is a JSON document and which does not name a canonicalization is not reproducible.
Restricted to the two multibase headers W3C Controlled Identifiers 1.0 §2.4 normatively requires — `z` (base58btc) and `u` (base64url-no-pad). CID permits others but states that "interoperability is not guaranteed between implementations using such values", and a registry whose purpose is interoperability should not mint digests a conforming verifier may be unable to read. The alphabets are enforced rather than assumed: base58btc excludes 0, O, I and l, and an earlier permissive pattern let three published examples carry digests that were not valid base58 at all. base58btc is RECOMMENDED, for consistency with `did:key` and `did:webvh`.*/
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct DigestMultibase(::std::string::String);
impl ::std::ops::Deref for DigestMultibase {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<DigestMultibase> for ::std::string::String {
fn from(value: DigestMultibase) -> Self {
value.0
}
}
impl ::std::str::FromStr for DigestMultibase {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() < 16usize {
return Err("shorter than 16 characters".into());
}
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| {
::regress::Regex::new("^(z[1-9A-HJ-NP-Za-km-z]+|u[A-Za-z0-9_-]+)$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err(
"doesn't match pattern \"^(z[1-9A-HJ-NP-Za-km-z]+|u[A-Za-z0-9_-]+)$\"".into(),
);
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for DigestMultibase {
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 DigestMultibase {
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 DigestMultibase {
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 DigestMultibase {
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())
})
}
}
///An ISO 8601 duration in weeks, days, hours, minutes and seconds only (e.g. `P120D`, `P2W`, `P1DT12H`, `PT15M`). Years and months are refused: their length depends on the calendar, and an age limit that means different things on different days is not a limit.
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct Duration(::std::string::String);
impl ::std::ops::Deref for Duration {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<Duration> for ::std::string::String {
fn from(value: Duration) -> Self {
value.0
}
}
impl ::std::str::FromStr for Duration {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 32usize {
return Err("longer than 32 characters".into());
}
static PATTERN: ::std::sync::LazyLock<::regress::Regex> = ::std::sync::LazyLock::new(
|| {
::regress::Regex::new(
"^P(([0-9]+W)?([0-9]+D)?T([0-9]+H([0-9]+M)?([0-9]+S)?|[0-9]+M([0-9]+S)?|[0-9]+S)|[0-9]+W([0-9]+D)?|[0-9]+D)$",
)
.unwrap()
},
);
if PATTERN.find(value).is_none() {
return Err(
"doesn't match pattern \"^P(([0-9]+W)?([0-9]+D)?T([0-9]+H([0-9]+M)?([0-9]+S)?|[0-9]+M([0-9]+S)?|[0-9]+S)|[0-9]+W([0-9]+D)?|[0-9]+D)$\""
.into(),
);
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for Duration {
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 Duration {
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 Duration {
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 Duration {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.
///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(transparent)]
pub struct Ext(pub ::std::collections::HashMap<ExtKey, ::serde_json::Value>);
impl ::std::ops::Deref for Ext {
type Target = ::std::collections::HashMap<ExtKey, ::serde_json::Value>;
fn deref(&self) -> &::std::collections::HashMap<ExtKey, ::serde_json::Value> {
&self.0
}
}
impl ::std::convert::From<Ext> for ::std::collections::HashMap<ExtKey, ::serde_json::Value> {
fn from(value: Ext) -> Self {
value.0
}
}
impl ::std::convert::From<::std::collections::HashMap<ExtKey, ::serde_json::Value>> for Ext {
fn from(value: ::std::collections::HashMap<ExtKey, ::serde_json::Value>) -> Self {
Self(value)
}
}
/**
Names the `ext` namespaces a consumer MUST understand or refuse, per SPEC.md §4.5.1.
Every entry MUST be an immediate key of the sibling `ext` object at the same level; an entry naming an absent namespace is non-conforming and the consumer rejects the document with `malformedRequest`. A consumer that does not recognize a namespace named here MUST NOT process the document as though the namespace were absent, and rejects it with `unsupportedExtension` — the exception to the rule that unrecognized namespaces are ignored.
A producer marks a namespace only where the document's meaning depends on it. Marking one that merely carries a hint or an annotation turns every consumer that has not implemented it into a failure where it would otherwise have interoperated. JSON Schema cannot check either of those rules: that an entry names a present namespace is checkable only against the sibling `ext`, and whether a namespace is load-bearing is not a schema question at all. Both are consumer-side checks.*/
///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(transparent)]
pub struct ExtCritical(pub Vec<ExtCriticalItem>);
impl ::std::ops::Deref for ExtCritical {
type Target = Vec<ExtCriticalItem>;
fn deref(&self) -> &Vec<ExtCriticalItem> {
&self.0
}
}
impl ::std::convert::From<ExtCritical> for Vec<ExtCriticalItem> {
fn from(value: ExtCritical) -> Self {
value.0
}
}
impl ::std::convert::From<Vec<ExtCriticalItem>> for ExtCritical {
fn from(value: Vec<ExtCriticalItem>) -> Self {
Self(value)
}
}
///`ExtCriticalItem`
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ExtCriticalItem(::std::string::String);
impl ::std::ops::Deref for ExtCriticalItem {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ExtCriticalItem> for ::std::string::String {
fn from(value: ExtCriticalItem) -> Self {
value.0
}
}
impl ::std::str::FromStr for ExtCriticalItem {
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 ExtCriticalItem {
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 ExtCriticalItem {
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 ExtCriticalItem {
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 ExtCriticalItem {
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())
})
}
}
///`ExtKey`
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ExtKey(::std::string::String);
impl ::std::ops::Deref for ExtKey {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ExtKey> for ::std::string::String {
fn from(value: ExtKey) -> Self {
value.0
}
}
impl ::std::str::FromStr for ExtKey {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| {
::regress::Regex::new("^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ExtKey {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for ExtKey {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for ExtKey {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for ExtKey {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///Discover a community's join criteria before applying. The request carries nothing. Version 0.2 adds, per criterion, an optional `vetting` requirements object — how many identity-vetting statements a community needs, by which methods, from whom — and a `requirementsDigest` that names the exact version of the criterion an applicant started under. The response may also carry `branding`, how the community asks to be shown.
///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
#[deprecated(note = "superseded by vtc/join-requests/manifest/0.4")]
pub struct Payload {
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ext: ::std::option::Option<Ext>,
}
impl ::std::default::Default for Payload {
fn default() -> Self {
Self {
ext: Default::default(),
}
}
}
impl Payload {
pub fn builder() -> builder::Payload {
Default::default()
}
}
///`Response`
///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
#[deprecated(note = "superseded by vtc/join-requests/manifest/0.4")]
pub struct Response {
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub branding: ::std::option::Option<CommunityBranding>,
#[serde(rename = "communityDid")]
pub community_did: ResponseCommunityDid,
pub criteria: ::std::vec::Vec<Criterion>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ext: ::std::option::Option<Ext>,
///What the community asks an applicant to tell it about themselves, as claim types — never values. Answered in persona terms: the applicant's agent discloses those attributes from the face the applicant chooses, and they arrive on vtc/join-requests/submit as `attributes`. SELF-ASSERTED: a community MUST NOT describe an answer as verified, and MUST NOT make a decision that assumes it is. Outside every criterion, so no `requirementsDigest` covers it. Absent when the community asks nothing.
#[serde(
rename = "requestedAttributes",
default,
skip_serializing_if = "::std::vec::Vec::is_empty"
)]
pub requested_attributes: ::std::vec::Vec<ResponseRequestedAttributesItem>,
}
impl Response {
pub fn builder() -> builder::Response {
Default::default()
}
}
///`ResponseCommunityDid`
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ResponseCommunityDid(::std::string::String);
impl ::std::ops::Deref for ResponseCommunityDid {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ResponseCommunityDid> for ::std::string::String {
fn from(value: ResponseCommunityDid) -> Self {
value.0
}
}
impl ::std::str::FromStr for ResponseCommunityDid {
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("^did:").unwrap());
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^did:\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ResponseCommunityDid {
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 ResponseCommunityDid {
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 ResponseCommunityDid {
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 ResponseCommunityDid {
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())
})
}
}
///`ResponseRequestedAttributesItem`
///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct ResponseRequestedAttributesItem {
///Why the community asks, in words shown to the applicant before they disclose.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub purpose: ::std::option::Option<ResponseRequestedAttributesItemPurpose>,
///False for an attribute the applicant may decline. A submission missing a required one is refused with vtc/join-requests/submit:attributesMissing.
#[serde(default = "defaults::default_bool::<true>")]
pub required: bool,
///A claim-type token from the persona claim-type registry (persona/_shared/0.1/CLAIM-TYPES.md) — `name.display`, `address.country` — or an `x:` extension token.
#[serde(rename = "type")]
pub type_: ResponseRequestedAttributesItemType,
}
impl ResponseRequestedAttributesItem {
pub fn builder() -> builder::ResponseRequestedAttributesItem {
Default::default()
}
}
///Why the community asks, in words shown to the applicant before they disclose.
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ResponseRequestedAttributesItemPurpose(::std::string::String);
impl ::std::ops::Deref for ResponseRequestedAttributesItemPurpose {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ResponseRequestedAttributesItemPurpose> for ::std::string::String {
fn from(value: ResponseRequestedAttributesItemPurpose) -> Self {
value.0
}
}
impl ::std::str::FromStr for ResponseRequestedAttributesItemPurpose {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 256usize {
return Err("longer than 256 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ResponseRequestedAttributesItemPurpose {
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 ResponseRequestedAttributesItemPurpose {
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 ResponseRequestedAttributesItemPurpose {
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 ResponseRequestedAttributesItemPurpose {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///A claim-type token from the persona claim-type registry (persona/_shared/0.1/CLAIM-TYPES.md) — `name.display`, `address.country` — or an `x:` extension token.
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ResponseRequestedAttributesItemType(::std::string::String);
impl ::std::ops::Deref for ResponseRequestedAttributesItemType {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ResponseRequestedAttributesItemType> for ::std::string::String {
fn from(value: ResponseRequestedAttributesItemType) -> Self {
value.0
}
}
impl ::std::str::FromStr for ResponseRequestedAttributesItemType {
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 ResponseRequestedAttributesItemType {
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 ResponseRequestedAttributesItemType {
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 ResponseRequestedAttributesItemType {
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 ResponseRequestedAttributesItemType {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///A class of documentation, named in lowerCamelCase. Open rather than enumerated, because what documentation a vetter accepts is each vetter's own choice. Well-known values: `passport`, `nationalId`, `driverLicence`, and `none` — the vetter will attest without a document, which is the `priorAcquaintance` case. Only the class ever travels — never a document number, an image, an issuing authority or an expiry date. `none` states a policy (what a vetter accepts); a record of what was relied on expresses 'no document' as an empty list instead.
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct VettingDocumentation(::std::string::String);
impl ::std::ops::Deref for VettingDocumentation {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<VettingDocumentation> for ::std::string::String {
fn from(value: VettingDocumentation) -> Self {
value.0
}
}
impl ::std::str::FromStr for VettingDocumentation {
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 VettingDocumentation {
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 VettingDocumentation {
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 VettingDocumentation {
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 VettingDocumentation {
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 the vetter established that the person they checked is the person controlling the applicant's DID. `inPerson` — both people were physically together. `video` — a live, two-way video call. `priorAcquaintance` — the vetter has known or worked with this person over a period, and attests from that knowledge rather than from a document. A method is a description of what happened, not an assurance level: which methods count, and how many of each, is community policy.
///
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum VettingMethod {
#[serde(rename = "inPerson")]
InPerson,
#[serde(rename = "video")]
Video,
#[serde(rename = "priorAcquaintance")]
PriorAcquaintance,
}
impl ::std::fmt::Display for VettingMethod {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::InPerson => f.write_str("inPerson"),
Self::Video => f.write_str("video"),
Self::PriorAcquaintance => f.write_str("priorAcquaintance"),
}
}
}
impl ::std::str::FromStr for VettingMethod {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"inPerson" => Ok(Self::InPerson),
"video" => Ok(Self::Video),
"priorAcquaintance" => Ok(Self::PriorAcquaintance),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for VettingMethod {
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 VettingMethod {
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 VettingMethod {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///The vetter's own declaration of how they relate to the applicant. Declared, not verified: it exists so community policy can cap how much evidence comes from people close to the applicant, and a false declaration is the vetter's attributable act.
///
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum VettingRelationship {
#[serde(rename = "none")]
None,
#[serde(rename = "communityColleague")]
CommunityColleague,
#[serde(rename = "sameEmployer")]
SameEmployer,
#[serde(rename = "family")]
Family,
#[serde(rename = "otherPersonal")]
OtherPersonal,
}
impl ::std::fmt::Display for VettingRelationship {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::None => f.write_str("none"),
Self::CommunityColleague => f.write_str("communityColleague"),
Self::SameEmployer => f.write_str("sameEmployer"),
Self::Family => f.write_str("family"),
Self::OtherPersonal => f.write_str("otherPersonal"),
}
}
}
impl ::std::str::FromStr for VettingRelationship {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"none" => Ok(Self::None),
"communityColleague" => Ok(Self::CommunityColleague),
"sameEmployer" => Ok(Self::SameEmployer),
"family" => Ok(Self::Family),
"otherPersonal" => Ok(Self::OtherPersonal),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for VettingRelationship {
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 VettingRelationship {
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 VettingRelationship {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///What identity-vetting evidence a criterion needs, beyond what a presentation-definition can express: distinct eligible vetters, per-method floors, independence caps. Every number is the community's own policy. This schema supplies no defaults — an absent optional member means the community imposes no constraint of that kind, never that some protocol value applies. Deliberately open: a consumer MUST ignore members it does not recognise, so a community publishing a newer shape does not make an older client unable to read the rest. Durations: `maxStatementAge` — a statement older than this at decision time does not count (absent: no limit beyond the statement's own validity); `decisionSla` — how long after submission the community undertakes to decide, including on a referred application; `requirementsGrace` — how long an application started under an earlier `requirementsDigest` is still evaluated under that version.
///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[non_exhaustive]
pub struct VettingRequirements {
///Documentation a statement must have relied on in order to count. Absent — the expected case — means each vetter decides what documentation they accept, including none for prior acquaintance, and the community counts what they attest.
#[serde(
rename = "acceptedDocumentClasses",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub accepted_document_classes: ::std::option::Option<Vec<VettingDocumentation>>,
///Methods whose statements count at all.
#[serde(rename = "acceptedMethods")]
pub accepted_methods: Vec<VettingMethod>,
#[serde(
rename = "decisionSla",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub decision_sla: ::std::option::Option<Duration>,
#[serde(rename = "eligibleVetters")]
pub eligible_vetters: VettingRequirementsEligibleVetters,
/**
Ecosystem-defined extension members per SPEC.md §4.5.1, for vetting parameters this version does not enumerate. A community publishing an admission mode the base members cannot express — the zero-knowledge parameters an applicant proves against, say — puts them under a namespace it controls, rather than waiting for a version that names them.
This object is already `additionalProperties: true`, so an unknown member here has always validated. That is not the same as reaching a consumer: a generated type names the members this schema declares and drops the rest, so an undeclared member is parsed and discarded, and it is discarded again on the re-serialization `requirementsDigest` is computed over. `ext` is a declared member, so it survives both.*/
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ext: ::std::option::Option<Ext>,
/**
Namespaces of `ext` an applicant MUST understand or refuse, per SPEC.md §4.5.1.
A community marks a namespace here when applying under this criterion without understanding it would mean something other than what the community requires — an applicant that ignored a hidden-vetting namespace, for instance, would submit named statements to a criterion whose whole point was that it does not receive them. An applicant that does not recognize a marked namespace stops rather than downgrading silently.
Absent, which is the common case, every namespace under `ext` is advisory and ignorable.*/
#[serde(
rename = "extCritical",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub ext_critical: ::std::option::Option<ExtCritical>,
///Where the community's vetting governance — including the attestation text vetters sign — is published.
#[serde(
rename = "governanceFrameworkUrl",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub governance_framework_url: ::std::option::Option<::std::string::String>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub independence: ::std::option::Option<VettingRequirementsIndependence>,
///Whether an invitation credential must accompany the statements at submission (`required`), may (`optional`), or plays no part (`none`). Absent: the presentation-definition alone governs.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub invitation: ::std::option::Option<VettingRequirementsInvitation>,
#[serde(
rename = "maxStatementAge",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub max_statement_age: ::std::option::Option<Duration>,
///Per-method floors within `minStatements` — e.g. `{ "inPerson": 1 }`. Every method named MUST also be in `acceptedMethods`. Absent: no method floor.
#[serde(
rename = "minByMethod",
default,
skip_serializing_if = ":: std :: collections :: HashMap::is_empty"
)]
pub min_by_method: ::std::collections::HashMap<VettingMethod, u64>,
///How many counted statements are needed, counting each vetter once however many DIDs they hold.
#[serde(rename = "minStatements")]
pub min_statements: ::std::num::NonZeroU64,
///Claim types an applicant MAY add to the card and a vetter MAY verify. They never affect whether a statement counts.
#[serde(
rename = "optionalClaims",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub optional_claims: ::std::option::Option<Vec<ClaimType>>,
///Claim types the applicant's Vetting Card must carry, which the identity commitment is computed over, and which a counted statement must list as verified. Absent: none.
#[serde(
rename = "requiredClaims",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub required_claims: ::std::option::Option<Vec<ClaimType>>,
#[serde(
rename = "requirementsGrace",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub requirements_grace: ::std::option::Option<Duration>,
///The predicate IRI a counted vetting statement carries in `credentialSubject.predicate` — `https://registry.trustoverip.org/dtg/vsc/vetted/1`, the DTG VSC registry's identity-vetting predicate, or a predicate in a namespace the community controls — registered as one the community accepts via vtc/endorsement-types/register. A statement under any other predicate does not count.
#[serde(rename = "statementType")]
pub statement_type: ::std::string::String,
///Version of this requirements object's shape. `0.1` for the members defined here.
pub version: VettingRequirementsVersion,
}
impl VettingRequirements {
pub fn builder() -> builder::VettingRequirements {
Default::default()
}
}
///How a vetter's eligibility is established.
///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct VettingRequirementsEligibleVetters {
///The role a statement's issuer must hold, matched as the action `role:<role>` in a Verifiable Authority Credential (`AuthorityCredential`) the community issued to that issuer, whose `authority.scope` is the community's DID (see `vtc/vetting/vetters/grant/0.1`). A statement counts only if its issuer holds such a credential.
pub role: VettingRequirementsEligibleVettersRole,
}
impl VettingRequirementsEligibleVetters {
pub fn builder() -> builder::VettingRequirementsEligibleVetters {
Default::default()
}
}
///The role a statement's issuer must hold, matched as the action `role:<role>` in a Verifiable Authority Credential (`AuthorityCredential`) the community issued to that issuer, whose `authority.scope` is the community's DID (see `vtc/vetting/vetters/grant/0.1`). A statement counts only if its issuer holds such a credential.
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct VettingRequirementsEligibleVettersRole(::std::string::String);
impl ::std::ops::Deref for VettingRequirementsEligibleVettersRole {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<VettingRequirementsEligibleVettersRole> for ::std::string::String {
fn from(value: VettingRequirementsEligibleVettersRole) -> Self {
value.0
}
}
impl ::std::str::FromStr for VettingRequirementsEligibleVettersRole {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 128usize {
return Err("longer than 128 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| {
::regress::Regex::new("^[a-zA-Z][a-zA-Z0-9_-]*$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[a-zA-Z][a-zA-Z0-9_-]*$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for VettingRequirementsEligibleVettersRole {
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 VettingRequirementsEligibleVettersRole {
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 VettingRequirementsEligibleVettersRole {
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 VettingRequirementsEligibleVettersRole {
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())
})
}
}
///Caps on how much evidence may come from people close to the applicant. Absent: no caps.
///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct VettingRequirementsIndependence {
///The most counted statements that may come from vetters declaring each relationship — e.g. `{ "family": 0 }`.
#[serde(
rename = "maxByDeclaredRelationship",
default,
skip_serializing_if = ":: std :: collections :: HashMap::is_empty"
)]
pub max_by_declared_relationship: ::std::collections::HashMap<VettingRelationship, u64>,
///When true, every counted statement must carry the same identity commitment — all vetters verified the same claimed identity. Absent: false.
#[serde(
rename = "requireConsistentIdentityCommitment",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub require_consistent_identity_commitment: ::std::option::Option<bool>,
}
impl ::std::default::Default for VettingRequirementsIndependence {
fn default() -> Self {
Self {
max_by_declared_relationship: Default::default(),
require_consistent_identity_commitment: Default::default(),
}
}
}
impl VettingRequirementsIndependence {
pub fn builder() -> builder::VettingRequirementsIndependence {
Default::default()
}
}
///Whether an invitation credential must accompany the statements at submission (`required`), may (`optional`), or plays no part (`none`). Absent: the presentation-definition alone governs.
///
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum VettingRequirementsInvitation {
#[serde(rename = "required")]
Required,
#[serde(rename = "optional")]
Optional,
#[serde(rename = "none")]
None,
}
impl ::std::fmt::Display for VettingRequirementsInvitation {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Required => f.write_str("required"),
Self::Optional => f.write_str("optional"),
Self::None => f.write_str("none"),
}
}
}
impl ::std::str::FromStr for VettingRequirementsInvitation {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"required" => Ok(Self::Required),
"optional" => Ok(Self::Optional),
"none" => Ok(Self::None),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for VettingRequirementsInvitation {
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 VettingRequirementsInvitation {
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 VettingRequirementsInvitation {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///Version of this requirements object's shape. `0.1` for the members defined here.
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct VettingRequirementsVersion(::std::string::String);
impl ::std::ops::Deref for VettingRequirementsVersion {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<VettingRequirementsVersion> for ::std::string::String {
fn from(value: VettingRequirementsVersion) -> Self {
value.0
}
}
impl ::std::str::FromStr for VettingRequirementsVersion {
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|[1-9][0-9]*)\\.(0|[1-9][0-9]*)$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for VettingRequirementsVersion {
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 VettingRequirementsVersion {
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 VettingRequirementsVersion {
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 VettingRequirementsVersion {
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())
})
}
}
/// Types for composing complex structures.
pub mod builder {
#[derive(Clone, Debug)]
pub struct CommunityBranding {
accent_color: ::std::result::Result<
::std::option::Option<super::CommunityBrandingAccentColor>,
::std::string::String,
>,
display_name: ::std::result::Result<
::std::option::Option<super::CommunityBrandingDisplayName>,
::std::string::String,
>,
ext: ::std::result::Result<::std::option::Option<super::Ext>, ::std::string::String>,
logo_url: ::std::result::Result<
::std::option::Option<::std::string::String>,
::std::string::String,
>,
}
impl ::std::default::Default for CommunityBranding {
fn default() -> Self {
Self {
accent_color: Ok(Default::default()),
display_name: Ok(Default::default()),
ext: Ok(Default::default()),
logo_url: Ok(Default::default()),
}
}
}
impl CommunityBranding {
pub fn accent_color<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::CommunityBrandingAccentColor>>,
T::Error: ::std::fmt::Display,
{
self.accent_color = value
.try_into()
.map_err(|e| format!("error converting supplied value for accent_color: {e}"));
self
}
pub fn display_name<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::CommunityBrandingDisplayName>>,
T::Error: ::std::fmt::Display,
{
self.display_name = value
.try_into()
.map_err(|e| format!("error converting supplied value for display_name: {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 logo_url<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>,
T::Error: ::std::fmt::Display,
{
self.logo_url = value
.try_into()
.map_err(|e| format!("error converting supplied value for logo_url: {e}"));
self
}
}
impl ::std::convert::TryFrom<CommunityBranding> for super::CommunityBranding {
type Error = super::error::ConversionError;
fn try_from(
value: CommunityBranding,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
accent_color: value.accent_color?,
display_name: value.display_name?,
ext: value.ext?,
logo_url: value.logo_url?,
})
}
}
impl ::std::convert::From<super::CommunityBranding> for CommunityBranding {
fn from(value: super::CommunityBranding) -> Self {
Self {
accent_color: Ok(value.accent_color),
display_name: Ok(value.display_name),
ext: Ok(value.ext),
logo_url: Ok(value.logo_url),
}
}
}
#[derive(Clone, Debug)]
pub struct Criterion {
admission: ::std::result::Result<super::CriterionAdmission, ::std::string::String>,
credential_issuers: ::std::result::Result<
::std::option::Option<super::CriterionCredentialIssuers>,
::std::string::String,
>,
description: ::std::result::Result<
::std::option::Option<super::CriterionDescription>,
::std::string::String,
>,
id: ::std::result::Result<super::CriterionId, ::std::string::String>,
invitation_required:
::std::result::Result<::std::option::Option<bool>, ::std::string::String>,
presentation_definition: ::std::result::Result<
::serde_json::Map<::std::string::String, ::serde_json::Value>,
::std::string::String,
>,
requirements_digest: ::std::result::Result<super::DigestMultibase, ::std::string::String>,
vetting: ::std::result::Result<
::std::option::Option<super::VettingRequirements>,
::std::string::String,
>,
}
impl ::std::default::Default for Criterion {
fn default() -> Self {
Self {
admission: Err("no value supplied for admission".to_string()),
credential_issuers: Ok(Default::default()),
description: Ok(Default::default()),
id: Err("no value supplied for id".to_string()),
invitation_required: Ok(Default::default()),
presentation_definition: Ok(Default::default()),
requirements_digest: Err("no value supplied for requirements_digest".to_string()),
vetting: Ok(Default::default()),
}
}
}
impl Criterion {
pub fn admission<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::CriterionAdmission>,
T::Error: ::std::fmt::Display,
{
self.admission = value
.try_into()
.map_err(|e| format!("error converting supplied value for admission: {e}"));
self
}
pub fn credential_issuers<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::CriterionCredentialIssuers>>,
T::Error: ::std::fmt::Display,
{
self.credential_issuers = value.try_into().map_err(|e| {
format!("error converting supplied value for credential_issuers: {e}")
});
self
}
pub fn description<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::CriterionDescription>>,
T::Error: ::std::fmt::Display,
{
self.description = value
.try_into()
.map_err(|e| format!("error converting supplied value for description: {e}"));
self
}
pub fn id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::CriterionId>,
T::Error: ::std::fmt::Display,
{
self.id = value
.try_into()
.map_err(|e| format!("error converting supplied value for id: {e}"));
self
}
pub fn invitation_required<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<bool>>,
T::Error: ::std::fmt::Display,
{
self.invitation_required = value.try_into().map_err(|e| {
format!("error converting supplied value for invitation_required: {e}")
});
self
}
pub fn presentation_definition<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<
::serde_json::Map<::std::string::String, ::serde_json::Value>,
>,
T::Error: ::std::fmt::Display,
{
self.presentation_definition = value.try_into().map_err(|e| {
format!("error converting supplied value for presentation_definition: {e}")
});
self
}
pub fn requirements_digest<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::DigestMultibase>,
T::Error: ::std::fmt::Display,
{
self.requirements_digest = value.try_into().map_err(|e| {
format!("error converting supplied value for requirements_digest: {e}")
});
self
}
pub fn vetting<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::VettingRequirements>>,
T::Error: ::std::fmt::Display,
{
self.vetting = value
.try_into()
.map_err(|e| format!("error converting supplied value for vetting: {e}"));
self
}
}
impl ::std::convert::TryFrom<Criterion> for super::Criterion {
type Error = super::error::ConversionError;
fn try_from(
value: Criterion,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
admission: value.admission?,
credential_issuers: value.credential_issuers?,
description: value.description?,
id: value.id?,
invitation_required: value.invitation_required?,
presentation_definition: value.presentation_definition?,
requirements_digest: value.requirements_digest?,
vetting: value.vetting?,
})
}
}
impl ::std::convert::From<super::Criterion> for Criterion {
fn from(value: super::Criterion) -> Self {
Self {
admission: Ok(value.admission),
credential_issuers: Ok(value.credential_issuers),
description: Ok(value.description),
id: Ok(value.id),
invitation_required: Ok(value.invitation_required),
presentation_definition: Ok(value.presentation_definition),
requirements_digest: Ok(value.requirements_digest),
vetting: Ok(value.vetting),
}
}
}
#[derive(Clone, Debug)]
pub struct Payload {
ext: ::std::result::Result<::std::option::Option<super::Ext>, ::std::string::String>,
}
impl ::std::default::Default for Payload {
fn default() -> Self {
Self {
ext: Ok(Default::default()),
}
}
}
impl Payload {
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
}
}
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 { ext: value.ext? })
}
}
impl ::std::convert::From<super::Payload> for Payload {
fn from(value: super::Payload) -> Self {
Self { ext: Ok(value.ext) }
}
}
#[derive(Clone, Debug)]
pub struct Response {
branding: ::std::result::Result<
::std::option::Option<super::CommunityBranding>,
::std::string::String,
>,
community_did: ::std::result::Result<super::ResponseCommunityDid, ::std::string::String>,
criteria: ::std::result::Result<::std::vec::Vec<super::Criterion>, ::std::string::String>,
ext: ::std::result::Result<::std::option::Option<super::Ext>, ::std::string::String>,
requested_attributes: ::std::result::Result<
::std::vec::Vec<super::ResponseRequestedAttributesItem>,
::std::string::String,
>,
}
impl ::std::default::Default for Response {
fn default() -> Self {
Self {
branding: Ok(Default::default()),
community_did: Err("no value supplied for community_did".to_string()),
criteria: Err("no value supplied for criteria".to_string()),
ext: Ok(Default::default()),
requested_attributes: Ok(Default::default()),
}
}
}
impl Response {
pub fn branding<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::CommunityBranding>>,
T::Error: ::std::fmt::Display,
{
self.branding = value
.try_into()
.map_err(|e| format!("error converting supplied value for branding: {e}"));
self
}
pub fn community_did<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::ResponseCommunityDid>,
T::Error: ::std::fmt::Display,
{
self.community_did = value
.try_into()
.map_err(|e| format!("error converting supplied value for community_did: {e}"));
self
}
pub fn criteria<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::vec::Vec<super::Criterion>>,
T::Error: ::std::fmt::Display,
{
self.criteria = value
.try_into()
.map_err(|e| format!("error converting supplied value for criteria: {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 requested_attributes<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::vec::Vec<super::ResponseRequestedAttributesItem>>,
T::Error: ::std::fmt::Display,
{
self.requested_attributes = value.try_into().map_err(|e| {
format!("error converting supplied value for requested_attributes: {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 {
branding: value.branding?,
community_did: value.community_did?,
criteria: value.criteria?,
ext: value.ext?,
requested_attributes: value.requested_attributes?,
})
}
}
impl ::std::convert::From<super::Response> for Response {
fn from(value: super::Response) -> Self {
Self {
branding: Ok(value.branding),
community_did: Ok(value.community_did),
criteria: Ok(value.criteria),
ext: Ok(value.ext),
requested_attributes: Ok(value.requested_attributes),
}
}
}
#[derive(Clone, Debug)]
pub struct ResponseRequestedAttributesItem {
purpose: ::std::result::Result<
::std::option::Option<super::ResponseRequestedAttributesItemPurpose>,
::std::string::String,
>,
required: ::std::result::Result<bool, ::std::string::String>,
type_: ::std::result::Result<
super::ResponseRequestedAttributesItemType,
::std::string::String,
>,
}
impl ::std::default::Default for ResponseRequestedAttributesItem {
fn default() -> Self {
Self {
purpose: Ok(Default::default()),
required: Ok(super::defaults::default_bool::<true>()),
type_: Err("no value supplied for type_".to_string()),
}
}
}
impl ResponseRequestedAttributesItem {
pub fn purpose<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<
::std::option::Option<super::ResponseRequestedAttributesItemPurpose>,
>,
T::Error: ::std::fmt::Display,
{
self.purpose = value
.try_into()
.map_err(|e| format!("error converting supplied value for purpose: {e}"));
self
}
pub fn required<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<bool>,
T::Error: ::std::fmt::Display,
{
self.required = value
.try_into()
.map_err(|e| format!("error converting supplied value for required: {e}"));
self
}
pub fn type_<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::ResponseRequestedAttributesItemType>,
T::Error: ::std::fmt::Display,
{
self.type_ = value
.try_into()
.map_err(|e| format!("error converting supplied value for type_: {e}"));
self
}
}
impl ::std::convert::TryFrom<ResponseRequestedAttributesItem>
for super::ResponseRequestedAttributesItem
{
type Error = super::error::ConversionError;
fn try_from(
value: ResponseRequestedAttributesItem,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
purpose: value.purpose?,
required: value.required?,
type_: value.type_?,
})
}
}
impl ::std::convert::From<super::ResponseRequestedAttributesItem>
for ResponseRequestedAttributesItem
{
fn from(value: super::ResponseRequestedAttributesItem) -> Self {
Self {
purpose: Ok(value.purpose),
required: Ok(value.required),
type_: Ok(value.type_),
}
}
}
#[derive(Clone, Debug)]
pub struct VettingRequirements {
accepted_document_classes: ::std::result::Result<
::std::option::Option<Vec<super::VettingDocumentation>>,
::std::string::String,
>,
accepted_methods: ::std::result::Result<Vec<super::VettingMethod>, ::std::string::String>,
decision_sla:
::std::result::Result<::std::option::Option<super::Duration>, ::std::string::String>,
eligible_vetters:
::std::result::Result<super::VettingRequirementsEligibleVetters, ::std::string::String>,
ext: ::std::result::Result<::std::option::Option<super::Ext>, ::std::string::String>,
ext_critical:
::std::result::Result<::std::option::Option<super::ExtCritical>, ::std::string::String>,
governance_framework_url: ::std::result::Result<
::std::option::Option<::std::string::String>,
::std::string::String,
>,
independence: ::std::result::Result<
::std::option::Option<super::VettingRequirementsIndependence>,
::std::string::String,
>,
invitation: ::std::result::Result<
::std::option::Option<super::VettingRequirementsInvitation>,
::std::string::String,
>,
max_statement_age:
::std::result::Result<::std::option::Option<super::Duration>, ::std::string::String>,
min_by_method: ::std::result::Result<
::std::collections::HashMap<super::VettingMethod, u64>,
::std::string::String,
>,
min_statements: ::std::result::Result<::std::num::NonZeroU64, ::std::string::String>,
optional_claims: ::std::result::Result<
::std::option::Option<Vec<super::ClaimType>>,
::std::string::String,
>,
required_claims: ::std::result::Result<
::std::option::Option<Vec<super::ClaimType>>,
::std::string::String,
>,
requirements_grace:
::std::result::Result<::std::option::Option<super::Duration>, ::std::string::String>,
statement_type: ::std::result::Result<::std::string::String, ::std::string::String>,
version: ::std::result::Result<super::VettingRequirementsVersion, ::std::string::String>,
}
impl ::std::default::Default for VettingRequirements {
fn default() -> Self {
Self {
accepted_document_classes: Ok(Default::default()),
accepted_methods: Err("no value supplied for accepted_methods".to_string()),
decision_sla: Ok(Default::default()),
eligible_vetters: Err("no value supplied for eligible_vetters".to_string()),
ext: Ok(Default::default()),
ext_critical: Ok(Default::default()),
governance_framework_url: Ok(Default::default()),
independence: Ok(Default::default()),
invitation: Ok(Default::default()),
max_statement_age: Ok(Default::default()),
min_by_method: Ok(Default::default()),
min_statements: Err("no value supplied for min_statements".to_string()),
optional_claims: Ok(Default::default()),
required_claims: Ok(Default::default()),
requirements_grace: Ok(Default::default()),
statement_type: Err("no value supplied for statement_type".to_string()),
version: Err("no value supplied for version".to_string()),
}
}
}
impl VettingRequirements {
pub fn accepted_document_classes<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<Vec<super::VettingDocumentation>>>,
T::Error: ::std::fmt::Display,
{
self.accepted_document_classes = value.try_into().map_err(|e| {
format!("error converting supplied value for accepted_document_classes: {e}")
});
self
}
pub fn accepted_methods<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<Vec<super::VettingMethod>>,
T::Error: ::std::fmt::Display,
{
self.accepted_methods = value
.try_into()
.map_err(|e| format!("error converting supplied value for accepted_methods: {e}"));
self
}
pub fn decision_sla<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::Duration>>,
T::Error: ::std::fmt::Display,
{
self.decision_sla = value
.try_into()
.map_err(|e| format!("error converting supplied value for decision_sla: {e}"));
self
}
pub fn eligible_vetters<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::VettingRequirementsEligibleVetters>,
T::Error: ::std::fmt::Display,
{
self.eligible_vetters = value
.try_into()
.map_err(|e| format!("error converting supplied value for eligible_vetters: {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 ext_critical<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::ExtCritical>>,
T::Error: ::std::fmt::Display,
{
self.ext_critical = value
.try_into()
.map_err(|e| format!("error converting supplied value for ext_critical: {e}"));
self
}
pub fn governance_framework_url<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>,
T::Error: ::std::fmt::Display,
{
self.governance_framework_url = value.try_into().map_err(|e| {
format!("error converting supplied value for governance_framework_url: {e}")
});
self
}
pub fn independence<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<
::std::option::Option<super::VettingRequirementsIndependence>,
>,
T::Error: ::std::fmt::Display,
{
self.independence = value
.try_into()
.map_err(|e| format!("error converting supplied value for independence: {e}"));
self
}
pub fn invitation<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::VettingRequirementsInvitation>>,
T::Error: ::std::fmt::Display,
{
self.invitation = value
.try_into()
.map_err(|e| format!("error converting supplied value for invitation: {e}"));
self
}
pub fn max_statement_age<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::Duration>>,
T::Error: ::std::fmt::Display,
{
self.max_statement_age = value
.try_into()
.map_err(|e| format!("error converting supplied value for max_statement_age: {e}"));
self
}
pub fn min_by_method<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::collections::HashMap<super::VettingMethod, u64>>,
T::Error: ::std::fmt::Display,
{
self.min_by_method = value
.try_into()
.map_err(|e| format!("error converting supplied value for min_by_method: {e}"));
self
}
pub fn min_statements<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::num::NonZeroU64>,
T::Error: ::std::fmt::Display,
{
self.min_statements = value
.try_into()
.map_err(|e| format!("error converting supplied value for min_statements: {e}"));
self
}
pub fn optional_claims<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<Vec<super::ClaimType>>>,
T::Error: ::std::fmt::Display,
{
self.optional_claims = value
.try_into()
.map_err(|e| format!("error converting supplied value for optional_claims: {e}"));
self
}
pub fn required_claims<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<Vec<super::ClaimType>>>,
T::Error: ::std::fmt::Display,
{
self.required_claims = value
.try_into()
.map_err(|e| format!("error converting supplied value for required_claims: {e}"));
self
}
pub fn requirements_grace<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::Duration>>,
T::Error: ::std::fmt::Display,
{
self.requirements_grace = value.try_into().map_err(|e| {
format!("error converting supplied value for requirements_grace: {e}")
});
self
}
pub fn statement_type<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::string::String>,
T::Error: ::std::fmt::Display,
{
self.statement_type = value
.try_into()
.map_err(|e| format!("error converting supplied value for statement_type: {e}"));
self
}
pub fn version<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::VettingRequirementsVersion>,
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<VettingRequirements> for super::VettingRequirements {
type Error = super::error::ConversionError;
fn try_from(
value: VettingRequirements,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
accepted_document_classes: value.accepted_document_classes?,
accepted_methods: value.accepted_methods?,
decision_sla: value.decision_sla?,
eligible_vetters: value.eligible_vetters?,
ext: value.ext?,
ext_critical: value.ext_critical?,
governance_framework_url: value.governance_framework_url?,
independence: value.independence?,
invitation: value.invitation?,
max_statement_age: value.max_statement_age?,
min_by_method: value.min_by_method?,
min_statements: value.min_statements?,
optional_claims: value.optional_claims?,
required_claims: value.required_claims?,
requirements_grace: value.requirements_grace?,
statement_type: value.statement_type?,
version: value.version?,
})
}
}
impl ::std::convert::From<super::VettingRequirements> for VettingRequirements {
fn from(value: super::VettingRequirements) -> Self {
Self {
accepted_document_classes: Ok(value.accepted_document_classes),
accepted_methods: Ok(value.accepted_methods),
decision_sla: Ok(value.decision_sla),
eligible_vetters: Ok(value.eligible_vetters),
ext: Ok(value.ext),
ext_critical: Ok(value.ext_critical),
governance_framework_url: Ok(value.governance_framework_url),
independence: Ok(value.independence),
invitation: Ok(value.invitation),
max_statement_age: Ok(value.max_statement_age),
min_by_method: Ok(value.min_by_method),
min_statements: Ok(value.min_statements),
optional_claims: Ok(value.optional_claims),
required_claims: Ok(value.required_claims),
requirements_grace: Ok(value.requirements_grace),
statement_type: Ok(value.statement_type),
version: Ok(value.version),
}
}
}
#[derive(Clone, Debug)]
pub struct VettingRequirementsEligibleVetters {
role: ::std::result::Result<
super::VettingRequirementsEligibleVettersRole,
::std::string::String,
>,
}
impl ::std::default::Default for VettingRequirementsEligibleVetters {
fn default() -> Self {
Self {
role: Err("no value supplied for role".to_string()),
}
}
}
impl VettingRequirementsEligibleVetters {
pub fn role<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::VettingRequirementsEligibleVettersRole>,
T::Error: ::std::fmt::Display,
{
self.role = value
.try_into()
.map_err(|e| format!("error converting supplied value for role: {e}"));
self
}
}
impl ::std::convert::TryFrom<VettingRequirementsEligibleVetters>
for super::VettingRequirementsEligibleVetters
{
type Error = super::error::ConversionError;
fn try_from(
value: VettingRequirementsEligibleVetters,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self { role: value.role? })
}
}
impl ::std::convert::From<super::VettingRequirementsEligibleVetters>
for VettingRequirementsEligibleVetters
{
fn from(value: super::VettingRequirementsEligibleVetters) -> Self {
Self {
role: Ok(value.role),
}
}
}
#[derive(Clone, Debug)]
pub struct VettingRequirementsIndependence {
max_by_declared_relationship: ::std::result::Result<
::std::collections::HashMap<super::VettingRelationship, u64>,
::std::string::String,
>,
require_consistent_identity_commitment:
::std::result::Result<::std::option::Option<bool>, ::std::string::String>,
}
impl ::std::default::Default for VettingRequirementsIndependence {
fn default() -> Self {
Self {
max_by_declared_relationship: Ok(Default::default()),
require_consistent_identity_commitment: Ok(Default::default()),
}
}
}
impl VettingRequirementsIndependence {
pub fn max_by_declared_relationship<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<
::std::collections::HashMap<super::VettingRelationship, u64>,
>,
T::Error: ::std::fmt::Display,
{
self.max_by_declared_relationship = value.try_into().map_err(|e| {
format!("error converting supplied value for max_by_declared_relationship: {e}")
});
self
}
pub fn require_consistent_identity_commitment<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<bool>>,
T::Error: ::std::fmt::Display,
{
self.require_consistent_identity_commitment = value
.try_into()
.map_err(|e| {
format!(
"error converting supplied value for require_consistent_identity_commitment: {e}"
)
});
self
}
}
impl ::std::convert::TryFrom<VettingRequirementsIndependence>
for super::VettingRequirementsIndependence
{
type Error = super::error::ConversionError;
fn try_from(
value: VettingRequirementsIndependence,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
max_by_declared_relationship: value.max_by_declared_relationship?,
require_consistent_identity_commitment: value
.require_consistent_identity_commitment?,
})
}
}
impl ::std::convert::From<super::VettingRequirementsIndependence>
for VettingRequirementsIndependence
{
fn from(value: super::VettingRequirementsIndependence) -> Self {
Self {
max_by_declared_relationship: Ok(value.max_by_declared_relationship),
require_consistent_identity_commitment: Ok(
value.require_consistent_identity_commitment
),
}
}
}
}
/// 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/vtc/join-requests/manifest/0.3";
const IS_RECIPIENT_REQUIRED: bool = true;
const PAYLOAD_SCHEMA: Option<&'static str> = Some(
"{\"$defs\":{\"ClaimType\":{\"description\":\"The vocabulary token naming what a value IS — `name.legal`, `phone.mobile`, `address.postal`, `person.birthDate`. Dotted, most-general segment first, so that a consumer with no knowledge of the specific token can still group by its prefix.\\n\\nThe token is the maintainer's own; no external vocabulary is primary. External vocabularies (vCard/jCard, OIDC standard claims, schema.org) are mappings applied at PRESENTATION by a renderer, not at rest, so that a query written in any of them can be matched without the store having to live inside any one of them.\\n\\nThe `x:` prefix is an open extension namespace and is not decoration. The closest prior art — Windows CardSpace's self-issued card — supported exactly fifteen predefined claim types with no extensibility, and that is the specific way it failed the requirement a holder actually has. An `x:` attribute stores, composes, binds and discloses exactly like a known one; it renders generically and matches only an explicit query.\",\"maxLength\":128,\"minLength\":1,\"pattern\":\"^(x:)?[a-z][a-zA-Z0-9]*(\\\\.[a-z][a-zA-Z0-9]*)*$\",\"title\":\"ClaimType\",\"type\":\"string\"},\"CommunityBranding\":{\"additionalProperties\":false,\"description\":\"OPTIONAL. How the community asks to be shown to a prospective applicant: a name, an accent colour and a logo. Presentation only, self-asserted and unverified — `communityDid` identifies the community, never `branding`. Not part of any criterion, so not covered by a `requirementsDigest`. Every member is optional.\",\"properties\":{\"accentColor\":{\"description\":\"An sRGB colour as `#rrggbb`, compared case-insensitively. A community SHOULD write it in lower case.\",\"pattern\":\"^#[0-9a-fA-F]{6}$\",\"type\":\"string\"},\"displayName\":{\"description\":\"The community's name as it asks to be shown.\",\"maxLength\":128,\"minLength\":1,\"type\":\"string\"},\"ext\":{\"$ref\":\"#/$defs/Ext\"},\"logoUrl\":{\"description\":\"An https URL of the community's logo. Fetched by the client, so an untrusted image from wherever it points.\",\"format\":\"uri\",\"maxLength\":2048,\"pattern\":\"^https://\",\"type\":\"string\"}},\"title\":\"CommunityBranding\",\"type\":\"object\"},\"Criterion\":{\"additionalProperties\":false,\"dependentRequired\":{\"credentialIssuers\":[\"presentationDefinition\"],\"presentationDefinition\":[\"credentialIssuers\"]},\"properties\":{\"admission\":{\"description\":\"How the community decides a submission that meets this criterion. `automatic`: it admits the applicant without a person deciding. `review`: it refers the submission to an administrator, who decides.\",\"enum\":[\"automatic\",\"review\"],\"type\":\"string\"},\"credentialIssuers\":{\"description\":\"Whose credentials meet `presentationDefinition`: `community` (this community's own), `recognised` (this community's, or a community it recognises), or `any` (any issuer whose credential verifies). Present exactly when `presentationDefinition` is.\",\"enum\":[\"any\",\"community\",\"recognised\"],\"type\":\"string\"},\"description\":{\"description\":\"Plain-language summary of the criterion, authored by the community and shown to prospective applicants. Informative: where it and `vetting` disagree, `vetting` governs.\",\"maxLength\":1024,\"type\":\"string\"},\"id\":{\"maxLength\":128,\"minLength\":1,\"type\":\"string\"},\"invitationRequired\":{\"description\":\"True: the criterion is met only by a submission carrying a valid, unconsumed invitation this community issued to the applicant.\",\"type\":\"boolean\"},\"presentationDefinition\":{\"description\":\"The credentials an applicant must present for this criterion (opaque here). Absent: the criterion requires no credential.\",\"type\":\"object\"},\"requirementsDigest\":{\"$ref\":\"#/$defs/DigestMultibase\",\"description\":\"Digest over the RFC 8785 (JCS) canonicalization of this criterion object with the `requirementsDigest` member removed, as a multibase-encoded multihash (SHA-256 and base58btc RECOMMENDED). Names one version of the criterion: an applicant records it when starting an application and echoes it to vetters and at submission.\"},\"vetting\":{\"$ref\":\"#/$defs/VettingRequirements\"}},\"required\":[\"id\",\"admission\",\"requirementsDigest\"],\"title\":\"Criterion\",\"type\":\"object\"},\"DigestMultibase\":{\"description\":\"A cryptographic digest as a multibase-encoded multihash — the encoding the W3C Verifiable Credentials Data Model 2.0 defines for `digestMultibase`, and the one `did:webvh` uses for its SCID and entry hashes.\\n\\nMultihash carries the hash algorithm in-band, so the value is self-describing and the wire format survives an algorithm change without a schema revision; multibase does the same for the base encoding, so a verifier never infers base58 from base64url by context. A bare hex string or a `sha-256:`-style prefix hard-codes one algorithm into the wire contract and is non-conforming here.\\n\\nThis definition constrains the *encoding only*. What the digest is computed over is stated by each referencing field, because it differs legitimately: a digest over a JSON document is taken over its RFC 8785 (JCS) canonicalization, while a digest over an opaque artifact is taken over its bytes. A field whose input is a JSON document and which does not name a canonicalization is not reproducible.\\n\\nRestricted to the two multibase headers W3C Controlled Identifiers 1.0 §2.4 normatively requires — `z` (base58btc) and `u` (base64url-no-pad). CID permits others but states that \\\"interoperability is not guaranteed between implementations using such values\\\", and a registry whose purpose is interoperability should not mint digests a conforming verifier may be unable to read. The alphabets are enforced rather than assumed: base58btc excludes 0, O, I and l, and an earlier permissive pattern let three published examples carry digests that were not valid base58 at all. base58btc is RECOMMENDED, for consistency with `did:key` and `did:webvh`.\",\"examples\":[\"zQmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR\"],\"minLength\":16,\"pattern\":\"^(z[1-9A-HJ-NP-Za-km-z]+|u[A-Za-z0-9_-]+)$\",\"title\":\"DigestMultibase\",\"type\":\"string\"},\"Duration\":{\"description\":\"An ISO 8601 duration in weeks, days, hours, minutes and seconds only (e.g. `P120D`, `P2W`, `P1DT12H`, `PT15M`). Years and months are refused: their length depends on the calendar, and an age limit that means different things on different days is not a limit.\",\"maxLength\":32,\"pattern\":\"^P(([0-9]+W)?([0-9]+D)?T([0-9]+H([0-9]+M)?([0-9]+S)?|[0-9]+M([0-9]+S)?|[0-9]+S)|[0-9]+W([0-9]+D)?|[0-9]+D)$\",\"title\":\"Duration\",\"type\":\"string\"},\"Ext\":{\"additionalProperties\":true,\"description\":\"Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.\",\"minProperties\":1,\"propertyNames\":{\"pattern\":\"^[a-z][a-z0-9-]*(\\\\.[a-z0-9-]+)+$\"},\"title\":\"Ext\",\"type\":\"object\"},\"ExtCritical\":{\"description\":\"Names the `ext` namespaces a consumer MUST understand or refuse, per SPEC.md §4.5.1.\\n\\nEvery entry MUST be an immediate key of the sibling `ext` object at the same level; an entry naming an absent namespace is non-conforming and the consumer rejects the document with `malformedRequest`. A consumer that does not recognize a namespace named here MUST NOT process the document as though the namespace were absent, and rejects it with `unsupportedExtension` — the exception to the rule that unrecognized namespaces are ignored.\\n\\nA producer marks a namespace only where the document's meaning depends on it. Marking one that merely carries a hint or an annotation turns every consumer that has not implemented it into a failure where it would otherwise have interoperated. JSON Schema cannot check either of those rules: that an entry names a present namespace is checkable only against the sibling `ext`, and whether a namespace is load-bearing is not a schema question at all. Both are consumer-side checks.\",\"examples\":[[\"org.openvtc.hidden-vetting\"]],\"items\":{\"pattern\":\"^[a-z][a-z0-9-]*(\\\\.[a-z0-9-]+)+$\",\"type\":\"string\"},\"minItems\":1,\"title\":\"ExtCritical\",\"type\":\"array\",\"uniqueItems\":true},\"Response\":{\"$anchor\":\"response\",\"additionalProperties\":false,\"properties\":{\"branding\":{\"$ref\":\"#/$defs/CommunityBranding\"},\"communityDid\":{\"pattern\":\"^did:\",\"type\":\"string\"},\"criteria\":{\"items\":{\"$ref\":\"#/$defs/Criterion\"},\"type\":\"array\"},\"ext\":{\"$ref\":\"#/$defs/Ext\"},\"requestedAttributes\":{\"description\":\"What the community asks an applicant to tell it about themselves, as claim types — never values. Answered in persona terms: the applicant's agent discloses those attributes from the face the applicant chooses, and they arrive on vtc/join-requests/submit as `attributes`. SELF-ASSERTED: a community MUST NOT describe an answer as verified, and MUST NOT make a decision that assumes it is. Outside every criterion, so no `requirementsDigest` covers it. Absent when the community asks nothing.\",\"items\":{\"additionalProperties\":false,\"properties\":{\"purpose\":{\"description\":\"Why the community asks, in words shown to the applicant before they disclose.\",\"maxLength\":256,\"type\":\"string\"},\"required\":{\"default\":true,\"description\":\"False for an attribute the applicant may decline. A submission missing a required one is refused with vtc/join-requests/submit:attributesMissing.\",\"type\":\"boolean\"},\"type\":{\"description\":\"A claim-type token from the persona claim-type registry (persona/_shared/0.1/CLAIM-TYPES.md) — `name.display`, `address.country` — or an `x:` extension token.\",\"maxLength\":128,\"minLength\":1,\"pattern\":\"^(x:)?[a-z][A-Za-z0-9]*(\\\\.[a-z][A-Za-z0-9]*)*$\",\"type\":\"string\"}},\"required\":[\"type\"],\"type\":\"object\"},\"maxItems\":32,\"type\":\"array\"}},\"required\":[\"communityDid\",\"criteria\"],\"title\":\"VTC Join-Requests Manifest — response payload\",\"type\":\"object\"},\"VettingDocumentation\":{\"description\":\"A class of documentation, named in lowerCamelCase. Open rather than enumerated, because what documentation a vetter accepts is each vetter's own choice. Well-known values: `passport`, `nationalId`, `driverLicence`, and `none` — the vetter will attest without a document, which is the `priorAcquaintance` case. Only the class ever travels — never a document number, an image, an issuing authority or an expiry date. `none` states a policy (what a vetter accepts); a record of what was relied on expresses 'no document' as an empty list instead.\",\"maxLength\":64,\"minLength\":1,\"pattern\":\"^[a-z][a-zA-Z0-9]*$\",\"title\":\"VettingDocumentation\",\"type\":\"string\"},\"VettingMethod\":{\"description\":\"How the vetter established that the person they checked is the person controlling the applicant's DID. `inPerson` — both people were physically together. `video` — a live, two-way video call. `priorAcquaintance` — the vetter has known or worked with this person over a period, and attests from that knowledge rather than from a document. A method is a description of what happened, not an assurance level: which methods count, and how many of each, is community policy.\",\"enum\":[\"inPerson\",\"video\",\"priorAcquaintance\"],\"title\":\"VettingMethod\",\"type\":\"string\"},\"VettingRelationship\":{\"description\":\"The vetter's own declaration of how they relate to the applicant. Declared, not verified: it exists so community policy can cap how much evidence comes from people close to the applicant, and a false declaration is the vetter's attributable act.\",\"enum\":[\"none\",\"communityColleague\",\"sameEmployer\",\"family\",\"otherPersonal\"],\"title\":\"VettingRelationship\",\"type\":\"string\"},\"VettingRequirements\":{\"additionalProperties\":true,\"description\":\"What identity-vetting evidence a criterion needs, beyond what a presentation-definition can express: distinct eligible vetters, per-method floors, independence caps. Every number is the community's own policy. This schema supplies no defaults — an absent optional member means the community imposes no constraint of that kind, never that some protocol value applies. Deliberately open: a consumer MUST ignore members it does not recognise, so a community publishing a newer shape does not make an older client unable to read the rest. Durations: `maxStatementAge` — a statement older than this at decision time does not count (absent: no limit beyond the statement's own validity); `decisionSla` — how long after submission the community undertakes to decide, including on a referred application; `requirementsGrace` — how long an application started under an earlier `requirementsDigest` is still evaluated under that version.\",\"properties\":{\"acceptedDocumentClasses\":{\"description\":\"Documentation a statement must have relied on in order to count. Absent — the expected case — means each vetter decides what documentation they accept, including none for prior acquaintance, and the community counts what they attest.\",\"items\":{\"$ref\":\"#/$defs/VettingDocumentation\"},\"minItems\":1,\"type\":\"array\",\"uniqueItems\":true},\"acceptedMethods\":{\"description\":\"Methods whose statements count at all.\",\"items\":{\"$ref\":\"#/$defs/VettingMethod\"},\"minItems\":1,\"type\":\"array\",\"uniqueItems\":true},\"decisionSla\":{\"$ref\":\"#/$defs/Duration\"},\"eligibleVetters\":{\"additionalProperties\":false,\"description\":\"How a vetter's eligibility is established.\",\"properties\":{\"role\":{\"description\":\"The role a statement's issuer must hold, matched as the action `role:<role>` in a Verifiable Authority Credential (`AuthorityCredential`) the community issued to that issuer, whose `authority.scope` is the community's DID (see `vtc/vetting/vetters/grant/0.1`). A statement counts only if its issuer holds such a credential.\",\"maxLength\":128,\"minLength\":1,\"pattern\":\"^[a-zA-Z][a-zA-Z0-9_-]*$\",\"type\":\"string\"}},\"required\":[\"role\"],\"type\":\"object\"},\"ext\":{\"$ref\":\"#/$defs/Ext\",\"description\":\"Ecosystem-defined extension members per SPEC.md §4.5.1, for vetting parameters this version does not enumerate. A community publishing an admission mode the base members cannot express — the zero-knowledge parameters an applicant proves against, say — puts them under a namespace it controls, rather than waiting for a version that names them.\\n\\nThis object is already `additionalProperties: true`, so an unknown member here has always validated. That is not the same as reaching a consumer: a generated type names the members this schema declares and drops the rest, so an undeclared member is parsed and discarded, and it is discarded again on the re-serialization `requirementsDigest` is computed over. `ext` is a declared member, so it survives both.\"},\"extCritical\":{\"$ref\":\"#/$defs/ExtCritical\",\"description\":\"Namespaces of `ext` an applicant MUST understand or refuse, per SPEC.md §4.5.1.\\n\\nA community marks a namespace here when applying under this criterion without understanding it would mean something other than what the community requires — an applicant that ignored a hidden-vetting namespace, for instance, would submit named statements to a criterion whose whole point was that it does not receive them. An applicant that does not recognize a marked namespace stops rather than downgrading silently.\\n\\nAbsent, which is the common case, every namespace under `ext` is advisory and ignorable.\"},\"governanceFrameworkUrl\":{\"description\":\"Where the community's vetting governance — including the attestation text vetters sign — is published.\",\"format\":\"uri\",\"maxLength\":2048,\"pattern\":\"^https://\",\"type\":\"string\"},\"independence\":{\"additionalProperties\":false,\"description\":\"Caps on how much evidence may come from people close to the applicant. Absent: no caps.\",\"properties\":{\"maxByDeclaredRelationship\":{\"additionalProperties\":{\"minimum\":0,\"type\":\"integer\"},\"description\":\"The most counted statements that may come from vetters declaring each relationship — e.g. `{ \\\"family\\\": 0 }`.\",\"propertyNames\":{\"$ref\":\"#/$defs/VettingRelationship\"},\"type\":\"object\"},\"requireConsistentIdentityCommitment\":{\"description\":\"When true, every counted statement must carry the same identity commitment — all vetters verified the same claimed identity. Absent: false.\",\"type\":\"boolean\"}},\"type\":\"object\"},\"invitation\":{\"description\":\"Whether an invitation credential must accompany the statements at submission (`required`), may (`optional`), or plays no part (`none`). Absent: the presentation-definition alone governs.\",\"enum\":[\"required\",\"optional\",\"none\"],\"type\":\"string\"},\"maxStatementAge\":{\"$ref\":\"#/$defs/Duration\"},\"minByMethod\":{\"additionalProperties\":{\"minimum\":0,\"type\":\"integer\"},\"description\":\"Per-method floors within `minStatements` — e.g. `{ \\\"inPerson\\\": 1 }`. Every method named MUST also be in `acceptedMethods`. Absent: no method floor.\",\"propertyNames\":{\"$ref\":\"#/$defs/VettingMethod\"},\"type\":\"object\"},\"minStatements\":{\"description\":\"How many counted statements are needed, counting each vetter once however many DIDs they hold.\",\"minimum\":1,\"type\":\"integer\"},\"optionalClaims\":{\"description\":\"Claim types an applicant MAY add to the card and a vetter MAY verify. They never affect whether a statement counts.\",\"items\":{\"$ref\":\"#/$defs/ClaimType\"},\"type\":\"array\",\"uniqueItems\":true},\"requiredClaims\":{\"description\":\"Claim types the applicant's Vetting Card must carry, which the identity commitment is computed over, and which a counted statement must list as verified. Absent: none.\",\"items\":{\"$ref\":\"#/$defs/ClaimType\"},\"type\":\"array\",\"uniqueItems\":true},\"requirementsGrace\":{\"$ref\":\"#/$defs/Duration\"},\"statementType\":{\"description\":\"The predicate IRI a counted vetting statement carries in `credentialSubject.predicate` — `https://registry.trustoverip.org/dtg/vsc/vetted/1`, the DTG VSC registry's identity-vetting predicate, or a predicate in a namespace the community controls — registered as one the community accepts via vtc/endorsement-types/register. A statement under any other predicate does not count.\",\"format\":\"uri\",\"maxLength\":512,\"minLength\":1,\"type\":\"string\"},\"version\":{\"description\":\"Version of this requirements object's shape. `0.1` for the members defined here.\",\"pattern\":\"^(0|[1-9][0-9]*)\\\\.(0|[1-9][0-9]*)$\",\"type\":\"string\"}},\"required\":[\"version\",\"statementType\",\"minStatements\",\"acceptedMethods\",\"eligibleVetters\"],\"title\":\"VettingRequirements\",\"type\":\"object\"}},\"$id\":\"https://trusttasks.org/spec/vtc/join-requests/manifest/0.3\",\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"additionalProperties\":false,\"description\":\"Discover a community's join criteria before applying. The request carries nothing. Version 0.2 adds, per criterion, an optional `vetting` requirements object — how many identity-vetting statements a community needs, by which methods, from whom — and a `requirementsDigest` that names the exact version of the criterion an applicant started under. The response may also carry `branding`, how the community asks to be shown.\",\"properties\":{\"ext\":{\"$ref\":\"#/$defs/Ext\"}},\"title\":\"VTC Join-Requests Manifest — payload\",\"type\":\"object\"}\n",
);
}
impl crate::Payload for Response {
const TYPE_URI: &'static str =
"https://trusttasks.org/spec/vtc/join-requests/manifest/0.3#response";
const IS_RECIPIENT_REQUIRED: bool = true;
const PAYLOAD_SCHEMA: Option<&'static str> = Some(
"{\"$defs\":{\"ClaimType\":{\"description\":\"The vocabulary token naming what a value IS — `name.legal`, `phone.mobile`, `address.postal`, `person.birthDate`. Dotted, most-general segment first, so that a consumer with no knowledge of the specific token can still group by its prefix.\\n\\nThe token is the maintainer's own; no external vocabulary is primary. External vocabularies (vCard/jCard, OIDC standard claims, schema.org) are mappings applied at PRESENTATION by a renderer, not at rest, so that a query written in any of them can be matched without the store having to live inside any one of them.\\n\\nThe `x:` prefix is an open extension namespace and is not decoration. The closest prior art — Windows CardSpace's self-issued card — supported exactly fifteen predefined claim types with no extensibility, and that is the specific way it failed the requirement a holder actually has. An `x:` attribute stores, composes, binds and discloses exactly like a known one; it renders generically and matches only an explicit query.\",\"maxLength\":128,\"minLength\":1,\"pattern\":\"^(x:)?[a-z][a-zA-Z0-9]*(\\\\.[a-z][a-zA-Z0-9]*)*$\",\"title\":\"ClaimType\",\"type\":\"string\"},\"CommunityBranding\":{\"additionalProperties\":false,\"description\":\"OPTIONAL. How the community asks to be shown to a prospective applicant: a name, an accent colour and a logo. Presentation only, self-asserted and unverified — `communityDid` identifies the community, never `branding`. Not part of any criterion, so not covered by a `requirementsDigest`. Every member is optional.\",\"properties\":{\"accentColor\":{\"description\":\"An sRGB colour as `#rrggbb`, compared case-insensitively. A community SHOULD write it in lower case.\",\"pattern\":\"^#[0-9a-fA-F]{6}$\",\"type\":\"string\"},\"displayName\":{\"description\":\"The community's name as it asks to be shown.\",\"maxLength\":128,\"minLength\":1,\"type\":\"string\"},\"ext\":{\"$ref\":\"#/$defs/Ext\"},\"logoUrl\":{\"description\":\"An https URL of the community's logo. Fetched by the client, so an untrusted image from wherever it points.\",\"format\":\"uri\",\"maxLength\":2048,\"pattern\":\"^https://\",\"type\":\"string\"}},\"title\":\"CommunityBranding\",\"type\":\"object\"},\"Criterion\":{\"additionalProperties\":false,\"dependentRequired\":{\"credentialIssuers\":[\"presentationDefinition\"],\"presentationDefinition\":[\"credentialIssuers\"]},\"properties\":{\"admission\":{\"description\":\"How the community decides a submission that meets this criterion. `automatic`: it admits the applicant without a person deciding. `review`: it refers the submission to an administrator, who decides.\",\"enum\":[\"automatic\",\"review\"],\"type\":\"string\"},\"credentialIssuers\":{\"description\":\"Whose credentials meet `presentationDefinition`: `community` (this community's own), `recognised` (this community's, or a community it recognises), or `any` (any issuer whose credential verifies). Present exactly when `presentationDefinition` is.\",\"enum\":[\"any\",\"community\",\"recognised\"],\"type\":\"string\"},\"description\":{\"description\":\"Plain-language summary of the criterion, authored by the community and shown to prospective applicants. Informative: where it and `vetting` disagree, `vetting` governs.\",\"maxLength\":1024,\"type\":\"string\"},\"id\":{\"maxLength\":128,\"minLength\":1,\"type\":\"string\"},\"invitationRequired\":{\"description\":\"True: the criterion is met only by a submission carrying a valid, unconsumed invitation this community issued to the applicant.\",\"type\":\"boolean\"},\"presentationDefinition\":{\"description\":\"The credentials an applicant must present for this criterion (opaque here). Absent: the criterion requires no credential.\",\"type\":\"object\"},\"requirementsDigest\":{\"$ref\":\"#/$defs/DigestMultibase\",\"description\":\"Digest over the RFC 8785 (JCS) canonicalization of this criterion object with the `requirementsDigest` member removed, as a multibase-encoded multihash (SHA-256 and base58btc RECOMMENDED). Names one version of the criterion: an applicant records it when starting an application and echoes it to vetters and at submission.\"},\"vetting\":{\"$ref\":\"#/$defs/VettingRequirements\"}},\"required\":[\"id\",\"admission\",\"requirementsDigest\"],\"title\":\"Criterion\",\"type\":\"object\"},\"DigestMultibase\":{\"description\":\"A cryptographic digest as a multibase-encoded multihash — the encoding the W3C Verifiable Credentials Data Model 2.0 defines for `digestMultibase`, and the one `did:webvh` uses for its SCID and entry hashes.\\n\\nMultihash carries the hash algorithm in-band, so the value is self-describing and the wire format survives an algorithm change without a schema revision; multibase does the same for the base encoding, so a verifier never infers base58 from base64url by context. A bare hex string or a `sha-256:`-style prefix hard-codes one algorithm into the wire contract and is non-conforming here.\\n\\nThis definition constrains the *encoding only*. What the digest is computed over is stated by each referencing field, because it differs legitimately: a digest over a JSON document is taken over its RFC 8785 (JCS) canonicalization, while a digest over an opaque artifact is taken over its bytes. A field whose input is a JSON document and which does not name a canonicalization is not reproducible.\\n\\nRestricted to the two multibase headers W3C Controlled Identifiers 1.0 §2.4 normatively requires — `z` (base58btc) and `u` (base64url-no-pad). CID permits others but states that \\\"interoperability is not guaranteed between implementations using such values\\\", and a registry whose purpose is interoperability should not mint digests a conforming verifier may be unable to read. The alphabets are enforced rather than assumed: base58btc excludes 0, O, I and l, and an earlier permissive pattern let three published examples carry digests that were not valid base58 at all. base58btc is RECOMMENDED, for consistency with `did:key` and `did:webvh`.\",\"examples\":[\"zQmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR\"],\"minLength\":16,\"pattern\":\"^(z[1-9A-HJ-NP-Za-km-z]+|u[A-Za-z0-9_-]+)$\",\"title\":\"DigestMultibase\",\"type\":\"string\"},\"Duration\":{\"description\":\"An ISO 8601 duration in weeks, days, hours, minutes and seconds only (e.g. `P120D`, `P2W`, `P1DT12H`, `PT15M`). Years and months are refused: their length depends on the calendar, and an age limit that means different things on different days is not a limit.\",\"maxLength\":32,\"pattern\":\"^P(([0-9]+W)?([0-9]+D)?T([0-9]+H([0-9]+M)?([0-9]+S)?|[0-9]+M([0-9]+S)?|[0-9]+S)|[0-9]+W([0-9]+D)?|[0-9]+D)$\",\"title\":\"Duration\",\"type\":\"string\"},\"Ext\":{\"additionalProperties\":true,\"description\":\"Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.\",\"minProperties\":1,\"propertyNames\":{\"pattern\":\"^[a-z][a-z0-9-]*(\\\\.[a-z0-9-]+)+$\"},\"title\":\"Ext\",\"type\":\"object\"},\"ExtCritical\":{\"description\":\"Names the `ext` namespaces a consumer MUST understand or refuse, per SPEC.md §4.5.1.\\n\\nEvery entry MUST be an immediate key of the sibling `ext` object at the same level; an entry naming an absent namespace is non-conforming and the consumer rejects the document with `malformedRequest`. A consumer that does not recognize a namespace named here MUST NOT process the document as though the namespace were absent, and rejects it with `unsupportedExtension` — the exception to the rule that unrecognized namespaces are ignored.\\n\\nA producer marks a namespace only where the document's meaning depends on it. Marking one that merely carries a hint or an annotation turns every consumer that has not implemented it into a failure where it would otherwise have interoperated. JSON Schema cannot check either of those rules: that an entry names a present namespace is checkable only against the sibling `ext`, and whether a namespace is load-bearing is not a schema question at all. Both are consumer-side checks.\",\"examples\":[[\"org.openvtc.hidden-vetting\"]],\"items\":{\"pattern\":\"^[a-z][a-z0-9-]*(\\\\.[a-z0-9-]+)+$\",\"type\":\"string\"},\"minItems\":1,\"title\":\"ExtCritical\",\"type\":\"array\",\"uniqueItems\":true},\"Response\":{\"$anchor\":\"response\",\"additionalProperties\":false,\"properties\":{\"branding\":{\"$ref\":\"#/$defs/CommunityBranding\"},\"communityDid\":{\"pattern\":\"^did:\",\"type\":\"string\"},\"criteria\":{\"items\":{\"$ref\":\"#/$defs/Criterion\"},\"type\":\"array\"},\"ext\":{\"$ref\":\"#/$defs/Ext\"},\"requestedAttributes\":{\"description\":\"What the community asks an applicant to tell it about themselves, as claim types — never values. Answered in persona terms: the applicant's agent discloses those attributes from the face the applicant chooses, and they arrive on vtc/join-requests/submit as `attributes`. SELF-ASSERTED: a community MUST NOT describe an answer as verified, and MUST NOT make a decision that assumes it is. Outside every criterion, so no `requirementsDigest` covers it. Absent when the community asks nothing.\",\"items\":{\"additionalProperties\":false,\"properties\":{\"purpose\":{\"description\":\"Why the community asks, in words shown to the applicant before they disclose.\",\"maxLength\":256,\"type\":\"string\"},\"required\":{\"default\":true,\"description\":\"False for an attribute the applicant may decline. A submission missing a required one is refused with vtc/join-requests/submit:attributesMissing.\",\"type\":\"boolean\"},\"type\":{\"description\":\"A claim-type token from the persona claim-type registry (persona/_shared/0.1/CLAIM-TYPES.md) — `name.display`, `address.country` — or an `x:` extension token.\",\"maxLength\":128,\"minLength\":1,\"pattern\":\"^(x:)?[a-z][A-Za-z0-9]*(\\\\.[a-z][A-Za-z0-9]*)*$\",\"type\":\"string\"}},\"required\":[\"type\"],\"type\":\"object\"},\"maxItems\":32,\"type\":\"array\"}},\"required\":[\"communityDid\",\"criteria\"],\"title\":\"VTC Join-Requests Manifest — response payload\",\"type\":\"object\"},\"VettingDocumentation\":{\"description\":\"A class of documentation, named in lowerCamelCase. Open rather than enumerated, because what documentation a vetter accepts is each vetter's own choice. Well-known values: `passport`, `nationalId`, `driverLicence`, and `none` — the vetter will attest without a document, which is the `priorAcquaintance` case. Only the class ever travels — never a document number, an image, an issuing authority or an expiry date. `none` states a policy (what a vetter accepts); a record of what was relied on expresses 'no document' as an empty list instead.\",\"maxLength\":64,\"minLength\":1,\"pattern\":\"^[a-z][a-zA-Z0-9]*$\",\"title\":\"VettingDocumentation\",\"type\":\"string\"},\"VettingMethod\":{\"description\":\"How the vetter established that the person they checked is the person controlling the applicant's DID. `inPerson` — both people were physically together. `video` — a live, two-way video call. `priorAcquaintance` — the vetter has known or worked with this person over a period, and attests from that knowledge rather than from a document. A method is a description of what happened, not an assurance level: which methods count, and how many of each, is community policy.\",\"enum\":[\"inPerson\",\"video\",\"priorAcquaintance\"],\"title\":\"VettingMethod\",\"type\":\"string\"},\"VettingRelationship\":{\"description\":\"The vetter's own declaration of how they relate to the applicant. Declared, not verified: it exists so community policy can cap how much evidence comes from people close to the applicant, and a false declaration is the vetter's attributable act.\",\"enum\":[\"none\",\"communityColleague\",\"sameEmployer\",\"family\",\"otherPersonal\"],\"title\":\"VettingRelationship\",\"type\":\"string\"},\"VettingRequirements\":{\"additionalProperties\":true,\"description\":\"What identity-vetting evidence a criterion needs, beyond what a presentation-definition can express: distinct eligible vetters, per-method floors, independence caps. Every number is the community's own policy. This schema supplies no defaults — an absent optional member means the community imposes no constraint of that kind, never that some protocol value applies. Deliberately open: a consumer MUST ignore members it does not recognise, so a community publishing a newer shape does not make an older client unable to read the rest. Durations: `maxStatementAge` — a statement older than this at decision time does not count (absent: no limit beyond the statement's own validity); `decisionSla` — how long after submission the community undertakes to decide, including on a referred application; `requirementsGrace` — how long an application started under an earlier `requirementsDigest` is still evaluated under that version.\",\"properties\":{\"acceptedDocumentClasses\":{\"description\":\"Documentation a statement must have relied on in order to count. Absent — the expected case — means each vetter decides what documentation they accept, including none for prior acquaintance, and the community counts what they attest.\",\"items\":{\"$ref\":\"#/$defs/VettingDocumentation\"},\"minItems\":1,\"type\":\"array\",\"uniqueItems\":true},\"acceptedMethods\":{\"description\":\"Methods whose statements count at all.\",\"items\":{\"$ref\":\"#/$defs/VettingMethod\"},\"minItems\":1,\"type\":\"array\",\"uniqueItems\":true},\"decisionSla\":{\"$ref\":\"#/$defs/Duration\"},\"eligibleVetters\":{\"additionalProperties\":false,\"description\":\"How a vetter's eligibility is established.\",\"properties\":{\"role\":{\"description\":\"The role a statement's issuer must hold, matched as the action `role:<role>` in a Verifiable Authority Credential (`AuthorityCredential`) the community issued to that issuer, whose `authority.scope` is the community's DID (see `vtc/vetting/vetters/grant/0.1`). A statement counts only if its issuer holds such a credential.\",\"maxLength\":128,\"minLength\":1,\"pattern\":\"^[a-zA-Z][a-zA-Z0-9_-]*$\",\"type\":\"string\"}},\"required\":[\"role\"],\"type\":\"object\"},\"ext\":{\"$ref\":\"#/$defs/Ext\",\"description\":\"Ecosystem-defined extension members per SPEC.md §4.5.1, for vetting parameters this version does not enumerate. A community publishing an admission mode the base members cannot express — the zero-knowledge parameters an applicant proves against, say — puts them under a namespace it controls, rather than waiting for a version that names them.\\n\\nThis object is already `additionalProperties: true`, so an unknown member here has always validated. That is not the same as reaching a consumer: a generated type names the members this schema declares and drops the rest, so an undeclared member is parsed and discarded, and it is discarded again on the re-serialization `requirementsDigest` is computed over. `ext` is a declared member, so it survives both.\"},\"extCritical\":{\"$ref\":\"#/$defs/ExtCritical\",\"description\":\"Namespaces of `ext` an applicant MUST understand or refuse, per SPEC.md §4.5.1.\\n\\nA community marks a namespace here when applying under this criterion without understanding it would mean something other than what the community requires — an applicant that ignored a hidden-vetting namespace, for instance, would submit named statements to a criterion whose whole point was that it does not receive them. An applicant that does not recognize a marked namespace stops rather than downgrading silently.\\n\\nAbsent, which is the common case, every namespace under `ext` is advisory and ignorable.\"},\"governanceFrameworkUrl\":{\"description\":\"Where the community's vetting governance — including the attestation text vetters sign — is published.\",\"format\":\"uri\",\"maxLength\":2048,\"pattern\":\"^https://\",\"type\":\"string\"},\"independence\":{\"additionalProperties\":false,\"description\":\"Caps on how much evidence may come from people close to the applicant. Absent: no caps.\",\"properties\":{\"maxByDeclaredRelationship\":{\"additionalProperties\":{\"minimum\":0,\"type\":\"integer\"},\"description\":\"The most counted statements that may come from vetters declaring each relationship — e.g. `{ \\\"family\\\": 0 }`.\",\"propertyNames\":{\"$ref\":\"#/$defs/VettingRelationship\"},\"type\":\"object\"},\"requireConsistentIdentityCommitment\":{\"description\":\"When true, every counted statement must carry the same identity commitment — all vetters verified the same claimed identity. Absent: false.\",\"type\":\"boolean\"}},\"type\":\"object\"},\"invitation\":{\"description\":\"Whether an invitation credential must accompany the statements at submission (`required`), may (`optional`), or plays no part (`none`). Absent: the presentation-definition alone governs.\",\"enum\":[\"required\",\"optional\",\"none\"],\"type\":\"string\"},\"maxStatementAge\":{\"$ref\":\"#/$defs/Duration\"},\"minByMethod\":{\"additionalProperties\":{\"minimum\":0,\"type\":\"integer\"},\"description\":\"Per-method floors within `minStatements` — e.g. `{ \\\"inPerson\\\": 1 }`. Every method named MUST also be in `acceptedMethods`. Absent: no method floor.\",\"propertyNames\":{\"$ref\":\"#/$defs/VettingMethod\"},\"type\":\"object\"},\"minStatements\":{\"description\":\"How many counted statements are needed, counting each vetter once however many DIDs they hold.\",\"minimum\":1,\"type\":\"integer\"},\"optionalClaims\":{\"description\":\"Claim types an applicant MAY add to the card and a vetter MAY verify. They never affect whether a statement counts.\",\"items\":{\"$ref\":\"#/$defs/ClaimType\"},\"type\":\"array\",\"uniqueItems\":true},\"requiredClaims\":{\"description\":\"Claim types the applicant's Vetting Card must carry, which the identity commitment is computed over, and which a counted statement must list as verified. Absent: none.\",\"items\":{\"$ref\":\"#/$defs/ClaimType\"},\"type\":\"array\",\"uniqueItems\":true},\"requirementsGrace\":{\"$ref\":\"#/$defs/Duration\"},\"statementType\":{\"description\":\"The predicate IRI a counted vetting statement carries in `credentialSubject.predicate` — `https://registry.trustoverip.org/dtg/vsc/vetted/1`, the DTG VSC registry's identity-vetting predicate, or a predicate in a namespace the community controls — registered as one the community accepts via vtc/endorsement-types/register. A statement under any other predicate does not count.\",\"format\":\"uri\",\"maxLength\":512,\"minLength\":1,\"type\":\"string\"},\"version\":{\"description\":\"Version of this requirements object's shape. `0.1` for the members defined here.\",\"pattern\":\"^(0|[1-9][0-9]*)\\\\.(0|[1-9][0-9]*)$\",\"type\":\"string\"}},\"required\":[\"version\",\"statementType\",\"minStatements\",\"acceptedMethods\",\"eligibleVetters\"],\"title\":\"VettingRequirements\",\"type\":\"object\"}},\"$ref\":\"#/$defs/Response\",\"$schema\":\"https://json-schema.org/draft/2020-12/schema\"}\n",
);
}
impl crate::RequestPayload for Payload {
type Response = Response;
}
/// The earlier `MAJOR.MINOR` of this slug that this version declares it
/// extends (front matter `extends`, SPEC §5.2 "Declared extension"), or
/// `None`. Only the direct declaration; walk a chain with
/// [`crate::extension::extends_for`].
pub const EXTENDS: Option<&str> = None;
/// The extended error codes this specification declares (SPEC §7.3 item 9,
/// §8.5), in declaration order. Empty when it declares none.
pub const ERROR_CODES: &[crate::DeclaredErrorCode] = &[];