pub type Result<T> = std::result::Result<T, ToolkitError>;
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum ToolkitError {
#[error("failed to parse config TOML: {0}")]
Parse(#[from] toml::de::Error),
#[error("missing required config field: {0}")]
MissingField(String),
#[error("tool synthesis failed: {0}")]
Synth(String),
#[error("code-mode wiring failed: {0}")]
CodeMode(String),
#[error("I/O error: {0}")]
Io(#[from] std::io::Error),
#[error("secret '{name}' not resolvable: {cause}")]
Secret {
name: String,
cause: String,
},
#[error("config validation failed: {0}")]
Validation(#[from] ConfigValidationError),
}
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum ConfigValidationError {
#[error("server.name must be non-empty")]
EmptyServerName,
#[error("server.version must be non-empty")]
EmptyServerVersion,
#[error("[[tools]] entry at index {0} has empty name")]
EmptyToolName(usize),
#[error("[[database.tables]] entry at index {0} has empty name")]
EmptyTableName(usize),
#[error(
"[code_mode].token_secret is an inline literal; use 'env:VAR_NAME' \
or set allow_inline_token_secret_for_dev=true (NEVER in production)"
)]
InlineSecretRejected,
#[error(
"[[tools]] entry at index {0} declares ambiguous tool kind: set exactly \
one of `sql`, `path`/`method`, or `script` (not a mixture)"
)]
AmbiguousToolKind(usize),
#[error(
"[backend].base_url must be non-empty (set the REST API root URL, \
e.g. \"https://api.example.com\")"
)]
EmptyBackendBaseUrl,
}