use super::ThreadUsage; use crate::JsonSchema; use crate::TS; use crate::protocol::common::AuthMode; use codex_experimental_api_macros::ExperimentalApi; use codex_protocol::account::PlanType; use codex_protocol::account::ProviderAccount; use codex_protocol::protocol::CreditsSnapshot as CoreCreditsSnapshot; use codex_protocol::protocol::RateLimitReachedType as CoreRateLimitReachedType; use codex_protocol::protocol::RateLimitSnapshot as CoreRateLimitSnapshot; use codex_protocol::protocol::RateLimitWindow as CoreRateLimitWindow; use codex_protocol::protocol::SpendControlLimitSnapshot as CoreSpendControlLimitSnapshot; use serde::Deserialize; use serde::Serialize; use std::collections::HashMap; use std::fmt; #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(tag = "type", rename_all = "camelCase")] #[ts(tag = "type")] #[ts(export_to = "v2/")] pub enum Account { #[serde(rename = "apiKey", rename_all = "camelCase")] #[ts(rename = "apiKey", rename_all = "camelCase")] ApiKey {}, #[serde(rename = "chatgpt", rename_all = "camelCase")] #[ts(rename = "chatgpt", rename_all = "camelCase")] Chatgpt { #[schemars( required, schema_with = "crate::protocol::serde_helpers::nullable_string_schema" )] email: Option, plan_type: PlanType, }, #[serde(rename = "amazonBedrock", rename_all = "camelCase")] #[ts(rename = "amazonBedrock", rename_all = "camelCase")] AmazonBedrock { #[serde(default)] uses_codex_managed_credentials: bool, }, } impl From for Account { fn from(account: ProviderAccount) -> Self { match account { ProviderAccount::ApiKey => Self::ApiKey {}, ProviderAccount::Chatgpt { email, plan_type } => Self::Chatgpt { email, plan_type }, ProviderAccount::AmazonBedrock { uses_codex_managed_credentials, } => Self::AmazonBedrock { uses_codex_managed_credentials, }, } } } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS, ExperimentalApi)] #[serde(tag = "type")] #[ts(tag = "type")] #[ts(export_to = "v2/")] pub enum LoginAccountParams { #[serde(rename = "apiKey", rename_all = "camelCase")] #[ts(rename = "apiKey", rename_all = "camelCase")] ApiKey { #[serde(rename = "apiKey")] #[ts(rename = "apiKey")] api_key: String, }, #[serde(rename = "chatgpt", rename_all = "camelCase")] #[ts(rename = "chatgpt", rename_all = "camelCase")] Chatgpt { #[serde(default, skip_serializing_if = "std::ops::Not::not")] codex_streamlined_login: bool, #[serde(default, skip_serializing_if = "std::ops::Not::not")] use_hosted_login_success_page: bool, #[serde(default)] #[ts(optional = nullable)] app_brand: Option, }, #[serde(rename = "chatgptDeviceCode")] #[ts(rename = "chatgptDeviceCode")] ChatgptDeviceCode, /// [UNSTABLE] FOR OPENAI INTERNAL USE ONLY - DO NOT USE. /// The access token must contain the same scopes that Codex-managed ChatGPT auth tokens have. #[experimental("account/login/start.chatgptAuthTokens")] #[serde(rename = "chatgptAuthTokens", rename_all = "camelCase")] #[ts(rename = "chatgptAuthTokens", rename_all = "camelCase")] ChatgptAuthTokens { /// Access token (JWT) supplied by the client. /// This token is used for backend API requests and email extraction. access_token: String, /// Workspace/account identifier supplied by the client. chatgpt_account_id: String, /// Optional plan type supplied by the client. /// /// When `null`, Codex attempts to derive the plan type from access-token /// claims. If unavailable, the plan defaults to `unknown`. #[ts(optional = nullable)] chatgpt_plan_type: Option, }, /// [UNSTABLE] Managed Amazon Bedrock login is experimental. #[experimental("account/login/start.amazonBedrock")] #[serde(rename = "amazonBedrock", rename_all = "camelCase")] #[ts(rename = "amazonBedrock", rename_all = "camelCase")] AmazonBedrock { api_key: String, region: String }, /// [UNSTABLE] Managed Amazon Bedrock AWS access key login is experimental. #[experimental("account/login/start.amazonBedrockAccessKeys")] #[serde(rename = "amazonBedrockAccessKeys", rename_all = "camelCase")] #[ts(rename = "amazonBedrockAccessKeys", rename_all = "camelCase")] AmazonBedrockAccessKeys { access_key_id: String, secret_access_key: String, #[ts(optional = nullable)] session_token: Option, region: String, }, } #[derive(Serialize, Deserialize, Debug, Default, Clone, Copy, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "lowercase")] #[ts(rename_all = "lowercase")] #[ts(export_to = "v2/")] pub enum LoginAppBrand { #[default] Codex, Chatgpt, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(tag = "type", rename_all = "camelCase")] #[ts(tag = "type")] #[ts(export_to = "v2/")] pub enum LoginAccountResponse { #[serde(rename = "apiKey", rename_all = "camelCase")] #[ts(rename = "apiKey", rename_all = "camelCase")] ApiKey {}, #[serde(rename = "chatgpt", rename_all = "camelCase")] #[ts(rename = "chatgpt", rename_all = "camelCase")] Chatgpt { // Use plain String for identifiers to avoid TS/JSON Schema quirks around uuid-specific types. // Convert to/from UUIDs at the application layer as needed. login_id: String, /// URL the client should open in a browser to initiate the OAuth flow. auth_url: String, }, #[serde(rename = "chatgptDeviceCode", rename_all = "camelCase")] #[ts(rename = "chatgptDeviceCode", rename_all = "camelCase")] ChatgptDeviceCode { // Use plain String for identifiers to avoid TS/JSON Schema quirks around uuid-specific types. // Convert to/from UUIDs at the application layer as needed. login_id: String, /// URL the client should open in a browser to complete device code authorization. verification_url: String, /// One-time code the user must enter after signing in. user_code: String, }, #[serde(rename = "chatgptAuthTokens", rename_all = "camelCase")] #[ts(rename = "chatgptAuthTokens", rename_all = "camelCase")] ChatgptAuthTokens {}, #[serde(rename = "amazonBedrock", rename_all = "camelCase")] #[ts(rename = "amazonBedrock", rename_all = "camelCase")] AmazonBedrock {}, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct CancelLoginAccountParams { pub login_id: String, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub enum CancelLoginAccountStatus { Canceled, NotFound, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct CancelLoginAccountResponse { pub status: CancelLoginAccountStatus, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct AccountSessionsAddParams { #[serde(default, skip_serializing_if = "std::ops::Not::not")] pub switch_to_added_account: bool, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct AccountSessionsListParams { #[serde(default, skip_serializing_if = "std::ops::Not::not")] pub refresh_workspace_metadata: bool, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct AccountSessionsLogoutParams { pub session_id: String, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct AccountSessionsSwitchParams { pub session_id: String, pub account_id: String, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct AccountSessionsResponse { pub active_session_id: Option, pub sessions: Vec, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct AccountSession { pub session_id: String, pub email: Option, pub user_id: Option, pub display_name: Option, pub image_url: Option, pub last_used_at: i64, pub is_active: bool, pub selected_workspace_account_id: Option, pub workspaces: Vec, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct AccountSessionWorkspace { pub account_id: String, pub name: Option, pub image_url: Option, pub kind: Option, } #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub enum AccountSessionWorkspaceKind { Personal, Workspace, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct LogoutAccountResponse {} #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub enum ChatgptAuthTokensRefreshReason { /// Codex attempted a backend request and received `401 Unauthorized`. Unauthorized, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct ChatgptAuthTokensRefreshParams { pub reason: ChatgptAuthTokensRefreshReason, /// Workspace/account identifier that Codex was previously using. /// /// Clients that manage multiple accounts/workspaces can use this as a hint /// to refresh the token for the correct workspace. /// /// This may be `null` when the prior auth state did not include a workspace /// identifier (`chatgpt_account_id`). #[ts(optional = nullable)] pub previous_account_id: Option, } #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct ChatgptAuthTokensRefreshResponse { pub access_token: String, pub chatgpt_account_id: String, pub chatgpt_plan_type: Option, } impl fmt::Debug for ChatgptAuthTokensRefreshResponse { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ChatgptAuthTokensRefreshResponse") .field("access_token", &"") .field("chatgpt_account_id", &self.chatgpt_account_id) .field("chatgpt_plan_type", &self.chatgpt_plan_type) .finish() } } /// Usage-read capabilities of the requesting client, never inferred from its experiment arm. #[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct GetAccountRateLimitsParams { /// The client supports automatic Luna Reserve fallback. For eligible ChatGPT CLI users, /// allow the backend to record experiment exposure after ordinary usage is blocked. #[serde(default, skip_serializing_if = "std::ops::Not::not")] pub supports_luna_reserve: bool, /// Skip the separate reset-credit detail lookup for background usage polls. The usage /// response still includes the available count; omitted/false preserves detailed reads. #[serde(default, skip_serializing_if = "std::ops::Not::not")] pub exclude_reset_credit_details: bool, } pub type NullableGetAccountRateLimitsParams = Option; #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct GetAccountRateLimitsResponse { /// Backend permission for ordinary included usage, validated against the active account. /// Null means unavailable; clients must not infer recovery from percentages or reset times. pub ordinary_usage_allowed: Option, /// Backward-compatible single-bucket view; mirrors the historical payload. pub rate_limits: RateLimitSnapshot, /// Multi-bucket view keyed by metered `limit_id` (for example, `codex`). pub rate_limits_by_limit_id: Option>, pub rate_limit_reset_credits: Option, /// Account associated with this usage snapshot, when supplied by the backend. pub account_id: Option, /// Optional backend-owned banner from the same usage read. Its nested keys retain the /// backend's snake_case contract; an absent banner leaves the client's existing UI unchanged. pub rate_limit_upsell: Option, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct RateLimitResetCreditsSummary { pub available_count: i64, /// Detail rows for available reset credits, when the backend provides them. /// /// `null` means only `availableCount` is known, while an empty array means details were fetched /// and no available credits were returned. The backend may cap this list, so its length can be /// less than `availableCount`. pub credits: Option>, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct RateLimitResetCredit { /// Opaque backend identifier for this reset credit. pub id: String, pub reset_type: RateLimitResetType, pub status: RateLimitResetCreditStatus, /// Unix timestamp in seconds when the credit was granted. #[ts(type = "number")] pub granted_at: i64, /// Unix timestamp in seconds when the credit expires, or `null` if it does not expire. #[ts(type = "number | null")] pub expires_at: Option, /// Backend-provided display title for this credit, or `null` when unavailable. pub title: Option, /// Backend-provided display description for this credit, or `null` when unavailable. pub description: Option, } #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/", rename_all = "camelCase")] pub enum RateLimitResetType { CodexRateLimits, #[serde(other)] Unknown, } #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/", rename_all = "camelCase")] pub enum RateLimitResetCreditStatus { Available, Redeeming, Redeemed, #[serde(other)] Unknown, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct ConsumeAccountRateLimitResetCreditParams { /// Identifies one logical reset attempt. A UUID is recommended; reuse the same value when /// retrying that attempt. pub idempotency_key: String, /// Opaque reset-credit identifier to redeem. When omitted, the backend selects the next /// available credit. #[ts(optional = nullable)] pub credit_id: Option, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct ConsumeAccountRateLimitResetCreditResponse { pub outcome: ConsumeAccountRateLimitResetCreditOutcome, } #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/", rename_all = "camelCase")] pub enum ConsumeAccountRateLimitResetCreditOutcome { /// A reset credit was consumed and the eligible rate-limit windows were reset. Reset, /// No current rate-limit window is eligible for a reset. NothingToReset, /// The account has no earned reset credits available. NoCredit, /// The same idempotency key already completed a reset successfully. AlreadyRedeemed, } #[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct GetAccountTokenUsageParams { /// When present, read estimated usage for this thread instead of account-wide token activity. #[ts(optional = nullable)] pub thread_id: Option, } pub type NullableGetAccountTokenUsageParams = Option; #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct GetAccountTokenUsageResponse { pub summary: AccountTokenUsageSummary, pub daily_usage_buckets: Option>, /// Estimated usage when a thread was requested and its billing route is available. #[serde(default)] #[ts(optional, as = "Option>")] pub thread_usage: Option, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct GetWorkspaceMessagesResponse { /// Whether the workspace-message backend route is available for this client. pub feature_enabled: bool, /// Active workspace messages returned by the backend. pub messages: Vec, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct WorkspaceMessage { pub message_id: String, pub message_type: WorkspaceMessageType, pub message_body: String, /// Unix timestamp (in seconds) when the message was created. #[ts(type = "number | null")] pub created_at: Option, /// Unix timestamp (in seconds) when the message was archived. #[ts(type = "number | null")] pub archived_at: Option, } #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "snake_case")] #[ts(export_to = "v2/", rename_all = "snake_case")] pub enum WorkspaceMessageType { Headline, Announcement, #[serde(other)] Unknown, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct AccountTokenUsageSummary { pub lifetime_tokens: Option, pub peak_daily_tokens: Option, pub longest_running_turn_sec: Option, pub current_streak_days: Option, pub longest_streak_days: Option, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct AccountTokenUsageDailyBucket { pub start_date: String, pub tokens: i64, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct SendAddCreditsNudgeEmailParams { pub credit_type: AddCreditsNudgeCreditType, } #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "snake_case")] #[ts(export_to = "v2/", rename_all = "snake_case")] pub enum AddCreditsNudgeCreditType { Credits, UsageLimit, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct SendAddCreditsNudgeEmailResponse { pub status: AddCreditsNudgeEmailStatus, } #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "snake_case")] #[ts(export_to = "v2/", rename_all = "snake_case")] pub enum AddCreditsNudgeEmailStatus { Sent, CooldownActive, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct GetAccountParams { /// When `true`, requests a proactive token refresh before returning. /// /// In managed auth mode this triggers the normal refresh-token flow. In /// external auth mode this flag is ignored. Clients should refresh tokens /// themselves and call `account/login/start` with `chatgptAuthTokens`. #[serde(default, skip_serializing_if = "std::ops::Not::not")] pub refresh_token: bool, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS, ExperimentalApi)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct GetAccountResponse { pub account: Option, pub requires_openai_auth: bool, #[experimental("account/read.workspaceRouting")] pub workspace_routing: Option, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct WorkspaceRouting { pub chatgpt_account_id: String, pub backend_origin: String, pub account_routing_override: AccountRoutingOverride, } /// Backend routing policy. Wire values match the accounts/check contract. #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "snake_case")] #[ts(export_to = "v2/", rename_all = "snake_case")] pub enum AccountRoutingOverride { #[serde(rename = "NO_CONSTRAINT")] #[ts(rename = "NO_CONSTRAINT")] NoConstraint, Us, UsCr, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct AccountUpdatedNotification { pub auth_mode: Option, pub plan_type: Option, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] /// Sparse rolling rate-limit update. /// /// Clients should merge available values into the most recent `account/rateLimits/read` response /// or refetch that snapshot. Nullable account metadata may be unavailable in a rolling update and /// does not clear a previously observed value. pub struct AccountRateLimitsUpdatedNotification { pub rate_limits: RateLimitSnapshot, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct RateLimitSnapshot { pub limit_id: Option, pub limit_name: Option, /// Normal model whose display name and reasoning options describe this quota alias. pub normal_model_slug: Option, pub primary: Option, pub secondary: Option, pub credits: Option, pub individual_limit: Option, /// Backend-reported spend-control state. `None` is unavailable, not a sparse-update recovery. pub spend_control_reached: Option, pub plan_type: Option, pub rate_limit_reached_type: Option, } impl From for RateLimitSnapshot { fn from(value: CoreRateLimitSnapshot) -> Self { Self { limit_id: value.limit_id, limit_name: value.limit_name, normal_model_slug: value.normal_model_slug, primary: value.primary.map(RateLimitWindow::from), secondary: value.secondary.map(RateLimitWindow::from), credits: value.credits.map(CreditsSnapshot::from), individual_limit: value.individual_limit.map(SpendControlLimitSnapshot::from), spend_control_reached: value.spend_control_reached, plan_type: value.plan_type, rate_limit_reached_type: value .rate_limit_reached_type .map(RateLimitReachedType::from), } } } #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "snake_case")] #[ts(export_to = "v2/", rename_all = "snake_case")] pub enum RateLimitReachedType { RateLimitReached, WorkspaceOwnerCreditsDepleted, WorkspaceMemberCreditsDepleted, WorkspaceOwnerUsageLimitReached, WorkspaceMemberUsageLimitReached, } impl From for RateLimitReachedType { fn from(value: CoreRateLimitReachedType) -> Self { match value { CoreRateLimitReachedType::RateLimitReached => Self::RateLimitReached, CoreRateLimitReachedType::WorkspaceOwnerCreditsDepleted => { Self::WorkspaceOwnerCreditsDepleted } CoreRateLimitReachedType::WorkspaceMemberCreditsDepleted => { Self::WorkspaceMemberCreditsDepleted } CoreRateLimitReachedType::WorkspaceOwnerUsageLimitReached => { Self::WorkspaceOwnerUsageLimitReached } CoreRateLimitReachedType::WorkspaceMemberUsageLimitReached => { Self::WorkspaceMemberUsageLimitReached } } } } impl From for CoreRateLimitReachedType { fn from(value: RateLimitReachedType) -> Self { match value { RateLimitReachedType::RateLimitReached => Self::RateLimitReached, RateLimitReachedType::WorkspaceOwnerCreditsDepleted => { Self::WorkspaceOwnerCreditsDepleted } RateLimitReachedType::WorkspaceMemberCreditsDepleted => { Self::WorkspaceMemberCreditsDepleted } RateLimitReachedType::WorkspaceOwnerUsageLimitReached => { Self::WorkspaceOwnerUsageLimitReached } RateLimitReachedType::WorkspaceMemberUsageLimitReached => { Self::WorkspaceMemberUsageLimitReached } } } } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct RateLimitWindow { pub used_percent: i32, #[ts(type = "number | null")] pub window_duration_mins: Option, #[ts(type = "number | null")] pub resets_at: Option, } impl From for RateLimitWindow { fn from(value: CoreRateLimitWindow) -> Self { Self { used_percent: value.used_percent.round() as i32, window_duration_mins: value.window_minutes, resets_at: value.resets_at, } } } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct CreditsSnapshot { pub has_credits: bool, pub unlimited: bool, pub balance: Option, } impl From for CreditsSnapshot { fn from(value: CoreCreditsSnapshot) -> Self { Self { has_credits: value.has_credits, unlimited: value.unlimited, balance: value.balance, } } } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct SpendControlLimitSnapshot { pub limit: String, pub used: String, pub remaining_percent: i32, #[ts(type = "number")] pub resets_at: i64, } impl From for SpendControlLimitSnapshot { fn from(value: CoreSpendControlLimitSnapshot) -> Self { Self { limit: value.limit, used: value.used, remaining_percent: value.remaining_percent, resets_at: value.resets_at, } } } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct AccountLoginCompletedNotification { // Use plain String for identifiers to avoid TS/JSON Schema quirks around uuid-specific types. // Convert to/from UUIDs at the application layer as needed. pub login_id: Option, pub success: bool, pub error: Option, pub onboarding_entrypoint: Option, } #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "snake_case")] #[ts(rename_all = "snake_case")] #[ts(export_to = "v2/")] pub enum DesktopOnboardingEntrypoint { LifeSciences, }