vtx-sdk 0.1.14

Official SDK for developing VTX plugins using Rust and WebAssembly.
Documentation
use serde::{Deserialize, Serialize};
use std::fmt;

/// Plugin runtime error type (unified error model).
///
/// Defines all known errors that may occur during plugin execution.
/// All errors support serialization and can be used for HTTP responses or log transmission.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum VtxError {
    /// Underlying database error (e.g., SQL execution failure, constraint conflicts).
    DatabaseError(String),

    /// Serialization or deserialization failure (e.g., JSON format mismatch).
    SerializationError(String),

    /// Authentication failed (includes suggested HTTP status code, e.g., 401 / 403).
    AuthDenied(u16),

    /// Insufficient permissions (e.g., attempting a write operation in a read-only environment).
    PermissionDenied(String),

    /// Resource not found (e.g., file, video, or user not found).
    NotFound(String),

    /// Internal plugin logic error (fallback type).
    Internal(String),
}

impl VtxError {
    /// Maps the `string` error message returned from the host side to a reasonably classified error type.
    pub fn from_host_message(message: impl Into<String>) -> Self {
        let msg = message.into();
        let lower = msg.to_lowercase();

        if lower.contains("permission denied") {
            return VtxError::PermissionDenied(msg);
        }

        if lower.contains("uuid not found") || lower.contains("not found") {
            return VtxError::NotFound(msg);
        }

        VtxError::Internal(msg)
    }
}

impl fmt::Display for VtxError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            VtxError::DatabaseError(msg) => write!(f, "Database error: {}", msg),
            VtxError::SerializationError(msg) => write!(f, "Data serialization error: {}", msg),
            VtxError::AuthDenied(code) => write!(f, "Authentication denied (Code: {})", code),
            VtxError::PermissionDenied(msg) => write!(f, "Permission denied: {}", msg),
            VtxError::NotFound(msg) => write!(f, "Resource not found: {}", msg),
            VtxError::Internal(msg) => write!(f, "Internal error: {}", msg),
        }
    }
}

impl std::error::Error for VtxError {}

/// Short alias for `VtxError`.
pub type Error = VtxError;

/// Plugin standard result type alias.
///
/// Recommended for use in all interfaces returning `VtxError` to ensure a unified error chain.
pub type VtxResult<T> = std::result::Result<T, VtxError>;

/// Short alias for `VtxResult`.
pub type Result<T> = VtxResult<T>;

#[cfg(test)]
mod tests {
    use super::VtxError;

    #[test]
    fn from_host_message_maps_permission_denied() {
        let err = VtxError::from_host_message("Permission denied: read only");
        match err {
            VtxError::PermissionDenied(msg) => {
                assert!(msg.contains("Permission denied"));
            }
            _ => panic!("expected PermissionDenied"),
        }
    }

    #[test]
    fn from_host_message_maps_not_found() {
        let err = VtxError::from_host_message("UUID not found: 1234");
        match err {
            VtxError::NotFound(msg) => {
                assert!(msg.contains("not found"));
            }
            _ => panic!("expected NotFound"),
        }
    }

    #[test]
    fn from_host_message_defaults_to_internal() {
        let err = VtxError::from_host_message("something unexpected");
        match err {
            VtxError::Internal(msg) => {
                assert!(msg.contains("unexpected"));
            }
            _ => panic!("expected Internal"),
        }
    }

    #[test]
    fn display_formats_errors() {
        let err = VtxError::AuthDenied(401);
        assert_eq!(err.to_string(), "Authentication denied (Code: 401)");

        let err = VtxError::DatabaseError("boom".to_string());
        assert_eq!(err.to_string(), "Database error: boom");
    }
}