Skip to main content

contextvm_sdk/transport/oversized_transfer/
errors.rs

1//! Error taxonomy for CEP-22 oversized transfers.
2//!
3//! Mirrors the TypeScript SDK's error classes
4//! (`sdk/src/transport/oversized-transfer/errors.ts`) so failure classification
5//! is identical across implementations. Surfaced through the crate-level
6//! [`crate::Error`] via a `#[from]` conversion.
7
8/// Errors raised while building, framing, or reassembling an oversized transfer.
9#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
10pub enum OversizedTransferError {
11    /// The remote peer aborted the transfer (terminal).
12    #[error("Transfer aborted (token: {token}){}", .reason.as_deref().map(|r| format!(": {r}")).unwrap_or_default())]
13    Abort {
14        /// The `progressToken` of the aborted transfer.
15        token: String,
16        /// Optional advisory reason supplied in the `abort` frame.
17        reason: Option<String>,
18    },
19
20    /// A frame violated a declared or configured policy limit
21    /// (`totalBytes`, `totalChunks`, concurrency, out-of-order bounds, chunk size).
22    #[error("Oversized transfer policy violation: {0}")]
23    Policy(String),
24
25    /// The byte length or SHA-256 digest of the reassembled payload did not match
26    /// the values declared in the `start` frame.
27    #[error("Oversized transfer integrity error: {0}")]
28    Digest(String),
29
30    /// Chunks could not be reassembled (missing frames, unresolved gaps, or the
31    /// reassembled payload is not a valid JSON-RPC message).
32    #[error("Oversized transfer reassembly error: {0}")]
33    Reassembly(String),
34
35    /// Frames violated CEP-22 sequencing rules (bad progress ordering,
36    /// duplicate `start`, conflicting duplicate chunk, missing token).
37    #[error("Oversized transfer sequence error: {0}")]
38    Sequence(String),
39}
40
41impl OversizedTransferError {
42    /// Construct an [`OversizedTransferError::Abort`].
43    pub fn abort(token: impl Into<String>, reason: Option<String>) -> Self {
44        Self::Abort {
45            token: token.into(),
46            reason,
47        }
48    }
49
50    /// Returns `true` if this is a terminal [`abort`](OversizedTransferError::Abort).
51    pub fn is_abort(&self) -> bool {
52        matches!(self, Self::Abort { .. })
53    }
54}