//! Managed temporary storage model. use serde::{Deserialize, Serialize}; use thiserror::Error; use crate::ids::ProjectId; use crate::ports::LocalPath; /// Opaque handle for an IdeA-managed temporary allocation. #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(transparent)] pub struct ManagedTempHandle(String); impl ManagedTempHandle { /// Builds a handle. /// /// # Errors /// [`ManagedTempError::Invalid`] when the handle is empty or path-like. pub fn new(value: impl Into) -> Result { let value = value.into(); if value.is_empty() || value.len() > 128 || !value .chars() .all(|c| c.is_ascii_alphanumeric() || c == '-' || c == '_') { return Err(ManagedTempError::Invalid( "invalid managed temp handle".to_owned(), )); } Ok(Self(value)) } /// Returns the raw handle. #[must_use] pub fn as_str(&self) -> &str { &self.0 } } /// Physical allocation kind. #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub enum ManagedTempKind { /// A directory allocation. Directory, /// An empty file allocation. File, } /// Lease lifecycle state. #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub enum ManagedTempState { /// The allocation can still be resolved. Active, /// The allocation was explicitly released and is GC-eligible. Released, } /// Allocation request persisted by the store. #[derive(Debug, Clone, PartialEq, Eq)] pub struct ManagedTempAllocation { /// Opaque handle allocated by the application layer. pub handle: ManagedTempHandle, /// Physical allocation kind. pub kind: ManagedTempKind, /// Optional project that requested the allocation. pub owner_project_id: Option, /// Short human/debug purpose. pub purpose: String, /// Creation time, epoch milliseconds. pub created_at_ms: u64, /// Optional expiry time, epoch milliseconds. pub expires_at_ms: Option, } /// Resolved managed temporary lease. #[derive(Debug, Clone, PartialEq, Eq)] pub struct ManagedTempLease { /// Opaque handle. pub handle: ManagedTempHandle, /// Physical allocation kind. pub kind: ManagedTempKind, /// Optional project that requested the allocation. pub owner_project_id: Option, /// Short human/debug purpose. pub purpose: String, /// Managed local path. It is produced by IdeA, never accepted as user input. pub path: LocalPath, /// Lease state. pub state: ManagedTempState, /// Creation time, epoch milliseconds. pub created_at_ms: u64, /// Last successful resolve time, epoch milliseconds. pub last_access_at_ms: u64, /// Optional expiry time, epoch milliseconds. pub expires_at_ms: Option, /// Explicit release time, epoch milliseconds. pub released_at_ms: Option, } /// GC outcome. #[derive(Debug, Clone, PartialEq, Eq)] pub struct ManagedTempGcReport { /// Number of deleted allocations. pub deleted: usize, } /// Managed temporary store errors. #[derive(Debug, Clone, PartialEq, Eq, Error)] pub enum ManagedTempError { /// Handle does not exist or is no longer resolvable. #[error("managed temp not found")] NotFound, /// Invalid input or persisted metadata. #[error("managed temp invalid: {0}")] Invalid(String), /// Store I/O or serialization failed. #[error("managed temp store failed: {0}")] Store(String), }