diff --git a/Cargo.lock b/Cargo.lock index 832b031a48..3b7e0508fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -618,6 +618,7 @@ dependencies = [ "api-error", "axum 0.8.8", "chrono", + "futures-util", "nango", "reqwest 0.13.2", "sentry", diff --git a/apps/api/openapi.gen.json b/apps/api/openapi.gen.json index 0abbc69471..30c748e20e 100644 --- a/apps/api/openapi.gen.json +++ b/apps/api/openapi.gen.json @@ -406,6 +406,37 @@ } } }, + "/nango/whoami": { + "get": { + "tags": [ + "nango" + ], + "operationId": "whoami", + "responses": { + "200": { + "description": "User info for all connections", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WhoAmIResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ] + } + }, "/stt/listen": { "get": { "tags": [ @@ -3643,6 +3674,53 @@ "unknown" ] }, + "WhoAmIItem": { + "type": "object", + "required": [ + "integration_id", + "connection_id" + ], + "properties": { + "connection_id": { + "type": "string" + }, + "display_name": { + "type": [ + "string", + "null" + ] + }, + "email": { + "type": [ + "string", + "null" + ] + }, + "error": { + "type": [ + "string", + "null" + ] + }, + "integration_id": { + "type": "string" + } + } + }, + "WhoAmIResponse": { + "type": "object", + "required": [ + "accounts" + ], + "properties": { + "accounts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/WhoAmIItem" + } + } + } + }, "WorkingLocationProperties": { "type": "object", "properties": { diff --git a/apps/web/src/hooks/use-whoami.ts b/apps/web/src/hooks/use-whoami.ts new file mode 100644 index 0000000000..c7f4cd1821 --- /dev/null +++ b/apps/web/src/hooks/use-whoami.ts @@ -0,0 +1,39 @@ +import { useQuery } from "@tanstack/react-query"; +import { jwtDecode } from "jwt-decode"; + +import { whoami } from "@hypr/api-client"; +import { createClient } from "@hypr/api-client/client"; + +import { env } from "@/env"; +import { getAccessToken } from "@/functions/access-token"; + +export function useWhoAmI(enabled = true) { + const authQuery = useQuery({ + queryKey: ["integration-status", "auth"], + queryFn: async () => { + const token = await getAccessToken(); + return { + token, + userId: jwtDecode<{ sub: string }>(token).sub, + }; + }, + retry: false, + enabled, + }); + + return useQuery({ + queryKey: ["whoami", authQuery.data?.userId], + enabled: enabled && !!authQuery.data?.userId, + queryFn: async () => { + const client = createClient({ + baseUrl: env.VITE_API_URL, + headers: { Authorization: `Bearer ${authQuery.data?.token}` }, + }); + const { data, error } = await whoami({ client }); + if (error) { + throw new Error("Failed to load account info"); + } + return data?.accounts ?? []; + }, + }); +} diff --git a/apps/web/src/routes/_view/app/-account-integrations.tsx b/apps/web/src/routes/_view/app/-account-integrations.tsx index 0eec4cc522..0109fda61d 100644 --- a/apps/web/src/routes/_view/app/-account-integrations.tsx +++ b/apps/web/src/routes/_view/app/-account-integrations.tsx @@ -1,7 +1,7 @@ import { Link, useNavigate } from "@tanstack/react-router"; import { ChevronDown, PlusIcon } from "lucide-react"; -import type { ConnectionItem } from "@hypr/api-client"; +import type { ConnectionItem, WhoAmIItem } from "@hypr/api-client"; import { DropdownMenu, DropdownMenuContent, @@ -11,6 +11,7 @@ import { import { useBilling } from "@/hooks/use-billing"; import { useConnections } from "@/hooks/use-connections"; +import { useWhoAmI } from "@/hooks/use-whoami"; const INTEGRATIONS = [ { id: "google-calendar", name: "Google Calendar" }, @@ -20,11 +21,16 @@ export function IntegrationsSettingsCard() { const navigate = useNavigate(); const { isPro } = useBilling(); const { data: connections, isLoading } = useConnections(isPro); + const { data: accounts } = useWhoAmI(isPro); const getProviderConnections = (integrationId: string) => { return connections?.filter((c) => c.integration_id === integrationId) ?? []; }; + const getAccountInfo = (connectionId: string) => { + return accounts?.find((a) => a.connection_id === connectionId); + }; + return (
@@ -86,6 +92,7 @@ export function IntegrationsSettingsCard() { key={connection.connection_id} connection={connection} integrationId={integration.id} + account={getAccountInfo(connection.connection_id)} /> ))}
@@ -100,12 +107,16 @@ export function IntegrationsSettingsCard() { function ConnectionRow({ connection, integrationId, + account, }: { connection: ConnectionItem; integrationId: string; + account?: WhoAmIItem; }) { const navigate = useNavigate(); const isReconnectRequired = connection.status === "reconnect_required"; + const displayLabel = + account?.email ?? account?.display_name ?? connection.connection_id; return (
@@ -116,9 +127,7 @@ function ConnectionRow({ isReconnectRequired ? "bg-amber-500" : "bg-green-500", ].join(" ")} /> - - {connection.connection_id} - + {displayLabel} {isReconnectRequired && ( Reconnect required )} diff --git a/crates/api-client/openapi.gen.json b/crates/api-client/openapi.gen.json index 613cc538ef..23a0f76268 100644 --- a/crates/api-client/openapi.gen.json +++ b/crates/api-client/openapi.gen.json @@ -1625,6 +1625,47 @@ ], "type": "string" }, + "WhoAmIItem": { + "properties": { + "connection_id": { + "type": "string" + }, + "display_name": { + "nullable": true, + "type": "string" + }, + "email": { + "nullable": true, + "type": "string" + }, + "error": { + "nullable": true, + "type": "string" + }, + "integration_id": { + "type": "string" + } + }, + "required": [ + "integration_id", + "connection_id" + ], + "type": "object" + }, + "WhoAmIResponse": { + "properties": { + "accounts": { + "items": { + "$ref": "#/components/schemas/WhoAmIItem" + }, + "type": "array" + } + }, + "required": [ + "accounts" + ], + "type": "object" + }, "WorkingLocationProperties": { "properties": { "customLocation": { @@ -2587,6 +2628,37 @@ ] } }, + "/nango/whoami": { + "get": { + "operationId": "whoami", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WhoAmIResponse" + } + } + }, + "description": "User info for all connections" + }, + "401": { + "description": "Unauthorized" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + "nango" + ] + } + }, "/subscription/can-start-trial": { "get": { "operationId": "can_start_trial", diff --git a/crates/api-nango/Cargo.toml b/crates/api-nango/Cargo.toml index 6b9c36c625..46a6d8f3a8 100644 --- a/crates/api-nango/Cargo.toml +++ b/crates/api-nango/Cargo.toml @@ -14,6 +14,7 @@ urlencoding = { workspace = true } utoipa = { workspace = true } axum = { workspace = true } +futures-util = { workspace = true } reqwest = { workspace = true, features = ["json"] } sentry = { workspace = true } tokio = { workspace = true } diff --git a/crates/api-nango/src/openapi.rs b/crates/api-nango/src/openapi.rs index b23ba3eba7..a4f16cba92 100644 --- a/crates/api-nango/src/openapi.rs +++ b/crates/api-nango/src/openapi.rs @@ -2,7 +2,8 @@ use utoipa::OpenApi; use crate::routes::{ ConnectionItem, CreateSessionRequest, DeleteConnectionRequest, DeleteConnectionResponse, - ListConnectionsResponse, SessionMode, SessionResponse, WebhookResponse, + ListConnectionsResponse, SessionMode, SessionResponse, WebhookResponse, WhoAmIItem, + WhoAmIResponse, }; #[derive(OpenApi)] @@ -12,6 +13,7 @@ use crate::routes::{ crate::routes::disconnect::delete_connection, crate::routes::status::list_connections, crate::routes::webhook::nango_webhook, + crate::routes::whoami::whoami, ), components( schemas( @@ -23,6 +25,8 @@ use crate::routes::{ ConnectionItem, ListConnectionsResponse, WebhookResponse, + WhoAmIItem, + WhoAmIResponse, ) ), tags( diff --git a/crates/api-nango/src/routes/mod.rs b/crates/api-nango/src/routes/mod.rs index 44b3c40051..f5e8fb367c 100644 --- a/crates/api-nango/src/routes/mod.rs +++ b/crates/api-nango/src/routes/mod.rs @@ -2,6 +2,7 @@ pub(crate) mod connect; pub(crate) mod disconnect; pub(crate) mod status; pub(crate) mod webhook; +pub(crate) mod whoami; use axum::{ Router, @@ -15,6 +16,7 @@ pub use connect::{CreateSessionRequest, SessionMode, SessionResponse}; pub use disconnect::{DeleteConnectionRequest, DeleteConnectionResponse}; pub use status::{ConnectionItem, ListConnectionsResponse}; pub use webhook::WebhookResponse; +pub use whoami::{WhoAmIItem, WhoAmIResponse}; pub fn router(config: NangoConfig) -> Router { let state = AppState::new(config); @@ -25,6 +27,7 @@ pub fn router(config: NangoConfig) -> Router { "/connections", get(status::list_connections).delete(disconnect::delete_connection), ) + .route("/whoami", get(whoami::whoami)) .with_state(state) } diff --git a/crates/api-nango/src/routes/whoami.rs b/crates/api-nango/src/routes/whoami.rs new file mode 100644 index 0000000000..24a12c63e9 --- /dev/null +++ b/crates/api-nango/src/routes/whoami.rs @@ -0,0 +1,147 @@ +use axum::{Extension, Json, extract::State}; +use hypr_api_auth::AuthContext; +use hypr_nango::OwnedNangoProxy; +use serde::{Deserialize, Serialize}; +use utoipa::ToSchema; + +use crate::error::Result; +use crate::state::AppState; + +#[derive(Debug, Serialize, ToSchema)] +pub struct WhoAmIItem { + pub integration_id: String, + pub connection_id: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub email: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub display_name: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub error: Option, +} + +#[derive(Debug, Serialize, ToSchema)] +pub struct WhoAmIResponse { + pub accounts: Vec, +} + +#[derive(Debug, Deserialize)] +struct GoogleUserInfo { + email: Option, + name: Option, +} + +#[derive(Debug, Deserialize)] +struct OutlookMe { + mail: Option, + #[serde(rename = "userPrincipalName")] + user_principal_name: Option, + #[serde(rename = "displayName")] + display_name: Option, +} + +// TODO: cache identity information in the database instead of fetching on every request +async fn fetch_identity( + nango: &hypr_nango::NangoClient, + integration_id: &str, + connection_id: &str, +) -> std::result::Result<(Option, Option), String> { + let proxy = OwnedNangoProxy::new(nango, integration_id.to_string(), connection_id.to_string()); + + match integration_id { + // https://docs.cloud.google.com/identity-platform/docs/reference/rest/v1/UserInfo + "google-calendar" | "google-drive" => { + let resp = proxy + .get("/oauth2/v1/userinfo?alt=json") + .map_err(|e| e.to_string())? + .send() + .await + .map_err(|e| e.to_string())? + .error_for_status() + .map_err(|e| e.to_string())?; + + let me: GoogleUserInfo = resp.json().await.map_err(|e| e.to_string())?; + Ok((me.email, me.name)) + } + + // https://learn.microsoft.com/en-us/graph/api/user-get + "outlook-calendar" => { + let resp = proxy + .get("/v1.0/me?$select=mail,userPrincipalName,displayName") + .map_err(|e| e.to_string())? + .send() + .await + .map_err(|e| e.to_string())? + .error_for_status() + .map_err(|e| e.to_string())?; + + let me: OutlookMe = resp.json().await.map_err(|e| e.to_string())?; + Ok((me.mail.or(me.user_principal_name), me.display_name)) + } + + other => Err(format!("unsupported integration: {other}")), + } +} + +#[utoipa::path( + get, + path = "/whoami", + responses( + (status = 200, description = "User info for all connections", body = WhoAmIResponse), + (status = 401, description = "Unauthorized"), + (status = 500, description = "Internal server error"), + ), + tag = "nango", +)] +pub async fn whoami( + State(state): State, + Extension(auth): Extension, +) -> Result> { + let rows = state + .supabase + .list_user_connections(&auth.token, &auth.claims.sub) + .await?; + + let futures = rows.into_iter().map(|row| { + let nango = state.nango.clone(); + async move { + if row.status == "reconnect_required" { + return WhoAmIItem { + integration_id: row.integration_id, + connection_id: row.connection_id, + email: None, + display_name: None, + error: Some("reconnect_required".to_string()), + }; + } + + match fetch_identity(&nango, &row.integration_id, &row.connection_id).await { + Ok((email, display_name)) => WhoAmIItem { + integration_id: row.integration_id, + connection_id: row.connection_id, + email, + display_name, + error: None, + }, + Err(e) => { + tracing::warn!( + integration_id = %row.integration_id, + connection_id = %row.connection_id, + error = %e, + "failed to fetch identity for connection" + ); + WhoAmIItem { + integration_id: row.integration_id, + connection_id: row.connection_id, + email: None, + display_name: None, + error: Some(e), + } + } + } + } + }); + + let accounts = futures_util::future::join_all(futures).await; + + Ok(Json(WhoAmIResponse { accounts })) +} diff --git a/packages/api-client/src/generated/index.ts b/packages/api-client/src/generated/index.ts index fbf7d1c1af..1f4b245fd3 100644 --- a/packages/api-client/src/generated/index.ts +++ b/packages/api-client/src/generated/index.ts @@ -1,4 +1,4 @@ // This file is auto-generated by @hey-api/openapi-ts -export { canStartTrial, createContact, createConversation, createSession, deleteAccount, deleteConnection, getMessages, googleListCalendars, googleListEvents, listConnections, listConversations, llmChatCompletions, nangoWebhook, type Options, outlookListCalendars, outlookListEvents, sendMessage, startTrial, sttListenBatch, sttListenStream, sttStatus, submit } from './sdk.gen'; -export type { AccessRole, AttendeeResponseStatus, AttendeeType, AutoDeclineMode, BatchAlternatives, BatchChannel, BatchListenSuccessResponse, BatchResponse, BatchResults, BatchWord, BirthdayProperties, BirthdayPropertyType, BodyType, Calendar, CalendarColor, CalendarListEntry, CalendarNotification, CanStartTrialData, CanStartTrialErrors, CanStartTrialReason, CanStartTrialResponse, CanStartTrialResponse2, CanStartTrialResponses, CharTask, ChatStatus, ClientOptions, ConferenceCreateRequest, ConferenceCreateRequestStatus, ConferenceCreateStatusCode, ConferenceData, ConferenceProperties, ConferenceSolution, ConferenceSolutionKey, ConferenceSolutionType, ConnectionItem, ConversationSummary, CreateContactData, CreateContactErrors, CreateContactRequest, CreateContactResponse, CreateContactResponse2, CreateContactResponses, CreateConversationData, CreateConversationErrors, CreateConversationRequest, CreateConversationResponse, CreateConversationResponse2, CreateConversationResponses, CreateEventRequest, CreateSessionData, CreateSessionErrors, CreateSessionRequest, CreateSessionResponse, CreateSessionResponses, CustomLocation, DateTimeTimeZone, DayOfWeek, DeleteAccountData, DeleteAccountErrors, DeleteAccountResponse, DeleteAccountResponse2, DeleteAccountResponses, DeleteConnectionData, DeleteConnectionErrors, DeleteConnectionRequest, DeleteConnectionResponse, DeleteConnectionResponse2, DeleteConnectionResponses, DeviceInfo, EmailAddress, EntryPoint, EntryPointType, EventAttachment, EventDateTime, EventOrderBy, EventPerson, EventShowAs, EventSource, EventStatus, ExtendedProperties, FeedbackRequest, FeedbackResponse, FeedbackType, FocusTimeProperties, Gadget, GadgetDisplay, GetMessagesData, GetMessagesErrors, GetMessagesResponse, GetMessagesResponses, GoogleAttendee, GoogleCreateEventBody, GoogleEvent, GoogleEventType, GoogleListCalendarsData, GoogleListCalendarsErrors, GoogleListCalendarsRequest, GoogleListCalendarsResponse, GoogleListCalendarsResponse2, GoogleListCalendarsResponses, GoogleListEventsData, GoogleListEventsErrors, GoogleListEventsRequest, GoogleListEventsResponse, GoogleListEventsResponse2, GoogleListEventsResponses, Importance, Interval, ItemBody, ListConnectionsData, ListConnectionsErrors, ListConnectionsResponse, ListConnectionsResponse2, ListConnectionsResponses, ListConversationsData, ListConversationsErrors, ListConversationsQuery, ListConversationsResponse, ListConversationsResponses, ListenCallbackRequest, ListenCallbackResponse, ListEventsRequest, LlmChatCompletionsData, LlmChatCompletionsErrors, LlmChatCompletionsResponses, Location, LocationType, MessageResponse, NangoWebhookData, NangoWebhookErrors, NangoWebhookResponse, NangoWebhookResponses, NotificationMethod, NotificationSettings, NotificationType, OfficeLocation, OnlineMeetingInfo, OnlineMeetingProviderType, OutlookAttendee, OutlookCreateEventBody, OutlookEvent, OutlookEventType, OutlookGeoCoordinates, OutlookListCalendarsData, OutlookListCalendarsErrors, OutlookListCalendarsRequest, OutlookListCalendarsResponse, OutlookListCalendarsResponse2, OutlookListCalendarsResponses, OutlookListEventsData, OutlookListEventsErrors, OutlookListEventsRequest, OutlookListEventsResponse, OutlookListEventsResponse2, OutlookListEventsResponses, OutOfOfficeProperties, PatternedRecurrence, PhysicalAddress, PipelineStatus, Recipient, RecurrencePattern, RecurrencePatternType, RecurrenceRange, RecurrenceRangeType, Reminder, ReminderMethod, Reminders, ResponseStatus, ResponseType, SendMessageData, SendMessageErrors, SendMessageRequest, SendMessageResponse, SendMessageResponses, Sensitivity, SessionMode, SessionResponse, StartTrialData, StartTrialErrors, StartTrialReason, StartTrialResponse, StartTrialResponse2, StartTrialResponses, StreamAlternatives, StreamChannel, StreamMetadata, StreamModelInfo, StreamResponse, StreamWord, SttListenBatchData, SttListenBatchErrors, SttListenBatchResponse, SttListenBatchResponses, SttListenStreamData, SttListenStreamErrors, SttStatusData, SttStatusErrors, SttStatusResponse, SttStatusResponse2, SttStatusResponses, SubmitData, SubmitError, SubmitErrors, SubmitResponse, SubmitResponses, Transparency, Visibility, WebhookResponse, WeekIndex, WorkingLocationProperties, WorkingLocationType } from './types.gen'; +export { canStartTrial, createContact, createConversation, createSession, deleteAccount, deleteConnection, getMessages, googleListCalendars, googleListEvents, listConnections, listConversations, llmChatCompletions, nangoWebhook, type Options, outlookListCalendars, outlookListEvents, sendMessage, startTrial, sttListenBatch, sttListenStream, sttStatus, submit, whoami } from './sdk.gen'; +export type { AccessRole, AttendeeResponseStatus, AttendeeType, AutoDeclineMode, BatchAlternatives, BatchChannel, BatchListenSuccessResponse, BatchResponse, BatchResults, BatchWord, BirthdayProperties, BirthdayPropertyType, BodyType, Calendar, CalendarColor, CalendarListEntry, CalendarNotification, CanStartTrialData, CanStartTrialErrors, CanStartTrialReason, CanStartTrialResponse, CanStartTrialResponse2, CanStartTrialResponses, CharTask, ChatStatus, ClientOptions, ConferenceCreateRequest, ConferenceCreateRequestStatus, ConferenceCreateStatusCode, ConferenceData, ConferenceProperties, ConferenceSolution, ConferenceSolutionKey, ConferenceSolutionType, ConnectionItem, ConversationSummary, CreateContactData, CreateContactErrors, CreateContactRequest, CreateContactResponse, CreateContactResponse2, CreateContactResponses, CreateConversationData, CreateConversationErrors, CreateConversationRequest, CreateConversationResponse, CreateConversationResponse2, CreateConversationResponses, CreateEventRequest, CreateSessionData, CreateSessionErrors, CreateSessionRequest, CreateSessionResponse, CreateSessionResponses, CustomLocation, DateTimeTimeZone, DayOfWeek, DeleteAccountData, DeleteAccountErrors, DeleteAccountResponse, DeleteAccountResponse2, DeleteAccountResponses, DeleteConnectionData, DeleteConnectionErrors, DeleteConnectionRequest, DeleteConnectionResponse, DeleteConnectionResponse2, DeleteConnectionResponses, DeviceInfo, EmailAddress, EntryPoint, EntryPointType, EventAttachment, EventDateTime, EventOrderBy, EventPerson, EventShowAs, EventSource, EventStatus, ExtendedProperties, FeedbackRequest, FeedbackResponse, FeedbackType, FocusTimeProperties, Gadget, GadgetDisplay, GetMessagesData, GetMessagesErrors, GetMessagesResponse, GetMessagesResponses, GoogleAttendee, GoogleCreateEventBody, GoogleEvent, GoogleEventType, GoogleListCalendarsData, GoogleListCalendarsErrors, GoogleListCalendarsRequest, GoogleListCalendarsResponse, GoogleListCalendarsResponse2, GoogleListCalendarsResponses, GoogleListEventsData, GoogleListEventsErrors, GoogleListEventsRequest, GoogleListEventsResponse, GoogleListEventsResponse2, GoogleListEventsResponses, Importance, Interval, ItemBody, ListConnectionsData, ListConnectionsErrors, ListConnectionsResponse, ListConnectionsResponse2, ListConnectionsResponses, ListConversationsData, ListConversationsErrors, ListConversationsQuery, ListConversationsResponse, ListConversationsResponses, ListenCallbackRequest, ListenCallbackResponse, ListEventsRequest, LlmChatCompletionsData, LlmChatCompletionsErrors, LlmChatCompletionsResponses, Location, LocationType, MessageResponse, NangoWebhookData, NangoWebhookErrors, NangoWebhookResponse, NangoWebhookResponses, NotificationMethod, NotificationSettings, NotificationType, OfficeLocation, OnlineMeetingInfo, OnlineMeetingProviderType, OutlookAttendee, OutlookCreateEventBody, OutlookEvent, OutlookEventType, OutlookGeoCoordinates, OutlookListCalendarsData, OutlookListCalendarsErrors, OutlookListCalendarsRequest, OutlookListCalendarsResponse, OutlookListCalendarsResponse2, OutlookListCalendarsResponses, OutlookListEventsData, OutlookListEventsErrors, OutlookListEventsRequest, OutlookListEventsResponse, OutlookListEventsResponse2, OutlookListEventsResponses, OutOfOfficeProperties, PatternedRecurrence, PhysicalAddress, PipelineStatus, Recipient, RecurrencePattern, RecurrencePatternType, RecurrenceRange, RecurrenceRangeType, Reminder, ReminderMethod, Reminders, ResponseStatus, ResponseType, SendMessageData, SendMessageErrors, SendMessageRequest, SendMessageResponse, SendMessageResponses, Sensitivity, SessionMode, SessionResponse, StartTrialData, StartTrialErrors, StartTrialReason, StartTrialResponse, StartTrialResponse2, StartTrialResponses, StreamAlternatives, StreamChannel, StreamMetadata, StreamModelInfo, StreamResponse, StreamWord, SttListenBatchData, SttListenBatchErrors, SttListenBatchResponse, SttListenBatchResponses, SttListenStreamData, SttListenStreamErrors, SttStatusData, SttStatusErrors, SttStatusResponse, SttStatusResponse2, SttStatusResponses, SubmitData, SubmitError, SubmitErrors, SubmitResponse, SubmitResponses, Transparency, Visibility, WebhookResponse, WeekIndex, WhoamiData, WhoamiErrors, WhoAmIItem, WhoamiResponse, WhoAmIResponse, WhoamiResponses, WorkingLocationProperties, WorkingLocationType } from './types.gen'; diff --git a/packages/api-client/src/generated/sdk.gen.ts b/packages/api-client/src/generated/sdk.gen.ts index 429086f72b..d432c8ca64 100644 --- a/packages/api-client/src/generated/sdk.gen.ts +++ b/packages/api-client/src/generated/sdk.gen.ts @@ -2,7 +2,7 @@ import type { Client, Options as Options2, TDataShape } from './client'; import { client } from './client.gen'; -import type { CanStartTrialData, CanStartTrialErrors, CanStartTrialResponses, CreateContactData, CreateContactErrors, CreateContactResponses, CreateConversationData, CreateConversationErrors, CreateConversationResponses, CreateSessionData, CreateSessionErrors, CreateSessionResponses, DeleteAccountData, DeleteAccountErrors, DeleteAccountResponses, DeleteConnectionData, DeleteConnectionErrors, DeleteConnectionResponses, GetMessagesData, GetMessagesErrors, GetMessagesResponses, GoogleListCalendarsData, GoogleListCalendarsErrors, GoogleListCalendarsResponses, GoogleListEventsData, GoogleListEventsErrors, GoogleListEventsResponses, ListConnectionsData, ListConnectionsErrors, ListConnectionsResponses, ListConversationsData, ListConversationsErrors, ListConversationsResponses, LlmChatCompletionsData, LlmChatCompletionsErrors, LlmChatCompletionsResponses, NangoWebhookData, NangoWebhookErrors, NangoWebhookResponses, OutlookListCalendarsData, OutlookListCalendarsErrors, OutlookListCalendarsResponses, OutlookListEventsData, OutlookListEventsErrors, OutlookListEventsResponses, SendMessageData, SendMessageErrors, SendMessageResponses, StartTrialData, StartTrialErrors, StartTrialResponses, SttListenBatchData, SttListenBatchErrors, SttListenBatchResponses, SttListenStreamData, SttListenStreamErrors, SttStatusData, SttStatusErrors, SttStatusResponses, SubmitData, SubmitErrors, SubmitResponses } from './types.gen'; +import type { CanStartTrialData, CanStartTrialErrors, CanStartTrialResponses, CreateContactData, CreateContactErrors, CreateContactResponses, CreateConversationData, CreateConversationErrors, CreateConversationResponses, CreateSessionData, CreateSessionErrors, CreateSessionResponses, DeleteAccountData, DeleteAccountErrors, DeleteAccountResponses, DeleteConnectionData, DeleteConnectionErrors, DeleteConnectionResponses, GetMessagesData, GetMessagesErrors, GetMessagesResponses, GoogleListCalendarsData, GoogleListCalendarsErrors, GoogleListCalendarsResponses, GoogleListEventsData, GoogleListEventsErrors, GoogleListEventsResponses, ListConnectionsData, ListConnectionsErrors, ListConnectionsResponses, ListConversationsData, ListConversationsErrors, ListConversationsResponses, LlmChatCompletionsData, LlmChatCompletionsErrors, LlmChatCompletionsResponses, NangoWebhookData, NangoWebhookErrors, NangoWebhookResponses, OutlookListCalendarsData, OutlookListCalendarsErrors, OutlookListCalendarsResponses, OutlookListEventsData, OutlookListEventsErrors, OutlookListEventsResponses, SendMessageData, SendMessageErrors, SendMessageResponses, StartTrialData, StartTrialErrors, StartTrialResponses, SttListenBatchData, SttListenBatchErrors, SttListenBatchResponses, SttListenStreamData, SttListenStreamErrors, SttStatusData, SttStatusErrors, SttStatusResponses, SubmitData, SubmitErrors, SubmitResponses, WhoamiData, WhoamiErrors, WhoamiResponses } from './types.gen'; export type Options = Options2 & { /** @@ -97,6 +97,12 @@ export const createSession = (options: Opt export const nangoWebhook = (options?: Options) => (options?.client ?? client).post({ url: '/nango/webhook', ...options }); +export const whoami = (options?: Options) => (options?.client ?? client).get({ + security: [{ scheme: 'bearer', type: 'http' }], + url: '/nango/whoami', + ...options +}); + export const sttListenStream = (options?: Options) => (options?.client ?? client).get({ url: '/stt/listen', ...options }); export const sttListenBatch = (options: Options) => (options.client ?? client).post({ diff --git a/packages/api-client/src/generated/types.gen.ts b/packages/api-client/src/generated/types.gen.ts index 5edc794d7a..9f02d319bd 100644 --- a/packages/api-client/src/generated/types.gen.ts +++ b/packages/api-client/src/generated/types.gen.ts @@ -628,6 +628,18 @@ export type WebhookResponse = { export type WeekIndex = 'first' | 'second' | 'third' | 'fourth' | 'last' | 'unknown'; +export type WhoAmIItem = { + connection_id: string; + display_name?: string | null; + email?: string | null; + error?: string | null; + integration_id: string; +}; + +export type WhoAmIResponse = { + accounts: Array; +}; + export type WorkingLocationProperties = { customLocation?: null | CustomLocation; homeOffice?: unknown; @@ -1114,6 +1126,33 @@ export type NangoWebhookResponses = { export type NangoWebhookResponse = NangoWebhookResponses[keyof NangoWebhookResponses]; +export type WhoamiData = { + body?: never; + path?: never; + query?: never; + url: '/nango/whoami'; +}; + +export type WhoamiErrors = { + /** + * Unauthorized + */ + 401: unknown; + /** + * Internal server error + */ + 500: unknown; +}; + +export type WhoamiResponses = { + /** + * User info for all connections + */ + 200: WhoAmIResponse; +}; + +export type WhoamiResponse = WhoamiResponses[keyof WhoamiResponses]; + export type SttListenStreamData = { body?: never; path?: never;