1use serde::Deserialize;
2use serde::Serialize;
3use strum_macros::Display;
4use thiserror::Error;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Display, Serialize, Deserialize)]
8#[serde(rename_all = "lowercase")]
9pub enum AuthMode {
10 ApiKey,
12 Chatgpt,
14 #[serde(rename = "chatgptAuthTokens")]
16 #[strum(serialize = "chatgptAuthTokens")]
17 ChatgptAuthTokens,
18 #[serde(rename = "headers")]
20 #[strum(serialize = "headers")]
21 Headers,
22 #[serde(rename = "agentIdentity")]
24 #[strum(serialize = "agentIdentity")]
25 AgentIdentity,
26 #[serde(rename = "personalAccessToken")]
28 #[strum(serialize = "personalAccessToken")]
29 PersonalAccessToken,
30 #[serde(rename = "bedrockApiKey")]
32 #[strum(serialize = "bedrockApiKey")]
33 BedrockApiKey,
34}
35
36impl AuthMode {
37 pub fn has_chatgpt_account(self) -> bool {
39 match self {
40 Self::Chatgpt | Self::ChatgptAuthTokens | Self::PersonalAccessToken => true,
41 Self::ApiKey | Self::Headers | Self::AgentIdentity | Self::BedrockApiKey => false,
42 }
43 }
44
45 pub fn uses_codex_backend(self) -> bool {
47 match self {
48 Self::Chatgpt
49 | Self::ChatgptAuthTokens
50 | Self::Headers
51 | Self::AgentIdentity
52 | Self::PersonalAccessToken => true,
53 Self::ApiKey | Self::BedrockApiKey => false,
54 }
55 }
56}
57
58#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
59#[serde(untagged)]
60pub enum PlanType {
61 Known(KnownPlan),
62 Unknown(String),
63}
64
65impl PlanType {
66 pub fn from_raw_value(raw: &str) -> Self {
67 match raw.to_ascii_lowercase().as_str() {
68 "free" => Self::Known(KnownPlan::Free),
69 "go" => Self::Known(KnownPlan::Go),
70 "plus" => Self::Known(KnownPlan::Plus),
71 "pro" => Self::Known(KnownPlan::Pro),
72 "prolite" => Self::Known(KnownPlan::ProLite),
73 "team" => Self::Known(KnownPlan::Team),
74 "self_serve_business_usage_based" => {
75 Self::Known(KnownPlan::SelfServeBusinessUsageBased)
76 }
77 "business" => Self::Known(KnownPlan::Business),
78 "enterprise_cbp_usage_based" => Self::Known(KnownPlan::EnterpriseCbpUsageBased),
79 "enterprise" | "hc" => Self::Known(KnownPlan::Enterprise),
80 "education" | "edu" => Self::Known(KnownPlan::Edu),
81 _ => Self::Unknown(raw.to_string()),
82 }
83 }
84}
85
86#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
87#[serde(rename_all = "lowercase")]
88pub enum KnownPlan {
89 Free,
90 Go,
91 Plus,
92 Pro,
93 ProLite,
94 Team,
95 #[serde(rename = "self_serve_business_usage_based")]
96 SelfServeBusinessUsageBased,
97 Business,
98 #[serde(rename = "enterprise_cbp_usage_based")]
99 EnterpriseCbpUsageBased,
100 #[serde(alias = "hc")]
101 Enterprise,
102 #[serde(alias = "education")]
103 Edu,
104}
105
106impl KnownPlan {
107 pub fn display_name(self) -> &'static str {
108 match self {
109 Self::Free => "Free",
110 Self::Go => "Go",
111 Self::Plus => "Plus",
112 Self::Pro => "Pro",
113 Self::ProLite => "Pro Lite",
114 Self::Team => "Team",
115 Self::SelfServeBusinessUsageBased => "Self Serve Business Usage Based",
116 Self::Business => "Business",
117 Self::EnterpriseCbpUsageBased => "Enterprise CBP Usage Based",
118 Self::Enterprise => "Enterprise",
119 Self::Edu => "Edu",
120 }
121 }
122
123 pub fn raw_value(self) -> &'static str {
124 match self {
125 Self::Free => "free",
126 Self::Go => "go",
127 Self::Plus => "plus",
128 Self::Pro => "pro",
129 Self::ProLite => "prolite",
130 Self::Team => "team",
131 Self::SelfServeBusinessUsageBased => "self_serve_business_usage_based",
132 Self::Business => "business",
133 Self::EnterpriseCbpUsageBased => "enterprise_cbp_usage_based",
134 Self::Enterprise => "enterprise",
135 Self::Edu => "edu",
136 }
137 }
138
139 pub fn is_workspace_account(self) -> bool {
140 matches!(
141 self,
142 Self::Team
143 | Self::SelfServeBusinessUsageBased
144 | Self::Business
145 | Self::EnterpriseCbpUsageBased
146 | Self::Enterprise
147 | Self::Edu
148 )
149 }
150}
151
152#[derive(Debug, Clone, PartialEq, Eq, Error)]
153#[error("{message}")]
154pub struct RefreshTokenFailedError {
155 pub reason: RefreshTokenFailedReason,
156 pub message: String,
157}
158
159impl RefreshTokenFailedError {
160 pub fn new(reason: RefreshTokenFailedReason, message: impl Into<String>) -> Self {
161 Self {
162 reason,
163 message: message.into(),
164 }
165 }
166}
167
168#[derive(Debug, Clone, Copy, PartialEq, Eq)]
169pub enum RefreshTokenFailedReason {
170 Expired,
171 Exhausted,
172 Revoked,
173 Other,
174}
175
176#[cfg(test)]
177mod tests {
178 use super::KnownPlan;
179 use super::PlanType;
180 use pretty_assertions::assert_eq;
181
182 #[test]
183 fn plan_type_deserializes_raw_aliases() {
184 assert_eq!(
185 serde_json::from_str::<PlanType>("\"hc\"").expect("hc should deserialize"),
186 PlanType::Known(KnownPlan::Enterprise)
187 );
188 assert_eq!(
189 serde_json::from_str::<PlanType>("\"education\"")
190 .expect("education should deserialize"),
191 PlanType::Known(KnownPlan::Edu)
192 );
193 }
194}