use super::reverification::ReverificationLevel;
use super::verification::InvalidTokenReason;
use serde_json::Value;
use thiserror::Error;
#[derive(Debug, Clone, Error, PartialEq, Eq)]
#[non_exhaustive]
pub enum ClerkError {
#[error("clerk has not finished loading")]
NotLoaded,
#[error("clerk lifecycle timed out: {0}")]
Timeout(String),
#[error("clerk-js is not available on this build target")]
UnsupportedTarget,
#[error("clerk-js failed to load: {0}")]
ScriptLoad(String),
#[error("clerk is offline")]
Offline,
#[error("unauthenticated")]
Unauthenticated,
#[error("session token expired")]
TokenExpired,
#[error("clerk jwks unavailable: {0}")]
JwksUnavailable(String),
#[error(
"no server context available; Clerk auth server context methods must be called inside a server function or SSR scope"
)]
NoServerContext,
#[error("invalid clerk configuration: {0}")]
InvalidConfig(String),
#[error("reverification required")]
NeedsReverification {
level: Option<ReverificationLevel>,
},
#[error("reverification cancelled")]
ReverificationCancelled,
#[error("clerk js error: {0}")]
Js(String),
}
impl ClerkError {
pub fn from_reverification_hint(value: &Value) -> Option<Self> {
let clerk_error = value.get("clerk_error")?;
if clerk_error.get("type").and_then(Value::as_str) != Some("forbidden")
|| clerk_error.get("reason").and_then(Value::as_str) != Some("reverification-error")
{
return None;
}
let level = clerk_error
.pointer("/metadata/reverification/level")
.and_then(Value::as_str)
.map(ReverificationLevel::from);
Some(Self::NeedsReverification { level })
}
}
impl From<InvalidTokenReason> for ClerkError {
fn from(reason: InvalidTokenReason) -> Self {
match reason {
InvalidTokenReason::Expired => Self::TokenExpired,
_ => Self::Unauthenticated,
}
}
}