@athenaintel/react 0.9.20 → 0.9.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/auth.cjs CHANGED
@@ -211,6 +211,8 @@ function AthenaSSOProvider({
211
211
  activeRequestRef.current = abortController;
212
212
  if (showLoading) {
213
213
  setLoading(true);
214
+ setError(null);
215
+ setSSOData(null);
214
216
  }
215
217
  try {
216
218
  const response = await fetch(ssoUrls.userInfo, {
package/dist/auth.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"auth.cjs","sources":["../src/auth/AthenaAuthProvider.tsx","../src/auth/AthenaSSOProvider.tsx"],"sourcesContent":["import {\n RequiredAuthProvider,\n RedirectToLogin,\n useAuthInfo,\n useLogoutFunction,\n} from '@propelauth/react';\nimport type { ReactNode } from 'react';\nimport { useEffect, useMemo, useState } from 'react';\nimport { AthenaAuthContext } from './AthenaAuthContext';\nimport type { AthenaAuthState, AthenaOrg, AthenaUser } from './types';\n\n// ─── Props ────────────────────────────────────────────────────────────\n\nexport interface AthenaAuthProviderProps {\n children: ReactNode;\n\n /**\n * Your PropelAuth auth URL (e.g. `https://auth.yourdomain.com`).\n * Found in the PropelAuth dashboard under Frontend Integration.\n */\n authUrl: string;\n\n /**\n * Where to redirect after a successful login.\n * Defaults to the current page URL.\n */\n postLoginRedirectUrl?: string;\n\n /**\n * Custom element displayed while the auth state is loading.\n * Defaults to `null` (renders nothing).\n */\n displayWhileLoading?: ReactNode;\n}\n\nconst ATHENA_LOCATION_CHANGE_EVENT = 'athena:location-change';\nlet historyPatched = false;\n\nfunction patchHistoryForLocationTracking(): void {\n if (historyPatched || typeof window === 'undefined') {\n return;\n }\n\n const notifyLocationChange = () => {\n window.dispatchEvent(new Event(ATHENA_LOCATION_CHANGE_EVENT));\n };\n\n const originalPushState = window.history.pushState;\n window.history.pushState = function pushState(...args) {\n const result = originalPushState.apply(this, args);\n notifyLocationChange();\n return result;\n };\n\n const originalReplaceState = window.history.replaceState;\n window.history.replaceState = function replaceState(...args) {\n const result = originalReplaceState.apply(this, args);\n notifyLocationChange();\n return result;\n };\n\n historyPatched = true;\n}\n\nfunction useCurrentHref(): string {\n const [href, setHref] = useState(\n typeof window !== 'undefined' ? window.location.href : '/',\n );\n\n useEffect(() => {\n if (typeof window === 'undefined') {\n return;\n }\n\n patchHistoryForLocationTracking();\n\n const updateHref = () => {\n setHref(window.location.href);\n };\n\n updateHref();\n window.addEventListener('popstate', updateHref);\n window.addEventListener('hashchange', updateHref);\n window.addEventListener(ATHENA_LOCATION_CHANGE_EVENT, updateHref);\n\n return () => {\n window.removeEventListener('popstate', updateHref);\n window.removeEventListener('hashchange', updateHref);\n window.removeEventListener(ATHENA_LOCATION_CHANGE_EVENT, updateHref);\n };\n }, []);\n\n return href;\n}\n\n// ─── Internal Bridge ──────────────────────────────────────────────────\n\n/**\n * Reads PropelAuth state via hooks and maps it into the SDK's\n * `AthenaAuthState`, which is placed on `AthenaAuthContext`.\n */\nfunction AthenaAuthBridge({\n children,\n displayWhileLoading,\n}: {\n children: ReactNode;\n displayWhileLoading?: ReactNode;\n}) {\n const authInfo = useAuthInfo();\n const logoutFn = useLogoutFunction();\n\n const authState: AthenaAuthState = useMemo(() => {\n if (authInfo.loading) {\n return {\n isLoggedIn: false,\n isLoading: true,\n user: null,\n accessToken: null,\n orgs: [],\n logout: async () => {},\n };\n }\n\n if (!authInfo.isLoggedIn) {\n return {\n isLoggedIn: false,\n isLoading: false,\n user: null,\n accessToken: null,\n orgs: [],\n logout: async (redirect = true) => logoutFn(redirect),\n };\n }\n\n const user: AthenaUser = {\n userId: authInfo.user.userId,\n email: authInfo.user.email,\n firstName: authInfo.user.firstName ?? undefined,\n lastName: authInfo.user.lastName ?? undefined,\n username: authInfo.user.username ?? undefined,\n pictureUrl: authInfo.user.pictureUrl ?? undefined,\n properties: authInfo.user.properties,\n };\n\n const orgs: AthenaOrg[] =\n authInfo.orgHelper?.getOrgs().map((org) => ({\n orgId: org.orgId,\n orgName: org.orgName,\n urlSafeOrgName: org.urlSafeOrgName,\n })) ?? [];\n\n return {\n isLoggedIn: true,\n isLoading: false,\n user,\n accessToken: authInfo.accessToken,\n orgs,\n logout: async (redirect = true) => logoutFn(redirect),\n };\n }, [authInfo, logoutFn]);\n\n if (authState.isLoading) {\n return <>{displayWhileLoading ?? null}</>;\n }\n\n return (\n <AthenaAuthContext.Provider value={authState}>\n {children}\n </AthenaAuthContext.Provider>\n );\n}\n\n// ─── Public Provider ──────────────────────────────────────────────────\n\n/**\n * Wraps your app with Athena authentication powered by PropelAuth.\n *\n * Place this **above** `<AthenaProvider>` in the component tree.\n * When present, `AthenaProvider` will automatically use the access token\n * from this provider — no need to pass `token` or `apiKey` manually.\n *\n * @example\n * ```tsx\n * import { AthenaAuthProvider } from '@athenaintel/react/auth';\n * import { AthenaProvider, AthenaChat } from '@athenaintel/react';\n *\n * function App() {\n * return (\n * <AthenaAuthProvider authUrl=\"https://auth.yourdomain.com\">\n * <AthenaProvider>\n * <AthenaChat />\n * </AthenaProvider>\n * </AthenaAuthProvider>\n * );\n * }\n * ```\n */\nexport function AthenaAuthProvider({\n children,\n authUrl,\n postLoginRedirectUrl,\n displayWhileLoading,\n}: AthenaAuthProviderProps) {\n const currentHref = useCurrentHref();\n const redirectUrl = postLoginRedirectUrl ?? currentHref;\n\n return (\n <RequiredAuthProvider\n authUrl={authUrl}\n displayWhileLoading={\n displayWhileLoading ? <>{displayWhileLoading}</> : undefined\n }\n displayIfLoggedOut={<RedirectToLogin postLoginRedirectUrl={redirectUrl} />}\n >\n <AthenaAuthBridge displayWhileLoading={displayWhileLoading}>\n {children}\n </AthenaAuthBridge>\n </RequiredAuthProvider>\n );\n}\n","import type { ReactNode } from 'react';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { AthenaAuthContext } from './AthenaAuthContext';\nimport type {\n AthenaAuthState,\n AthenaOrg,\n AthenaSSOUserInfo,\n AthenaUser,\n} from './types';\n\n// ─── Props ────────────────────────────────────────────────────────────\n\nexport interface AthenaSSOProviderProps {\n children: ReactNode;\n\n /**\n * Base URL used to resolve the Athena SSO endpoints.\n *\n * When omitted, the provider defaults to same-origin relative paths:\n * `/api/sso/userinfo`, `/api/sso/initiate`, and `/api/sso/logout`.\n *\n * Use this when your frontend and backend live on different origins\n * (for example `https://app.example.com` + `https://api.example.com`).\n */\n ssoBaseUrl?: string;\n\n /**\n * Optional override for the SSO user-info endpoint that returns the\n * authenticated user's data and access token.\n *\n * The endpoint must return JSON matching `AthenaSSOUserInfo`:\n * ```json\n * {\n * \"user\": { \"user_id\": \"…\", \"email\": \"…\", … },\n * \"orgMemberInfos\": [{ \"orgId\": \"…\", \"orgName\": \"…\", \"urlSafeOrgName\": \"…\" }],\n * \"accessToken\": \"…\"\n * }\n * ```\n *\n * The request is sent with `credentials: 'include'` so that\n * session cookies are forwarded automatically.\n */\n ssoUserInfoUrl?: string;\n\n /**\n * Optional override for the URL to redirect the user to when no valid\n * SSO session exists.\n * This is typically the SSO initiation endpoint on your backend\n * (e.g. `https://api.yourdomain.com/api/sso/initiate`).\n */\n ssoLoginUrl?: string;\n\n /**\n * Optional override for the backend SSO logout endpoint.\n * Defaults to `/api/sso/logout` (or `${ssoBaseUrl}/api/sso/logout`).\n */\n ssoLogoutUrl?: string;\n\n /**\n * Custom element displayed while the SSO session is being verified.\n * Defaults to `null` (renders nothing).\n */\n displayWhileLoading?: ReactNode;\n\n /**\n * Custom element displayed when SSO authentication fails.\n * If not provided, the user is automatically redirected to `ssoLoginUrl`.\n */\n displayOnError?: ReactNode;\n\n /**\n * Re-validate the SSO session when the window regains focus.\n * Enabled by default so token expiry and user switching are picked up\n * without requiring a full page reload.\n */\n revalidateOnWindowFocus?: boolean;\n}\n\n// ─── Helpers ──────────────────────────────────────────────────────────\n\ntype AthenaSSOError = 'unauthenticated' | 'invalid_response' | 'request_failed';\n\nconst DEFAULT_SSO_PATHS = {\n userInfo: '/api/sso/userinfo',\n login: '/api/sso/initiate',\n logout: '/api/sso/logout',\n} as const;\n\nconst trimTrailingSlash = (value: string): string => value.replace(/\\/+$/, '');\n\nfunction resolveSSOUrl({\n baseUrl,\n overrideUrl,\n defaultPath,\n}: {\n baseUrl?: string;\n overrideUrl?: string;\n defaultPath: string;\n}): string {\n if (overrideUrl) {\n return overrideUrl;\n }\n\n if (!baseUrl) {\n return defaultPath;\n }\n\n return `${trimTrailingSlash(baseUrl)}${defaultPath}`;\n}\n\nfunction isValidSSOUserInfo(data: unknown): data is AthenaSSOUserInfo {\n if (!data || typeof data !== 'object') {\n return false;\n }\n\n const candidate = data as {\n accessToken?: unknown;\n orgMemberInfos?: unknown;\n user?: {\n user_id?: unknown;\n email?: unknown;\n };\n };\n\n return (\n typeof candidate.accessToken === 'string' &&\n Array.isArray(candidate.orgMemberInfos) &&\n !!candidate.user &&\n typeof candidate.user.user_id === 'string' &&\n typeof candidate.user.email === 'string'\n );\n}\n\n/** Map the backend SSO response to the SDK's user/org types. */\nfunction mapSSOResponse(data: AthenaSSOUserInfo): {\n user: AthenaUser;\n orgs: AthenaOrg[];\n accessToken: string;\n} {\n const user: AthenaUser = {\n userId: data.user.user_id,\n email: data.user.email,\n firstName: data.user.first_name || undefined,\n lastName: data.user.last_name || undefined,\n username: data.user.username || undefined,\n pictureUrl: data.user.picture_url || undefined,\n properties: data.user.properties,\n };\n\n const orgs: AthenaOrg[] = data.orgMemberInfos.map((org) => ({\n orgId: org.orgId,\n orgName: org.orgName,\n urlSafeOrgName: org.urlSafeOrgName,\n }));\n\n return { user, orgs, accessToken: data.accessToken };\n}\n\n// ─── Provider ─────────────────────────────────────────────────────────\n\n/**\n * Wraps your app with Athena authentication powered by an external SSO\n * identity provider (e.g. Microsoft Entra / Azure AD, Okta, etc.).\n *\n * The SSO login flow is handled entirely by your backend. This provider\n * verifies the session by fetching `ssoUserInfoUrl` and exposes the\n * same `AthenaAuthState` context that `AthenaAuthProvider` (PropelAuth)\n * provides, so downstream components like `<AthenaProvider>` and\n * `useAthenaAuth()` work identically.\n *\n * Place this **above** `<AthenaProvider>` in the component tree.\n *\n * @example\n * ```tsx\n * import { AthenaSSOProvider } from '@athenaintel/react/auth';\n * import { AthenaProvider, AthenaChat } from '@athenaintel/react';\n *\n * function App() {\n * return (\n * <AthenaSSOProvider\n * ssoUserInfoUrl=\"https://api.yourdomain.com/api/sso/userinfo\"\n * ssoLoginUrl=\"https://api.yourdomain.com/api/sso/initiate\"\n * >\n * <AthenaProvider>\n * <AthenaChat />\n * </AthenaProvider>\n * </AthenaSSOProvider>\n * );\n * }\n * ```\n */\nexport function AthenaSSOProvider({\n children,\n ssoBaseUrl,\n ssoUserInfoUrl,\n ssoLoginUrl,\n ssoLogoutUrl,\n displayWhileLoading,\n displayOnError,\n revalidateOnWindowFocus = true,\n}: AthenaSSOProviderProps) {\n const [ssoData, setSSOData] = useState<AthenaSSOUserInfo | null>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<AthenaSSOError | null>(null);\n const activeRequestRef = useRef<AbortController | null>(null);\n\n const ssoUrls = useMemo(\n () => ({\n userInfo: resolveSSOUrl({\n baseUrl: ssoBaseUrl,\n overrideUrl: ssoUserInfoUrl,\n defaultPath: DEFAULT_SSO_PATHS.userInfo,\n }),\n login: resolveSSOUrl({\n baseUrl: ssoBaseUrl,\n overrideUrl: ssoLoginUrl,\n defaultPath: DEFAULT_SSO_PATHS.login,\n }),\n logout: resolveSSOUrl({\n baseUrl: ssoBaseUrl,\n overrideUrl: ssoLogoutUrl,\n defaultPath: DEFAULT_SSO_PATHS.logout,\n }),\n }),\n [ssoBaseUrl, ssoUserInfoUrl, ssoLoginUrl, ssoLogoutUrl],\n );\n\n const refreshSession = useCallback(\n async ({ showLoading = false }: { showLoading?: boolean } = {}): Promise<void> => {\n activeRequestRef.current?.abort();\n const abortController = new AbortController();\n activeRequestRef.current = abortController;\n\n if (showLoading) {\n setLoading(true);\n }\n\n try {\n const response = await fetch(ssoUrls.userInfo, {\n credentials: 'include',\n signal: abortController.signal,\n });\n\n if (!response.ok) {\n if (response.status === 401 || response.status === 403) {\n setSSOData(null);\n setError('unauthenticated');\n } else {\n setError('request_failed');\n }\n return;\n }\n\n const data: unknown = await response.json();\n\n if (!isValidSSOUserInfo(data)) {\n console.error(\n '[AthenaSDK] Invalid SSO userinfo response: expected \"user.user_id\", \"user.email\", \"orgMemberInfos\", and \"accessToken\"',\n );\n setSSOData(null);\n setError('invalid_response');\n return;\n }\n\n setSSOData(data);\n setError(null);\n } catch (fetchError) {\n if (fetchError instanceof DOMException && fetchError.name === 'AbortError') {\n return;\n }\n\n setError('request_failed');\n } finally {\n if (activeRequestRef.current === abortController) {\n activeRequestRef.current = null;\n setLoading(false);\n }\n }\n },\n [ssoUrls.userInfo],\n );\n\n useEffect(() => {\n void refreshSession({ showLoading: true });\n\n return () => {\n activeRequestRef.current?.abort();\n };\n }, [refreshSession]);\n\n useEffect(() => {\n if (!revalidateOnWindowFocus || typeof window === 'undefined') {\n return;\n }\n\n const handleFocus = () => {\n void refreshSession();\n };\n const handleVisibilityChange = () => {\n if (document.visibilityState === 'visible') {\n void refreshSession();\n }\n };\n\n window.addEventListener('focus', handleFocus);\n document.addEventListener('visibilitychange', handleVisibilityChange);\n\n return () => {\n window.removeEventListener('focus', handleFocus);\n document.removeEventListener('visibilitychange', handleVisibilityChange);\n };\n }, [revalidateOnWindowFocus, refreshSession]);\n\n // Redirect to SSO login when session is invalid and no error UI provided.\n useEffect(() => {\n if (\n !loading &&\n error === 'unauthenticated' &&\n !displayOnError &&\n typeof window !== 'undefined'\n ) {\n window.location.assign(ssoUrls.login);\n }\n }, [loading, error, displayOnError, ssoUrls.login]);\n\n const logout = useCallback(async (redirectOnLogout = true) => {\n activeRequestRef.current?.abort();\n\n try {\n await fetch(ssoUrls.logout, {\n method: 'POST',\n credentials: 'include',\n });\n } catch (logoutError) {\n console.error('[AthenaSDK] Failed to invalidate SSO session during logout', logoutError);\n }\n\n setSSOData(null);\n setError(null);\n setLoading(false);\n\n if (redirectOnLogout && typeof window !== 'undefined') {\n window.location.assign(ssoUrls.login);\n }\n }, [ssoUrls.login, ssoUrls.logout]);\n\n const authState: AthenaAuthState = useMemo(() => {\n if (loading) {\n return {\n isLoggedIn: false,\n isLoading: true,\n user: null,\n accessToken: null,\n orgs: [],\n logout: async () => {},\n };\n }\n\n if (error === 'request_failed' && ssoData) {\n const { user, orgs, accessToken } = mapSSOResponse(ssoData);\n\n return {\n isLoggedIn: true,\n isLoading: false,\n user,\n accessToken,\n orgs,\n logout,\n };\n }\n\n if (error || !ssoData) {\n return {\n isLoggedIn: false,\n isLoading: false,\n user: null,\n accessToken: null,\n orgs: [],\n logout,\n };\n }\n\n const { user, orgs, accessToken } = mapSSOResponse(ssoData);\n\n return {\n isLoggedIn: true,\n isLoading: false,\n user,\n accessToken,\n orgs,\n logout,\n };\n }, [loading, error, ssoData, logout]);\n\n if (authState.isLoading) {\n return <>{displayWhileLoading ?? null}</>;\n }\n\n if (!authState.isLoggedIn) {\n return displayOnError ? <>{displayOnError}</> : null;\n }\n\n return (\n <AthenaAuthContext.Provider value={authState}>\n {children}\n </AthenaAuthContext.Provider>\n );\n}\n"],"names":["useState","useEffect","useAuthInfo","useLogoutFunction","useMemo","jsx","Fragment","AthenaAuthContext","RequiredAuthProvider","RedirectToLogin","useRef","useCallback","user","orgs","accessToken"],"mappings":"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"}
1
+ {"version":3,"file":"auth.cjs","sources":["../src/auth/AthenaAuthProvider.tsx","../src/auth/AthenaSSOProvider.tsx"],"sourcesContent":["import {\n RequiredAuthProvider,\n RedirectToLogin,\n useAuthInfo,\n useLogoutFunction,\n} from '@propelauth/react';\nimport type { ReactNode } from 'react';\nimport { useEffect, useMemo, useState } from 'react';\nimport { AthenaAuthContext } from './AthenaAuthContext';\nimport type { AthenaAuthState, AthenaOrg, AthenaUser } from './types';\n\n// ─── Props ────────────────────────────────────────────────────────────\n\nexport interface AthenaAuthProviderProps {\n children: ReactNode;\n\n /**\n * Your PropelAuth auth URL (e.g. `https://auth.yourdomain.com`).\n * Found in the PropelAuth dashboard under Frontend Integration.\n */\n authUrl: string;\n\n /**\n * Where to redirect after a successful login.\n * Defaults to the current page URL.\n */\n postLoginRedirectUrl?: string;\n\n /**\n * Custom element displayed while the auth state is loading.\n * Defaults to `null` (renders nothing).\n */\n displayWhileLoading?: ReactNode;\n}\n\nconst ATHENA_LOCATION_CHANGE_EVENT = 'athena:location-change';\nlet historyPatched = false;\n\nfunction patchHistoryForLocationTracking(): void {\n if (historyPatched || typeof window === 'undefined') {\n return;\n }\n\n const notifyLocationChange = () => {\n window.dispatchEvent(new Event(ATHENA_LOCATION_CHANGE_EVENT));\n };\n\n const originalPushState = window.history.pushState;\n window.history.pushState = function pushState(...args) {\n const result = originalPushState.apply(this, args);\n notifyLocationChange();\n return result;\n };\n\n const originalReplaceState = window.history.replaceState;\n window.history.replaceState = function replaceState(...args) {\n const result = originalReplaceState.apply(this, args);\n notifyLocationChange();\n return result;\n };\n\n historyPatched = true;\n}\n\nfunction useCurrentHref(): string {\n const [href, setHref] = useState(\n typeof window !== 'undefined' ? window.location.href : '/',\n );\n\n useEffect(() => {\n if (typeof window === 'undefined') {\n return;\n }\n\n patchHistoryForLocationTracking();\n\n const updateHref = () => {\n setHref(window.location.href);\n };\n\n updateHref();\n window.addEventListener('popstate', updateHref);\n window.addEventListener('hashchange', updateHref);\n window.addEventListener(ATHENA_LOCATION_CHANGE_EVENT, updateHref);\n\n return () => {\n window.removeEventListener('popstate', updateHref);\n window.removeEventListener('hashchange', updateHref);\n window.removeEventListener(ATHENA_LOCATION_CHANGE_EVENT, updateHref);\n };\n }, []);\n\n return href;\n}\n\n// ─── Internal Bridge ──────────────────────────────────────────────────\n\n/**\n * Reads PropelAuth state via hooks and maps it into the SDK's\n * `AthenaAuthState`, which is placed on `AthenaAuthContext`.\n */\nfunction AthenaAuthBridge({\n children,\n displayWhileLoading,\n}: {\n children: ReactNode;\n displayWhileLoading?: ReactNode;\n}) {\n const authInfo = useAuthInfo();\n const logoutFn = useLogoutFunction();\n\n const authState: AthenaAuthState = useMemo(() => {\n if (authInfo.loading) {\n return {\n isLoggedIn: false,\n isLoading: true,\n user: null,\n accessToken: null,\n orgs: [],\n logout: async () => {},\n };\n }\n\n if (!authInfo.isLoggedIn) {\n return {\n isLoggedIn: false,\n isLoading: false,\n user: null,\n accessToken: null,\n orgs: [],\n logout: async (redirect = true) => logoutFn(redirect),\n };\n }\n\n const user: AthenaUser = {\n userId: authInfo.user.userId,\n email: authInfo.user.email,\n firstName: authInfo.user.firstName ?? undefined,\n lastName: authInfo.user.lastName ?? undefined,\n username: authInfo.user.username ?? undefined,\n pictureUrl: authInfo.user.pictureUrl ?? undefined,\n properties: authInfo.user.properties,\n };\n\n const orgs: AthenaOrg[] =\n authInfo.orgHelper?.getOrgs().map((org) => ({\n orgId: org.orgId,\n orgName: org.orgName,\n urlSafeOrgName: org.urlSafeOrgName,\n })) ?? [];\n\n return {\n isLoggedIn: true,\n isLoading: false,\n user,\n accessToken: authInfo.accessToken,\n orgs,\n logout: async (redirect = true) => logoutFn(redirect),\n };\n }, [authInfo, logoutFn]);\n\n if (authState.isLoading) {\n return <>{displayWhileLoading ?? null}</>;\n }\n\n return (\n <AthenaAuthContext.Provider value={authState}>\n {children}\n </AthenaAuthContext.Provider>\n );\n}\n\n// ─── Public Provider ──────────────────────────────────────────────────\n\n/**\n * Wraps your app with Athena authentication powered by PropelAuth.\n *\n * Place this **above** `<AthenaProvider>` in the component tree.\n * When present, `AthenaProvider` will automatically use the access token\n * from this provider — no need to pass `token` or `apiKey` manually.\n *\n * @example\n * ```tsx\n * import { AthenaAuthProvider } from '@athenaintel/react/auth';\n * import { AthenaProvider, AthenaChat } from '@athenaintel/react';\n *\n * function App() {\n * return (\n * <AthenaAuthProvider authUrl=\"https://auth.yourdomain.com\">\n * <AthenaProvider>\n * <AthenaChat />\n * </AthenaProvider>\n * </AthenaAuthProvider>\n * );\n * }\n * ```\n */\nexport function AthenaAuthProvider({\n children,\n authUrl,\n postLoginRedirectUrl,\n displayWhileLoading,\n}: AthenaAuthProviderProps) {\n const currentHref = useCurrentHref();\n const redirectUrl = postLoginRedirectUrl ?? currentHref;\n\n return (\n <RequiredAuthProvider\n authUrl={authUrl}\n displayWhileLoading={\n displayWhileLoading ? <>{displayWhileLoading}</> : undefined\n }\n displayIfLoggedOut={<RedirectToLogin postLoginRedirectUrl={redirectUrl} />}\n >\n <AthenaAuthBridge displayWhileLoading={displayWhileLoading}>\n {children}\n </AthenaAuthBridge>\n </RequiredAuthProvider>\n );\n}\n","import type { ReactNode } from 'react';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { AthenaAuthContext } from './AthenaAuthContext';\nimport type {\n AthenaAuthState,\n AthenaOrg,\n AthenaSSOUserInfo,\n AthenaUser,\n} from './types';\n\n// ─── Props ────────────────────────────────────────────────────────────\n\nexport interface AthenaSSOProviderProps {\n children: ReactNode;\n\n /**\n * Base URL used to resolve the Athena SSO endpoints.\n *\n * When omitted, the provider defaults to same-origin relative paths:\n * `/api/sso/userinfo`, `/api/sso/initiate`, and `/api/sso/logout`.\n *\n * Use this when your frontend and backend live on different origins\n * (for example `https://app.example.com` + `https://api.example.com`).\n */\n ssoBaseUrl?: string;\n\n /**\n * Optional override for the SSO user-info endpoint that returns the\n * authenticated user's data and access token.\n *\n * The endpoint must return JSON matching `AthenaSSOUserInfo`:\n * ```json\n * {\n * \"user\": { \"user_id\": \"…\", \"email\": \"…\", … },\n * \"orgMemberInfos\": [{ \"orgId\": \"…\", \"orgName\": \"…\", \"urlSafeOrgName\": \"…\" }],\n * \"accessToken\": \"…\"\n * }\n * ```\n *\n * The request is sent with `credentials: 'include'` so that\n * session cookies are forwarded automatically.\n */\n ssoUserInfoUrl?: string;\n\n /**\n * Optional override for the URL to redirect the user to when no valid\n * SSO session exists.\n * This is typically the SSO initiation endpoint on your backend\n * (e.g. `https://api.yourdomain.com/api/sso/initiate`).\n */\n ssoLoginUrl?: string;\n\n /**\n * Optional override for the backend SSO logout endpoint.\n * Defaults to `/api/sso/logout` (or `${ssoBaseUrl}/api/sso/logout`).\n */\n ssoLogoutUrl?: string;\n\n /**\n * Custom element displayed while the SSO session is being verified.\n * Defaults to `null` (renders nothing).\n */\n displayWhileLoading?: ReactNode;\n\n /**\n * Custom element displayed when SSO authentication fails.\n * If not provided, the user is automatically redirected to `ssoLoginUrl`.\n */\n displayOnError?: ReactNode;\n\n /**\n * Re-validate the SSO session when the window regains focus.\n * Enabled by default so token expiry and user switching are picked up\n * without requiring a full page reload.\n */\n revalidateOnWindowFocus?: boolean;\n}\n\n// ─── Helpers ──────────────────────────────────────────────────────────\n\ntype AthenaSSOError = 'unauthenticated' | 'invalid_response' | 'request_failed';\n\nconst DEFAULT_SSO_PATHS = {\n userInfo: '/api/sso/userinfo',\n login: '/api/sso/initiate',\n logout: '/api/sso/logout',\n} as const;\n\nconst trimTrailingSlash = (value: string): string => value.replace(/\\/+$/, '');\n\nfunction resolveSSOUrl({\n baseUrl,\n overrideUrl,\n defaultPath,\n}: {\n baseUrl?: string;\n overrideUrl?: string;\n defaultPath: string;\n}): string {\n if (overrideUrl) {\n return overrideUrl;\n }\n\n if (!baseUrl) {\n return defaultPath;\n }\n\n return `${trimTrailingSlash(baseUrl)}${defaultPath}`;\n}\n\nfunction isValidSSOUserInfo(data: unknown): data is AthenaSSOUserInfo {\n if (!data || typeof data !== 'object') {\n return false;\n }\n\n const candidate = data as {\n accessToken?: unknown;\n orgMemberInfos?: unknown;\n user?: {\n user_id?: unknown;\n email?: unknown;\n };\n };\n\n return (\n typeof candidate.accessToken === 'string' &&\n Array.isArray(candidate.orgMemberInfos) &&\n !!candidate.user &&\n typeof candidate.user.user_id === 'string' &&\n typeof candidate.user.email === 'string'\n );\n}\n\n/** Map the backend SSO response to the SDK's user/org types. */\nfunction mapSSOResponse(data: AthenaSSOUserInfo): {\n user: AthenaUser;\n orgs: AthenaOrg[];\n accessToken: string;\n} {\n const user: AthenaUser = {\n userId: data.user.user_id,\n email: data.user.email,\n firstName: data.user.first_name || undefined,\n lastName: data.user.last_name || undefined,\n username: data.user.username || undefined,\n pictureUrl: data.user.picture_url || undefined,\n properties: data.user.properties,\n };\n\n const orgs: AthenaOrg[] = data.orgMemberInfos.map((org) => ({\n orgId: org.orgId,\n orgName: org.orgName,\n urlSafeOrgName: org.urlSafeOrgName,\n }));\n\n return { user, orgs, accessToken: data.accessToken };\n}\n\n// ─── Provider ─────────────────────────────────────────────────────────\n\n/**\n * Wraps your app with Athena authentication powered by an external SSO\n * identity provider (e.g. Microsoft Entra / Azure AD, Okta, etc.).\n *\n * The SSO login flow is handled entirely by your backend. This provider\n * verifies the session by fetching `ssoUserInfoUrl` and exposes the\n * same `AthenaAuthState` context that `AthenaAuthProvider` (PropelAuth)\n * provides, so downstream components like `<AthenaProvider>` and\n * `useAthenaAuth()` work identically.\n *\n * Place this **above** `<AthenaProvider>` in the component tree.\n *\n * @example\n * ```tsx\n * import { AthenaSSOProvider } from '@athenaintel/react/auth';\n * import { AthenaProvider, AthenaChat } from '@athenaintel/react';\n *\n * function App() {\n * return (\n * <AthenaSSOProvider\n * ssoUserInfoUrl=\"https://api.yourdomain.com/api/sso/userinfo\"\n * ssoLoginUrl=\"https://api.yourdomain.com/api/sso/initiate\"\n * >\n * <AthenaProvider>\n * <AthenaChat />\n * </AthenaProvider>\n * </AthenaSSOProvider>\n * );\n * }\n * ```\n */\nexport function AthenaSSOProvider({\n children,\n ssoBaseUrl,\n ssoUserInfoUrl,\n ssoLoginUrl,\n ssoLogoutUrl,\n displayWhileLoading,\n displayOnError,\n revalidateOnWindowFocus = true,\n}: AthenaSSOProviderProps) {\n const [ssoData, setSSOData] = useState<AthenaSSOUserInfo | null>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<AthenaSSOError | null>(null);\n const activeRequestRef = useRef<AbortController | null>(null);\n\n const ssoUrls = useMemo(\n () => ({\n userInfo: resolveSSOUrl({\n baseUrl: ssoBaseUrl,\n overrideUrl: ssoUserInfoUrl,\n defaultPath: DEFAULT_SSO_PATHS.userInfo,\n }),\n login: resolveSSOUrl({\n baseUrl: ssoBaseUrl,\n overrideUrl: ssoLoginUrl,\n defaultPath: DEFAULT_SSO_PATHS.login,\n }),\n logout: resolveSSOUrl({\n baseUrl: ssoBaseUrl,\n overrideUrl: ssoLogoutUrl,\n defaultPath: DEFAULT_SSO_PATHS.logout,\n }),\n }),\n [ssoBaseUrl, ssoUserInfoUrl, ssoLoginUrl, ssoLogoutUrl],\n );\n\n const refreshSession = useCallback(\n async ({ showLoading = false }: { showLoading?: boolean } = {}): Promise<void> => {\n activeRequestRef.current?.abort();\n const abortController = new AbortController();\n activeRequestRef.current = abortController;\n\n if (showLoading) {\n setLoading(true);\n setError(null);\n setSSOData(null);\n }\n\n try {\n const response = await fetch(ssoUrls.userInfo, {\n credentials: 'include',\n signal: abortController.signal,\n });\n\n if (!response.ok) {\n if (response.status === 401 || response.status === 403) {\n setSSOData(null);\n setError('unauthenticated');\n } else {\n setError('request_failed');\n }\n return;\n }\n\n const data: unknown = await response.json();\n\n if (!isValidSSOUserInfo(data)) {\n console.error(\n '[AthenaSDK] Invalid SSO userinfo response: expected \"user.user_id\", \"user.email\", \"orgMemberInfos\", and \"accessToken\"',\n );\n setSSOData(null);\n setError('invalid_response');\n return;\n }\n\n setSSOData(data);\n setError(null);\n } catch (fetchError) {\n if (fetchError instanceof DOMException && fetchError.name === 'AbortError') {\n return;\n }\n\n setError('request_failed');\n } finally {\n if (activeRequestRef.current === abortController) {\n activeRequestRef.current = null;\n setLoading(false);\n }\n }\n },\n [ssoUrls.userInfo],\n );\n\n useEffect(() => {\n void refreshSession({ showLoading: true });\n\n return () => {\n activeRequestRef.current?.abort();\n };\n }, [refreshSession]);\n\n useEffect(() => {\n if (!revalidateOnWindowFocus || typeof window === 'undefined') {\n return;\n }\n\n const handleFocus = () => {\n void refreshSession();\n };\n const handleVisibilityChange = () => {\n if (document.visibilityState === 'visible') {\n void refreshSession();\n }\n };\n\n window.addEventListener('focus', handleFocus);\n document.addEventListener('visibilitychange', handleVisibilityChange);\n\n return () => {\n window.removeEventListener('focus', handleFocus);\n document.removeEventListener('visibilitychange', handleVisibilityChange);\n };\n }, [revalidateOnWindowFocus, refreshSession]);\n\n // Redirect to SSO login when session is invalid and no error UI provided.\n useEffect(() => {\n if (\n !loading &&\n error === 'unauthenticated' &&\n !displayOnError &&\n typeof window !== 'undefined'\n ) {\n window.location.assign(ssoUrls.login);\n }\n }, [loading, error, displayOnError, ssoUrls.login]);\n\n const logout = useCallback(async (redirectOnLogout = true) => {\n activeRequestRef.current?.abort();\n\n try {\n await fetch(ssoUrls.logout, {\n method: 'POST',\n credentials: 'include',\n });\n } catch (logoutError) {\n console.error('[AthenaSDK] Failed to invalidate SSO session during logout', logoutError);\n }\n\n setSSOData(null);\n setError(null);\n setLoading(false);\n\n if (redirectOnLogout && typeof window !== 'undefined') {\n window.location.assign(ssoUrls.login);\n }\n }, [ssoUrls.login, ssoUrls.logout]);\n\n const authState: AthenaAuthState = useMemo(() => {\n if (loading) {\n return {\n isLoggedIn: false,\n isLoading: true,\n user: null,\n accessToken: null,\n orgs: [],\n logout: async () => {},\n };\n }\n\n if (error === 'request_failed' && ssoData) {\n const { user, orgs, accessToken } = mapSSOResponse(ssoData);\n\n return {\n isLoggedIn: true,\n isLoading: false,\n user,\n accessToken,\n orgs,\n logout,\n };\n }\n\n if (error || !ssoData) {\n return {\n isLoggedIn: false,\n isLoading: false,\n user: null,\n accessToken: null,\n orgs: [],\n logout,\n };\n }\n\n const { user, orgs, accessToken } = mapSSOResponse(ssoData);\n\n return {\n isLoggedIn: true,\n isLoading: false,\n user,\n accessToken,\n orgs,\n logout,\n };\n }, [loading, error, ssoData, logout]);\n\n if (authState.isLoading) {\n return <>{displayWhileLoading ?? null}</>;\n }\n\n if (!authState.isLoggedIn) {\n return displayOnError ? <>{displayOnError}</> : null;\n }\n\n return (\n <AthenaAuthContext.Provider value={authState}>\n {children}\n </AthenaAuthContext.Provider>\n );\n}\n"],"names":["useState","useEffect","useAuthInfo","useLogoutFunction","useMemo","jsx","Fragment","AthenaAuthContext","RequiredAuthProvider","RedirectToLogin","useRef","useCallback","user","orgs","accessToken"],"mappings":"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"}
package/dist/auth.js CHANGED
@@ -210,6 +210,8 @@ function AthenaSSOProvider({
210
210
  activeRequestRef.current = abortController;
211
211
  if (showLoading) {
212
212
  setLoading(true);
213
+ setError(null);
214
+ setSSOData(null);
213
215
  }
214
216
  try {
215
217
  const response = await fetch(ssoUrls.userInfo, {
package/dist/auth.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"auth.js","sources":["../src/auth/AthenaAuthProvider.tsx","../src/auth/AthenaSSOProvider.tsx"],"sourcesContent":["import {\n RequiredAuthProvider,\n RedirectToLogin,\n useAuthInfo,\n useLogoutFunction,\n} from '@propelauth/react';\nimport type { ReactNode } from 'react';\nimport { useEffect, useMemo, useState } from 'react';\nimport { AthenaAuthContext } from './AthenaAuthContext';\nimport type { AthenaAuthState, AthenaOrg, AthenaUser } from './types';\n\n// ─── Props ────────────────────────────────────────────────────────────\n\nexport interface AthenaAuthProviderProps {\n children: ReactNode;\n\n /**\n * Your PropelAuth auth URL (e.g. `https://auth.yourdomain.com`).\n * Found in the PropelAuth dashboard under Frontend Integration.\n */\n authUrl: string;\n\n /**\n * Where to redirect after a successful login.\n * Defaults to the current page URL.\n */\n postLoginRedirectUrl?: string;\n\n /**\n * Custom element displayed while the auth state is loading.\n * Defaults to `null` (renders nothing).\n */\n displayWhileLoading?: ReactNode;\n}\n\nconst ATHENA_LOCATION_CHANGE_EVENT = 'athena:location-change';\nlet historyPatched = false;\n\nfunction patchHistoryForLocationTracking(): void {\n if (historyPatched || typeof window === 'undefined') {\n return;\n }\n\n const notifyLocationChange = () => {\n window.dispatchEvent(new Event(ATHENA_LOCATION_CHANGE_EVENT));\n };\n\n const originalPushState = window.history.pushState;\n window.history.pushState = function pushState(...args) {\n const result = originalPushState.apply(this, args);\n notifyLocationChange();\n return result;\n };\n\n const originalReplaceState = window.history.replaceState;\n window.history.replaceState = function replaceState(...args) {\n const result = originalReplaceState.apply(this, args);\n notifyLocationChange();\n return result;\n };\n\n historyPatched = true;\n}\n\nfunction useCurrentHref(): string {\n const [href, setHref] = useState(\n typeof window !== 'undefined' ? window.location.href : '/',\n );\n\n useEffect(() => {\n if (typeof window === 'undefined') {\n return;\n }\n\n patchHistoryForLocationTracking();\n\n const updateHref = () => {\n setHref(window.location.href);\n };\n\n updateHref();\n window.addEventListener('popstate', updateHref);\n window.addEventListener('hashchange', updateHref);\n window.addEventListener(ATHENA_LOCATION_CHANGE_EVENT, updateHref);\n\n return () => {\n window.removeEventListener('popstate', updateHref);\n window.removeEventListener('hashchange', updateHref);\n window.removeEventListener(ATHENA_LOCATION_CHANGE_EVENT, updateHref);\n };\n }, []);\n\n return href;\n}\n\n// ─── Internal Bridge ──────────────────────────────────────────────────\n\n/**\n * Reads PropelAuth state via hooks and maps it into the SDK's\n * `AthenaAuthState`, which is placed on `AthenaAuthContext`.\n */\nfunction AthenaAuthBridge({\n children,\n displayWhileLoading,\n}: {\n children: ReactNode;\n displayWhileLoading?: ReactNode;\n}) {\n const authInfo = useAuthInfo();\n const logoutFn = useLogoutFunction();\n\n const authState: AthenaAuthState = useMemo(() => {\n if (authInfo.loading) {\n return {\n isLoggedIn: false,\n isLoading: true,\n user: null,\n accessToken: null,\n orgs: [],\n logout: async () => {},\n };\n }\n\n if (!authInfo.isLoggedIn) {\n return {\n isLoggedIn: false,\n isLoading: false,\n user: null,\n accessToken: null,\n orgs: [],\n logout: async (redirect = true) => logoutFn(redirect),\n };\n }\n\n const user: AthenaUser = {\n userId: authInfo.user.userId,\n email: authInfo.user.email,\n firstName: authInfo.user.firstName ?? undefined,\n lastName: authInfo.user.lastName ?? undefined,\n username: authInfo.user.username ?? undefined,\n pictureUrl: authInfo.user.pictureUrl ?? undefined,\n properties: authInfo.user.properties,\n };\n\n const orgs: AthenaOrg[] =\n authInfo.orgHelper?.getOrgs().map((org) => ({\n orgId: org.orgId,\n orgName: org.orgName,\n urlSafeOrgName: org.urlSafeOrgName,\n })) ?? [];\n\n return {\n isLoggedIn: true,\n isLoading: false,\n user,\n accessToken: authInfo.accessToken,\n orgs,\n logout: async (redirect = true) => logoutFn(redirect),\n };\n }, [authInfo, logoutFn]);\n\n if (authState.isLoading) {\n return <>{displayWhileLoading ?? null}</>;\n }\n\n return (\n <AthenaAuthContext.Provider value={authState}>\n {children}\n </AthenaAuthContext.Provider>\n );\n}\n\n// ─── Public Provider ──────────────────────────────────────────────────\n\n/**\n * Wraps your app with Athena authentication powered by PropelAuth.\n *\n * Place this **above** `<AthenaProvider>` in the component tree.\n * When present, `AthenaProvider` will automatically use the access token\n * from this provider — no need to pass `token` or `apiKey` manually.\n *\n * @example\n * ```tsx\n * import { AthenaAuthProvider } from '@athenaintel/react/auth';\n * import { AthenaProvider, AthenaChat } from '@athenaintel/react';\n *\n * function App() {\n * return (\n * <AthenaAuthProvider authUrl=\"https://auth.yourdomain.com\">\n * <AthenaProvider>\n * <AthenaChat />\n * </AthenaProvider>\n * </AthenaAuthProvider>\n * );\n * }\n * ```\n */\nexport function AthenaAuthProvider({\n children,\n authUrl,\n postLoginRedirectUrl,\n displayWhileLoading,\n}: AthenaAuthProviderProps) {\n const currentHref = useCurrentHref();\n const redirectUrl = postLoginRedirectUrl ?? currentHref;\n\n return (\n <RequiredAuthProvider\n authUrl={authUrl}\n displayWhileLoading={\n displayWhileLoading ? <>{displayWhileLoading}</> : undefined\n }\n displayIfLoggedOut={<RedirectToLogin postLoginRedirectUrl={redirectUrl} />}\n >\n <AthenaAuthBridge displayWhileLoading={displayWhileLoading}>\n {children}\n </AthenaAuthBridge>\n </RequiredAuthProvider>\n );\n}\n","import type { ReactNode } from 'react';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { AthenaAuthContext } from './AthenaAuthContext';\nimport type {\n AthenaAuthState,\n AthenaOrg,\n AthenaSSOUserInfo,\n AthenaUser,\n} from './types';\n\n// ─── Props ────────────────────────────────────────────────────────────\n\nexport interface AthenaSSOProviderProps {\n children: ReactNode;\n\n /**\n * Base URL used to resolve the Athena SSO endpoints.\n *\n * When omitted, the provider defaults to same-origin relative paths:\n * `/api/sso/userinfo`, `/api/sso/initiate`, and `/api/sso/logout`.\n *\n * Use this when your frontend and backend live on different origins\n * (for example `https://app.example.com` + `https://api.example.com`).\n */\n ssoBaseUrl?: string;\n\n /**\n * Optional override for the SSO user-info endpoint that returns the\n * authenticated user's data and access token.\n *\n * The endpoint must return JSON matching `AthenaSSOUserInfo`:\n * ```json\n * {\n * \"user\": { \"user_id\": \"…\", \"email\": \"…\", … },\n * \"orgMemberInfos\": [{ \"orgId\": \"…\", \"orgName\": \"…\", \"urlSafeOrgName\": \"…\" }],\n * \"accessToken\": \"…\"\n * }\n * ```\n *\n * The request is sent with `credentials: 'include'` so that\n * session cookies are forwarded automatically.\n */\n ssoUserInfoUrl?: string;\n\n /**\n * Optional override for the URL to redirect the user to when no valid\n * SSO session exists.\n * This is typically the SSO initiation endpoint on your backend\n * (e.g. `https://api.yourdomain.com/api/sso/initiate`).\n */\n ssoLoginUrl?: string;\n\n /**\n * Optional override for the backend SSO logout endpoint.\n * Defaults to `/api/sso/logout` (or `${ssoBaseUrl}/api/sso/logout`).\n */\n ssoLogoutUrl?: string;\n\n /**\n * Custom element displayed while the SSO session is being verified.\n * Defaults to `null` (renders nothing).\n */\n displayWhileLoading?: ReactNode;\n\n /**\n * Custom element displayed when SSO authentication fails.\n * If not provided, the user is automatically redirected to `ssoLoginUrl`.\n */\n displayOnError?: ReactNode;\n\n /**\n * Re-validate the SSO session when the window regains focus.\n * Enabled by default so token expiry and user switching are picked up\n * without requiring a full page reload.\n */\n revalidateOnWindowFocus?: boolean;\n}\n\n// ─── Helpers ──────────────────────────────────────────────────────────\n\ntype AthenaSSOError = 'unauthenticated' | 'invalid_response' | 'request_failed';\n\nconst DEFAULT_SSO_PATHS = {\n userInfo: '/api/sso/userinfo',\n login: '/api/sso/initiate',\n logout: '/api/sso/logout',\n} as const;\n\nconst trimTrailingSlash = (value: string): string => value.replace(/\\/+$/, '');\n\nfunction resolveSSOUrl({\n baseUrl,\n overrideUrl,\n defaultPath,\n}: {\n baseUrl?: string;\n overrideUrl?: string;\n defaultPath: string;\n}): string {\n if (overrideUrl) {\n return overrideUrl;\n }\n\n if (!baseUrl) {\n return defaultPath;\n }\n\n return `${trimTrailingSlash(baseUrl)}${defaultPath}`;\n}\n\nfunction isValidSSOUserInfo(data: unknown): data is AthenaSSOUserInfo {\n if (!data || typeof data !== 'object') {\n return false;\n }\n\n const candidate = data as {\n accessToken?: unknown;\n orgMemberInfos?: unknown;\n user?: {\n user_id?: unknown;\n email?: unknown;\n };\n };\n\n return (\n typeof candidate.accessToken === 'string' &&\n Array.isArray(candidate.orgMemberInfos) &&\n !!candidate.user &&\n typeof candidate.user.user_id === 'string' &&\n typeof candidate.user.email === 'string'\n );\n}\n\n/** Map the backend SSO response to the SDK's user/org types. */\nfunction mapSSOResponse(data: AthenaSSOUserInfo): {\n user: AthenaUser;\n orgs: AthenaOrg[];\n accessToken: string;\n} {\n const user: AthenaUser = {\n userId: data.user.user_id,\n email: data.user.email,\n firstName: data.user.first_name || undefined,\n lastName: data.user.last_name || undefined,\n username: data.user.username || undefined,\n pictureUrl: data.user.picture_url || undefined,\n properties: data.user.properties,\n };\n\n const orgs: AthenaOrg[] = data.orgMemberInfos.map((org) => ({\n orgId: org.orgId,\n orgName: org.orgName,\n urlSafeOrgName: org.urlSafeOrgName,\n }));\n\n return { user, orgs, accessToken: data.accessToken };\n}\n\n// ─── Provider ─────────────────────────────────────────────────────────\n\n/**\n * Wraps your app with Athena authentication powered by an external SSO\n * identity provider (e.g. Microsoft Entra / Azure AD, Okta, etc.).\n *\n * The SSO login flow is handled entirely by your backend. This provider\n * verifies the session by fetching `ssoUserInfoUrl` and exposes the\n * same `AthenaAuthState` context that `AthenaAuthProvider` (PropelAuth)\n * provides, so downstream components like `<AthenaProvider>` and\n * `useAthenaAuth()` work identically.\n *\n * Place this **above** `<AthenaProvider>` in the component tree.\n *\n * @example\n * ```tsx\n * import { AthenaSSOProvider } from '@athenaintel/react/auth';\n * import { AthenaProvider, AthenaChat } from '@athenaintel/react';\n *\n * function App() {\n * return (\n * <AthenaSSOProvider\n * ssoUserInfoUrl=\"https://api.yourdomain.com/api/sso/userinfo\"\n * ssoLoginUrl=\"https://api.yourdomain.com/api/sso/initiate\"\n * >\n * <AthenaProvider>\n * <AthenaChat />\n * </AthenaProvider>\n * </AthenaSSOProvider>\n * );\n * }\n * ```\n */\nexport function AthenaSSOProvider({\n children,\n ssoBaseUrl,\n ssoUserInfoUrl,\n ssoLoginUrl,\n ssoLogoutUrl,\n displayWhileLoading,\n displayOnError,\n revalidateOnWindowFocus = true,\n}: AthenaSSOProviderProps) {\n const [ssoData, setSSOData] = useState<AthenaSSOUserInfo | null>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<AthenaSSOError | null>(null);\n const activeRequestRef = useRef<AbortController | null>(null);\n\n const ssoUrls = useMemo(\n () => ({\n userInfo: resolveSSOUrl({\n baseUrl: ssoBaseUrl,\n overrideUrl: ssoUserInfoUrl,\n defaultPath: DEFAULT_SSO_PATHS.userInfo,\n }),\n login: resolveSSOUrl({\n baseUrl: ssoBaseUrl,\n overrideUrl: ssoLoginUrl,\n defaultPath: DEFAULT_SSO_PATHS.login,\n }),\n logout: resolveSSOUrl({\n baseUrl: ssoBaseUrl,\n overrideUrl: ssoLogoutUrl,\n defaultPath: DEFAULT_SSO_PATHS.logout,\n }),\n }),\n [ssoBaseUrl, ssoUserInfoUrl, ssoLoginUrl, ssoLogoutUrl],\n );\n\n const refreshSession = useCallback(\n async ({ showLoading = false }: { showLoading?: boolean } = {}): Promise<void> => {\n activeRequestRef.current?.abort();\n const abortController = new AbortController();\n activeRequestRef.current = abortController;\n\n if (showLoading) {\n setLoading(true);\n }\n\n try {\n const response = await fetch(ssoUrls.userInfo, {\n credentials: 'include',\n signal: abortController.signal,\n });\n\n if (!response.ok) {\n if (response.status === 401 || response.status === 403) {\n setSSOData(null);\n setError('unauthenticated');\n } else {\n setError('request_failed');\n }\n return;\n }\n\n const data: unknown = await response.json();\n\n if (!isValidSSOUserInfo(data)) {\n console.error(\n '[AthenaSDK] Invalid SSO userinfo response: expected \"user.user_id\", \"user.email\", \"orgMemberInfos\", and \"accessToken\"',\n );\n setSSOData(null);\n setError('invalid_response');\n return;\n }\n\n setSSOData(data);\n setError(null);\n } catch (fetchError) {\n if (fetchError instanceof DOMException && fetchError.name === 'AbortError') {\n return;\n }\n\n setError('request_failed');\n } finally {\n if (activeRequestRef.current === abortController) {\n activeRequestRef.current = null;\n setLoading(false);\n }\n }\n },\n [ssoUrls.userInfo],\n );\n\n useEffect(() => {\n void refreshSession({ showLoading: true });\n\n return () => {\n activeRequestRef.current?.abort();\n };\n }, [refreshSession]);\n\n useEffect(() => {\n if (!revalidateOnWindowFocus || typeof window === 'undefined') {\n return;\n }\n\n const handleFocus = () => {\n void refreshSession();\n };\n const handleVisibilityChange = () => {\n if (document.visibilityState === 'visible') {\n void refreshSession();\n }\n };\n\n window.addEventListener('focus', handleFocus);\n document.addEventListener('visibilitychange', handleVisibilityChange);\n\n return () => {\n window.removeEventListener('focus', handleFocus);\n document.removeEventListener('visibilitychange', handleVisibilityChange);\n };\n }, [revalidateOnWindowFocus, refreshSession]);\n\n // Redirect to SSO login when session is invalid and no error UI provided.\n useEffect(() => {\n if (\n !loading &&\n error === 'unauthenticated' &&\n !displayOnError &&\n typeof window !== 'undefined'\n ) {\n window.location.assign(ssoUrls.login);\n }\n }, [loading, error, displayOnError, ssoUrls.login]);\n\n const logout = useCallback(async (redirectOnLogout = true) => {\n activeRequestRef.current?.abort();\n\n try {\n await fetch(ssoUrls.logout, {\n method: 'POST',\n credentials: 'include',\n });\n } catch (logoutError) {\n console.error('[AthenaSDK] Failed to invalidate SSO session during logout', logoutError);\n }\n\n setSSOData(null);\n setError(null);\n setLoading(false);\n\n if (redirectOnLogout && typeof window !== 'undefined') {\n window.location.assign(ssoUrls.login);\n }\n }, [ssoUrls.login, ssoUrls.logout]);\n\n const authState: AthenaAuthState = useMemo(() => {\n if (loading) {\n return {\n isLoggedIn: false,\n isLoading: true,\n user: null,\n accessToken: null,\n orgs: [],\n logout: async () => {},\n };\n }\n\n if (error === 'request_failed' && ssoData) {\n const { user, orgs, accessToken } = mapSSOResponse(ssoData);\n\n return {\n isLoggedIn: true,\n isLoading: false,\n user,\n accessToken,\n orgs,\n logout,\n };\n }\n\n if (error || !ssoData) {\n return {\n isLoggedIn: false,\n isLoading: false,\n user: null,\n accessToken: null,\n orgs: [],\n logout,\n };\n }\n\n const { user, orgs, accessToken } = mapSSOResponse(ssoData);\n\n return {\n isLoggedIn: true,\n isLoading: false,\n user,\n accessToken,\n orgs,\n logout,\n };\n }, [loading, error, ssoData, logout]);\n\n if (authState.isLoading) {\n return <>{displayWhileLoading ?? null}</>;\n }\n\n if (!authState.isLoggedIn) {\n return displayOnError ? <>{displayOnError}</> : null;\n }\n\n return (\n <AthenaAuthContext.Provider value={authState}>\n {children}\n </AthenaAuthContext.Provider>\n );\n}\n"],"names":["user","orgs","accessToken"],"mappings":";;;;;AAmCA,MAAM,+BAA+B;AACrC,IAAI,iBAAiB;AAErB,SAAS,kCAAwC;AAC/C,MAAI,kBAAkB,OAAO,WAAW,aAAa;AACnD;AAAA,EACF;AAEA,QAAM,uBAAuB,MAAM;AACjC,WAAO,cAAc,IAAI,MAAM,4BAA4B,CAAC;AAAA,EAC9D;AAEA,QAAM,oBAAoB,OAAO,QAAQ;AACzC,SAAO,QAAQ,YAAY,SAAS,aAAa,MAAM;AACrD,UAAM,SAAS,kBAAkB,MAAM,MAAM,IAAI;AACjD,yBAAA;AACA,WAAO;AAAA,EACT;AAEA,QAAM,uBAAuB,OAAO,QAAQ;AAC5C,SAAO,QAAQ,eAAe,SAAS,gBAAgB,MAAM;AAC3D,UAAM,SAAS,qBAAqB,MAAM,MAAM,IAAI;AACpD,yBAAA;AACA,WAAO;AAAA,EACT;AAEA,mBAAiB;AACnB;AAEA,SAAS,iBAAyB;AAChC,QAAM,CAAC,MAAM,OAAO,IAAI;AAAA,IACtB,OAAO,WAAW,cAAc,OAAO,SAAS,OAAO;AAAA,EAAA;AAGzD,YAAU,MAAM;AACd,QAAI,OAAO,WAAW,aAAa;AACjC;AAAA,IACF;AAEA,oCAAA;AAEA,UAAM,aAAa,MAAM;AACvB,cAAQ,OAAO,SAAS,IAAI;AAAA,IAC9B;AAEA,eAAA;AACA,WAAO,iBAAiB,YAAY,UAAU;AAC9C,WAAO,iBAAiB,cAAc,UAAU;AAChD,WAAO,iBAAiB,8BAA8B,UAAU;AAEhE,WAAO,MAAM;AACX,aAAO,oBAAoB,YAAY,UAAU;AACjD,aAAO,oBAAoB,cAAc,UAAU;AACnD,aAAO,oBAAoB,8BAA8B,UAAU;AAAA,IACrE;AAAA,EACF,GAAG,CAAA,CAAE;AAEL,SAAO;AACT;AAQA,SAAS,iBAAiB;AAAA,EACxB;AAAA,EACA;AACF,GAGG;AACD,QAAM,WAAW,YAAA;AACjB,QAAM,WAAW,kBAAA;AAEjB,QAAM,YAA6B,QAAQ,MAAM;;AAC/C,QAAI,SAAS,SAAS;AACpB,aAAO;AAAA,QACL,YAAY;AAAA,QACZ,WAAW;AAAA,QACX,MAAM;AAAA,QACN,aAAa;AAAA,QACb,MAAM,CAAA;AAAA,QACN,QAAQ,YAAY;AAAA,QAAC;AAAA,MAAA;AAAA,IAEzB;AAEA,QAAI,CAAC,SAAS,YAAY;AACxB,aAAO;AAAA,QACL,YAAY;AAAA,QACZ,WAAW;AAAA,QACX,MAAM;AAAA,QACN,aAAa;AAAA,QACb,MAAM,CAAA;AAAA,QACN,QAAQ,OAAO,WAAW,SAAS,SAAS,QAAQ;AAAA,MAAA;AAAA,IAExD;AAEA,UAAM,OAAmB;AAAA,MACvB,QAAQ,SAAS,KAAK;AAAA,MACtB,OAAO,SAAS,KAAK;AAAA,MACrB,WAAW,SAAS,KAAK,aAAa;AAAA,MACtC,UAAU,SAAS,KAAK,YAAY;AAAA,MACpC,UAAU,SAAS,KAAK,YAAY;AAAA,MACpC,YAAY,SAAS,KAAK,cAAc;AAAA,MACxC,YAAY,SAAS,KAAK;AAAA,IAAA;AAG5B,UAAM,SACJ,cAAS,cAAT,mBAAoB,UAAU,IAAI,CAAC,SAAS;AAAA,MAC1C,OAAO,IAAI;AAAA,MACX,SAAS,IAAI;AAAA,MACb,gBAAgB,IAAI;AAAA,IAAA,QACf,CAAA;AAET,WAAO;AAAA,MACL,YAAY;AAAA,MACZ,WAAW;AAAA,MACX;AAAA,MACA,aAAa,SAAS;AAAA,MACtB;AAAA,MACA,QAAQ,OAAO,WAAW,SAAS,SAAS,QAAQ;AAAA,IAAA;AAAA,EAExD,GAAG,CAAC,UAAU,QAAQ,CAAC;AAEvB,MAAI,UAAU,WAAW;AACvB,WAAO,oBAAA,UAAA,EAAG,iCAAuB,KAAA,CAAK;AAAA,EACxC;AAEA,6BACG,kBAAkB,UAAlB,EAA2B,OAAO,WAChC,UACH;AAEJ;AA2BO,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA4B;AAC1B,QAAM,cAAc,eAAA;AACpB,QAAM,cAAc,wBAAwB;AAE5C,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC;AAAA,MACA,qBACE,sBAAsB,oBAAA,UAAA,EAAG,UAAA,oBAAA,CAAoB,IAAM;AAAA,MAErD,oBAAoB,oBAAC,iBAAA,EAAgB,sBAAsB,YAAA,CAAa;AAAA,MAExE,UAAA,oBAAC,kBAAA,EAAiB,qBACf,SAAA,CACH;AAAA,IAAA;AAAA,EAAA;AAGN;ACzIA,MAAM,oBAAoB;AAAA,EACxB,UAAU;AAAA,EACV,OAAO;AAAA,EACP,QAAQ;AACV;AAEA,MAAM,oBAAoB,CAAC,UAA0B,MAAM,QAAQ,QAAQ,EAAE;AAE7E,SAAS,cAAc;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AACF,GAIW;AACT,MAAI,aAAa;AACf,WAAO;AAAA,EACT;AAEA,MAAI,CAAC,SAAS;AACZ,WAAO;AAAA,EACT;AAEA,SAAO,GAAG,kBAAkB,OAAO,CAAC,GAAG,WAAW;AACpD;AAEA,SAAS,mBAAmB,MAA0C;AACpE,MAAI,CAAC,QAAQ,OAAO,SAAS,UAAU;AACrC,WAAO;AAAA,EACT;AAEA,QAAM,YAAY;AASlB,SACE,OAAO,UAAU,gBAAgB,YACjC,MAAM,QAAQ,UAAU,cAAc,KACtC,CAAC,CAAC,UAAU,QACZ,OAAO,UAAU,KAAK,YAAY,YAClC,OAAO,UAAU,KAAK,UAAU;AAEpC;AAGA,SAAS,eAAe,MAItB;AACA,QAAM,OAAmB;AAAA,IACvB,QAAQ,KAAK,KAAK;AAAA,IAClB,OAAO,KAAK,KAAK;AAAA,IACjB,WAAW,KAAK,KAAK,cAAc;AAAA,IACnC,UAAU,KAAK,KAAK,aAAa;AAAA,IACjC,UAAU,KAAK,KAAK,YAAY;AAAA,IAChC,YAAY,KAAK,KAAK,eAAe;AAAA,IACrC,YAAY,KAAK,KAAK;AAAA,EAAA;AAGxB,QAAM,OAAoB,KAAK,eAAe,IAAI,CAAC,SAAS;AAAA,IAC1D,OAAO,IAAI;AAAA,IACX,SAAS,IAAI;AAAA,IACb,gBAAgB,IAAI;AAAA,EAAA,EACpB;AAEF,SAAO,EAAE,MAAM,MAAM,aAAa,KAAK,YAAA;AACzC;AAmCO,SAAS,kBAAkB;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,0BAA0B;AAC5B,GAA2B;AACzB,QAAM,CAAC,SAAS,UAAU,IAAI,SAAmC,IAAI;AACrE,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,IAAI;AAC3C,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAgC,IAAI;AAC9D,QAAM,mBAAmB,OAA+B,IAAI;AAE5D,QAAM,UAAU;AAAA,IACd,OAAO;AAAA,MACL,UAAU,cAAc;AAAA,QACtB,SAAS;AAAA,QACT,aAAa;AAAA,QACb,aAAa,kBAAkB;AAAA,MAAA,CAChC;AAAA,MACD,OAAO,cAAc;AAAA,QACnB,SAAS;AAAA,QACT,aAAa;AAAA,QACb,aAAa,kBAAkB;AAAA,MAAA,CAChC;AAAA,MACD,QAAQ,cAAc;AAAA,QACpB,SAAS;AAAA,QACT,aAAa;AAAA,QACb,aAAa,kBAAkB;AAAA,MAAA,CAChC;AAAA,IAAA;AAAA,IAEH,CAAC,YAAY,gBAAgB,aAAa,YAAY;AAAA,EAAA;AAGxD,QAAM,iBAAiB;AAAA,IACrB,OAAO,EAAE,cAAc,MAAA,IAAqC,OAAsB;;AAChF,6BAAiB,YAAjB,mBAA0B;AAC1B,YAAM,kBAAkB,IAAI,gBAAA;AAC5B,uBAAiB,UAAU;AAE3B,UAAI,aAAa;AACf,mBAAW,IAAI;AAAA,MACjB;AAEA,UAAI;AACF,cAAM,WAAW,MAAM,MAAM,QAAQ,UAAU;AAAA,UAC7C,aAAa;AAAA,UACb,QAAQ,gBAAgB;AAAA,QAAA,CACzB;AAED,YAAI,CAAC,SAAS,IAAI;AAChB,cAAI,SAAS,WAAW,OAAO,SAAS,WAAW,KAAK;AACtD,uBAAW,IAAI;AACf,qBAAS,iBAAiB;AAAA,UAC5B,OAAO;AACL,qBAAS,gBAAgB;AAAA,UAC3B;AACA;AAAA,QACF;AAEA,cAAM,OAAgB,MAAM,SAAS,KAAA;AAErC,YAAI,CAAC,mBAAmB,IAAI,GAAG;AAC7B,kBAAQ;AAAA,YACN;AAAA,UAAA;AAEF,qBAAW,IAAI;AACf,mBAAS,kBAAkB;AAC3B;AAAA,QACF;AAEA,mBAAW,IAAI;AACf,iBAAS,IAAI;AAAA,MACf,SAAS,YAAY;AACnB,YAAI,sBAAsB,gBAAgB,WAAW,SAAS,cAAc;AAC1E;AAAA,QACF;AAEA,iBAAS,gBAAgB;AAAA,MAC3B,UAAA;AACE,YAAI,iBAAiB,YAAY,iBAAiB;AAChD,2BAAiB,UAAU;AAC3B,qBAAW,KAAK;AAAA,QAClB;AAAA,MACF;AAAA,IACF;AAAA,IACA,CAAC,QAAQ,QAAQ;AAAA,EAAA;AAGnB,YAAU,MAAM;AACd,SAAK,eAAe,EAAE,aAAa,MAAM;AAEzC,WAAO,MAAM;;AACX,6BAAiB,YAAjB,mBAA0B;AAAA,IAC5B;AAAA,EACF,GAAG,CAAC,cAAc,CAAC;AAEnB,YAAU,MAAM;AACd,QAAI,CAAC,2BAA2B,OAAO,WAAW,aAAa;AAC7D;AAAA,IACF;AAEA,UAAM,cAAc,MAAM;AACxB,WAAK,eAAA;AAAA,IACP;AACA,UAAM,yBAAyB,MAAM;AACnC,UAAI,SAAS,oBAAoB,WAAW;AAC1C,aAAK,eAAA;AAAA,MACP;AAAA,IACF;AAEA,WAAO,iBAAiB,SAAS,WAAW;AAC5C,aAAS,iBAAiB,oBAAoB,sBAAsB;AAEpE,WAAO,MAAM;AACX,aAAO,oBAAoB,SAAS,WAAW;AAC/C,eAAS,oBAAoB,oBAAoB,sBAAsB;AAAA,IACzE;AAAA,EACF,GAAG,CAAC,yBAAyB,cAAc,CAAC;AAG5C,YAAU,MAAM;AACd,QACE,CAAC,WACD,UAAU,qBACV,CAAC,kBACD,OAAO,WAAW,aAClB;AACA,aAAO,SAAS,OAAO,QAAQ,KAAK;AAAA,IACtC;AAAA,EACF,GAAG,CAAC,SAAS,OAAO,gBAAgB,QAAQ,KAAK,CAAC;AAElD,QAAM,SAAS,YAAY,OAAO,mBAAmB,SAAS;;AAC5D,2BAAiB,YAAjB,mBAA0B;AAE1B,QAAI;AACF,YAAM,MAAM,QAAQ,QAAQ;AAAA,QAC1B,QAAQ;AAAA,QACR,aAAa;AAAA,MAAA,CACd;AAAA,IACH,SAAS,aAAa;AACpB,cAAQ,MAAM,8DAA8D,WAAW;AAAA,IACzF;AAEA,eAAW,IAAI;AACf,aAAS,IAAI;AACb,eAAW,KAAK;AAEhB,QAAI,oBAAoB,OAAO,WAAW,aAAa;AACrD,aAAO,SAAS,OAAO,QAAQ,KAAK;AAAA,IACtC;AAAA,EACF,GAAG,CAAC,QAAQ,OAAO,QAAQ,MAAM,CAAC;AAElC,QAAM,YAA6B,QAAQ,MAAM;AAC/C,QAAI,SAAS;AACX,aAAO;AAAA,QACL,YAAY;AAAA,QACZ,WAAW;AAAA,QACX,MAAM;AAAA,QACN,aAAa;AAAA,QACb,MAAM,CAAA;AAAA,QACN,QAAQ,YAAY;AAAA,QAAC;AAAA,MAAA;AAAA,IAEzB;AAEA,QAAI,UAAU,oBAAoB,SAAS;AACzC,YAAM,EAAE,MAAAA,OAAM,MAAAC,OAAM,aAAAC,aAAAA,IAAgB,eAAe,OAAO;AAE1D,aAAO;AAAA,QACL,YAAY;AAAA,QACZ,WAAW;AAAA,QACX,MAAAF;AAAAA,QACA,aAAAE;AAAAA,QACA,MAAAD;AAAAA,QACA;AAAA,MAAA;AAAA,IAEJ;AAEA,QAAI,SAAS,CAAC,SAAS;AACrB,aAAO;AAAA,QACL,YAAY;AAAA,QACZ,WAAW;AAAA,QACX,MAAM;AAAA,QACN,aAAa;AAAA,QACb,MAAM,CAAA;AAAA,QACN;AAAA,MAAA;AAAA,IAEJ;AAEA,UAAM,EAAE,MAAM,MAAM,YAAA,IAAgB,eAAe,OAAO;AAE1D,WAAO;AAAA,MACL,YAAY;AAAA,MACZ,WAAW;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,EAEJ,GAAG,CAAC,SAAS,OAAO,SAAS,MAAM,CAAC;AAEpC,MAAI,UAAU,WAAW;AACvB,WAAO,oBAAA,UAAA,EAAG,iCAAuB,KAAA,CAAK;AAAA,EACxC;AAEA,MAAI,CAAC,UAAU,YAAY;AACzB,WAAO,iBAAiB,oBAAA,UAAA,EAAG,UAAA,eAAA,CAAe,IAAM;AAAA,EAClD;AAEA,6BACG,kBAAkB,UAAlB,EAA2B,OAAO,WAChC,UACH;AAEJ;"}
1
+ {"version":3,"file":"auth.js","sources":["../src/auth/AthenaAuthProvider.tsx","../src/auth/AthenaSSOProvider.tsx"],"sourcesContent":["import {\n RequiredAuthProvider,\n RedirectToLogin,\n useAuthInfo,\n useLogoutFunction,\n} from '@propelauth/react';\nimport type { ReactNode } from 'react';\nimport { useEffect, useMemo, useState } from 'react';\nimport { AthenaAuthContext } from './AthenaAuthContext';\nimport type { AthenaAuthState, AthenaOrg, AthenaUser } from './types';\n\n// ─── Props ────────────────────────────────────────────────────────────\n\nexport interface AthenaAuthProviderProps {\n children: ReactNode;\n\n /**\n * Your PropelAuth auth URL (e.g. `https://auth.yourdomain.com`).\n * Found in the PropelAuth dashboard under Frontend Integration.\n */\n authUrl: string;\n\n /**\n * Where to redirect after a successful login.\n * Defaults to the current page URL.\n */\n postLoginRedirectUrl?: string;\n\n /**\n * Custom element displayed while the auth state is loading.\n * Defaults to `null` (renders nothing).\n */\n displayWhileLoading?: ReactNode;\n}\n\nconst ATHENA_LOCATION_CHANGE_EVENT = 'athena:location-change';\nlet historyPatched = false;\n\nfunction patchHistoryForLocationTracking(): void {\n if (historyPatched || typeof window === 'undefined') {\n return;\n }\n\n const notifyLocationChange = () => {\n window.dispatchEvent(new Event(ATHENA_LOCATION_CHANGE_EVENT));\n };\n\n const originalPushState = window.history.pushState;\n window.history.pushState = function pushState(...args) {\n const result = originalPushState.apply(this, args);\n notifyLocationChange();\n return result;\n };\n\n const originalReplaceState = window.history.replaceState;\n window.history.replaceState = function replaceState(...args) {\n const result = originalReplaceState.apply(this, args);\n notifyLocationChange();\n return result;\n };\n\n historyPatched = true;\n}\n\nfunction useCurrentHref(): string {\n const [href, setHref] = useState(\n typeof window !== 'undefined' ? window.location.href : '/',\n );\n\n useEffect(() => {\n if (typeof window === 'undefined') {\n return;\n }\n\n patchHistoryForLocationTracking();\n\n const updateHref = () => {\n setHref(window.location.href);\n };\n\n updateHref();\n window.addEventListener('popstate', updateHref);\n window.addEventListener('hashchange', updateHref);\n window.addEventListener(ATHENA_LOCATION_CHANGE_EVENT, updateHref);\n\n return () => {\n window.removeEventListener('popstate', updateHref);\n window.removeEventListener('hashchange', updateHref);\n window.removeEventListener(ATHENA_LOCATION_CHANGE_EVENT, updateHref);\n };\n }, []);\n\n return href;\n}\n\n// ─── Internal Bridge ──────────────────────────────────────────────────\n\n/**\n * Reads PropelAuth state via hooks and maps it into the SDK's\n * `AthenaAuthState`, which is placed on `AthenaAuthContext`.\n */\nfunction AthenaAuthBridge({\n children,\n displayWhileLoading,\n}: {\n children: ReactNode;\n displayWhileLoading?: ReactNode;\n}) {\n const authInfo = useAuthInfo();\n const logoutFn = useLogoutFunction();\n\n const authState: AthenaAuthState = useMemo(() => {\n if (authInfo.loading) {\n return {\n isLoggedIn: false,\n isLoading: true,\n user: null,\n accessToken: null,\n orgs: [],\n logout: async () => {},\n };\n }\n\n if (!authInfo.isLoggedIn) {\n return {\n isLoggedIn: false,\n isLoading: false,\n user: null,\n accessToken: null,\n orgs: [],\n logout: async (redirect = true) => logoutFn(redirect),\n };\n }\n\n const user: AthenaUser = {\n userId: authInfo.user.userId,\n email: authInfo.user.email,\n firstName: authInfo.user.firstName ?? undefined,\n lastName: authInfo.user.lastName ?? undefined,\n username: authInfo.user.username ?? undefined,\n pictureUrl: authInfo.user.pictureUrl ?? undefined,\n properties: authInfo.user.properties,\n };\n\n const orgs: AthenaOrg[] =\n authInfo.orgHelper?.getOrgs().map((org) => ({\n orgId: org.orgId,\n orgName: org.orgName,\n urlSafeOrgName: org.urlSafeOrgName,\n })) ?? [];\n\n return {\n isLoggedIn: true,\n isLoading: false,\n user,\n accessToken: authInfo.accessToken,\n orgs,\n logout: async (redirect = true) => logoutFn(redirect),\n };\n }, [authInfo, logoutFn]);\n\n if (authState.isLoading) {\n return <>{displayWhileLoading ?? null}</>;\n }\n\n return (\n <AthenaAuthContext.Provider value={authState}>\n {children}\n </AthenaAuthContext.Provider>\n );\n}\n\n// ─── Public Provider ──────────────────────────────────────────────────\n\n/**\n * Wraps your app with Athena authentication powered by PropelAuth.\n *\n * Place this **above** `<AthenaProvider>` in the component tree.\n * When present, `AthenaProvider` will automatically use the access token\n * from this provider — no need to pass `token` or `apiKey` manually.\n *\n * @example\n * ```tsx\n * import { AthenaAuthProvider } from '@athenaintel/react/auth';\n * import { AthenaProvider, AthenaChat } from '@athenaintel/react';\n *\n * function App() {\n * return (\n * <AthenaAuthProvider authUrl=\"https://auth.yourdomain.com\">\n * <AthenaProvider>\n * <AthenaChat />\n * </AthenaProvider>\n * </AthenaAuthProvider>\n * );\n * }\n * ```\n */\nexport function AthenaAuthProvider({\n children,\n authUrl,\n postLoginRedirectUrl,\n displayWhileLoading,\n}: AthenaAuthProviderProps) {\n const currentHref = useCurrentHref();\n const redirectUrl = postLoginRedirectUrl ?? currentHref;\n\n return (\n <RequiredAuthProvider\n authUrl={authUrl}\n displayWhileLoading={\n displayWhileLoading ? <>{displayWhileLoading}</> : undefined\n }\n displayIfLoggedOut={<RedirectToLogin postLoginRedirectUrl={redirectUrl} />}\n >\n <AthenaAuthBridge displayWhileLoading={displayWhileLoading}>\n {children}\n </AthenaAuthBridge>\n </RequiredAuthProvider>\n );\n}\n","import type { ReactNode } from 'react';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { AthenaAuthContext } from './AthenaAuthContext';\nimport type {\n AthenaAuthState,\n AthenaOrg,\n AthenaSSOUserInfo,\n AthenaUser,\n} from './types';\n\n// ─── Props ────────────────────────────────────────────────────────────\n\nexport interface AthenaSSOProviderProps {\n children: ReactNode;\n\n /**\n * Base URL used to resolve the Athena SSO endpoints.\n *\n * When omitted, the provider defaults to same-origin relative paths:\n * `/api/sso/userinfo`, `/api/sso/initiate`, and `/api/sso/logout`.\n *\n * Use this when your frontend and backend live on different origins\n * (for example `https://app.example.com` + `https://api.example.com`).\n */\n ssoBaseUrl?: string;\n\n /**\n * Optional override for the SSO user-info endpoint that returns the\n * authenticated user's data and access token.\n *\n * The endpoint must return JSON matching `AthenaSSOUserInfo`:\n * ```json\n * {\n * \"user\": { \"user_id\": \"…\", \"email\": \"…\", … },\n * \"orgMemberInfos\": [{ \"orgId\": \"…\", \"orgName\": \"…\", \"urlSafeOrgName\": \"…\" }],\n * \"accessToken\": \"…\"\n * }\n * ```\n *\n * The request is sent with `credentials: 'include'` so that\n * session cookies are forwarded automatically.\n */\n ssoUserInfoUrl?: string;\n\n /**\n * Optional override for the URL to redirect the user to when no valid\n * SSO session exists.\n * This is typically the SSO initiation endpoint on your backend\n * (e.g. `https://api.yourdomain.com/api/sso/initiate`).\n */\n ssoLoginUrl?: string;\n\n /**\n * Optional override for the backend SSO logout endpoint.\n * Defaults to `/api/sso/logout` (or `${ssoBaseUrl}/api/sso/logout`).\n */\n ssoLogoutUrl?: string;\n\n /**\n * Custom element displayed while the SSO session is being verified.\n * Defaults to `null` (renders nothing).\n */\n displayWhileLoading?: ReactNode;\n\n /**\n * Custom element displayed when SSO authentication fails.\n * If not provided, the user is automatically redirected to `ssoLoginUrl`.\n */\n displayOnError?: ReactNode;\n\n /**\n * Re-validate the SSO session when the window regains focus.\n * Enabled by default so token expiry and user switching are picked up\n * without requiring a full page reload.\n */\n revalidateOnWindowFocus?: boolean;\n}\n\n// ─── Helpers ──────────────────────────────────────────────────────────\n\ntype AthenaSSOError = 'unauthenticated' | 'invalid_response' | 'request_failed';\n\nconst DEFAULT_SSO_PATHS = {\n userInfo: '/api/sso/userinfo',\n login: '/api/sso/initiate',\n logout: '/api/sso/logout',\n} as const;\n\nconst trimTrailingSlash = (value: string): string => value.replace(/\\/+$/, '');\n\nfunction resolveSSOUrl({\n baseUrl,\n overrideUrl,\n defaultPath,\n}: {\n baseUrl?: string;\n overrideUrl?: string;\n defaultPath: string;\n}): string {\n if (overrideUrl) {\n return overrideUrl;\n }\n\n if (!baseUrl) {\n return defaultPath;\n }\n\n return `${trimTrailingSlash(baseUrl)}${defaultPath}`;\n}\n\nfunction isValidSSOUserInfo(data: unknown): data is AthenaSSOUserInfo {\n if (!data || typeof data !== 'object') {\n return false;\n }\n\n const candidate = data as {\n accessToken?: unknown;\n orgMemberInfos?: unknown;\n user?: {\n user_id?: unknown;\n email?: unknown;\n };\n };\n\n return (\n typeof candidate.accessToken === 'string' &&\n Array.isArray(candidate.orgMemberInfos) &&\n !!candidate.user &&\n typeof candidate.user.user_id === 'string' &&\n typeof candidate.user.email === 'string'\n );\n}\n\n/** Map the backend SSO response to the SDK's user/org types. */\nfunction mapSSOResponse(data: AthenaSSOUserInfo): {\n user: AthenaUser;\n orgs: AthenaOrg[];\n accessToken: string;\n} {\n const user: AthenaUser = {\n userId: data.user.user_id,\n email: data.user.email,\n firstName: data.user.first_name || undefined,\n lastName: data.user.last_name || undefined,\n username: data.user.username || undefined,\n pictureUrl: data.user.picture_url || undefined,\n properties: data.user.properties,\n };\n\n const orgs: AthenaOrg[] = data.orgMemberInfos.map((org) => ({\n orgId: org.orgId,\n orgName: org.orgName,\n urlSafeOrgName: org.urlSafeOrgName,\n }));\n\n return { user, orgs, accessToken: data.accessToken };\n}\n\n// ─── Provider ─────────────────────────────────────────────────────────\n\n/**\n * Wraps your app with Athena authentication powered by an external SSO\n * identity provider (e.g. Microsoft Entra / Azure AD, Okta, etc.).\n *\n * The SSO login flow is handled entirely by your backend. This provider\n * verifies the session by fetching `ssoUserInfoUrl` and exposes the\n * same `AthenaAuthState` context that `AthenaAuthProvider` (PropelAuth)\n * provides, so downstream components like `<AthenaProvider>` and\n * `useAthenaAuth()` work identically.\n *\n * Place this **above** `<AthenaProvider>` in the component tree.\n *\n * @example\n * ```tsx\n * import { AthenaSSOProvider } from '@athenaintel/react/auth';\n * import { AthenaProvider, AthenaChat } from '@athenaintel/react';\n *\n * function App() {\n * return (\n * <AthenaSSOProvider\n * ssoUserInfoUrl=\"https://api.yourdomain.com/api/sso/userinfo\"\n * ssoLoginUrl=\"https://api.yourdomain.com/api/sso/initiate\"\n * >\n * <AthenaProvider>\n * <AthenaChat />\n * </AthenaProvider>\n * </AthenaSSOProvider>\n * );\n * }\n * ```\n */\nexport function AthenaSSOProvider({\n children,\n ssoBaseUrl,\n ssoUserInfoUrl,\n ssoLoginUrl,\n ssoLogoutUrl,\n displayWhileLoading,\n displayOnError,\n revalidateOnWindowFocus = true,\n}: AthenaSSOProviderProps) {\n const [ssoData, setSSOData] = useState<AthenaSSOUserInfo | null>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<AthenaSSOError | null>(null);\n const activeRequestRef = useRef<AbortController | null>(null);\n\n const ssoUrls = useMemo(\n () => ({\n userInfo: resolveSSOUrl({\n baseUrl: ssoBaseUrl,\n overrideUrl: ssoUserInfoUrl,\n defaultPath: DEFAULT_SSO_PATHS.userInfo,\n }),\n login: resolveSSOUrl({\n baseUrl: ssoBaseUrl,\n overrideUrl: ssoLoginUrl,\n defaultPath: DEFAULT_SSO_PATHS.login,\n }),\n logout: resolveSSOUrl({\n baseUrl: ssoBaseUrl,\n overrideUrl: ssoLogoutUrl,\n defaultPath: DEFAULT_SSO_PATHS.logout,\n }),\n }),\n [ssoBaseUrl, ssoUserInfoUrl, ssoLoginUrl, ssoLogoutUrl],\n );\n\n const refreshSession = useCallback(\n async ({ showLoading = false }: { showLoading?: boolean } = {}): Promise<void> => {\n activeRequestRef.current?.abort();\n const abortController = new AbortController();\n activeRequestRef.current = abortController;\n\n if (showLoading) {\n setLoading(true);\n setError(null);\n setSSOData(null);\n }\n\n try {\n const response = await fetch(ssoUrls.userInfo, {\n credentials: 'include',\n signal: abortController.signal,\n });\n\n if (!response.ok) {\n if (response.status === 401 || response.status === 403) {\n setSSOData(null);\n setError('unauthenticated');\n } else {\n setError('request_failed');\n }\n return;\n }\n\n const data: unknown = await response.json();\n\n if (!isValidSSOUserInfo(data)) {\n console.error(\n '[AthenaSDK] Invalid SSO userinfo response: expected \"user.user_id\", \"user.email\", \"orgMemberInfos\", and \"accessToken\"',\n );\n setSSOData(null);\n setError('invalid_response');\n return;\n }\n\n setSSOData(data);\n setError(null);\n } catch (fetchError) {\n if (fetchError instanceof DOMException && fetchError.name === 'AbortError') {\n return;\n }\n\n setError('request_failed');\n } finally {\n if (activeRequestRef.current === abortController) {\n activeRequestRef.current = null;\n setLoading(false);\n }\n }\n },\n [ssoUrls.userInfo],\n );\n\n useEffect(() => {\n void refreshSession({ showLoading: true });\n\n return () => {\n activeRequestRef.current?.abort();\n };\n }, [refreshSession]);\n\n useEffect(() => {\n if (!revalidateOnWindowFocus || typeof window === 'undefined') {\n return;\n }\n\n const handleFocus = () => {\n void refreshSession();\n };\n const handleVisibilityChange = () => {\n if (document.visibilityState === 'visible') {\n void refreshSession();\n }\n };\n\n window.addEventListener('focus', handleFocus);\n document.addEventListener('visibilitychange', handleVisibilityChange);\n\n return () => {\n window.removeEventListener('focus', handleFocus);\n document.removeEventListener('visibilitychange', handleVisibilityChange);\n };\n }, [revalidateOnWindowFocus, refreshSession]);\n\n // Redirect to SSO login when session is invalid and no error UI provided.\n useEffect(() => {\n if (\n !loading &&\n error === 'unauthenticated' &&\n !displayOnError &&\n typeof window !== 'undefined'\n ) {\n window.location.assign(ssoUrls.login);\n }\n }, [loading, error, displayOnError, ssoUrls.login]);\n\n const logout = useCallback(async (redirectOnLogout = true) => {\n activeRequestRef.current?.abort();\n\n try {\n await fetch(ssoUrls.logout, {\n method: 'POST',\n credentials: 'include',\n });\n } catch (logoutError) {\n console.error('[AthenaSDK] Failed to invalidate SSO session during logout', logoutError);\n }\n\n setSSOData(null);\n setError(null);\n setLoading(false);\n\n if (redirectOnLogout && typeof window !== 'undefined') {\n window.location.assign(ssoUrls.login);\n }\n }, [ssoUrls.login, ssoUrls.logout]);\n\n const authState: AthenaAuthState = useMemo(() => {\n if (loading) {\n return {\n isLoggedIn: false,\n isLoading: true,\n user: null,\n accessToken: null,\n orgs: [],\n logout: async () => {},\n };\n }\n\n if (error === 'request_failed' && ssoData) {\n const { user, orgs, accessToken } = mapSSOResponse(ssoData);\n\n return {\n isLoggedIn: true,\n isLoading: false,\n user,\n accessToken,\n orgs,\n logout,\n };\n }\n\n if (error || !ssoData) {\n return {\n isLoggedIn: false,\n isLoading: false,\n user: null,\n accessToken: null,\n orgs: [],\n logout,\n };\n }\n\n const { user, orgs, accessToken } = mapSSOResponse(ssoData);\n\n return {\n isLoggedIn: true,\n isLoading: false,\n user,\n accessToken,\n orgs,\n logout,\n };\n }, [loading, error, ssoData, logout]);\n\n if (authState.isLoading) {\n return <>{displayWhileLoading ?? null}</>;\n }\n\n if (!authState.isLoggedIn) {\n return displayOnError ? <>{displayOnError}</> : null;\n }\n\n return (\n <AthenaAuthContext.Provider value={authState}>\n {children}\n </AthenaAuthContext.Provider>\n );\n}\n"],"names":["user","orgs","accessToken"],"mappings":"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"}
package/dist/index.cjs CHANGED
@@ -16600,6 +16600,7 @@ function isTrustedOrigin({
16600
16600
  }
16601
16601
  }
16602
16602
  const BRIDGE_TIMEOUT_MS = 2e3;
16603
+ const EMPTY_TRUSTED_ORIGINS = [];
16603
16604
  const normalizeOrigin = (value) => {
16604
16605
  try {
16605
16606
  return new URL(value).origin;
@@ -16608,17 +16609,13 @@ const normalizeOrigin = (value) => {
16608
16609
  }
16609
16610
  };
16610
16611
  function useParentBridge({
16611
- trustedOrigins = []
16612
+ trustedOrigins = EMPTY_TRUSTED_ORIGINS
16612
16613
  } = {}) {
16613
16614
  const isInIframe = typeof window !== "undefined" && window.parent !== window;
16614
16615
  const runtimeTrustedOrigins = React.useMemo(() => {
16615
16616
  const origins = /* @__PURE__ */ new Set();
16616
16617
  if (typeof window !== "undefined") {
16617
16618
  origins.add(window.location.origin);
16618
- const referrerOrigin = normalizeOrigin(document.referrer);
16619
- if (referrerOrigin) {
16620
- origins.add(referrerOrigin);
16621
- }
16622
16619
  }
16623
16620
  for (const trustedOrigin of trustedOrigins) {
16624
16621
  const normalizedOrigin = normalizeOrigin(trustedOrigin);