//! Generated by `trust-tasks-codegen` — do not edit by hand.
//!
//! Spec slug: `vtc/storage/configs/create`. Version: `0.2`.
#[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 ARN of an AWS IAM role, in any AWS partition (`arn:aws:`, `arn:aws-cn:`, `arn:aws-us-gov:`). Validated here because the community passes it to STS AssumeRole and derives the partition of the session policy's resources from it; it must never carry anything but a role ARN.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "AwsRoleArn",
/// "description": "The ARN of an AWS IAM role, in any AWS partition (`arn:aws:`, `arn:aws-cn:`, `arn:aws-us-gov:`). Validated here because the community passes it to STS AssumeRole and derives the partition of the session policy's resources from it; it must never carry anything but a role ARN.",
/// "type": "string",
/// "maxLength": 2048,
/// "minLength": 20,
/// "pattern": "^arn:aws(-[a-z]+)*:iam::[0-9]{12}:role/[A-Za-z0-9+=,.@_/-]{1,512}$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct AwsRoleArn(::std::string::String);
impl ::std::ops::Deref for AwsRoleArn {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<AwsRoleArn> for ::std::string::String {
fn from(value: AwsRoleArn) -> Self {
value.0
}
}
impl ::std::str::FromStr for AwsRoleArn {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 2048usize {
return Err("longer than 2048 characters".into());
}
if value.chars().count() < 20usize {
return Err("shorter than 20 characters".into());
}
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| {
::regress::Regex::new(
"^arn:aws(-[a-z]+)*:iam::[0-9]{12}:role/[A-Za-z0-9+=,.@_/-]{1,512}$",
)
.unwrap()
});
if PATTERN.find(value).is_none() {
return Err(
"doesn't match pattern \"^arn:aws(-[a-z]+)*:iam::[0-9]{12}:role/[A-Za-z0-9+=,.@_/-]{1,512}$\""
.into(),
);
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for AwsRoleArn {
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 AwsRoleArn {
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 AwsRoleArn {
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 AwsRoleArn {
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())
})
}
}
///`active`: accepts new rooms and new uploads. `draining`: retired by an administrator while blobs still name it — refuses new rooms and new uploads, keeps serving reads, and becomes `retired` when a migration has emptied it. `retired`: refuses new rooms and new uploads and holds no blob. A config is never deleted while a blob names it.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "ConfigState",
/// "description": "`active`: accepts new rooms and new uploads. `draining`: retired by an administrator while blobs still name it — refuses new rooms and new uploads, keeps serving reads, and becomes `retired` when a migration has emptied it. `retired`: refuses new rooms and new uploads and holds no blob. A config is never deleted while a blob names it.",
/// "type": "string",
/// "enum": [
/// "active",
/// "draining",
/// "retired"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum ConfigState {
#[serde(rename = "active")]
Active,
#[serde(rename = "draining")]
Draining,
#[serde(rename = "retired")]
Retired,
}
impl ::std::fmt::Display for ConfigState {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Active => f.write_str("active"),
Self::Draining => f.write_str("draining"),
Self::Retired => f.write_str("retired"),
}
}
}
impl ::std::str::FromStr for ConfigState {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"active" => Ok(Self::Active),
"draining" => Ok(Self::Draining),
"retired" => Ok(Self::Retired),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for ConfigState {
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 ConfigState {
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 ConfigState {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Ext",
/// "description": "Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.",
/// "type": "object",
/// "minProperties": 1,
/// "additionalProperties": true,
/// "propertyNames": {
/// "pattern": "^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$"
/// }
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(transparent)]
pub struct Ext(pub ::std::collections::HashMap<ExtKey, ::serde_json::Value>);
impl ::std::ops::Deref for Ext {
type Target = ::std::collections::HashMap<ExtKey, ::serde_json::Value>;
fn deref(&self) -> &::std::collections::HashMap<ExtKey, ::serde_json::Value> {
&self.0
}
}
impl ::std::convert::From<Ext> for ::std::collections::HashMap<ExtKey, ::serde_json::Value> {
fn from(value: Ext) -> Self {
value.0
}
}
impl ::std::convert::From<::std::collections::HashMap<ExtKey, ::serde_json::Value>> for Ext {
fn from(value: ::std::collections::HashMap<ExtKey, ::serde_json::Value>) -> Self {
Self(value)
}
}
///`ExtKey`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "pattern": "^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ExtKey(::std::string::String);
impl ::std::ops::Deref for ExtKey {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ExtKey> for ::std::string::String {
fn from(value: ExtKey) -> Self {
value.0
}
}
impl ::std::str::FromStr for ExtKey {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| {
::regress::Regex::new("^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ExtKey {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for ExtKey {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for ExtKey {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for ExtKey {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///The context at the community's VTA that owns an external account. The VTA names an account by its context and its identifier, and decides who may use it by act scope in that context: the community must hold `external-auth-use` there, and be bound to the account, for the account to issue it anything. Naming a context grants nothing; the VTA's binding is the gate.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "ExternalAccountContextId",
/// "description": "The context at the community's VTA that owns an external account. The VTA names an account by its context and its identifier, and decides who may use it by act scope in that context: the community must hold `external-auth-use` there, and be bound to the account, for the account to issue it anything. Naming a context grants nothing; the VTA's binding is the gate.",
/// "type": "string",
/// "maxLength": 256,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ExternalAccountContextId(::std::string::String);
impl ::std::ops::Deref for ExternalAccountContextId {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ExternalAccountContextId> for ::std::string::String {
fn from(value: ExternalAccountContextId) -> Self {
value.0
}
}
impl ::std::str::FromStr for ExternalAccountContextId {
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());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ExternalAccountContextId {
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 ExternalAccountContextId {
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 ExternalAccountContextId {
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 ExternalAccountContextId {
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 identifier of an external account held by the community's VTA (the external/accounts/* family), which issues the community short-lived, room-scoped credentials and holds the long-lived authority itself.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "ExternalAccountId",
/// "description": "The identifier of an external account held by the community's VTA (the external/accounts/* family), which issues the community short-lived, room-scoped credentials and holds the long-lived authority itself.",
/// "type": "string",
/// "maxLength": 64,
/// "minLength": 1,
/// "pattern": "^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ExternalAccountId(::std::string::String);
impl ::std::ops::Deref for ExternalAccountId {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ExternalAccountId> for ::std::string::String {
fn from(value: ExternalAccountId) -> Self {
value.0
}
}
impl ::std::str::FromStr for ExternalAccountId {
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-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ExternalAccountId {
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 ExternalAccountId {
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 ExternalAccountId {
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 ExternalAccountId {
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())
})
}
}
///`GcsSettings`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "GcsSettings",
/// "type": "object",
/// "required": [
/// "bucket",
/// "kind"
/// ],
/// "properties": {
/// "bucket": {
/// "description": "The bucket name. Validated against GCS naming rules here, because it is placed in a Credential Access Boundary condition and must never carry anything but a name.",
/// "type": "string",
/// "maxLength": 222,
/// "minLength": 3,
/// "pattern": "^[a-z0-9][a-z0-9._-]{1,220}[a-z0-9]$"
/// },
/// "kind": {
/// "const": "gcs"
/// },
/// "prefix": {
/// "$ref": "#/definitions/ObjectPrefix"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct GcsSettings {
///The bucket name. Validated against GCS naming rules here, because it is placed in a Credential Access Boundary condition and must never carry anything but a name.
pub bucket: GcsSettingsBucket,
pub kind: ::serde_json::Value,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub prefix: ::std::option::Option<ObjectPrefix>,
}
impl GcsSettings {
pub fn builder() -> builder::GcsSettings {
Default::default()
}
}
///The bucket name. Validated against GCS naming rules here, because it is placed in a Credential Access Boundary condition and must never carry anything but a name.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "The bucket name. Validated against GCS naming rules here, because it is placed in a Credential Access Boundary condition and must never carry anything but a name.",
/// "type": "string",
/// "maxLength": 222,
/// "minLength": 3,
/// "pattern": "^[a-z0-9][a-z0-9._-]{1,220}[a-z0-9]$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct GcsSettingsBucket(::std::string::String);
impl ::std::ops::Deref for GcsSettingsBucket {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<GcsSettingsBucket> for ::std::string::String {
fn from(value: GcsSettingsBucket) -> Self {
value.0
}
}
impl ::std::str::FromStr for GcsSettingsBucket {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 222usize {
return Err("longer than 222 characters".into());
}
if value.chars().count() < 3usize {
return Err("shorter than 3 characters".into());
}
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| {
::regress::Regex::new("^[a-z0-9][a-z0-9._-]{1,220}[a-z0-9]$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[a-z0-9][a-z0-9._-]{1,220}[a-z0-9]$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for GcsSettingsBucket {
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 GcsSettingsBucket {
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 GcsSettingsBucket {
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 GcsSettingsBucket {
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())
})
}
}
///`LocalSettings`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "LocalSettings",
/// "type": "object",
/// "required": [
/// "kind",
/// "root"
/// ],
/// "properties": {
/// "kind": {
/// "const": "local"
/// },
/// "root": {
/// "description": "Absolute path of the directory the community writes blobs under, on its own host. Created owner-only. Not carried by the community's backup: back it up beside it.",
/// "type": "string",
/// "maxLength": 1024,
/// "minLength": 1,
/// "pattern": "^/"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct LocalSettings {
pub kind: ::serde_json::Value,
///Absolute path of the directory the community writes blobs under, on its own host. Created owner-only. Not carried by the community's backup: back it up beside it.
pub root: LocalSettingsRoot,
}
impl LocalSettings {
pub fn builder() -> builder::LocalSettings {
Default::default()
}
}
///Absolute path of the directory the community writes blobs under, on its own host. Created owner-only. Not carried by the community's backup: back it up beside it.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Absolute path of the directory the community writes blobs under, on its own host. Created owner-only. Not carried by the community's backup: back it up beside it.",
/// "type": "string",
/// "maxLength": 1024,
/// "minLength": 1,
/// "pattern": "^/"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct LocalSettingsRoot(::std::string::String);
impl ::std::ops::Deref for LocalSettingsRoot {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<LocalSettingsRoot> for ::std::string::String {
fn from(value: LocalSettingsRoot) -> Self {
value.0
}
}
impl ::std::str::FromStr for LocalSettingsRoot {
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());
}
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("^/").unwrap());
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^/\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for LocalSettingsRoot {
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 LocalSettingsRoot {
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 LocalSettingsRoot {
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 LocalSettingsRoot {
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 key prefix inside the bucket, ending in `/`, under which the config's `rooms/` tree is placed. Restricted to the S3 safe-character set so that it can be placed in a downscoped policy without escaping.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "ObjectPrefix",
/// "description": "A key prefix inside the bucket, ending in `/`, under which the config's `rooms/` tree is placed. Restricted to the S3 safe-character set so that it can be placed in a downscoped policy without escaping.",
/// "type": "string",
/// "maxLength": 256,
/// "minLength": 1,
/// "pattern": "^[A-Za-z0-9!_.*'()/-]+/$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ObjectPrefix(::std::string::String);
impl ::std::ops::Deref for ObjectPrefix {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ObjectPrefix> for ::std::string::String {
fn from(value: ObjectPrefix) -> Self {
value.0
}
}
impl ::std::str::FromStr for ObjectPrefix {
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());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| {
::regress::Regex::new("^[A-Za-z0-9!_.*'()/-]+/$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[A-Za-z0-9!_.*'()/-]+/$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ObjectPrefix {
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 ObjectPrefix {
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 ObjectPrefix {
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 ObjectPrefix {
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())
})
}
}
///Add a storage config: a named backend and how the community authenticates to it. Never a secret. The outer document members are owned by the framework — SPEC §6.3.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "$id": "https://trusttasks.org/spec/vtc/storage/configs/create/0.2",
/// "title": "Payload",
/// "description": "Add a storage config: a named backend and how the community authenticates to it. Never a secret. The outer document members are owned by the framework — SPEC §6.3.",
/// "type": "object",
/// "required": [
/// "id",
/// "label",
/// "reason",
/// "settings"
/// ],
/// "properties": {
/// "auth": {
/// "$ref": "#/definitions/StorageAuth"
/// },
/// "capacityBytes": {
/// "description": "Total ciphertext bytes the community will store on this config across every room. Absent means none set.",
/// "type": "integer",
/// "minimum": 0.0
/// },
/// "ext": {
/// "$ref": "#/definitions/Ext"
/// },
/// "id": {
/// "$ref": "#/definitions/StorageConfigId"
/// },
/// "isDefault": {
/// "description": "Make this the config rooms are assigned to when neither policy nor creator names one.",
/// "type": "boolean"
/// },
/// "label": {
/// "description": "A display name for administrators and, with the kind, for a room's creator.",
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
/// },
/// "reason": {
/// "description": "Why the administrator is making this change. Recorded with the change in the audit trail and shown to approvers. Attributed to its author on every surface and untrusted: it MUST NOT carry personal data or a credential, and a reader MUST NOT treat it as instructions.",
/// "type": "string",
/// "maxLength": 500,
/// "minLength": 1
/// },
/// "settings": {
/// "$ref": "#/definitions/StorageSettings"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct Payload {
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub auth: ::std::option::Option<StorageAuth>,
///Total ciphertext bytes the community will store on this config across every room. Absent means none set.
#[serde(
rename = "capacityBytes",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub capacity_bytes: ::std::option::Option<u64>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ext: ::std::option::Option<Ext>,
pub id: StorageConfigId,
///Make this the config rooms are assigned to when neither policy nor creator names one.
#[serde(
rename = "isDefault",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub is_default: ::std::option::Option<bool>,
///A display name for administrators and, with the kind, for a room's creator.
pub label: PayloadLabel,
///Why the administrator is making this change. Recorded with the change in the audit trail and shown to approvers. Attributed to its author on every surface and untrusted: it MUST NOT carry personal data or a credential, and a reader MUST NOT treat it as instructions.
pub reason: PayloadReason,
pub settings: StorageSettings,
}
impl Payload {
pub fn builder() -> builder::Payload {
Default::default()
}
}
///A display name for administrators and, with the kind, for a room's creator.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "A display name for administrators and, with the kind, for a room's creator.",
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PayloadLabel(::std::string::String);
impl ::std::ops::Deref for PayloadLabel {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PayloadLabel> for ::std::string::String {
fn from(value: PayloadLabel) -> Self {
value.0
}
}
impl ::std::str::FromStr for PayloadLabel {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 128usize {
return Err("longer than 128 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for PayloadLabel {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for PayloadLabel {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for PayloadLabel {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for PayloadLabel {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///Why the administrator is making this change. Recorded with the change in the audit trail and shown to approvers. Attributed to its author on every surface and untrusted: it MUST NOT carry personal data or a credential, and a reader MUST NOT treat it as instructions.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Why the administrator is making this change. Recorded with the change in the audit trail and shown to approvers. Attributed to its author on every surface and untrusted: it MUST NOT carry personal data or a credential, and a reader MUST NOT treat it as instructions.",
/// "type": "string",
/// "maxLength": 500,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PayloadReason(::std::string::String);
impl ::std::ops::Deref for PayloadReason {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PayloadReason> for ::std::string::String {
fn from(value: PayloadReason) -> Self {
value.0
}
}
impl ::std::str::FromStr for PayloadReason {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 500usize {
return Err("longer than 500 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 PayloadReason {
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 PayloadReason {
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 PayloadReason {
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 PayloadReason {
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())
})
}
}
///`Response`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Response",
/// "type": "object",
/// "required": [
/// "config"
/// ],
/// "properties": {
/// "config": {
/// "$ref": "#/definitions/StorageConfig"
/// },
/// "ext": {
/// "$ref": "#/definitions/Ext"
/// }
/// },
/// "additionalProperties": false,
/// "$anchor": "response"
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct Response {
pub config: StorageConfig,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ext: ::std::option::Option<Ext>,
}
impl Response {
pub fn builder() -> builder::Response {
Default::default()
}
}
///`S3Settings`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "S3Settings",
/// "type": "object",
/// "required": [
/// "bucket",
/// "kind",
/// "region"
/// ],
/// "properties": {
/// "bucket": {
/// "description": "The bucket name. Validated against S3 naming rules here, because it is placed in downscoped session policies and must never carry anything but a name.",
/// "type": "string",
/// "maxLength": 63,
/// "minLength": 3,
/// "pattern": "^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$"
/// },
/// "endpoint": {
/// "description": "The S3 API endpoint, for a store other than AWS (R2, B2, MinIO). Absent means AWS S3 in `region`. HTTPS only.",
/// "type": "string",
/// "format": "uri",
/// "maxLength": 2048,
/// "pattern": "^https://"
/// },
/// "kind": {
/// "const": "s3"
/// },
/// "pathStyle": {
/// "description": "Address the bucket in the path rather than the host name, as MinIO usually needs. Absent means virtual-hosted style.",
/// "type": "boolean"
/// },
/// "prefix": {
/// "$ref": "#/definitions/ObjectPrefix"
/// },
/// "region": {
/// "description": "The bucket's region, as the store names it (`eu-west-1`; `auto` for R2).",
/// "type": "string",
/// "maxLength": 64,
/// "minLength": 1,
/// "pattern": "^[a-z0-9-]+$"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct S3Settings {
///The bucket name. Validated against S3 naming rules here, because it is placed in downscoped session policies and must never carry anything but a name.
pub bucket: S3SettingsBucket,
///The S3 API endpoint, for a store other than AWS (R2, B2, MinIO). Absent means AWS S3 in `region`. HTTPS only.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub endpoint: ::std::option::Option<::std::string::String>,
pub kind: ::serde_json::Value,
///Address the bucket in the path rather than the host name, as MinIO usually needs. Absent means virtual-hosted style.
#[serde(
rename = "pathStyle",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub path_style: ::std::option::Option<bool>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub prefix: ::std::option::Option<ObjectPrefix>,
///The bucket's region, as the store names it (`eu-west-1`; `auto` for R2).
pub region: S3SettingsRegion,
}
impl S3Settings {
pub fn builder() -> builder::S3Settings {
Default::default()
}
}
///The bucket name. Validated against S3 naming rules here, because it is placed in downscoped session policies and must never carry anything but a name.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "The bucket name. Validated against S3 naming rules here, because it is placed in downscoped session policies and must never carry anything but a name.",
/// "type": "string",
/// "maxLength": 63,
/// "minLength": 3,
/// "pattern": "^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct S3SettingsBucket(::std::string::String);
impl ::std::ops::Deref for S3SettingsBucket {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<S3SettingsBucket> for ::std::string::String {
fn from(value: S3SettingsBucket) -> Self {
value.0
}
}
impl ::std::str::FromStr for S3SettingsBucket {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 63usize {
return Err("longer than 63 characters".into());
}
if value.chars().count() < 3usize {
return Err("shorter than 3 characters".into());
}
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| {
::regress::Regex::new("^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for S3SettingsBucket {
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 S3SettingsBucket {
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 S3SettingsBucket {
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 S3SettingsBucket {
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 bucket's region, as the store names it (`eu-west-1`; `auto` for R2).
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "The bucket's region, as the store names it (`eu-west-1`; `auto` for R2).",
/// "type": "string",
/// "maxLength": 64,
/// "minLength": 1,
/// "pattern": "^[a-z0-9-]+$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct S3SettingsRegion(::std::string::String);
impl ::std::ops::Deref for S3SettingsRegion {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<S3SettingsRegion> for ::std::string::String {
fn from(value: S3SettingsRegion) -> Self {
value.0
}
}
impl ::std::str::FromStr for S3SettingsRegion {
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-z0-9-]+$").unwrap());
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[a-z0-9-]+$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for S3SettingsRegion {
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 S3SettingsRegion {
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 S3SettingsRegion {
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 S3SettingsRegion {
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 community authenticates to a config's backend. Absent on a `local` config, which needs none.
`vta-account` (RECOMMENDED): an external account in the community's VTA, named by the context that owns it and its identifier there. The VTA holds the long-lived authority; the community holds nothing that outlives a credential lifetime, and asks for credentials scoped to one room's prefix for at most 15 minutes, every issuance audited at the VTA. Required for a `walrus` config other than a `sealed` one, since the VTA's `sui-signer` account signs its storage transactions.
`ambient`: the cloud identity of the machine the community runs on (an instance role, workload identity), downscoped to one room's prefix by the community itself under the rules of vtc/storage/configs/create/0.2 — on `s3`, by assuming `roleArn` (or the role the host is configured with) with an inline session policy; on `gcs`, by a Credential Access Boundary. Not audited or rate-limited by the VTA, and usable by anything on that machine that reaches the metadata endpoint. Not valid for `walrus`; `roleArn` is valid only on `s3`.
`sealed` (discouraged): a long-lived credential stored by the community, set with vtc/storage/credentials/set (0.2: a `SealedStorageCredential`). Protects against every administrator through every surface the community offers; does NOT protect against whoever operates the machine, and a community labels it so wherever the config is shown.
`ambient` and `sealed` are host-operator choices: a community MAY refuse either by its own host configuration, whatever its administrators ask.*/
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "StorageAuth",
/// "description": "How the community authenticates to a config's backend. Absent on a `local` config, which needs none.\n\n`vta-account` (RECOMMENDED): an external account in the community's VTA, named by the context that owns it and its identifier there. The VTA holds the long-lived authority; the community holds nothing that outlives a credential lifetime, and asks for credentials scoped to one room's prefix for at most 15 minutes, every issuance audited at the VTA. Required for a `walrus` config other than a `sealed` one, since the VTA's `sui-signer` account signs its storage transactions.\n\n`ambient`: the cloud identity of the machine the community runs on (an instance role, workload identity), downscoped to one room's prefix by the community itself under the rules of vtc/storage/configs/create/0.2 — on `s3`, by assuming `roleArn` (or the role the host is configured with) with an inline session policy; on `gcs`, by a Credential Access Boundary. Not audited or rate-limited by the VTA, and usable by anything on that machine that reaches the metadata endpoint. Not valid for `walrus`; `roleArn` is valid only on `s3`.\n\n`sealed` (discouraged): a long-lived credential stored by the community, set with vtc/storage/credentials/set (0.2: a `SealedStorageCredential`). Protects against every administrator through every surface the community offers; does NOT protect against whoever operates the machine, and a community labels it so wherever the config is shown.\n\n`ambient` and `sealed` are host-operator choices: a community MAY refuse either by its own host configuration, whatever its administrators ask.",
/// "oneOf": [
/// {
/// "type": "object",
/// "required": [
/// "account",
/// "context",
/// "mode"
/// ],
/// "properties": {
/// "account": {
/// "$ref": "#/definitions/ExternalAccountId"
/// },
/// "context": {
/// "$ref": "#/definitions/ExternalAccountContextId"
/// },
/// "mode": {
/// "const": "vta-account"
/// }
/// },
/// "additionalProperties": false
/// },
/// {
/// "type": "object",
/// "required": [
/// "mode"
/// ],
/// "properties": {
/// "mode": {
/// "const": "ambient"
/// },
/// "roleArn": {
/// "description": "`s3` only: the IAM role the community assumes, with the machine's ambient identity, to obtain each room-scoped session. Absent, the community assumes the role its host configuration names, and with none configured, the role of the ambient identity itself (which must then trust itself to be assumed). Refused on any other kind with `authNotAllowed`.",
/// "$ref": "#/definitions/AwsRoleArn"
/// }
/// },
/// "additionalProperties": false
/// },
/// {
/// "type": "object",
/// "required": [
/// "mode"
/// ],
/// "properties": {
/// "mode": {
/// "const": "sealed"
/// }
/// },
/// "additionalProperties": false
/// }
/// ]
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(tag = "mode", deny_unknown_fields)]
#[non_exhaustive]
pub enum StorageAuth {
#[serde(rename = "vta-account")]
VtaAccount {
account: ExternalAccountId,
context: ExternalAccountContextId,
},
#[serde(rename = "ambient")]
Ambient {
///`s3` only: the IAM role the community assumes, with the machine's ambient identity, to obtain each room-scoped session. Absent, the community assumes the role its host configuration names, and with none configured, the role of the ambient identity itself (which must then trust itself to be assumed). Refused on any other kind with `authNotAllowed`.
#[serde(
rename = "roleArn",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
role_arn: ::std::option::Option<AwsRoleArn>,
},
#[serde(rename = "sealed")]
Sealed,
}
///One storage config as the community holds it. Carries no secret.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "StorageConfig",
/// "description": "One storage config as the community holds it. Carries no secret.",
/// "type": "object",
/// "required": [
/// "createdAt",
/// "createdBy",
/// "id",
/// "label",
/// "settings",
/// "state"
/// ],
/// "properties": {
/// "auth": {
/// "$ref": "#/definitions/StorageAuth"
/// },
/// "capacityBytes": {
/// "description": "Total ciphertext bytes the community will store on this config, across every room assigned to it. A capacity, not a policy: an upload that would cross it is refused with scope `storage`. Absent means no capacity set.",
/// "type": "integer",
/// "minimum": 0.0
/// },
/// "createdAt": {
/// "type": "string",
/// "format": "date-time"
/// },
/// "createdBy": {
/// "type": "string",
/// "maxLength": 2048,
/// "pattern": "^did:"
/// },
/// "id": {
/// "$ref": "#/definitions/StorageConfigId"
/// },
/// "isDefault": {
/// "description": "True for the config a room is assigned to when neither the community's policy nor its creator names one.",
/// "type": "boolean"
/// },
/// "label": {
/// "description": "A display name for administrators (`EU — S3 (main account)`). Shown to a room's creator with the config's kind when the community lets them choose.",
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
/// },
/// "settings": {
/// "$ref": "#/definitions/StorageSettings"
/// },
/// "state": {
/// "$ref": "#/definitions/ConfigState"
/// },
/// "updatedAt": {
/// "type": "string",
/// "format": "date-time"
/// },
/// "updatedBy": {
/// "type": "string",
/// "maxLength": 2048,
/// "pattern": "^did:"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct StorageConfig {
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub auth: ::std::option::Option<StorageAuth>,
///Total ciphertext bytes the community will store on this config, across every room assigned to it. A capacity, not a policy: an upload that would cross it is refused with scope `storage`. Absent means no capacity set.
#[serde(
rename = "capacityBytes",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub capacity_bytes: ::std::option::Option<u64>,
#[serde(rename = "createdAt")]
pub created_at: ::chrono::DateTime<::chrono::offset::Utc>,
#[serde(rename = "createdBy")]
pub created_by: StorageConfigCreatedBy,
pub id: StorageConfigId,
///True for the config a room is assigned to when neither the community's policy nor its creator names one.
#[serde(
rename = "isDefault",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub is_default: ::std::option::Option<bool>,
///A display name for administrators (`EU — S3 (main account)`). Shown to a room's creator with the config's kind when the community lets them choose.
pub label: StorageConfigLabel,
pub settings: StorageSettings,
pub state: ConfigState,
#[serde(
rename = "updatedAt",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub updated_at: ::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
#[serde(
rename = "updatedBy",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub updated_by: ::std::option::Option<StorageConfigUpdatedBy>,
}
impl StorageConfig {
pub fn builder() -> builder::StorageConfig {
Default::default()
}
}
///`StorageConfigCreatedBy`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "maxLength": 2048,
/// "pattern": "^did:"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct StorageConfigCreatedBy(::std::string::String);
impl ::std::ops::Deref for StorageConfigCreatedBy {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<StorageConfigCreatedBy> for ::std::string::String {
fn from(value: StorageConfigCreatedBy) -> Self {
value.0
}
}
impl ::std::str::FromStr for StorageConfigCreatedBy {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 2048usize {
return Err("longer than 2048 characters".into());
}
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 StorageConfigCreatedBy {
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 StorageConfigCreatedBy {
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 StorageConfigCreatedBy {
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 StorageConfigCreatedBy {
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 storage config's identifier, chosen by the administrator who creates it and immutable thereafter: lowercase letters, digits and inner hyphens, at most 64 characters (`eu-s3-primary`, `walrus-main`). Unique within the community. Never reused after a config is retired, because blobs name their config by this value.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "StorageConfigId",
/// "description": "A storage config's identifier, chosen by the administrator who creates it and immutable thereafter: lowercase letters, digits and inner hyphens, at most 64 characters (`eu-s3-primary`, `walrus-main`). Unique within the community. Never reused after a config is retired, because blobs name their config by this value.",
/// "type": "string",
/// "maxLength": 64,
/// "minLength": 1,
/// "pattern": "^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct StorageConfigId(::std::string::String);
impl ::std::ops::Deref for StorageConfigId {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<StorageConfigId> for ::std::string::String {
fn from(value: StorageConfigId) -> Self {
value.0
}
}
impl ::std::str::FromStr for StorageConfigId {
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-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for StorageConfigId {
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 StorageConfigId {
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 StorageConfigId {
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 StorageConfigId {
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 display name for administrators (`EU — S3 (main account)`). Shown to a room's creator with the config's kind when the community lets them choose.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "A display name for administrators (`EU — S3 (main account)`). Shown to a room's creator with the config's kind when the community lets them choose.",
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct StorageConfigLabel(::std::string::String);
impl ::std::ops::Deref for StorageConfigLabel {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<StorageConfigLabel> for ::std::string::String {
fn from(value: StorageConfigLabel) -> Self {
value.0
}
}
impl ::std::str::FromStr for StorageConfigLabel {
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 StorageConfigLabel {
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 StorageConfigLabel {
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 StorageConfigLabel {
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 StorageConfigLabel {
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())
})
}
}
///`StorageConfigUpdatedBy`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "maxLength": 2048,
/// "pattern": "^did:"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct StorageConfigUpdatedBy(::std::string::String);
impl ::std::ops::Deref for StorageConfigUpdatedBy {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<StorageConfigUpdatedBy> for ::std::string::String {
fn from(value: StorageConfigUpdatedBy) -> Self {
value.0
}
}
impl ::std::str::FromStr for StorageConfigUpdatedBy {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 2048usize {
return Err("longer than 2048 characters".into());
}
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 StorageConfigUpdatedBy {
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 StorageConfigUpdatedBy {
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 StorageConfigUpdatedBy {
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 StorageConfigUpdatedBy {
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 config's backend settings, discriminated by `kind`. Never a secret: a credential is a StorageAuth, held elsewhere.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "StorageSettings",
/// "description": "A config's backend settings, discriminated by `kind`. Never a secret: a credential is a StorageAuth, held elsewhere.",
/// "oneOf": [
/// {
/// "$ref": "#/definitions/LocalSettings"
/// },
/// {
/// "$ref": "#/definitions/S3Settings"
/// },
/// {
/// "$ref": "#/definitions/GcsSettings"
/// },
/// {
/// "$ref": "#/definitions/WalrusSettings"
/// }
/// ]
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(untagged)]
#[non_exhaustive]
pub enum StorageSettings {
LocalSettings(LocalSettings),
S3Settings(S3Settings),
GcsSettings(GcsSettings),
WalrusSettings(WalrusSettings),
}
impl ::std::convert::From<LocalSettings> for StorageSettings {
fn from(value: LocalSettings) -> Self {
Self::LocalSettings(value)
}
}
impl ::std::convert::From<S3Settings> for StorageSettings {
fn from(value: S3Settings) -> Self {
Self::S3Settings(value)
}
}
impl ::std::convert::From<GcsSettings> for StorageSettings {
fn from(value: GcsSettings) -> Self {
Self::GcsSettings(value)
}
}
impl ::std::convert::From<WalrusSettings> for StorageSettings {
fn from(value: WalrusSettings) -> Self {
Self::WalrusSettings(value)
}
}
///`WalrusSettings`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "WalrusSettings",
/// "type": "object",
/// "required": [
/// "aggregatorUrl",
/// "epochs",
/// "extendBeforeEpochs",
/// "kind",
/// "relayUrl"
/// ],
/// "properties": {
/// "aggregatorUrl": {
/// "description": "The Walrus aggregator the community reads through.",
/// "type": "string",
/// "format": "uri",
/// "maxLength": 2048,
/// "pattern": "^https://"
/// },
/// "epochs": {
/// "description": "Storage epochs to buy when a blob is registered. Walrus sells storage in epochs (two weeks on mainnet) and caps one purchase at 53.",
/// "type": "integer",
/// "maximum": 53.0,
/// "minimum": 1.0
/// },
/// "extendBeforeEpochs": {
/// "description": "How many epochs before a live blob's end epoch the community extends it. A blob that has become an orphan is not extended, and lapses: the Walrus form of deletion.",
/// "type": "integer",
/// "maximum": 52.0,
/// "minimum": 1.0
/// },
/// "kind": {
/// "const": "walrus"
/// },
/// "relayUrl": {
/// "description": "The Walrus upload relay the community writes through. The community never runs a publisher: a publisher holds a hot wallet in its own configuration, which is the long-lived secret these tasks exist to avoid.",
/// "type": "string",
/// "format": "uri",
/// "maxLength": 2048,
/// "pattern": "^https://"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct WalrusSettings {
///The Walrus aggregator the community reads through.
#[serde(rename = "aggregatorUrl")]
pub aggregator_url: ::std::string::String,
///Storage epochs to buy when a blob is registered. Walrus sells storage in epochs (two weeks on mainnet) and caps one purchase at 53.
pub epochs: ::std::num::NonZeroU64,
///How many epochs before a live blob's end epoch the community extends it. A blob that has become an orphan is not extended, and lapses: the Walrus form of deletion.
#[serde(rename = "extendBeforeEpochs")]
pub extend_before_epochs: ::std::num::NonZeroU64,
pub kind: ::serde_json::Value,
///The Walrus upload relay the community writes through. The community never runs a publisher: a publisher holds a hot wallet in its own configuration, which is the long-lived secret these tasks exist to avoid.
#[serde(rename = "relayUrl")]
pub relay_url: ::std::string::String,
}
impl WalrusSettings {
pub fn builder() -> builder::WalrusSettings {
Default::default()
}
}
/// Types for composing complex structures.
pub mod builder {
#[derive(Clone, Debug)]
pub struct GcsSettings {
bucket: ::std::result::Result<super::GcsSettingsBucket, ::std::string::String>,
kind: ::std::result::Result<::serde_json::Value, ::std::string::String>,
prefix: ::std::result::Result<
::std::option::Option<super::ObjectPrefix>,
::std::string::String,
>,
}
impl ::std::default::Default for GcsSettings {
fn default() -> Self {
Self {
bucket: Err("no value supplied for bucket".to_string()),
kind: Err("no value supplied for kind".to_string()),
prefix: Ok(Default::default()),
}
}
}
impl GcsSettings {
pub fn bucket<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::GcsSettingsBucket>,
T::Error: ::std::fmt::Display,
{
self.bucket = value
.try_into()
.map_err(|e| format!("error converting supplied value for bucket: {e}"));
self
}
pub fn kind<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::serde_json::Value>,
T::Error: ::std::fmt::Display,
{
self.kind = value
.try_into()
.map_err(|e| format!("error converting supplied value for kind: {e}"));
self
}
pub fn prefix<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::ObjectPrefix>>,
T::Error: ::std::fmt::Display,
{
self.prefix = value
.try_into()
.map_err(|e| format!("error converting supplied value for prefix: {e}"));
self
}
}
impl ::std::convert::TryFrom<GcsSettings> for super::GcsSettings {
type Error = super::error::ConversionError;
fn try_from(
value: GcsSettings,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
bucket: value.bucket?,
kind: value.kind?,
prefix: value.prefix?,
})
}
}
impl ::std::convert::From<super::GcsSettings> for GcsSettings {
fn from(value: super::GcsSettings) -> Self {
Self {
bucket: Ok(value.bucket),
kind: Ok(value.kind),
prefix: Ok(value.prefix),
}
}
}
#[derive(Clone, Debug)]
pub struct LocalSettings {
kind: ::std::result::Result<::serde_json::Value, ::std::string::String>,
root: ::std::result::Result<super::LocalSettingsRoot, ::std::string::String>,
}
impl ::std::default::Default for LocalSettings {
fn default() -> Self {
Self {
kind: Err("no value supplied for kind".to_string()),
root: Err("no value supplied for root".to_string()),
}
}
}
impl LocalSettings {
pub fn kind<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::serde_json::Value>,
T::Error: ::std::fmt::Display,
{
self.kind = value
.try_into()
.map_err(|e| format!("error converting supplied value for kind: {e}"));
self
}
pub fn root<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::LocalSettingsRoot>,
T::Error: ::std::fmt::Display,
{
self.root = value
.try_into()
.map_err(|e| format!("error converting supplied value for root: {e}"));
self
}
}
impl ::std::convert::TryFrom<LocalSettings> for super::LocalSettings {
type Error = super::error::ConversionError;
fn try_from(
value: LocalSettings,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
kind: value.kind?,
root: value.root?,
})
}
}
impl ::std::convert::From<super::LocalSettings> for LocalSettings {
fn from(value: super::LocalSettings) -> Self {
Self {
kind: Ok(value.kind),
root: Ok(value.root),
}
}
}
#[derive(Clone, Debug)]
pub struct Payload {
auth:
::std::result::Result<::std::option::Option<super::StorageAuth>, ::std::string::String>,
capacity_bytes: ::std::result::Result<::std::option::Option<u64>, ::std::string::String>,
ext: ::std::result::Result<::std::option::Option<super::Ext>, ::std::string::String>,
id: ::std::result::Result<super::StorageConfigId, ::std::string::String>,
is_default: ::std::result::Result<::std::option::Option<bool>, ::std::string::String>,
label: ::std::result::Result<super::PayloadLabel, ::std::string::String>,
reason: ::std::result::Result<super::PayloadReason, ::std::string::String>,
settings: ::std::result::Result<super::StorageSettings, ::std::string::String>,
}
impl ::std::default::Default for Payload {
fn default() -> Self {
Self {
auth: Ok(Default::default()),
capacity_bytes: Ok(Default::default()),
ext: Ok(Default::default()),
id: Err("no value supplied for id".to_string()),
is_default: Ok(Default::default()),
label: Err("no value supplied for label".to_string()),
reason: Err("no value supplied for reason".to_string()),
settings: Err("no value supplied for settings".to_string()),
}
}
}
impl Payload {
pub fn auth<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::StorageAuth>>,
T::Error: ::std::fmt::Display,
{
self.auth = value
.try_into()
.map_err(|e| format!("error converting supplied value for auth: {e}"));
self
}
pub fn capacity_bytes<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<u64>>,
T::Error: ::std::fmt::Display,
{
self.capacity_bytes = value
.try_into()
.map_err(|e| format!("error converting supplied value for capacity_bytes: {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 id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::StorageConfigId>,
T::Error: ::std::fmt::Display,
{
self.id = value
.try_into()
.map_err(|e| format!("error converting supplied value for id: {e}"));
self
}
pub fn is_default<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<bool>>,
T::Error: ::std::fmt::Display,
{
self.is_default = value
.try_into()
.map_err(|e| format!("error converting supplied value for is_default: {e}"));
self
}
pub fn label<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::PayloadLabel>,
T::Error: ::std::fmt::Display,
{
self.label = value
.try_into()
.map_err(|e| format!("error converting supplied value for label: {e}"));
self
}
pub fn reason<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::PayloadReason>,
T::Error: ::std::fmt::Display,
{
self.reason = value
.try_into()
.map_err(|e| format!("error converting supplied value for reason: {e}"));
self
}
pub fn settings<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::StorageSettings>,
T::Error: ::std::fmt::Display,
{
self.settings = value
.try_into()
.map_err(|e| format!("error converting supplied value for settings: {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 {
auth: value.auth?,
capacity_bytes: value.capacity_bytes?,
ext: value.ext?,
id: value.id?,
is_default: value.is_default?,
label: value.label?,
reason: value.reason?,
settings: value.settings?,
})
}
}
impl ::std::convert::From<super::Payload> for Payload {
fn from(value: super::Payload) -> Self {
Self {
auth: Ok(value.auth),
capacity_bytes: Ok(value.capacity_bytes),
ext: Ok(value.ext),
id: Ok(value.id),
is_default: Ok(value.is_default),
label: Ok(value.label),
reason: Ok(value.reason),
settings: Ok(value.settings),
}
}
}
#[derive(Clone, Debug)]
pub struct Response {
config: ::std::result::Result<super::StorageConfig, ::std::string::String>,
ext: ::std::result::Result<::std::option::Option<super::Ext>, ::std::string::String>,
}
impl ::std::default::Default for Response {
fn default() -> Self {
Self {
config: Err("no value supplied for config".to_string()),
ext: Ok(Default::default()),
}
}
}
impl Response {
pub fn config<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::StorageConfig>,
T::Error: ::std::fmt::Display,
{
self.config = value
.try_into()
.map_err(|e| format!("error converting supplied value for config: {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
}
}
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 {
config: value.config?,
ext: value.ext?,
})
}
}
impl ::std::convert::From<super::Response> for Response {
fn from(value: super::Response) -> Self {
Self {
config: Ok(value.config),
ext: Ok(value.ext),
}
}
}
#[derive(Clone, Debug)]
pub struct S3Settings {
bucket: ::std::result::Result<super::S3SettingsBucket, ::std::string::String>,
endpoint: ::std::result::Result<
::std::option::Option<::std::string::String>,
::std::string::String,
>,
kind: ::std::result::Result<::serde_json::Value, ::std::string::String>,
path_style: ::std::result::Result<::std::option::Option<bool>, ::std::string::String>,
prefix: ::std::result::Result<
::std::option::Option<super::ObjectPrefix>,
::std::string::String,
>,
region: ::std::result::Result<super::S3SettingsRegion, ::std::string::String>,
}
impl ::std::default::Default for S3Settings {
fn default() -> Self {
Self {
bucket: Err("no value supplied for bucket".to_string()),
endpoint: Ok(Default::default()),
kind: Err("no value supplied for kind".to_string()),
path_style: Ok(Default::default()),
prefix: Ok(Default::default()),
region: Err("no value supplied for region".to_string()),
}
}
}
impl S3Settings {
pub fn bucket<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::S3SettingsBucket>,
T::Error: ::std::fmt::Display,
{
self.bucket = value
.try_into()
.map_err(|e| format!("error converting supplied value for bucket: {e}"));
self
}
pub fn endpoint<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>,
T::Error: ::std::fmt::Display,
{
self.endpoint = value
.try_into()
.map_err(|e| format!("error converting supplied value for endpoint: {e}"));
self
}
pub fn kind<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::serde_json::Value>,
T::Error: ::std::fmt::Display,
{
self.kind = value
.try_into()
.map_err(|e| format!("error converting supplied value for kind: {e}"));
self
}
pub fn path_style<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<bool>>,
T::Error: ::std::fmt::Display,
{
self.path_style = value
.try_into()
.map_err(|e| format!("error converting supplied value for path_style: {e}"));
self
}
pub fn prefix<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::ObjectPrefix>>,
T::Error: ::std::fmt::Display,
{
self.prefix = value
.try_into()
.map_err(|e| format!("error converting supplied value for prefix: {e}"));
self
}
pub fn region<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::S3SettingsRegion>,
T::Error: ::std::fmt::Display,
{
self.region = value
.try_into()
.map_err(|e| format!("error converting supplied value for region: {e}"));
self
}
}
impl ::std::convert::TryFrom<S3Settings> for super::S3Settings {
type Error = super::error::ConversionError;
fn try_from(
value: S3Settings,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
bucket: value.bucket?,
endpoint: value.endpoint?,
kind: value.kind?,
path_style: value.path_style?,
prefix: value.prefix?,
region: value.region?,
})
}
}
impl ::std::convert::From<super::S3Settings> for S3Settings {
fn from(value: super::S3Settings) -> Self {
Self {
bucket: Ok(value.bucket),
endpoint: Ok(value.endpoint),
kind: Ok(value.kind),
path_style: Ok(value.path_style),
prefix: Ok(value.prefix),
region: Ok(value.region),
}
}
}
#[derive(Clone, Debug)]
pub struct StorageConfig {
auth:
::std::result::Result<::std::option::Option<super::StorageAuth>, ::std::string::String>,
capacity_bytes: ::std::result::Result<::std::option::Option<u64>, ::std::string::String>,
created_at:
::std::result::Result<::chrono::DateTime<::chrono::offset::Utc>, ::std::string::String>,
created_by: ::std::result::Result<super::StorageConfigCreatedBy, ::std::string::String>,
id: ::std::result::Result<super::StorageConfigId, ::std::string::String>,
is_default: ::std::result::Result<::std::option::Option<bool>, ::std::string::String>,
label: ::std::result::Result<super::StorageConfigLabel, ::std::string::String>,
settings: ::std::result::Result<super::StorageSettings, ::std::string::String>,
state: ::std::result::Result<super::ConfigState, ::std::string::String>,
updated_at: ::std::result::Result<
::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
::std::string::String,
>,
updated_by: ::std::result::Result<
::std::option::Option<super::StorageConfigUpdatedBy>,
::std::string::String,
>,
}
impl ::std::default::Default for StorageConfig {
fn default() -> Self {
Self {
auth: Ok(Default::default()),
capacity_bytes: Ok(Default::default()),
created_at: Err("no value supplied for created_at".to_string()),
created_by: Err("no value supplied for created_by".to_string()),
id: Err("no value supplied for id".to_string()),
is_default: Ok(Default::default()),
label: Err("no value supplied for label".to_string()),
settings: Err("no value supplied for settings".to_string()),
state: Err("no value supplied for state".to_string()),
updated_at: Ok(Default::default()),
updated_by: Ok(Default::default()),
}
}
}
impl StorageConfig {
pub fn auth<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::StorageAuth>>,
T::Error: ::std::fmt::Display,
{
self.auth = value
.try_into()
.map_err(|e| format!("error converting supplied value for auth: {e}"));
self
}
pub fn capacity_bytes<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<u64>>,
T::Error: ::std::fmt::Display,
{
self.capacity_bytes = value
.try_into()
.map_err(|e| format!("error converting supplied value for capacity_bytes: {e}"));
self
}
pub fn created_at<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::chrono::DateTime<::chrono::offset::Utc>>,
T::Error: ::std::fmt::Display,
{
self.created_at = value
.try_into()
.map_err(|e| format!("error converting supplied value for created_at: {e}"));
self
}
pub fn created_by<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::StorageConfigCreatedBy>,
T::Error: ::std::fmt::Display,
{
self.created_by = value
.try_into()
.map_err(|e| format!("error converting supplied value for created_by: {e}"));
self
}
pub fn id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::StorageConfigId>,
T::Error: ::std::fmt::Display,
{
self.id = value
.try_into()
.map_err(|e| format!("error converting supplied value for id: {e}"));
self
}
pub fn is_default<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<bool>>,
T::Error: ::std::fmt::Display,
{
self.is_default = value
.try_into()
.map_err(|e| format!("error converting supplied value for is_default: {e}"));
self
}
pub fn label<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::StorageConfigLabel>,
T::Error: ::std::fmt::Display,
{
self.label = value
.try_into()
.map_err(|e| format!("error converting supplied value for label: {e}"));
self
}
pub fn settings<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::StorageSettings>,
T::Error: ::std::fmt::Display,
{
self.settings = value
.try_into()
.map_err(|e| format!("error converting supplied value for settings: {e}"));
self
}
pub fn state<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::ConfigState>,
T::Error: ::std::fmt::Display,
{
self.state = value
.try_into()
.map_err(|e| format!("error converting supplied value for state: {e}"));
self
}
pub fn updated_at<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<
::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
>,
T::Error: ::std::fmt::Display,
{
self.updated_at = value
.try_into()
.map_err(|e| format!("error converting supplied value for updated_at: {e}"));
self
}
pub fn updated_by<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::StorageConfigUpdatedBy>>,
T::Error: ::std::fmt::Display,
{
self.updated_by = value
.try_into()
.map_err(|e| format!("error converting supplied value for updated_by: {e}"));
self
}
}
impl ::std::convert::TryFrom<StorageConfig> for super::StorageConfig {
type Error = super::error::ConversionError;
fn try_from(
value: StorageConfig,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
auth: value.auth?,
capacity_bytes: value.capacity_bytes?,
created_at: value.created_at?,
created_by: value.created_by?,
id: value.id?,
is_default: value.is_default?,
label: value.label?,
settings: value.settings?,
state: value.state?,
updated_at: value.updated_at?,
updated_by: value.updated_by?,
})
}
}
impl ::std::convert::From<super::StorageConfig> for StorageConfig {
fn from(value: super::StorageConfig) -> Self {
Self {
auth: Ok(value.auth),
capacity_bytes: Ok(value.capacity_bytes),
created_at: Ok(value.created_at),
created_by: Ok(value.created_by),
id: Ok(value.id),
is_default: Ok(value.is_default),
label: Ok(value.label),
settings: Ok(value.settings),
state: Ok(value.state),
updated_at: Ok(value.updated_at),
updated_by: Ok(value.updated_by),
}
}
}
#[derive(Clone, Debug)]
pub struct WalrusSettings {
aggregator_url: ::std::result::Result<::std::string::String, ::std::string::String>,
epochs: ::std::result::Result<::std::num::NonZeroU64, ::std::string::String>,
extend_before_epochs: ::std::result::Result<::std::num::NonZeroU64, ::std::string::String>,
kind: ::std::result::Result<::serde_json::Value, ::std::string::String>,
relay_url: ::std::result::Result<::std::string::String, ::std::string::String>,
}
impl ::std::default::Default for WalrusSettings {
fn default() -> Self {
Self {
aggregator_url: Err("no value supplied for aggregator_url".to_string()),
epochs: Err("no value supplied for epochs".to_string()),
extend_before_epochs: Err("no value supplied for extend_before_epochs".to_string()),
kind: Err("no value supplied for kind".to_string()),
relay_url: Err("no value supplied for relay_url".to_string()),
}
}
}
impl WalrusSettings {
pub fn aggregator_url<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::string::String>,
T::Error: ::std::fmt::Display,
{
self.aggregator_url = value
.try_into()
.map_err(|e| format!("error converting supplied value for aggregator_url: {e}"));
self
}
pub fn epochs<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::num::NonZeroU64>,
T::Error: ::std::fmt::Display,
{
self.epochs = value
.try_into()
.map_err(|e| format!("error converting supplied value for epochs: {e}"));
self
}
pub fn extend_before_epochs<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::num::NonZeroU64>,
T::Error: ::std::fmt::Display,
{
self.extend_before_epochs = value.try_into().map_err(|e| {
format!("error converting supplied value for extend_before_epochs: {e}")
});
self
}
pub fn kind<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::serde_json::Value>,
T::Error: ::std::fmt::Display,
{
self.kind = value
.try_into()
.map_err(|e| format!("error converting supplied value for kind: {e}"));
self
}
pub fn relay_url<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::string::String>,
T::Error: ::std::fmt::Display,
{
self.relay_url = value
.try_into()
.map_err(|e| format!("error converting supplied value for relay_url: {e}"));
self
}
}
impl ::std::convert::TryFrom<WalrusSettings> for super::WalrusSettings {
type Error = super::error::ConversionError;
fn try_from(
value: WalrusSettings,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
aggregator_url: value.aggregator_url?,
epochs: value.epochs?,
extend_before_epochs: value.extend_before_epochs?,
kind: value.kind?,
relay_url: value.relay_url?,
})
}
}
impl ::std::convert::From<super::WalrusSettings> for WalrusSettings {
fn from(value: super::WalrusSettings) -> Self {
Self {
aggregator_url: Ok(value.aggregator_url),
epochs: Ok(value.epochs),
extend_before_epochs: Ok(value.extend_before_epochs),
kind: Ok(value.kind),
relay_url: Ok(value.relay_url),
}
}
}
}
impl crate::Payload for Payload {
const TYPE_URI: &'static str = "https://trusttasks.org/spec/vtc/storage/configs/create/0.2";
const IS_PROOF_REQUIRED: bool = true;
const IS_ISSUED_AT_REQUIRED: bool = true;
const IS_RECIPIENT_REQUIRED: bool = true;
const PAYLOAD_SCHEMA: Option<&'static str> = Some(
"{\n \"$defs\": {\n \"AwsRoleArn\": {\n \"description\": \"The ARN of an AWS IAM role, in any AWS partition (`arn:aws:`, `arn:aws-cn:`, `arn:aws-us-gov:`). Validated here because the community passes it to STS AssumeRole and derives the partition of the session policy's resources from it; it must never carry anything but a role ARN.\",\n \"maxLength\": 2048,\n \"minLength\": 20,\n \"pattern\": \"^arn:aws(-[a-z]+)*:iam::[0-9]{12}:role/[A-Za-z0-9+=,.@_/-]{1,512}$\",\n \"title\": \"AwsRoleArn\",\n \"type\": \"string\"\n },\n \"ConfigState\": {\n \"description\": \"`active`: accepts new rooms and new uploads. `draining`: retired by an administrator while blobs still name it — refuses new rooms and new uploads, keeps serving reads, and becomes `retired` when a migration has emptied it. `retired`: refuses new rooms and new uploads and holds no blob. A config is never deleted while a blob names it.\",\n \"enum\": [\n \"active\",\n \"draining\",\n \"retired\"\n ],\n \"title\": \"ConfigState\",\n \"type\": \"string\"\n },\n \"Ext\": {\n \"additionalProperties\": true,\n \"description\": \"Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.\",\n \"minProperties\": 1,\n \"propertyNames\": {\n \"pattern\": \"^[a-z][a-z0-9-]*(\\\\.[a-z0-9-]+)+$\"\n },\n \"title\": \"Ext\",\n \"type\": \"object\"\n },\n \"ExternalAccountContextId\": {\n \"description\": \"The context at the community's VTA that owns an external account. The VTA names an account by its context and its identifier, and decides who may use it by act scope in that context: the community must hold `external-auth-use` there, and be bound to the account, for the account to issue it anything. Naming a context grants nothing; the VTA's binding is the gate.\",\n \"maxLength\": 256,\n \"minLength\": 1,\n \"title\": \"ExternalAccountContextId\",\n \"type\": \"string\"\n },\n \"ExternalAccountId\": {\n \"description\": \"The identifier of an external account held by the community's VTA (the external/accounts/* family), which issues the community short-lived, room-scoped credentials and holds the long-lived authority itself.\",\n \"maxLength\": 64,\n \"minLength\": 1,\n \"pattern\": \"^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$\",\n \"title\": \"ExternalAccountId\",\n \"type\": \"string\"\n },\n \"GcsSettings\": {\n \"additionalProperties\": false,\n \"properties\": {\n \"bucket\": {\n \"description\": \"The bucket name. Validated against GCS naming rules here, because it is placed in a Credential Access Boundary condition and must never carry anything but a name.\",\n \"maxLength\": 222,\n \"minLength\": 3,\n \"pattern\": \"^[a-z0-9][a-z0-9._-]{1,220}[a-z0-9]$\",\n \"type\": \"string\"\n },\n \"kind\": {\n \"const\": \"gcs\"\n },\n \"prefix\": {\n \"$ref\": \"#/$defs/ObjectPrefix\"\n }\n },\n \"required\": [\n \"kind\",\n \"bucket\"\n ],\n \"title\": \"GcsSettings\",\n \"type\": \"object\"\n },\n \"LocalSettings\": {\n \"additionalProperties\": false,\n \"properties\": {\n \"kind\": {\n \"const\": \"local\"\n },\n \"root\": {\n \"description\": \"Absolute path of the directory the community writes blobs under, on its own host. Created owner-only. Not carried by the community's backup: back it up beside it.\",\n \"maxLength\": 1024,\n \"minLength\": 1,\n \"pattern\": \"^/\",\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"kind\",\n \"root\"\n ],\n \"title\": \"LocalSettings\",\n \"type\": \"object\"\n },\n \"ObjectPrefix\": {\n \"description\": \"A key prefix inside the bucket, ending in `/`, under which the config's `rooms/` tree is placed. Restricted to the S3 safe-character set so that it can be placed in a downscoped policy without escaping.\",\n \"maxLength\": 256,\n \"minLength\": 1,\n \"pattern\": \"^[A-Za-z0-9!_.*'()/-]+/$\",\n \"title\": \"ObjectPrefix\",\n \"type\": \"string\"\n },\n \"Response\": {\n \"$anchor\": \"response\",\n \"additionalProperties\": false,\n \"properties\": {\n \"config\": {\n \"$ref\": \"#/$defs/StorageConfig\"\n },\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\"\n }\n },\n \"required\": [\n \"config\"\n ],\n \"title\": \"VTC Storage — Configs — Create — response payload\",\n \"type\": \"object\"\n },\n \"S3Settings\": {\n \"additionalProperties\": false,\n \"properties\": {\n \"bucket\": {\n \"description\": \"The bucket name. Validated against S3 naming rules here, because it is placed in downscoped session policies and must never carry anything but a name.\",\n \"maxLength\": 63,\n \"minLength\": 3,\n \"pattern\": \"^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$\",\n \"type\": \"string\"\n },\n \"endpoint\": {\n \"description\": \"The S3 API endpoint, for a store other than AWS (R2, B2, MinIO). Absent means AWS S3 in `region`. HTTPS only.\",\n \"format\": \"uri\",\n \"maxLength\": 2048,\n \"pattern\": \"^https://\",\n \"type\": \"string\"\n },\n \"kind\": {\n \"const\": \"s3\"\n },\n \"pathStyle\": {\n \"description\": \"Address the bucket in the path rather than the host name, as MinIO usually needs. Absent means virtual-hosted style.\",\n \"type\": \"boolean\"\n },\n \"prefix\": {\n \"$ref\": \"#/$defs/ObjectPrefix\"\n },\n \"region\": {\n \"description\": \"The bucket's region, as the store names it (`eu-west-1`; `auto` for R2).\",\n \"maxLength\": 64,\n \"minLength\": 1,\n \"pattern\": \"^[a-z0-9-]+$\",\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"kind\",\n \"region\",\n \"bucket\"\n ],\n \"title\": \"S3Settings\",\n \"type\": \"object\"\n },\n \"StorageAuth\": {\n \"description\": \"How the community authenticates to a config's backend. Absent on a `local` config, which needs none.\\n\\n`vta-account` (RECOMMENDED): an external account in the community's VTA, named by the context that owns it and its identifier there. The VTA holds the long-lived authority; the community holds nothing that outlives a credential lifetime, and asks for credentials scoped to one room's prefix for at most 15 minutes, every issuance audited at the VTA. Required for a `walrus` config other than a `sealed` one, since the VTA's `sui-signer` account signs its storage transactions.\\n\\n`ambient`: the cloud identity of the machine the community runs on (an instance role, workload identity), downscoped to one room's prefix by the community itself under the rules of vtc/storage/configs/create/0.2 — on `s3`, by assuming `roleArn` (or the role the host is configured with) with an inline session policy; on `gcs`, by a Credential Access Boundary. Not audited or rate-limited by the VTA, and usable by anything on that machine that reaches the metadata endpoint. Not valid for `walrus`; `roleArn` is valid only on `s3`.\\n\\n`sealed` (discouraged): a long-lived credential stored by the community, set with vtc/storage/credentials/set (0.2: a `SealedStorageCredential`). Protects against every administrator through every surface the community offers; does NOT protect against whoever operates the machine, and a community labels it so wherever the config is shown.\\n\\n`ambient` and `sealed` are host-operator choices: a community MAY refuse either by its own host configuration, whatever its administrators ask.\",\n \"oneOf\": [\n {\n \"additionalProperties\": false,\n \"properties\": {\n \"account\": {\n \"$ref\": \"#/$defs/ExternalAccountId\"\n },\n \"context\": {\n \"$ref\": \"#/$defs/ExternalAccountContextId\"\n },\n \"mode\": {\n \"const\": \"vta-account\"\n }\n },\n \"required\": [\n \"mode\",\n \"context\",\n \"account\"\n ],\n \"type\": \"object\"\n },\n {\n \"additionalProperties\": false,\n \"properties\": {\n \"mode\": {\n \"const\": \"ambient\"\n },\n \"roleArn\": {\n \"$ref\": \"#/$defs/AwsRoleArn\",\n \"description\": \"`s3` only: the IAM role the community assumes, with the machine's ambient identity, to obtain each room-scoped session. Absent, the community assumes the role its host configuration names, and with none configured, the role of the ambient identity itself (which must then trust itself to be assumed). Refused on any other kind with `authNotAllowed`.\"\n }\n },\n \"required\": [\n \"mode\"\n ],\n \"type\": \"object\"\n },\n {\n \"additionalProperties\": false,\n \"properties\": {\n \"mode\": {\n \"const\": \"sealed\"\n }\n },\n \"required\": [\n \"mode\"\n ],\n \"type\": \"object\"\n }\n ],\n \"title\": \"StorageAuth\"\n },\n \"StorageConfig\": {\n \"additionalProperties\": false,\n \"description\": \"One storage config as the community holds it. Carries no secret.\",\n \"properties\": {\n \"auth\": {\n \"$ref\": \"#/$defs/StorageAuth\"\n },\n \"capacityBytes\": {\n \"description\": \"Total ciphertext bytes the community will store on this config, across every room assigned to it. A capacity, not a policy: an upload that would cross it is refused with scope `storage`. Absent means no capacity set.\",\n \"minimum\": 0,\n \"type\": \"integer\"\n },\n \"createdAt\": {\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"createdBy\": {\n \"maxLength\": 2048,\n \"pattern\": \"^did:\",\n \"type\": \"string\"\n },\n \"id\": {\n \"$ref\": \"#/$defs/StorageConfigId\"\n },\n \"isDefault\": {\n \"description\": \"True for the config a room is assigned to when neither the community's policy nor its creator names one.\",\n \"type\": \"boolean\"\n },\n \"label\": {\n \"description\": \"A display name for administrators (`EU — S3 (main account)`). Shown to a room's creator with the config's kind when the community lets them choose.\",\n \"maxLength\": 128,\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"settings\": {\n \"$ref\": \"#/$defs/StorageSettings\"\n },\n \"state\": {\n \"$ref\": \"#/$defs/ConfigState\"\n },\n \"updatedAt\": {\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"updatedBy\": {\n \"maxLength\": 2048,\n \"pattern\": \"^did:\",\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"id\",\n \"label\",\n \"settings\",\n \"state\",\n \"createdBy\",\n \"createdAt\"\n ],\n \"title\": \"StorageConfig\",\n \"type\": \"object\"\n },\n \"StorageConfigId\": {\n \"description\": \"A storage config's identifier, chosen by the administrator who creates it and immutable thereafter: lowercase letters, digits and inner hyphens, at most 64 characters (`eu-s3-primary`, `walrus-main`). Unique within the community. Never reused after a config is retired, because blobs name their config by this value.\",\n \"maxLength\": 64,\n \"minLength\": 1,\n \"pattern\": \"^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$\",\n \"title\": \"StorageConfigId\",\n \"type\": \"string\"\n },\n \"StorageSettings\": {\n \"description\": \"A config's backend settings, discriminated by `kind`. Never a secret: a credential is a StorageAuth, held elsewhere.\",\n \"oneOf\": [\n {\n \"$ref\": \"#/$defs/LocalSettings\"\n },\n {\n \"$ref\": \"#/$defs/S3Settings\"\n },\n {\n \"$ref\": \"#/$defs/GcsSettings\"\n },\n {\n \"$ref\": \"#/$defs/WalrusSettings\"\n }\n ],\n \"title\": \"StorageSettings\"\n },\n \"WalrusSettings\": {\n \"additionalProperties\": false,\n \"properties\": {\n \"aggregatorUrl\": {\n \"description\": \"The Walrus aggregator the community reads through.\",\n \"format\": \"uri\",\n \"maxLength\": 2048,\n \"pattern\": \"^https://\",\n \"type\": \"string\"\n },\n \"epochs\": {\n \"description\": \"Storage epochs to buy when a blob is registered. Walrus sells storage in epochs (two weeks on mainnet) and caps one purchase at 53.\",\n \"maximum\": 53,\n \"minimum\": 1,\n \"type\": \"integer\"\n },\n \"extendBeforeEpochs\": {\n \"description\": \"How many epochs before a live blob's end epoch the community extends it. A blob that has become an orphan is not extended, and lapses: the Walrus form of deletion.\",\n \"maximum\": 52,\n \"minimum\": 1,\n \"type\": \"integer\"\n },\n \"kind\": {\n \"const\": \"walrus\"\n },\n \"relayUrl\": {\n \"description\": \"The Walrus upload relay the community writes through. The community never runs a publisher: a publisher holds a hot wallet in its own configuration, which is the long-lived secret these tasks exist to avoid.\",\n \"format\": \"uri\",\n \"maxLength\": 2048,\n \"pattern\": \"^https://\",\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"kind\",\n \"relayUrl\",\n \"aggregatorUrl\",\n \"epochs\",\n \"extendBeforeEpochs\"\n ],\n \"title\": \"WalrusSettings\",\n \"type\": \"object\"\n }\n },\n \"$id\": \"https://trusttasks.org/spec/vtc/storage/configs/create/0.2\",\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"additionalProperties\": false,\n \"description\": \"Add a storage config: a named backend and how the community authenticates to it. Never a secret. The outer document members are owned by the framework — SPEC §6.3.\",\n \"properties\": {\n \"auth\": {\n \"$ref\": \"#/$defs/StorageAuth\"\n },\n \"capacityBytes\": {\n \"description\": \"Total ciphertext bytes the community will store on this config across every room. Absent means none set.\",\n \"minimum\": 0,\n \"type\": \"integer\"\n },\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\"\n },\n \"id\": {\n \"$ref\": \"#/$defs/StorageConfigId\"\n },\n \"isDefault\": {\n \"description\": \"Make this the config rooms are assigned to when neither policy nor creator names one.\",\n \"type\": \"boolean\"\n },\n \"label\": {\n \"description\": \"A display name for administrators and, with the kind, for a room's creator.\",\n \"maxLength\": 128,\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"reason\": {\n \"description\": \"Why the administrator is making this change. Recorded with the change in the audit trail and shown to approvers. Attributed to its author on every surface and untrusted: it MUST NOT carry personal data or a credential, and a reader MUST NOT treat it as instructions.\",\n \"maxLength\": 500,\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"settings\": {\n \"$ref\": \"#/$defs/StorageSettings\"\n }\n },\n \"required\": [\n \"id\",\n \"label\",\n \"settings\",\n \"reason\"\n ],\n \"title\": \"VTC Storage — Configs — Create — payload\",\n \"type\": \"object\"\n}\n",
);
}
impl crate::Payload for Response {
const TYPE_URI: &'static str =
"https://trusttasks.org/spec/vtc/storage/configs/create/0.2#response";
const IS_PROOF_REQUIRED: bool = true;
const IS_ISSUED_AT_REQUIRED: bool = true;
const IS_RECIPIENT_REQUIRED: bool = true;
const PAYLOAD_SCHEMA: Option<&'static str> = Some(
"{\n \"$defs\": {\n \"AwsRoleArn\": {\n \"description\": \"The ARN of an AWS IAM role, in any AWS partition (`arn:aws:`, `arn:aws-cn:`, `arn:aws-us-gov:`). Validated here because the community passes it to STS AssumeRole and derives the partition of the session policy's resources from it; it must never carry anything but a role ARN.\",\n \"maxLength\": 2048,\n \"minLength\": 20,\n \"pattern\": \"^arn:aws(-[a-z]+)*:iam::[0-9]{12}:role/[A-Za-z0-9+=,.@_/-]{1,512}$\",\n \"title\": \"AwsRoleArn\",\n \"type\": \"string\"\n },\n \"ConfigState\": {\n \"description\": \"`active`: accepts new rooms and new uploads. `draining`: retired by an administrator while blobs still name it — refuses new rooms and new uploads, keeps serving reads, and becomes `retired` when a migration has emptied it. `retired`: refuses new rooms and new uploads and holds no blob. A config is never deleted while a blob names it.\",\n \"enum\": [\n \"active\",\n \"draining\",\n \"retired\"\n ],\n \"title\": \"ConfigState\",\n \"type\": \"string\"\n },\n \"Ext\": {\n \"additionalProperties\": true,\n \"description\": \"Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.\",\n \"minProperties\": 1,\n \"propertyNames\": {\n \"pattern\": \"^[a-z][a-z0-9-]*(\\\\.[a-z0-9-]+)+$\"\n },\n \"title\": \"Ext\",\n \"type\": \"object\"\n },\n \"ExternalAccountContextId\": {\n \"description\": \"The context at the community's VTA that owns an external account. The VTA names an account by its context and its identifier, and decides who may use it by act scope in that context: the community must hold `external-auth-use` there, and be bound to the account, for the account to issue it anything. Naming a context grants nothing; the VTA's binding is the gate.\",\n \"maxLength\": 256,\n \"minLength\": 1,\n \"title\": \"ExternalAccountContextId\",\n \"type\": \"string\"\n },\n \"ExternalAccountId\": {\n \"description\": \"The identifier of an external account held by the community's VTA (the external/accounts/* family), which issues the community short-lived, room-scoped credentials and holds the long-lived authority itself.\",\n \"maxLength\": 64,\n \"minLength\": 1,\n \"pattern\": \"^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$\",\n \"title\": \"ExternalAccountId\",\n \"type\": \"string\"\n },\n \"GcsSettings\": {\n \"additionalProperties\": false,\n \"properties\": {\n \"bucket\": {\n \"description\": \"The bucket name. Validated against GCS naming rules here, because it is placed in a Credential Access Boundary condition and must never carry anything but a name.\",\n \"maxLength\": 222,\n \"minLength\": 3,\n \"pattern\": \"^[a-z0-9][a-z0-9._-]{1,220}[a-z0-9]$\",\n \"type\": \"string\"\n },\n \"kind\": {\n \"const\": \"gcs\"\n },\n \"prefix\": {\n \"$ref\": \"#/$defs/ObjectPrefix\"\n }\n },\n \"required\": [\n \"kind\",\n \"bucket\"\n ],\n \"title\": \"GcsSettings\",\n \"type\": \"object\"\n },\n \"LocalSettings\": {\n \"additionalProperties\": false,\n \"properties\": {\n \"kind\": {\n \"const\": \"local\"\n },\n \"root\": {\n \"description\": \"Absolute path of the directory the community writes blobs under, on its own host. Created owner-only. Not carried by the community's backup: back it up beside it.\",\n \"maxLength\": 1024,\n \"minLength\": 1,\n \"pattern\": \"^/\",\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"kind\",\n \"root\"\n ],\n \"title\": \"LocalSettings\",\n \"type\": \"object\"\n },\n \"ObjectPrefix\": {\n \"description\": \"A key prefix inside the bucket, ending in `/`, under which the config's `rooms/` tree is placed. Restricted to the S3 safe-character set so that it can be placed in a downscoped policy without escaping.\",\n \"maxLength\": 256,\n \"minLength\": 1,\n \"pattern\": \"^[A-Za-z0-9!_.*'()/-]+/$\",\n \"title\": \"ObjectPrefix\",\n \"type\": \"string\"\n },\n \"Response\": {\n \"$anchor\": \"response\",\n \"additionalProperties\": false,\n \"properties\": {\n \"config\": {\n \"$ref\": \"#/$defs/StorageConfig\"\n },\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\"\n }\n },\n \"required\": [\n \"config\"\n ],\n \"title\": \"VTC Storage — Configs — Create — response payload\",\n \"type\": \"object\"\n },\n \"S3Settings\": {\n \"additionalProperties\": false,\n \"properties\": {\n \"bucket\": {\n \"description\": \"The bucket name. Validated against S3 naming rules here, because it is placed in downscoped session policies and must never carry anything but a name.\",\n \"maxLength\": 63,\n \"minLength\": 3,\n \"pattern\": \"^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$\",\n \"type\": \"string\"\n },\n \"endpoint\": {\n \"description\": \"The S3 API endpoint, for a store other than AWS (R2, B2, MinIO). Absent means AWS S3 in `region`. HTTPS only.\",\n \"format\": \"uri\",\n \"maxLength\": 2048,\n \"pattern\": \"^https://\",\n \"type\": \"string\"\n },\n \"kind\": {\n \"const\": \"s3\"\n },\n \"pathStyle\": {\n \"description\": \"Address the bucket in the path rather than the host name, as MinIO usually needs. Absent means virtual-hosted style.\",\n \"type\": \"boolean\"\n },\n \"prefix\": {\n \"$ref\": \"#/$defs/ObjectPrefix\"\n },\n \"region\": {\n \"description\": \"The bucket's region, as the store names it (`eu-west-1`; `auto` for R2).\",\n \"maxLength\": 64,\n \"minLength\": 1,\n \"pattern\": \"^[a-z0-9-]+$\",\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"kind\",\n \"region\",\n \"bucket\"\n ],\n \"title\": \"S3Settings\",\n \"type\": \"object\"\n },\n \"StorageAuth\": {\n \"description\": \"How the community authenticates to a config's backend. Absent on a `local` config, which needs none.\\n\\n`vta-account` (RECOMMENDED): an external account in the community's VTA, named by the context that owns it and its identifier there. The VTA holds the long-lived authority; the community holds nothing that outlives a credential lifetime, and asks for credentials scoped to one room's prefix for at most 15 minutes, every issuance audited at the VTA. Required for a `walrus` config other than a `sealed` one, since the VTA's `sui-signer` account signs its storage transactions.\\n\\n`ambient`: the cloud identity of the machine the community runs on (an instance role, workload identity), downscoped to one room's prefix by the community itself under the rules of vtc/storage/configs/create/0.2 — on `s3`, by assuming `roleArn` (or the role the host is configured with) with an inline session policy; on `gcs`, by a Credential Access Boundary. Not audited or rate-limited by the VTA, and usable by anything on that machine that reaches the metadata endpoint. Not valid for `walrus`; `roleArn` is valid only on `s3`.\\n\\n`sealed` (discouraged): a long-lived credential stored by the community, set with vtc/storage/credentials/set (0.2: a `SealedStorageCredential`). Protects against every administrator through every surface the community offers; does NOT protect against whoever operates the machine, and a community labels it so wherever the config is shown.\\n\\n`ambient` and `sealed` are host-operator choices: a community MAY refuse either by its own host configuration, whatever its administrators ask.\",\n \"oneOf\": [\n {\n \"additionalProperties\": false,\n \"properties\": {\n \"account\": {\n \"$ref\": \"#/$defs/ExternalAccountId\"\n },\n \"context\": {\n \"$ref\": \"#/$defs/ExternalAccountContextId\"\n },\n \"mode\": {\n \"const\": \"vta-account\"\n }\n },\n \"required\": [\n \"mode\",\n \"context\",\n \"account\"\n ],\n \"type\": \"object\"\n },\n {\n \"additionalProperties\": false,\n \"properties\": {\n \"mode\": {\n \"const\": \"ambient\"\n },\n \"roleArn\": {\n \"$ref\": \"#/$defs/AwsRoleArn\",\n \"description\": \"`s3` only: the IAM role the community assumes, with the machine's ambient identity, to obtain each room-scoped session. Absent, the community assumes the role its host configuration names, and with none configured, the role of the ambient identity itself (which must then trust itself to be assumed). Refused on any other kind with `authNotAllowed`.\"\n }\n },\n \"required\": [\n \"mode\"\n ],\n \"type\": \"object\"\n },\n {\n \"additionalProperties\": false,\n \"properties\": {\n \"mode\": {\n \"const\": \"sealed\"\n }\n },\n \"required\": [\n \"mode\"\n ],\n \"type\": \"object\"\n }\n ],\n \"title\": \"StorageAuth\"\n },\n \"StorageConfig\": {\n \"additionalProperties\": false,\n \"description\": \"One storage config as the community holds it. Carries no secret.\",\n \"properties\": {\n \"auth\": {\n \"$ref\": \"#/$defs/StorageAuth\"\n },\n \"capacityBytes\": {\n \"description\": \"Total ciphertext bytes the community will store on this config, across every room assigned to it. A capacity, not a policy: an upload that would cross it is refused with scope `storage`. Absent means no capacity set.\",\n \"minimum\": 0,\n \"type\": \"integer\"\n },\n \"createdAt\": {\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"createdBy\": {\n \"maxLength\": 2048,\n \"pattern\": \"^did:\",\n \"type\": \"string\"\n },\n \"id\": {\n \"$ref\": \"#/$defs/StorageConfigId\"\n },\n \"isDefault\": {\n \"description\": \"True for the config a room is assigned to when neither the community's policy nor its creator names one.\",\n \"type\": \"boolean\"\n },\n \"label\": {\n \"description\": \"A display name for administrators (`EU — S3 (main account)`). Shown to a room's creator with the config's kind when the community lets them choose.\",\n \"maxLength\": 128,\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"settings\": {\n \"$ref\": \"#/$defs/StorageSettings\"\n },\n \"state\": {\n \"$ref\": \"#/$defs/ConfigState\"\n },\n \"updatedAt\": {\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"updatedBy\": {\n \"maxLength\": 2048,\n \"pattern\": \"^did:\",\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"id\",\n \"label\",\n \"settings\",\n \"state\",\n \"createdBy\",\n \"createdAt\"\n ],\n \"title\": \"StorageConfig\",\n \"type\": \"object\"\n },\n \"StorageConfigId\": {\n \"description\": \"A storage config's identifier, chosen by the administrator who creates it and immutable thereafter: lowercase letters, digits and inner hyphens, at most 64 characters (`eu-s3-primary`, `walrus-main`). Unique within the community. Never reused after a config is retired, because blobs name their config by this value.\",\n \"maxLength\": 64,\n \"minLength\": 1,\n \"pattern\": \"^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$\",\n \"title\": \"StorageConfigId\",\n \"type\": \"string\"\n },\n \"StorageSettings\": {\n \"description\": \"A config's backend settings, discriminated by `kind`. Never a secret: a credential is a StorageAuth, held elsewhere.\",\n \"oneOf\": [\n {\n \"$ref\": \"#/$defs/LocalSettings\"\n },\n {\n \"$ref\": \"#/$defs/S3Settings\"\n },\n {\n \"$ref\": \"#/$defs/GcsSettings\"\n },\n {\n \"$ref\": \"#/$defs/WalrusSettings\"\n }\n ],\n \"title\": \"StorageSettings\"\n },\n \"WalrusSettings\": {\n \"additionalProperties\": false,\n \"properties\": {\n \"aggregatorUrl\": {\n \"description\": \"The Walrus aggregator the community reads through.\",\n \"format\": \"uri\",\n \"maxLength\": 2048,\n \"pattern\": \"^https://\",\n \"type\": \"string\"\n },\n \"epochs\": {\n \"description\": \"Storage epochs to buy when a blob is registered. Walrus sells storage in epochs (two weeks on mainnet) and caps one purchase at 53.\",\n \"maximum\": 53,\n \"minimum\": 1,\n \"type\": \"integer\"\n },\n \"extendBeforeEpochs\": {\n \"description\": \"How many epochs before a live blob's end epoch the community extends it. A blob that has become an orphan is not extended, and lapses: the Walrus form of deletion.\",\n \"maximum\": 52,\n \"minimum\": 1,\n \"type\": \"integer\"\n },\n \"kind\": {\n \"const\": \"walrus\"\n },\n \"relayUrl\": {\n \"description\": \"The Walrus upload relay the community writes through. The community never runs a publisher: a publisher holds a hot wallet in its own configuration, which is the long-lived secret these tasks exist to avoid.\",\n \"format\": \"uri\",\n \"maxLength\": 2048,\n \"pattern\": \"^https://\",\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"kind\",\n \"relayUrl\",\n \"aggregatorUrl\",\n \"epochs\",\n \"extendBeforeEpochs\"\n ],\n \"title\": \"WalrusSettings\",\n \"type\": \"object\"\n }\n },\n \"$ref\": \"#/$defs/Response\",\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\"\n}\n",
);
}
impl crate::RequestPayload for Payload {
type Response = Response;
}
/// The extended error codes this specification declares (SPEC §7.3 item 9,
/// §8.5), in declaration order. Empty when it declares none.
pub const ERROR_CODES: &[crate::DeclaredErrorCode] = &[
error_codes::EXISTS,
error_codes::INVALID_SETTINGS,
error_codes::AUTH_NOT_ALLOWED,
error_codes::UNKNOWN_ACCOUNT,
];
/// One constant per extended error code this specification declares
/// (SPEC §7.3 item 9), named for its local part.
///
/// Emit these rather than a string literal: the code is read from the
/// specification, so it cannot name a code the specification never
/// declared.
pub mod error_codes {
/// `vtc/storage/configs/create:exists`
///
/// A config with this identifier exists, or existed and was retired; identifiers are never reused, because blobs name their config by it.
///
/// Declared `retryable: false`.
pub const EXISTS: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "vtc/storage/configs/create:exists",
retryable: false,
details_schema: ::core::option::Option::None,
};
/// `vtc/storage/configs/create:invalidSettings`
///
/// The settings are well-formed but unusable — a `local` root the community may not write, an endpoint it will not reach, a bucket name the backend rejects. `details` names the member and the problem.
///
/// Declared `retryable: false`.
/// Declares a `detailsSchema` for the error's `details` member.
pub const INVALID_SETTINGS: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "vtc/storage/configs/create:invalidSettings",
retryable: false,
details_schema: ::core::option::Option::Some(
"{\"additionalProperties\":false,\"properties\":{\"member\":{\"maxLength\":64,\"type\":\"string\"},\"problem\":{\"maxLength\":500,\"type\":\"string\"}},\"required\":[\"member\",\"problem\"],\"type\":\"object\"}",
),
};
/// `vtc/storage/configs/create:authNotAllowed`
///
/// `auth` is not accepted for this config. `details.reason` says why: `doesNotFitKind` — present on a `local` config, absent on any other, or `ambient` on a `walrus` config (Walrus storage is paid for by a signer, which no ambient cloud identity provides); `roleArnNotApplicable` — `roleArn` on a kind other than `s3`; `disabledByHost` — `ambient` or `sealed` on a community whose host configuration does not permit that mode.
///
/// Declared `retryable: false`.
/// Declares a `detailsSchema` for the error's `details` member.
pub const AUTH_NOT_ALLOWED: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "vtc/storage/configs/create:authNotAllowed",
retryable: false,
details_schema: ::core::option::Option::Some(
"{\"additionalProperties\":false,\"properties\":{\"reason\":{\"enum\":[\"doesNotFitKind\",\"roleArnNotApplicable\",\"disabledByHost\"],\"type\":\"string\"}},\"required\":[\"reason\"],\"type\":\"object\"}",
),
};
/// `vtc/storage/configs/create:unknownAccount`
///
/// `auth.context` and `auth.account` name no external account at the community's VTA that the community is bound to use.
///
/// Declared `retryable: false`.
pub const UNKNOWN_ACCOUNT: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "vtc/storage/configs/create:unknownAccount",
retryable: false,
details_schema: ::core::option::Option::None,
};
}