Initial public release of Warp.

Repo-Sync-Origin: warpdotdev/warp-internal@12af1d983b
This commit is contained in:
David Stern
2026-04-28 08:43:33 -05:00
commit 0dbd3d567a
4982 changed files with 1431549 additions and 0 deletions
+145
View File
@@ -0,0 +1,145 @@
use anyhow::{anyhow, Result};
use serde::{Deserialize, Serialize};
/// Format for error response payloads for Google APIs.
///
/// This error format is standardized across 'v1' Google APIs; its used for both
/// POST /v1/accounts/lookup and POST /v1/token requests.
///
/// This format is documented at https://firebase.google.com/docs/reference/rest/auth#section-error-format
/// as well as https://cloud.google.com/apis/design/errors#error_mapping. In the Google Cloud
/// documentation, refer to the 'HTTP mapping' for the schema (which is canonically defined in
/// protobuf).
///
/// The nested 'errors' field mentioned in the documentation is explicitly omitted since it is
/// deprecated and largely redundant with the top level error `code` and `message`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FirebaseError {
pub code: i32,
pub message: String,
}
impl std::error::Error for FirebaseError {}
impl std::fmt::Display for FirebaseError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Firebase request failed with status {} and message: {}",
self.code, self.message
)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
struct ProviderUserInfo {
display_name: Option<String>,
email: Option<String>,
provider_id: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AccountInfo {
pub local_id: String,
pub photo_url: Option<String>,
pub screen_name: Option<String>,
display_name: Option<String>,
email: Option<String>,
#[serde(default)]
provider_user_info: Vec<ProviderUserInfo>,
}
impl AccountInfo {
/// Construct a partial `AccountInfo` given user profile information.
pub fn from_profile(
firebase_uid: String,
photo_url: Option<String>,
display_name: Option<String>,
email: Option<String>,
) -> Self {
Self {
local_id: firebase_uid,
photo_url,
screen_name: display_name.clone(),
display_name,
email,
provider_user_info: vec![],
}
}
pub fn display_name(&self) -> Option<&str> {
self.display_name.as_deref().or_else(|| {
self.provider_user_info
.iter()
.find_map(|user_info| user_info.display_name.as_deref())
})
}
pub fn email(&self) -> Result<&str> {
self.email
.as_deref()
.or_else(|| {
self.provider_user_info
.iter()
.find_map(|user_info| user_info.email.as_deref())
})
.ok_or_else(|| anyhow!("Email address missing from user information"))
}
pub fn has_sso_link(&self) -> bool {
self.provider_user_info
.iter()
.any(|user_info| user_info.provider_id.as_deref() == Some("oidc.workos"))
}
}
/// Format for successful response payload for POST /v1/accounts/lookup request.
///
/// Reference: https://cloud.google.com/identity-platform/docs/use-rest-api#section-get-account-info.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GetAccountInfoResponsePayload {
users: Vec<AccountInfo>,
}
impl GetAccountInfoResponsePayload {
pub fn user_account_info(self) -> Result<AccountInfo> {
self.users.into_iter().next().ok_or_else(|| {
anyhow!("field `users` was unexpectedly empty in GetAccountInfoResponse")
})
}
}
/// Top-level response format for POST /v1/accounts/lookup request (part of the identitytoolkit GCP
/// API).
///
/// Reference: https://cloud.google.com/identity-platform/docs/use-rest-api#section-get-account-info.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum GetAccountInfoResponse {
Success(GetAccountInfoResponsePayload),
Error { error: FirebaseError },
}
/// The possible response values from fetching an access token from a refresh token
/// See https://firebase.google.com/docs/reference/rest/auth
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum FetchAccessTokenResponse {
// Note we need to support both camel and snake case because the two different
// endpoints for converting refresh / custom tokens to access tokens use different conventions.
Success {
#[serde(alias = "expiresIn")]
expires_in: String,
#[serde(alias = "idToken")]
id_token: String,
#[serde(alias = "refreshToken")]
refresh_token: String,
},
Error {
error: FirebaseError,
},
}