Skip to main content

walletkit_core/storage/
error.rs

1//! Error types for credential storage components.
2
3use thiserror::Error;
4
5/// Result type for storage operations.
6pub type StorageResult<T> = Result<T, StorageError>;
7
8/// Errors raised by credential storage primitives.
9#[derive(Debug, Error, uniffi::Error)]
10pub enum StorageError {
11    /// Errors coming from the device keystore.
12    #[error("keystore error: {0}")]
13    Keystore(String),
14
15    /// Errors coming from the blob store.
16    #[error("blob store error: {0}")]
17    BlobStore(String),
18
19    /// Errors coming from the storage lock.
20    #[error("storage lock error: {0}")]
21    Lock(String),
22
23    /// Serialization/deserialization failures.
24    #[error("serialization error: {0}")]
25    Serialization(String),
26
27    /// Cryptographic failures (AEAD, HKDF, etc.).
28    #[error("crypto error: {0}")]
29    Crypto(String),
30
31    /// Invalid or malformed account key envelope.
32    #[error("invalid envelope: {0}")]
33    InvalidEnvelope(String),
34
35    /// Invalid input supplied to a storage operation.
36    #[error("invalid input: {0}")]
37    InvalidInput(String),
38
39    /// Unsupported envelope version.
40    #[error("unsupported envelope version: {0}")]
41    UnsupportedEnvelopeVersion(u32),
42
43    /// Errors coming from the vault database.
44    #[error("vault db error: {0}")]
45    VaultDb(String),
46
47    /// Errors coming from the cache database.
48    #[error("cache db error: {0}")]
49    CacheDb(String),
50
51    /// Errors initializing or administering persistent browser storage.
52    #[error("persistent storage error: {0}")]
53    PersistentStorage(String),
54
55    /// Leaf index mismatch during initialization.
56    #[error("leaf index mismatch: expected {expected}, got {provided}")]
57    InvalidLeafIndex {
58        /// Leaf index stored in the vault.
59        expected: u64,
60        /// Leaf index provided by the caller.
61        provided: u64,
62    },
63
64    /// Vault database integrity check failed.
65    #[error("vault integrity check failed: {0}")]
66    CorruptedVault(String),
67
68    /// Storage has not been initialized yet.
69    #[error("storage not initialized")]
70    NotInitialized,
71
72    /// Nullifier already disclosed for a different request.
73    #[error("nullifier already disclosed")]
74    NullifierAlreadyDisclosed,
75
76    /// Credential not found in the vault.
77    #[error("credential not found")]
78    CredentialNotFound,
79
80    /// Credential ID not found when deleting from the vault.
81    #[error("credential id not found: {credential_id}")]
82    CredentialIdNotFound {
83        /// Credential ID provided by the caller.
84        credential_id: u64,
85    },
86
87    /// Corrupted cache entry
88    #[error("corrupted cache entry at {key_prefix}")]
89    CorruptedCacheEntry {
90        /// The prefix of the corrupted cache entry (identifies the type of entry).
91        key_prefix: u8,
92    },
93
94    /// Errors coming from the activity database.
95    #[error("activity db error: {0}")]
96    ActivityDb(String),
97
98    /// An `ActivityEntry` violated the `failure_reason`/`outcome` invariant.
99    #[error("invalid activity record: {0}")]
100    ActivityInvalidRecord(String),
101
102    /// Unexpected `UniFFI` callback error.
103    #[error("unexpected uniffi callback error: {0}")]
104    UnexpectedUniFFICallbackError(String),
105}
106
107impl From<uniffi::UnexpectedUniFFICallbackError> for StorageError {
108    fn from(error: uniffi::UnexpectedUniFFICallbackError) -> Self {
109        Self::UnexpectedUniFFICallbackError(error.reason)
110    }
111}
112
113/// 1-1 variant mapping is intentional: hosts pattern-match on `StorageError`
114/// for UX, and `walletkit-db` is uniffi-free by design, so the translation
115/// has to live in each FFI-exporting consumer. Don't flatten.
116///
117/// TODO: when a second consumer (`OrbKit`, `IssuerKit`) ships its own
118/// uniffi-exported error mirroring `StoreError`, extract this mapping into a
119/// shared `walletkit-ffi-shared` crate. Not worth it for one consumer.
120impl From<walletkit_db::StoreError> for StorageError {
121    fn from(err: walletkit_db::StoreError) -> Self {
122        match err {
123            walletkit_db::StoreError::Keystore(s) => Self::Keystore(s),
124            walletkit_db::StoreError::BlobStore(s) => Self::BlobStore(s),
125            walletkit_db::StoreError::Lock(s) => Self::Lock(s),
126            walletkit_db::StoreError::Serialization(s) => Self::Serialization(s),
127            walletkit_db::StoreError::Crypto(s) => Self::Crypto(s),
128            walletkit_db::StoreError::InvalidEnvelope(s) => Self::InvalidEnvelope(s),
129            walletkit_db::StoreError::InvalidInput(s) => Self::InvalidInput(s),
130            walletkit_db::StoreError::UnsupportedEnvelopeVersion(v) => {
131                Self::UnsupportedEnvelopeVersion(v)
132            }
133            walletkit_db::StoreError::Db(e) => Self::VaultDb(e.to_string()),
134            walletkit_db::StoreError::IntegrityCheckFailed(s) => {
135                Self::CorruptedVault(s)
136            }
137        }
138    }
139}