@vertesia/ui 1.6.0-dev.20260918.090710Z → 1.6.0-dev.20260923.085325Z
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/lib/boot/branding.d.ts +13 -0
- package/lib/boot/branding.d.ts.map +1 -1
- package/lib/boot/branding.js +7 -0
- package/lib/boot/branding.js.map +1 -1
- package/lib/boot/index.d.ts +1 -1
- package/lib/boot/index.d.ts.map +1 -1
- package/lib/boot/index.js +5 -23
- package/lib/boot/index.js.map +1 -1
- package/lib/boot/loading.d.ts +4 -0
- package/lib/boot/loading.d.ts.map +1 -0
- package/lib/boot/loading.js +28 -0
- package/lib/boot/loading.js.map +1 -0
- package/lib/core/components/SelectList.d.ts.map +1 -1
- package/lib/core/components/SelectList.js +3 -3
- package/lib/core/components/SelectList.js.map +1 -1
- package/lib/core/components/SidePanel.d.ts.map +1 -1
- package/lib/core/components/SidePanel.js +2 -1
- package/lib/core/components/SidePanel.js.map +1 -1
- package/lib/core/components/shadcn/theme/ThemeProvider.d.ts.map +1 -1
- package/lib/core/components/shadcn/theme/ThemeProvider.js +21 -5
- package/lib/core/components/shadcn/theme/ThemeProvider.js.map +1 -1
- package/lib/env/index.d.ts +11 -0
- package/lib/env/index.d.ts.map +1 -1
- package/lib/env/index.js +16 -3
- package/lib/env/index.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentConversation.js +4 -1
- package/lib/features/agent/chat/ModernAgentConversation.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageInput.d.ts +5 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageInput.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageInput.js +9 -2
- package/lib/features/agent/chat/ModernAgentOutput/MessageInput.js.map +1 -1
- package/lib/features/magic-pdf/GroundedExtractionView.js +3 -3
- package/lib/features/magic-pdf/GroundedExtractionView.js.map +1 -1
- package/lib/features/media-viewer/AudioPanel.d.ts +10 -2
- package/lib/features/media-viewer/AudioPanel.d.ts.map +1 -1
- package/lib/features/media-viewer/AudioPanel.js +78 -13
- package/lib/features/media-viewer/AudioPanel.js.map +1 -1
- package/lib/features/oauth/McpConnectionsButton.d.ts +2 -2
- package/lib/features/oauth/McpConnectionsButton.d.ts.map +1 -1
- package/lib/features/oauth/McpConnectionsButton.js +9 -7
- package/lib/features/oauth/McpConnectionsButton.js.map +1 -1
- package/lib/features/oauth/McpConnectionsDialog.d.ts.map +1 -1
- package/lib/features/oauth/McpConnectionsDialog.js +7 -3
- package/lib/features/oauth/McpConnectionsDialog.js.map +1 -1
- package/lib/features/oauth/useMcpConnections.d.ts +4 -2
- package/lib/features/oauth/useMcpConnections.d.ts.map +1 -1
- package/lib/features/oauth/useMcpConnections.js +15 -9
- package/lib/features/oauth/useMcpConnections.js.map +1 -1
- package/lib/features/store/objects/selection/ObjectsActionContext.d.ts.map +1 -1
- package/lib/features/store/objects/selection/ObjectsActionContext.js +2 -0
- package/lib/features/store/objects/selection/ObjectsActionContext.js.map +1 -1
- package/lib/features/store/objects/selection/SelectionActions.d.ts +4 -2
- package/lib/features/store/objects/selection/SelectionActions.d.ts.map +1 -1
- package/lib/features/store/objects/selection/SelectionActions.js +6 -3
- package/lib/features/store/objects/selection/SelectionActions.js.map +1 -1
- package/lib/features/store/objects/selection/actions/StartWorkflowAction.d.ts +4 -0
- package/lib/features/store/objects/selection/actions/StartWorkflowAction.d.ts.map +1 -0
- package/lib/features/store/objects/selection/actions/StartWorkflowAction.js +81 -0
- package/lib/features/store/objects/selection/actions/StartWorkflowAction.js.map +1 -0
- package/lib/features/store/objects/selection/actions/index.d.ts +1 -0
- package/lib/features/store/objects/selection/actions/index.d.ts.map +1 -1
- package/lib/features/store/objects/selection/actions/index.js +1 -0
- package/lib/features/store/objects/selection/actions/index.js.map +1 -1
- package/lib/features/store/types/TypeRegistry.d.ts +345 -155
- package/lib/features/store/types/TypeRegistry.d.ts.map +1 -1
- package/lib/features/store/types/search/ObjectTypeSearchContext.d.ts +345 -155
- package/lib/features/store/types/search/ObjectTypeSearchContext.d.ts.map +1 -1
- package/lib/i18n/locales/ar.json +10 -2
- package/lib/i18n/locales/de.json +6 -2
- package/lib/i18n/locales/en.json +6 -2
- package/lib/i18n/locales/es.json +6 -2
- package/lib/i18n/locales/fr.json +7 -2
- package/lib/i18n/locales/it.json +6 -2
- package/lib/i18n/locales/ja.json +6 -2
- package/lib/i18n/locales/ko.json +6 -2
- package/lib/i18n/locales/pt.json +6 -2
- package/lib/i18n/locales/ru.json +8 -2
- package/lib/i18n/locales/tr.json +6 -2
- package/lib/i18n/locales/zh-TW.json +6 -2
- package/lib/i18n/locales/zh.json +6 -2
- package/lib/session/UserSession.d.ts +3 -0
- package/lib/session/UserSession.d.ts.map +1 -1
- package/lib/session/UserSession.js +18 -8
- package/lib/session/UserSession.js.map +1 -1
- package/lib/session/UserSessionProvider.d.ts.map +1 -1
- package/lib/session/UserSessionProvider.js +34 -24
- package/lib/session/UserSessionProvider.js.map +1 -1
- package/lib/session/auth/authRoundTrip.d.ts +8 -0
- package/lib/session/auth/authRoundTrip.d.ts.map +1 -0
- package/lib/session/auth/authRoundTrip.js +22 -0
- package/lib/session/auth/authRoundTrip.js.map +1 -0
- package/lib/session/auth/composable.d.ts.map +1 -1
- package/lib/session/auth/composable.js +9 -7
- package/lib/session/auth/composable.js.map +1 -1
- package/lib/session/auth/domainRouting.d.ts +13 -6
- package/lib/session/auth/domainRouting.d.ts.map +1 -1
- package/lib/session/auth/domainRouting.js +2 -21
- package/lib/session/auth/domainRouting.js.map +1 -1
- package/lib/session/auth/oauth.d.ts +6 -1
- package/lib/session/auth/oauth.d.ts.map +1 -1
- package/lib/session/auth/oauth.js +145 -8
- package/lib/session/auth/oauth.js.map +1 -1
- package/lib/session/auth/tokenIssuer.d.ts +3 -0
- package/lib/session/auth/tokenIssuer.d.ts.map +1 -0
- package/lib/session/auth/tokenIssuer.js +27 -0
- package/lib/session/auth/tokenIssuer.js.map +1 -0
- package/lib/session/auth/vertesiaHosts.d.ts +47 -0
- package/lib/session/auth/vertesiaHosts.d.ts.map +1 -0
- package/lib/session/auth/vertesiaHosts.js +79 -0
- package/lib/session/auth/vertesiaHosts.js.map +1 -0
- package/lib/session/index.d.ts +1 -0
- package/lib/session/index.d.ts.map +1 -1
- package/lib/session/index.js +1 -0
- package/lib/session/index.js.map +1 -1
- package/lib/shell/AuthScreenPreview.d.ts +1 -1
- package/lib/shell/AuthScreenPreview.d.ts.map +1 -1
- package/lib/shell/AuthScreenPreview.js +2 -5
- package/lib/shell/AuthScreenPreview.js.map +1 -1
- package/lib/shell/BrandedAuthScreens.d.ts +1 -4
- package/lib/shell/BrandedAuthScreens.d.ts.map +1 -1
- package/lib/shell/BrandedAuthScreens.js +5 -26
- package/lib/shell/BrandedAuthScreens.js.map +1 -1
- package/lib/shell/BrandedLoadingIndicator.d.ts +11 -0
- package/lib/shell/BrandedLoadingIndicator.d.ts.map +1 -0
- package/lib/shell/BrandedLoadingIndicator.js +27 -0
- package/lib/shell/BrandedLoadingIndicator.js.map +1 -0
- package/lib/shell/SplashScreen.d.ts.map +1 -1
- package/lib/shell/SplashScreen.js +2 -1
- package/lib/shell/SplashScreen.js.map +1 -1
- package/lib/shell/apps/AppInstallationProvider.d.ts +16 -4
- package/lib/shell/apps/AppInstallationProvider.d.ts.map +1 -1
- package/lib/shell/apps/iframe-auth.d.ts +2 -0
- package/lib/shell/apps/iframe-auth.d.ts.map +1 -1
- package/lib/shell/apps/iframe-auth.js +6 -2
- package/lib/shell/apps/iframe-auth.js.map +1 -1
- package/lib/shell/index.d.ts +1 -0
- package/lib/shell/index.d.ts.map +1 -1
- package/lib/shell/index.js +1 -0
- package/lib/shell/index.js.map +1 -1
- package/lib/shell/login/SignInAuthPending.js +2 -2
- package/lib/shell/login/SignInAuthPending.js.map +1 -1
- package/lib/shell/login/SignInEmailStep.d.ts.map +1 -1
- package/lib/shell/login/SignInEmailStep.js +2 -2
- package/lib/shell/login/SignInEmailStep.js.map +1 -1
- package/lib/shell/login/TerminalLogin.d.ts.map +1 -1
- package/lib/shell/login/TerminalLogin.js +28 -21
- package/lib/shell/login/TerminalLogin.js.map +1 -1
- package/lib/vertesia-ui-boot.js +33 -29
- package/lib/vertesia-ui-boot.js.map +1 -1
- package/lib/vertesia-ui-core.js +34 -34
- package/lib/vertesia-ui-core.js.map +1 -1
- package/lib/vertesia-ui-env.js +1 -1
- package/lib/vertesia-ui-env.js.map +1 -1
- package/lib/vertesia-ui-features.js +163 -163
- package/lib/vertesia-ui-features.js.map +1 -1
- package/lib/vertesia-ui-i18n.Bl8KeZUK.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.Bl8KeZUK.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.BmT06XFI.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.BmT06XFI.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.Ch-Jjj0L.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.Ch-Jjj0L.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.CjhloW9s.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.CjhloW9s.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.CkfHdQzY.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.CkfHdQzY.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.DFuKfTe1.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.DFuKfTe1.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.DHqNVekZ.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.DHqNVekZ.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.DOaKbmaj.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.DOaKbmaj.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.Dge3Gl-h.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.Dge3Gl-h.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.GLt-10Lx.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.GLt-10Lx.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.T-XtAGbw.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.T-XtAGbw.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.VOJyTpMM.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.VOJyTpMM.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.js +3 -3
- package/lib/vertesia-ui-i18n.js.map +1 -1
- package/lib/vertesia-ui-layout.js +15 -15
- package/lib/vertesia-ui-layout.js.map +1 -1
- package/lib/vertesia-ui-rich-text.js +44 -44
- package/lib/vertesia-ui-rich-text.js.map +1 -1
- package/lib/vertesia-ui-session.js +1 -1
- package/lib/vertesia-ui-session.js.map +1 -1
- package/lib/vertesia-ui-shell.js +72 -48
- package/lib/vertesia-ui-shell.js.map +1 -1
- package/lib/vertesia-ui-widgets.js +51 -51
- package/lib/vertesia-ui-widgets.js.map +1 -1
- package/package.json +19 -19
- package/src/boot/branding.ts +8 -0
- package/src/boot/index.ts +6 -23
- package/src/boot/loading.ts +27 -0
- package/src/core/components/SelectList.tsx +5 -2
- package/src/core/components/SidePanel.tsx +65 -60
- package/src/core/components/shadcn/theme/ThemeProvider.test.tsx +101 -0
- package/src/core/components/shadcn/theme/ThemeProvider.tsx +21 -9
- package/src/env/index.test.ts +21 -0
- package/src/env/index.ts +33 -2
- package/src/features/agent/chat/ModernAgentConversation.test.tsx +81 -0
- package/src/features/agent/chat/ModernAgentConversation.tsx +5 -0
- package/src/features/agent/chat/ModernAgentOutput/MessageInput.tsx +17 -1
- package/src/features/magic-pdf/GroundedExtractionView.tsx +3 -3
- package/src/features/media-viewer/AudioPanel.test.ts +84 -0
- package/src/features/media-viewer/AudioPanel.tsx +97 -14
- package/src/features/oauth/McpConnectionsButton.test.tsx +56 -0
- package/src/features/oauth/McpConnectionsButton.tsx +9 -6
- package/src/features/oauth/McpConnectionsDialog.tsx +14 -5
- package/src/features/oauth/useMcpConnections.test.ts +10 -0
- package/src/features/oauth/useMcpConnections.ts +18 -10
- package/src/features/store/objects/selection/ObjectsActionContext.tsx +2 -0
- package/src/features/store/objects/selection/SelectionActions.tsx +13 -6
- package/src/features/store/objects/selection/actions/StartWorkflowAction.tsx +162 -0
- package/src/features/store/objects/selection/actions/index.ts +1 -0
- package/src/i18n/locales/ar.json +10 -2
- package/src/i18n/locales/de.json +6 -2
- package/src/i18n/locales/en.json +6 -2
- package/src/i18n/locales/es.json +6 -2
- package/src/i18n/locales/fr.json +7 -2
- package/src/i18n/locales/it.json +6 -2
- package/src/i18n/locales/ja.json +6 -2
- package/src/i18n/locales/ko.json +6 -2
- package/src/i18n/locales/pt.json +6 -2
- package/src/i18n/locales/ru.json +8 -2
- package/src/i18n/locales/tr.json +6 -2
- package/src/i18n/locales/zh-TW.json +6 -2
- package/src/i18n/locales/zh.json +6 -2
- package/src/session/UserSession.test.ts +48 -3
- package/src/session/UserSession.ts +20 -8
- package/src/session/UserSessionProvider.handoff.test.tsx +103 -0
- package/src/session/UserSessionProvider.iframe.test.tsx +178 -0
- package/src/session/UserSessionProvider.state-mismatch.test.tsx +43 -0
- package/src/session/UserSessionProvider.tsx +35 -23
- package/src/session/auth/auth-flow.md +18 -5
- package/src/session/auth/authRoundTrip.ts +24 -0
- package/src/session/auth/composable.test.ts +23 -1
- package/src/session/auth/composable.ts +10 -8
- package/src/session/auth/domainRouting.ts +4 -25
- package/src/session/auth/oauth.test.ts +121 -4
- package/src/session/auth/oauth.ts +172 -11
- package/src/session/auth/tokenIssuer.test.ts +25 -0
- package/src/session/auth/tokenIssuer.ts +25 -0
- package/src/session/auth/vertesiaHosts.test.ts +26 -0
- package/src/session/auth/vertesiaHosts.ts +85 -0
- package/src/session/index.ts +1 -0
- package/src/shell/AuthScreenPreview.tsx +2 -6
- package/src/shell/BrandedAuthScreens.test.tsx +26 -0
- package/src/shell/BrandedAuthScreens.tsx +4 -40
- package/src/shell/BrandedLoadingIndicator.tsx +42 -0
- package/src/shell/SplashScreen.tsx +4 -4
- package/src/shell/apps/iframe-auth.test.ts +8 -11
- package/src/shell/apps/iframe-auth.ts +10 -1
- package/src/shell/index.tsx +1 -0
- package/src/shell/login/SignInAuthPending.tsx +2 -2
- package/src/shell/login/SignInEmailStep.tsx +4 -2
- package/src/shell/login/TerminalLogin.test.tsx +111 -0
- package/src/shell/login/TerminalLogin.tsx +61 -37
- package/lib/features/store/objects/selection/actions/StartWorkflowButton.d.ts +0 -7
- package/lib/features/store/objects/selection/actions/StartWorkflowButton.d.ts.map +0 -1
- package/lib/features/store/objects/selection/actions/StartWorkflowButton.js +0 -51
- package/lib/features/store/objects/selection/actions/StartWorkflowButton.js.map +0 -1
- package/lib/vertesia-ui-i18n.B3NFclwl.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.B3NFclwl.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.BWSrNIxc.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.BWSrNIxc.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.BWvWeB1p.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.BWvWeB1p.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.BZCXvTC1.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.BZCXvTC1.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.BbJMvFZW.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.BbJMvFZW.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.CE5ldwpt.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.CE5ldwpt.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.CMC0IShY.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.CMC0IShY.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.CkcRqBKU.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.CkcRqBKU.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.D-Mq1sw_.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.D-Mq1sw_.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.DkK68-A-.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.DkK68-A-.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.XE_dcCg6.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.XE_dcCg6.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.qgNqMPvK.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.qgNqMPvK.chunk.js.map +0 -1
- package/src/features/store/objects/selection/actions/StartWorkflowButton.tsx +0 -104
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{NO_ACCESSIBLE_ACCOUNT_ERROR_CODE as e,REQUESTED_SCOPE_UNAVAILABLE_ERROR_CODE as t,RESTRICTED_ENVIRONMENT_ERROR_CODE as n}from"@vertesia/common";import{Env as r}from"@vertesia/ui/env";import{jwtDecode as i}from"jwt-decode";import{getAnalytics as a,logEvent as o}from"firebase/analytics";import{initializeApp as s}from"firebase/app";import{getAuth as c,onAuthStateChanged as l}from"firebase/auth";import{createContext as u,useCallback as d,useContext as f,useEffect as p,useMemo as m,useRef as h,useState as g}from"react";import{NAMESPACE as _,i18nInstance as v}from"@vertesia/ui/i18n";import{VertesiaClient as y}from"@vertesia/client";import{jsx as b}from"react/jsx-runtime";const x=`composableai.lastSelectedAccountId`,S=`composableai.lastSelectedProjectId`,ee=`auth_state`,te=`auth_state_expiry`;function C(){let e=crypto.randomUUID();return sessionStorage.setItem(ee,e),sessionStorage.setItem(te,String(Date.now()+3e5)),e}function ne(e){if(!e)return`Missing state`;let t=sessionStorage.getItem(ee),n=parseInt(sessionStorage.getItem(te)||`0`,10);if(t!==e)return`State mismatched (${t} !== ${e})`;if(Date.now()>n)return`State expired`}function re(){sessionStorage.removeItem(ee),sessionStorage.removeItem(te)}function w(){if(typeof window>`u`||window.parent!==window)return!1;let e=window.__VERTESIA_RUNTIME_CONFIG__;return e?.authMode===`central`&&e.gatewaySession===!0}function ie(){let e=new URL(window.location.href),t=new URL(`/__appgen/auth/login`,e.origin);return t.searchParams.set(`target`,`${e.pathname}${e.search}${e.hash}`),t.toString()}async function T(e,t){let n=new Request(e,t);if(new URL(n.url).origin!==window.location.origin)throw Error(`Gateway session requests must stay on the application origin`);let r=new Headers(n.headers);r.delete(`authorization`),r.set(`x-vertesia-app-session`,`1`);let i=await fetch(new Request(n,{headers:r,credentials:`same-origin`,cache:`no-store`}));return i.status===401&&i.headers.get(`x-vertesia-session-required`)===`1`?(window.location.replace(ie()),new Promise(()=>{})):i}async function ae(){let e=await T(new URL(`/__appgen/session`,window.location.origin).toString());if(!e.ok)throw Error(`Application session could not be loaded (${e.status})`);let t=await e.json();if(!t.sub||!t.account?.id||!t.project?.id)throw Error(`Application session returned invalid user information`);return t}async function oe(){let e=await T(new URL(`/__appgen/session/logout`,window.location.origin).toString(),{method:`POST`});if(!e.ok)throw Error(`Application sign-out failed (${e.status})`)}const E=`vertesia.oauth.transaction`,D=`vertesia.oauth.access`;let O;function k(){return!(!r.oauth||window.parent!==window||window.AUTH_MODE===`firebase`||w())}function se(e){return btoa(String.fromCharCode(...e)).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=+$/,``)}function ce(){return se(crypto.getRandomValues(new Uint8Array(32)))}function le(e){let t=new URL(e);if(t.protocol!==`https:`||t.username||t.password)throw Error(`OAuth endpoint must use HTTPS`);return t}function ue(){sessionStorage.removeItem(D),sessionStorage.removeItem(E)}async function de(){let e=r.oauth;if(!e)throw Error(`Application OAuth is not configured`);let t=e.clientId.trim();if(!t)throw Error(`OAuth client ID is required`);let n=new URL(e.redirectUri),a=n.hostname===`localhost`||n.hostname.endsWith(`.localhost`)||n.hostname===`[::1]`||/^127\.\d+\.\d+\.\d+$/.test(n.hostname);if(n.protocol!==`https:`&&!(a&&n.protocol===`http:`))throw Error(`OAuth callback must use HTTPS or loopback HTTP`);let o=n.toString();if(new URL(o).origin!==window.location.origin)throw Error(`OAuth callback must be same-origin`);let s=r.endpoints.sts.replace(/\/+$/,``),c=new URL(window.location.href),l=c.origin+c.pathname===new URL(o).origin+new URL(o).pathname,u=l?c.searchParams.get(`state`):null,d=l?c.searchParams.get(`code`):null,f=l?c.searchParams.get(`error`):null,p;if(u||d||f){let e=sessionStorage.getItem(E);if(sessionStorage.removeItem(E),p=e?JSON.parse(e):void 0,!p||p.state!==u||p.clientId!==t||p.redirectUri!==o||p.issuer!==s||Date.now()-p.created>6e5||p.created>Date.now())throw Error(`Invalid or expired OAuth login state`);if(f||!d)throw Error(`Application sign-in was not completed (${f||`missing code`})`)}else{let e=sessionStorage.getItem(D);if(e){let n=JSON.parse(e),r=i(n.token);if(n.clientId===t&&n.issuer===s&&r.exp>Date.now()/1e3+30&&(!c.searchParams.get(`p`)||r.project?.id===c.searchParams.get(`p`))&&(!c.searchParams.get(`a`)||r.account?.id===c.searchParams.get(`a`)))return n.token}}let m=await fetch(`${s}/.well-known/oauth-authorization-server`);if(!m.ok)throw Error(`OAuth discovery failed (${m.status})`);let h=await m.json();if(h.issuer.replace(/\/+$/,``)!==s)throw Error(`OAuth issuer mismatch`);let g=le(h.authorization_endpoint),_=le(h.token_endpoint);if(p&&d){let e=await fetch(_,{method:`POST`,headers:{"Content-Type":`application/x-www-form-urlencoded`},body:new URLSearchParams({grant_type:`authorization_code`,code:d,client_id:t,redirect_uri:o,code_verifier:p.verifier})});if(!e.ok)throw Error(`OAuth code exchange failed (${e.status})`);let n=await e.json();if(!n.access_token||n.token_type?.toLowerCase()!==`bearer`)throw Error(`Invalid OAuth grant`);let r=i(n.access_token);if(r.iss.replace(/\/+$/,``)!==s||r.client_id!==t||r.exp<=Date.now()/1e3)throw Error(`OAuth grant does not match this application`);sessionStorage.setItem(D,JSON.stringify({token:n.access_token,clientId:t,issuer:s}));let a=new URL(p.target);if(a.origin!==window.location.origin)throw Error(`Invalid OAuth return target`);return window.history.replaceState(window.history.state,``,a),n.access_token}let v=e.scopes??[`openid`,`profile`];if(t.startsWith(`https://`)){let n=await fetch(le(t),{cache:`no-store`});if(!n.ok)throw Error(`Application CIMD unavailable (${n.status})`);let r=await n.json();if(!r.redirect_uris?.includes(o))throw Error(`Application CIMD does not allow this callback`);!e.scopes&&r.scope&&(v=r.scope.split(/\s+/))}let y=ce(),b={state:ce(),verifier:y,clientId:t,redirectUri:o,issuer:s,target:c.toString(),created:Date.now()},x=await crypto.subtle.digest(`SHA-256`,new TextEncoder().encode(y));g.searchParams.set(`client_id`,t),g.searchParams.set(`redirect_uri`,o),g.searchParams.set(`response_type`,`code`),g.searchParams.set(`state`,b.state),g.searchParams.set(`code_challenge_method`,`S256`),g.searchParams.set(`code_challenge`,se(new Uint8Array(x))),g.searchParams.set(`scope`,v.filter(e=>e!==`offline_access`).join(` `));let S=c.searchParams.get(`p`);return S&&g.searchParams.set(`project_id`,S),sessionStorage.setItem(E,JSON.stringify(b)),window.location.replace(g.toString()),new Promise(()=>{})}function A(){return O??=de().finally(()=>{O=void 0}),O}function fe(){return r.endpoints.auth||`https://auth.vertesia.io/`}function pe(e){return window.AUTH_MODE===`firebase`}function j(e){return!pe()}function M(){let e=new URL(document.baseURI),t=new URL(window.location.href),n=t.pathname.startsWith(e.pathname)?t:e;return n.hash=``,n}function N(){let e=new URL(document.baseURI);return e.hash=``,e.search=``,e}function P(e,t,n,r,i={}){let a=new URL(n);i.projectId&&a.searchParams.set(`p`,i.projectId),i.accountId&&a.searchParams.set(`a`,i.accountId);let o=new URL(e);return o.searchParams.set(`sts`,t),o.searchParams.set(`redirect_uri`,a.toString()),o.searchParams.set(`state`,r),o}function me(e,t){return`vtsauth=${e}; Path=/; Max-Age=${t}; SameSite=Lax${window.location.protocol===`https:`?`; Secure`:``}`}function he(){document.cookie=me(`1`,300)}function ge(){document.cookie=me(``,0)}function F(e={}){if(k()){A().catch(e=>r.logger.error(`Application OAuth sign-in failed`,e));return}if(w()){window.location.replace(ie());return}let t=P(fe(),r.endpoints.sts??`https://sts.vertesia.io`,M(),C(),e);he(),location.replace(t.toString())}function _e(){if(w()||k()||!j()||r.authTokenProvider||r.isLocalDev&&r.devAuthToken)return!1;let e=new URLSearchParams(window.location.hash.substring(1));return!(e.get(`token`)&&e.get(`state`))}let I=null,ve=null,L=null;function R(){if(!I)try{if(!r.firebase)throw Error(`Firebase configuration is not available in the environment`);I=s(r.firebase)}catch(e){throw console.error(`Failed to initialize Firebase app:`,e),Error(`Firebase initialization failed - environment may not be properly initialized`,{cause:e})}return I}function ye(){return ve||=a(R()),ve}function z(){return L||(L=c(R()),L.tenantId=r.firebase?.tenantId??null),L}async function be(e){if(r.firebase?.tenantId)return z().tenantId=r.firebase.tenantId,{firebaseTenantId:r.firebase.tenantId,provider:r.firebase.providerType??`oidc`,name:``,label:``};if(!e){console.log(`No tenant name or email specified, skipping tenant setup`);return}if(!r.firebase){console.log(`Firebase configuration is not available in the environment`);return}try{e&&console.log(`Resolving tenant ID from email: ${e}`);let t=3,n=250;for(;t>0;)try{let t=await fetch(`/api/resolve-tenant`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({tenantEmail:e}),signal:AbortSignal.timeout(5e3)});if(!t)throw Error(`No response received from tenant API`);if(!t.ok){try{let e=await t.json();console.error(`Failed to resolve tenant ID:`,e.error)}catch{console.error(`Failed to resolve tenant ID: HTTP ${t.status}`)}if(t.status===404){console.warn(`Tenant not found for ${e}`);return}throw Error(`HTTP error ${t.status}`)}let n=await t.json();if(n?.firebaseTenantId){let e=z();return e.tenantId=n.firebaseTenantId,r.firebase.providerType=n.provider??`oidc`,console.log(`Tenant ID set to ${e.tenantId}`),n}console.error(`Invalid response format, missing tenantId for ${e}`);return}catch(e){if(t>1)console.warn(`Tenant resolution failed, retrying in ${n}ms...`,e),await new Promise(e=>setTimeout(e,n)),n*=2,t--;else throw e}}catch(e){console.error(`Error setting Firebase tenant:`,e instanceof Error?e.message:`Unknown error`)}}async function xe(e){let t=z().currentUser;return t?t.getIdToken(e).then(n=>(r.logger.debug(`Got Firebase token`,{vertesia:{user_email:t.email,user_name:t.displayName,user_id:t.uid,refresh:e}}),n)).catch(n=>(r.logger.error(`Failed to get Firebase token`,{vertesia:{user_email:t.email,user_name:t.displayName,user_id:t.uid,refresh:e,error:n}}),console.error(`Failed to get access token`,n),null)):(r.logger.warn(`No user found`),Promise.resolve(null))}let B,V,H=!1;const Se=`vt.centralAuthRenewalAt`;function Ce(){if(!H||!j())return!1;let e=0;try{e=Number(sessionStorage.getItem(Se)??`0`)}catch{}if(Number.isFinite(e)&&e>0&&Date.now()-e<6e4)return r.logger.warn(`Central Auth session renewal already attempted; surfacing the failure instead`,{vertesia:{last_attempt_ms_ago:Date.now()-e}}),!1;try{sessionStorage.setItem(Se,String(Date.now()))}catch{}r.logger.info(`Renewing an expired Central Auth session through the broker`);let t=P(fe(),r.endpoints.sts??`https://sts.vertesia.io`,M(),C());return location.replace(t.toString()),!0}function we(e,t){if(!e)return;let n=`${S}-${e}`;if(t){let r=localStorage.getItem(n)===t;r&&localStorage.removeItem(n),r&&localStorage.getItem(`composableai.lastSelectedAccountId`)===e&&localStorage.removeItem(x);return}localStorage.getItem(`composableai.lastSelectedAccountId`)===e&&(localStorage.removeItem(x),localStorage.removeItem(n))}function Te(e){try{let t=i(e);return typeof t.email!=`string`||!t.email?void 0:{email:t.email,name:typeof t.name==`string`&&t.name?t.name:void 0}}catch{return}}function Ee(e){let t=e.searchParams.has(`a`)||e.searchParams.has(`p`)?void 0:r.defaultAuthSelection,n=e.searchParams.get(`a`)??t?.accountId,i=e.searchParams.get(`p`)??t?.projectId,a=n??(i===void 0?localStorage.getItem(`composableai.lastSelectedAccountId`)??void 0:void 0);return{accountId:a,projectId:i??localStorage.getItem(`composableai.lastSelectedProjectId-${a}`)??void 0}}function De(e){return e?.replace(/\/+$/,``)}function U(e){return i(e)}function Oe(e){if(!e)return!1;try{return De(U(e).iss)===De(r.endpoints.sts)}catch{return!1}}function ke(e,t,n){let r=U(e);return!(!r.exp||r.exp<=Date.now()/1e3+300||!(r.permissions?.length||r.account_roles?.length||r.project_roles?.length||r.apps?.length)||t&&r.account?.id!==t||n&&r.project?.id!==n)}async function W(a,o,s,c,l=0){r.logger.debug(`Getting/refreshing composable token`,{vertesia:{account_id:o,project_id:s,retry_count:l}});let u=await a();if(!u)throw Error(`No id token found`);let d=r.endpoints.sts;r.logger.debug(`Using STS for token generation`,{vertesia:{account_id:o,project_id:s,sts_url:d}});try{let f=new URL(`${d}/token/issue`),p={type:`user`,account_id:o,project_id:s,expires_at:c?Math.floor(Date.now()/1e3)+c:void 0},m=await fetch(f,{method:`POST`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${u}`},body:JSON.stringify(p)}).catch(e=>{throw console.error(`Failed to call STS endpoint`,e),r.logger.error(`Failed to call STS endpoint`,{vertesia:{account_id:o,project_id:s,error:e}}),new Z(`The authentication service could not be reached`,d,{cause:e})});if(u&&m?.status===404){r.logger.debug(`404: User not found - calling ensure-user endpoint`,{vertesia:{account_id:o,project_id:s,status:m?.status}});let e=await fetch(`${r.endpoints.studio}/auth/ensure-user`,{method:`POST`,headers:{Authorization:`Bearer ${u}`,"Content-Type":`application/json`}});if(e.status===412){r.logger.debug(`412: No invite found - signup required`,{vertesia:{account_id:o,project_id:s}});let e=i(u);throw e?.email?new K(`User not found - signup required`,e.email):(r.logger.error(`No email found in id token`),Error(`No email found in id token`))}if(e.status===403)throw r.logger.warn(`403: Customer-domain user requires an invite to join`,{vertesia:{account_id:o,project_id:s}}),Error(`Customer-domain user requires an invite to join`);if(!e.ok)throw console.error(`Failed to ensure user exists`,e.status),r.logger.error(`Failed to ensure user exists`,{vertesia:{account_id:o,project_id:s,status:e.status}}),Error(`Failed to ensure user exists`);return r.logger.debug(`User ensured - retrying token generation`,{vertesia:{account_id:o,project_id:s}}),W(a,o,s,c,l)}if(u&&m?.status===412){r.logger.info(`412: auth succeeded but user doesn't exist - signup required`,{vertesia:{account_id:o,project_id:s,status:m?.status}});let e=i(u);throw e?.email?(r.logger.info(`User not found`,{vertesia:{account_id:o,project_id:s,email:e.email}}),new K(`User not found`,e.email)):(r.logger.error(`No email found in id token`),Error(`No email found in id token`))}if(m.status===401)throw r.logger.warn(`STS rejected the identity credential`,{vertesia:{account_id:o,project_id:s,status:m.status}}),new X(`Your sign-in credentials could not be verified`,d,{status:m.status});if(m.status===403){let i=await m.json().catch(()=>void 0),a=Te(u);throw i?.errorCode===n?(r.logger.warn(`403: User lacks early-access for this restricted environment`,{vertesia:{account_id:o,project_id:s}}),new Q(i.message??`You don't have sufficient permission to visit unstable environments`)):i?.errorCode===e?(r.logger.warn(`STS identity has no accessible account`,{vertesia:{error_code:i.errorCode,status:m.status}}),new Y(d,i.message,a)):!i?.errorCode||i.errorCode===t?(r.logger.warn(`STS rejected the requested account or project`,{vertesia:{account_id:o,project_id:s,status:m.status,error_code:i?.errorCode??t}}),new J(d,o,s,i?.errorCode?i.message:void 0,a)):(r.logger.error(`STS returned an unrecognized forbidden response`,{vertesia:{account_id:o,project_id:s,status:m.status,error_code:i.errorCode}}),new Z(`The authentication service rejected the request`,d,{status:m.status,errorCode:i.errorCode,cause:i}))}if(!m.ok){let e=await m.text();throw console.error(`STS token generation failed:`,m.status,e),r.logger.error(`STS token generation failed`,{vertesia:{status:m.status,error:e,account_id:o,project_id:s}}),new Z(`The authentication service could not complete sign-in`,d,{status:m.status,cause:e})}let{token:h}=await m.json();return r.logger.debug(`Successfully got token from STS`),h}catch(e){throw e instanceof K||e instanceof q||e instanceof Q||e instanceof Error&&e.message===`Customer-domain user requires an invite to join`?e:(console.error(`Failed to get composable token from STS`,e),r.logger.error(`Failed to get composable token from STS`,{vertesia:{account_id:o,project_id:s,error:e}}),new Z(`The authentication service could not complete sign-in`,d,{cause:e}))}}async function Ae(e,t,n){return W(xe,e,t,n)}async function je(e,t,n,r){return W(()=>Promise.resolve(e),t,n,r)}function Me(){return B}async function G(e,t,n,i=!1,a=!1){let o=e??(t===void 0?localStorage.getItem(`composableai.lastSelectedAccountId`)??void 0:void 0),s=t??localStorage.getItem(`composableai.lastSelectedProjectId-${o}`)??void 0,c=r.isLocalDev?r.devAuthToken:void 0,l=c??n??B,u=(!o||V?.account?.id===o)&&(!s||V?.project?.id===s);if(!i&&B&&V&&u&&V.exp>Date.now()/1e3+300)return H=!0,{rawToken:B,token:V,error:!1};if(!i&&Oe(l)&&ke(l,o,s)){if(B=l,V=U(B),!V.exp)throw Error(`Invalid composable token`);return H=!0,{rawToken:B,token:V,error:!1}}try{if(!c&&!a&&z().currentUser)B=await Ae(o,s);else if(c)c&&(B=c);else{let e=await r.authTokenProvider?.()??n??B;B=!i&&e&&Oe(e)&&ke(e,o,s)?e:e?await W(()=>Promise.resolve(e),o,s):void 0}}catch(e){throw(e instanceof J||e instanceof Y||e instanceof X)&&(B=void 0,V=void 0,e instanceof J&&we(o,s)),e instanceof X&&Ce(),e}if(!B)throw r.logger.error(`Cannot acquire a composable token`,{vertesia:{account_id:o,project_id:s}}),Ce(),Error(`Cannot acquire a composable token`);if(V=U(B),!V?.exp||!B)throw console.error(`Invalid composable token`,V),r.logger.error(`Invalid composable token`,{vertesia:{account_id:o,project_id:s}}),Error(`Invalid composable token`);return H=!0,{rawToken:B,token:V,error:!1}}var K=class extends Error{email;constructor(e,t){super(e),this.name=`UserNotFoundError`,this.email=t}},q=class extends Error{stsURL;status;errorCode;constructor(e,t,n){super(e,n),this.name=`STSError`,this.stsURL=t,this.status=n?.status,this.errorCode=n?.errorCode}},J=class extends q{accountId;projectId;identity;requestedScope;selectorSource;recoveryUrl;constructor(e,n,r,i,a){super(i??`The requested account or project is not available.`,e,{status:403,errorCode:t}),this.accountId=n,this.projectId=r,this.identity=a,this.name=`RequestedScopeUnavailableError`,this.requestedScope=r?`project`:`account`}};const Ne=J;var Y=class extends q{identity;constructor(t,n,r){super(n??`No accessible account is available for this user.`,t,{status:403,errorCode:e}),this.identity=r,this.name=`NoAccessibleAccountError`}},X=class extends q{constructor(e,t,n){super(e,t,n),this.name=`CredentialError`}},Z=class extends q{constructor(e,t,n){super(e,t,n),this.name=`AuthenticationServiceError`}};function Pe(e){return e instanceof J}function Fe(e){return e instanceof Y}function Ie(e){return e instanceof X}function Le(e){return e instanceof Z}var Q=class extends Error{constructor(e){super(e),this.name=`RestrictedEnvironmentError`}};function Re(){return{generateState:d(()=>C(),[]),verifyState:d(e=>ne(e),[]),clearState:d(()=>re(),[])}}var ze=class e{isLoading=!0;client;authError;authToken;setSession;lastSelectedAccount;lastSelectedProject;onboardingComplete;constructor(e,t){this.client=e||new y({serverUrl:w()?`${window.location.origin}/__appgen/session/studio`:r.endpoints.studio,storeUrl:w()?`${window.location.origin}/__appgen/session/store`:r.endpoints.zeno,tokenServerUrl:r.endpoints.sts,fetch:w()?T:void 0}),t&&(this.setSession=t),this.logout=this.logout.bind(this),this.signOut=this.signOut.bind(this)}get store(){return this.client.store}get user(){return this.authToken}get account(){return this.authToken?.account}get project(){return this.authToken?.project}get accounts(){return this.authToken?.accounts}get authCallback(){return this.rawAuthToken.then(e=>`Bearer ${e}`)}get rawAuthToken(){return k()?A():w()?Promise.reject(Error(`Gateway session credentials are not available to application JavaScript`)):G().then(e=>{let t=e?.rawToken;if(!t)throw Error(`No token available`);return this.authToken=i(t),t})}async refreshAuthToken(){if(w()){let e=await this.loginGatewaySession();return this.setSession?.(this.clone()),e}if(k())return ue(),this.authToken=i(await A()),this.setSession?.(this.clone()),this.authToken;let e=(await G(void 0,void 0,void 0,!0))?.rawToken;if(!e)throw Error(`No token available`);return this.authToken=i(e),this.setSession?.(this.clone()),this.authToken}signOut(){this.logout()}getAccount(){return this.authToken?.account}async login(e,t={}){return this.authError=void 0,this.isLoading=!1,this.client.withAuthCallback(()=>this.authCallback),this.authToken=i(e),console.log(`Logging in as ${this.authToken?.name} with account ${this.authToken?.account.name} (${this.authToken?.account.id}, and project ${this.authToken?.project?.name} (${this.authToken?.project?.id})`),localStorage.setItem(x,this.authToken.account.id),localStorage.setItem(`${S}-${this.authToken.account.id}`,this.authToken.project?.id??``),r.onLogin?.(this.authToken),(t.loadOnboardingStatus??!0)&&await this.fetchOnboardingStatus(),Promise.resolve()}async loginGatewaySession(){return this.authToken=await ae(),this.client.withAuthCallback(void 0),this.authError=void 0,this.isLoading=!1,r.onLogin?.(this.authToken),this.authToken}isLoggedIn(){return!!this.authToken}logout(){if(console.log(`Logging out`),w()){oe().then(()=>{this.authToken=void 0,this.authError=void 0,this.isLoading=!1,r.onLogout?.(),this.setSession?.(this.clone())}).catch(e=>{this.authError=e instanceof Error?e:Error(String(e)),this.setSession?.(this.clone())});return}if(k()){ue(),this.client.withAuthCallback(void 0),this.authToken=void 0,this.authError=void 0,this.isLoading=!1,r.onLogout?.(),this.setSession?.(this.clone());return}if(j()){console.log(`Using central auth logout`),this.authError=void 0,this.isLoading=!1,this.authToken=void 0,this.setSession=void 0,this.client.withAuthCallback(void 0);let e=new URL(fe()),t=M();e.pathname=`/logout`,e.searchParams.set(`redirect_uri`,t.toString()),location.replace(e.toString())}else{console.log(`Using Firebase logout`);let e=!!this.authToken;this.authToken&&z().signOut(),this.authError=void 0,this.isLoading=!1,this.authToken=void 0,this.setSession=void 0,this.client.withAuthCallback(void 0),e&&location.replace(N().toString())}}async switchAccount(e){localStorage.setItem(x,e),this&&(this.account&&this.project?localStorage.setItem(`${S}-${this.account.id}`,this.project.id):this.account&&localStorage.removeItem(`${S}-${this.account.id}`));let t=N();t.searchParams.set(`a`,e),window.location.replace(t.toString())}async switchProject(e){this.account&&localStorage.setItem(`${S}-${this.account.id}`,e);let t=N();this.account?.id&&t.searchParams.set(`a`,this.account.id),t.searchParams.set(`p`,e),window.location.replace(t.toString())}async fetchAccounts(){return this.client.accounts.list().then(e=>{if(!this.authToken)throw Error(`No token available`);this.authToken.accounts=e,this.setSession?.(this.clone())}).catch(e=>{throw console.error(`Failed to fetch accounts`,e),e})}async fetchProjects(e){return this.client.projects.list([e]).then(t=>{if(!this.authToken)throw Error(`No token available`);this.authToken={...this.authToken,accounts:this.authToken.accounts?.map(n=>n.id===e?{...n,projects:t.filter(t=>t.account===e)}:n)},this.setSession?.(this.clone())}).catch(e=>{throw console.error(`Failed to fetch projects`,e),e})}async fetchOnboardingStatus(){if(!this.project?.id)return!1;if(this.onboardingComplete)return console.log(`Onboarding already completed`),!1;let e=this.onboardingComplete;try{let t=await this.client.account.onboardingProgress();return this.onboardingComplete=Object.values(t).every(e=>e===!0),e!==this.onboardingComplete&&this.setSession?.(this.clone()),e===!1&&this.onboardingComplete}catch(t){console.error(`Error fetching onboarding status:`,t),this.onboardingComplete=!1,e!==this.onboardingComplete&&this.setSession?.(this.clone())}return!1}clone(){let t=new e(this.client);return t.isLoading=this.isLoading,t.authError=this.authError,t.authToken=this.authToken,t.setSession=this.setSession,t.lastSelectedAccount=this.lastSelectedAccount,t.switchAccount=this.switchAccount,t.onboardingComplete=this.onboardingComplete,t}};const $=u(void 0);function Be(){let e=f($);if(!e)throw Error(`useUserSession must be used within a UserSessionProvider`);return e}function Ve(){let{user:e}=Be(),[t,n]=g(null),[r,i]=g(!0),[a,o]=g(null);return p(()=>{(async()=>{if(!e?.email){n(null),i(!1);return}try{let t=await fetch(`/api/resolve-tenant`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({tenantEmail:e.email})});if(t.ok){let e=await t.json();n(e?{tenantKey:e.name||`unknown`,name:e.label||e.name||`Unknown`,domain:e.domain||[],firebaseTenantId:e.firebaseTenantId,provider:e.provider,logo:e.logo}:null)}else n(null)}catch(e){console.error(`Error loading current tenant:`,e),o(v.getFixedT(null,_)(`errors.failedToLoadTenantConfig`)),n(null)}finally{i(!1)}})()},[e?.email]),{currentTenant:t,isLoading:r,error:a}}function He(e){let[,t]=e.split(`.`);if(!t)throw Error(`Invalid Vertesia auth token`);let n=t.replace(/-/g,`+`).replace(/_/g,`/`).padEnd(Math.ceil(t.length/4)*4,`=`);return JSON.parse(atob(n))}function Ue({children:e,token:t}){let n=m(()=>{let e=new ze;e.isLoading=!1;try{e.authToken=He(t),e.client.withAuthCallback(()=>Promise.resolve(`Bearer ${t}`)),localStorage.setItem(x,e.authToken.account.id),localStorage.setItem(`${S}-${e.authToken.account.id}`,e.authToken.project?.id??``)}catch(t){e.authError=t instanceof Error?t:Error(String(t))}return e.clone()},[t]);return b($.Provider,{value:n,children:e})}function We(){let e=new URL(window.location.href);e.hash=``,window.history.replaceState(window.history.state,``,`${e.pathname}${e.search}`)}function Ge(e,t,n=!1){let r=new URL(e),i=r.searchParams.get(`a`)??void 0,a=r.searchParams.get(`p`)??void 0;return i&&a&&i===t.accountId&&a===t.projectId?(r.searchParams.delete(`a`),r.searchParams.delete(`p`),t.requestedScope=`project`,t.selectorSource=`url`):a&&a===t.projectId?(r.searchParams.delete(`p`),t.requestedScope=`project`,t.selectorSource=`url`):i&&i===t.accountId?(r.searchParams.delete(`a`),t.requestedScope=`account`,t.selectorSource=`url`):(t.requestedScope=t.projectId?`project`:`account`,t.selectorSource=`persisted`),n&&(r.hash=``),t.recoveryUrl=r.toString(),r}function Ke({children:e,loadOnboardingStatus:n=!0}){let i=new URLSearchParams(location.hash.substring(1)),a=i.get(`token`),o=i.get(`state`),[s,c]=g(new ze),{verifyState:u,clearState:d}=Re(),f=h(!1),m=h(void 0),_=(e,n=!1)=>{let i=Ge(new URL(window.location.href),e,n);window.history.replaceState(window.history.state,``,i),r.logger.warn(`Sanitized an unavailable authentication scope`,{vertesia:{account_id:e.accountId,project_id:e.projectId,error_code:t,selector_source:e.selectorSource,requested_scope:e.requestedScope,recovery_action:`url_sanitized`}})},v=(e,t=!1)=>e instanceof J||e instanceof Y||e instanceof X||e instanceof Z||e instanceof K||e instanceof Q?(e instanceof J?_(e,t):t&&We(),s.isLoading=!1,s.authError=e,c(s.clone()),!0):!1;return m.current=()=>{if(f.current){r.logger.debug(`Skipping duplicate auth flow initiation`);return}f.current=!0,r.logger.debug(`Starting auth flow`);let{accountId:e,projectId:t}=Ee(new URL(window.location.href));if(r.logger.debug(`Selected account and project`,{vertesia:{account_id:e,project_id:t}}),w()||k()){let e=!1;return s.setSession=c,(w()?s.loginGatewaySession():A().then(e=>s.login(e,{loadOnboardingStatus:!1}))).then(()=>{e||c(s.clone())}).catch(t=>{e||(s.isLoading=!1,s.authError=t instanceof Error?t:Error(String(t)),c(s.clone()))}),()=>{e=!0,f.current=!1}}if(r.isLocalDev&&r.devAuthToken){s.setSession=c,G(e,t,r.devAuthToken).then(e=>s.login(e.rawToken).then(()=>c(s.clone()))).catch(n=>{v(n)||(console.error(`Failed to initialize dev auth token`,n),r.logger.error(`Failed to initialize dev auth token`,{vertesia:{account_id:e,project_id:t,error:n}}),s.isLoading=!1,s.authError=n instanceof Error?n:Error(String(n)),c(s.clone()))});return}if(a&&o){s.setSession=c;let i=u(o);i?(console.error(`Auth: invalid state: ${i}`),r.logger.error(`Invalid state: ${i}`,{vertesia:{state:o}}),F({accountId:e,projectId:t})):d(),G(e,t,a,!1,j()).then(e=>s.login(e.rawToken,{loadOnboardingStatus:n}).then(()=>{c(s.clone()),We()})).catch(n=>{v(n,!0)||(console.error(`Failed to fetch user token from studio, redirecting to central auth`,n),r.logger.error(`Failed to fetch user token from studio, redirecting to central auth`,{vertesia:{error:n}}),F({accountId:e,projectId:t}))});return}let i=!1,p,m=()=>{if(!i){if(!s.isLoggedIn()){if(r.logger.debug(`Not logged in & no token/state`,{vertesia:{account_id:e,project_id:t}}),j()){r.logger.debug(`Redirecting to central auth with selection`,{vertesia:{account_id:e,project_id:t}}),F({accountId:e,projectId:t});return}r.logger.debug(`Host is in Firebase auth allowlist`,{vertesia:{account_id:e,project_id:t}})}p=l(z(),async i=>{i?(r.logger.debug(`Successful login with firebase`,{vertesia:{account_id:e,project_id:t}}),s.setSession=c,await G(e,t,void 0,!1,j()).then(e=>s.login(e.rawToken,{loadOnboardingStatus:n}).then(()=>c(s.clone()))).catch(n=>{v(n)||(console.error(`Unexpected failure while fetching a user token`,n),r.logger.error(`Unexpected failure while fetching a user token`,{vertesia:{account_id:e,project_id:t,error:n}}),s.logout(),s.isLoading=!1,s.authError=n,c(s.clone()))})):(r.logger.debug(`Using anonymous user`,{vertesia:{account_id:e,project_id:t}}),s.client.withAuthCallback(void 0),s.logout(),c(s.clone()))})}};return r.authTokenProvider?(s.setSession=c,r.authTokenProvider().then(async r=>{if(i)return;if(!r){m();return}let a=await G(e,t,r,!1,j());await s.login(a.rawToken,{loadOnboardingStatus:n}),i||c(s.clone())}).catch(n=>{i||v(n)||(console.warn(`Auth: failed to initialize injected auth token`,n),r.logger.warn(`Failed to initialize injected auth token`,{vertesia:{account_id:e,project_id:t,error:n}}),s.isLoading=!1,s.authError=n instanceof Error?n:Error(String(n)),c(s.clone()))}),()=>{i=!0,f.current=!1,p?.()}):(m(),()=>{i=!0,f.current=!1,p?.()})},p(()=>m.current?.(),[]),b($.Provider,{value:s,children:e})}function qe(){return{tagUserSession:async e=>{let t=window.localStorage.getItem(`composableSignupData`);if(!e){console.error(`No user found -- skipping tagging`);return}t&&window.localStorage.removeItem(`composableSignupData`)},trackEvent:(e,t)=>{r.isProd||console.debug(`track event`,e,t),r.firebase?.apiKey&&o(ye(),e,{...t,debug_mode:!r.isProd})}}}export{Z as AuthenticationServiceError,X as CredentialError,Ue as DevSessionProvider,x as LastSelectedAccountId_KEY,S as LastSelectedProjectId_KEY,Y as NoAccessibleAccountError,J as RequestedScopeUnavailableError,Q as RestrictedEnvironmentError,q as STSError,Ne as TokenAuthorizationError,K as UserNotFoundError,ze as UserSession,$ as UserSessionContext,Ke as UserSessionProvider,P as buildCentralAuthRedirectUrl,ge as clearCentralAuthRoundTripMarker,W as fetchComposableToken,Ae as fetchComposableTokenFromFirebaseToken,je as fetchComposableTokenFromVertesiaToken,G as getComposableToken,Me as getCurrentVertesiaToken,ye as getFirebaseAnalytics,R as getFirebaseApp,z as getFirebaseAuth,xe as getFirebaseAuthToken,Le as isAuthenticationServiceError,_e as isCentralAuthRedirectPending,Ie as isCredentialError,Fe as isNoAccessibleAccountError,Pe as isRequestedScopeUnavailableError,F as redirectToCentralAuth,Ee as resolveAuthSelection,Ge as sanitizeRejectedScopeUrl,be as setFirebaseTenant,Re as useAuthState,Ve as useCurrentTenant,qe as useUXTracking,Be as useUserSession};
|
|
1
|
+
import{NO_ACCESSIBLE_ACCOUNT_ERROR_CODE as e,REQUESTED_SCOPE_UNAVAILABLE_ERROR_CODE as t,RESTRICTED_ENVIRONMENT_ERROR_CODE as n}from"@vertesia/common";import{Env as r}from"@vertesia/ui/env";import{jwtDecode as i}from"jwt-decode";import{getAnalytics as a,logEvent as o}from"firebase/analytics";import{initializeApp as s}from"firebase/app";import{getAuth as c,onAuthStateChanged as l}from"firebase/auth";import{createContext as u,useCallback as d,useContext as f,useEffect as p,useMemo as m,useRef as h,useState as g}from"react";import{NAMESPACE as _,i18nInstance as v}from"@vertesia/ui/i18n";import{VertesiaClient as y}from"@vertesia/client";import{jsx as b}from"react/jsx-runtime";const x=`composableai.lastSelectedAccountId`,S=`composableai.lastSelectedProjectId`,C=`auth_state`,w=`auth_state_expiry`;function T(){let e=crypto.randomUUID();return sessionStorage.setItem(C,e),sessionStorage.setItem(w,String(Date.now()+3e5)),e}function E(e){if(!e)return`Missing state`;let t=sessionStorage.getItem(C),n=parseInt(sessionStorage.getItem(w)||`0`,10);if(t!==e)return`State mismatched (${t} !== ${e})`;if(Date.now()>n)return`State expired`}function ee(){sessionStorage.removeItem(C),sessionStorage.removeItem(w)}function te(e,t){return`vtsauth=${e}; Path=/; Max-Age=${t}; SameSite=Lax${window.location.protocol===`https:`?`; Secure`:``}`}function ne(){document.cookie=te(`1`,300)}function re(){document.cookie=te(``,0)}function D(){if(typeof window>`u`||window.parent!==window)return!1;let e=window.__VERTESIA_RUNTIME_CONFIG__;return e?.authMode===`central`&&e.gatewaySession===!0}function ie(){let e=new URL(window.location.href),t=new URL(`/__appgen/auth/login`,e.origin);return t.searchParams.set(`target`,`${e.pathname}${e.search}${e.hash}`),t.toString()}async function ae(e,t){let n=new Request(e,t);if(new URL(n.url).origin!==window.location.origin)throw Error(`Gateway session requests must stay on the application origin`);let r=new Headers(n.headers);r.delete(`authorization`),r.set(`x-vertesia-app-session`,`1`);let i=await fetch(new Request(n,{headers:r,credentials:`same-origin`,cache:`no-store`}));return i.status===401&&i.headers.get(`x-vertesia-session-required`)===`1`?(window.location.replace(ie()),new Promise(()=>{})):i}async function oe(){let e=await ae(new URL(`/__appgen/session`,window.location.origin).toString());if(!e.ok)throw Error(`Application session could not be loaded (${e.status})`);let t=await e.json();if(!t.sub||!t.account?.id||!t.project?.id)throw Error(`Application session returned invalid user information`);return t}async function se(){let e=await ae(new URL(`/__appgen/session/logout`,window.location.origin).toString(),{method:`POST`});if(!e.ok)throw Error(`Application sign-out failed (${e.status})`)}function ce(e,t){if(!e)return!1;let n=e.replace(/\/+$/,``);if(n===t.replace(/\/+$/,``))return!0;try{let e=new URL(t),r=/^token-server-dev-[a-z0-9-]+\.api\.(dev1|dev2)\.vertesia\.io$/.exec(e.hostname);return!(!r||e.protocol!==`https:`||e.port||e.username||e.password||e.pathname!==`/`||e.search||e.hash||n!==`https://sts.${r[1]}.vertesia.io`)}catch{return!1}}const O=`vertesia.oauth.transaction`,k=`vertesia.oauth.access`;let le,A;var ue=class extends Error{};function de(){try{let e=new URLSearchParams(window.location.hash.slice(1)),t=e.get(`token`);return!t||E(e.get(`state`))?!1:ce(i(t).iss,r.endpoints.sts)}catch{return!1}}function j(){return!(!r.oauth||window.parent!==window||window.AUTH_MODE===`firebase`||D()||de())}function fe(e){return btoa(String.fromCharCode(...e)).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=+$/,``)}function pe(){return fe(crypto.getRandomValues(new Uint8Array(32)))}function M(e){let t=new URL(e);if(t.protocol!==`https:`||t.username||t.password)throw Error(`OAuth endpoint must use HTTPS`);return t}function me(){A=void 0,sessionStorage.removeItem(k),sessionStorage.removeItem(O)}async function he(e=!1){let t=r.oauth;if(!t)throw Error(`Application OAuth is not configured`);let n=t.clientId.trim();if(!n)throw Error(`OAuth client ID is required`);let a=new URL(t.redirectUri),o=a.hostname===`localhost`||a.hostname.endsWith(`.localhost`)||a.hostname===`[::1]`||/^127\.\d+\.\d+\.\d+$/.test(a.hostname);if(a.protocol!==`https:`&&!(o&&a.protocol===`http:`))throw Error(`OAuth callback must use HTTPS or loopback HTTP`);let s=a.toString();if(new URL(s).origin!==window.location.origin)throw Error(`OAuth callback must be same-origin`);let c=r.endpoints.sts.replace(/\/+$/,``),l=new URL(window.location.href),u=l.origin+l.pathname===new URL(s).origin+new URL(s).pathname,d=u?l.searchParams.get(`state`):null,f=u?l.searchParams.get(`code`):null,p=u?l.searchParams.get(`error`):null,m,h;if(d||f||p){let e=sessionStorage.getItem(O);if(sessionStorage.removeItem(O),h=e?JSON.parse(e):void 0,!h||h.state!==d||h.clientId!==n||h.redirectUri!==s||h.issuer!==c||Date.now()-h.created>6e5||h.created>Date.now())throw Error(`Invalid or expired OAuth login state`);if(p||!f)throw Error(`Application sign-in was not completed (${p||`missing code`})`)}else{let r=sessionStorage.getItem(k);if(r){let a=JSON.parse(r),o=i(a.token);if(t.offlineAccess&&a.clientId===n&&a.issuer===c&&(!l.searchParams.get(`p`)||o.project?.id===l.searchParams.get(`p`))&&(!l.searchParams.get(`a`)||o.account?.id===l.searchParams.get(`a`))&&(m=A?.clientId===n&&A.issuer===c?A.token:void 0),a.refreshToken&&sessionStorage.removeItem(k),a.clientId===n&&a.issuer===c&&!e&&o.exp>Date.now()/1e3+(t.offlineAccess?300:30)&&(!l.searchParams.get(`p`)||o.project?.id===l.searchParams.get(`p`))&&(!l.searchParams.get(`a`)||o.account?.id===l.searchParams.get(`a`)))return a.token}}let g=await fetch(`${c}/.well-known/oauth-authorization-server`);if(!g.ok)throw Error(`OAuth discovery failed (${g.status})`);let _=await g.json();if(_.issuer.replace(/\/+$/,``)!==c)throw Error(`OAuth issuer mismatch`);let v=M(_.authorization_endpoint),y=M(_.token_endpoint),b=_.revocation_endpoint===void 0?void 0:M(_.revocation_endpoint).toString(),x=new URL(_.issuer).toString();if(m){try{let e=await fetch(y,{method:`POST`,headers:{"Content-Type":`application/x-www-form-urlencoded`},body:new URLSearchParams({grant_type:`refresh_token`,client_id:n,refresh_token:m,resource:x})});if(e.ok){let t=await e.json();if(!t.access_token||t.token_type?.toLowerCase()!==`bearer`)throw new ue(`Invalid OAuth refresh grant`);let r=i(t.access_token);if(r.iss.replace(/\/+$/,``)!==c||r.client_id!==n||r.exp<=Date.now()/1e3||l.searchParams.get(`a`)&&r.account?.id!==l.searchParams.get(`a`)||l.searchParams.get(`p`)&&r.project?.id!==l.searchParams.get(`p`))throw new ue(`Invalid OAuth refresh identity`);return sessionStorage.setItem(k,JSON.stringify({token:t.access_token,clientId:n,issuer:c})),A={token:t.refresh_token??m,clientId:n,issuer:c,tokenEndpoint:y.toString(),revocationEndpoint:b},t.access_token}}catch{}A=void 0,sessionStorage.removeItem(k)}if(h&&f){let e=await fetch(y,{method:`POST`,headers:{"Content-Type":`application/x-www-form-urlencoded`},body:new URLSearchParams({grant_type:`authorization_code`,resource:x,code:f,client_id:n,redirect_uri:s,code_verifier:h.verifier})});if(!e.ok)throw Error(`OAuth code exchange failed (${e.status})`);let r=await e.json();if(!r.access_token||r.token_type?.toLowerCase()!==`bearer`)throw Error(`Invalid OAuth grant`);let a=i(r.access_token);if(a.iss.replace(/\/+$/,``)!==c||a.client_id!==n||a.exp<=Date.now()/1e3)throw Error(`OAuth grant does not match this application`);sessionStorage.setItem(k,JSON.stringify({token:r.access_token,clientId:n,issuer:c})),A=t.offlineAccess&&r.refresh_token?{token:r.refresh_token,clientId:n,issuer:c,tokenEndpoint:y.toString(),revocationEndpoint:b}:void 0;let o=new URL(h.target);if(o.origin!==window.location.origin)throw Error(`Invalid OAuth return target`);return a.account?.id?o.searchParams.set(`a`,a.account.id):o.searchParams.delete(`a`),a.project?.id?o.searchParams.set(`p`,a.project.id):o.searchParams.delete(`p`),o.pathname===`/auth/callback`&&(o.pathname=`/`),window.history.replaceState(window.history.state,``,o),r.access_token}let S=t.scopes??[`openid`,`profile`];if(n.startsWith(`https://`)){let e=await fetch(M(n),{cache:`no-store`});if(!e.ok)throw Error(`Application CIMD unavailable (${e.status})`);let r=await e.json();if(!r.redirect_uris?.includes(s))throw Error(`Application CIMD does not allow this callback`);!t.scopes&&r.scope&&(S=r.scope.split(/\s+/))}let C=pe(),w={state:pe(),verifier:C,clientId:n,redirectUri:s,issuer:c,target:l.toString(),created:Date.now()},T=await crypto.subtle.digest(`SHA-256`,new TextEncoder().encode(C));v.searchParams.set(`client_id`,n),v.searchParams.set(`redirect_uri`,s),v.searchParams.set(`response_type`,`code`),v.searchParams.set(`resource`,x),v.searchParams.set(`state`,w.state),v.searchParams.set(`code_challenge_method`,`S256`),v.searchParams.set(`code_challenge`,fe(new Uint8Array(T))),v.searchParams.set(`scope`,(t.offlineAccess?[...new Set([...S,`offline_access`])]:S.filter(e=>e!==`offline_access`)).join(` `));let E=l.searchParams.get(`a`);E&&v.searchParams.set(`account_id`,E);let ee=l.searchParams.get(`p`);return ee&&v.searchParams.set(`project_id`,ee),sessionStorage.setItem(O,JSON.stringify(w)),ne(),window.location.replace(v.toString()),new Promise(()=>{})}function N(e=!1){return le??=he(e).finally(()=>{le=void 0}),le}function ge(){return j()}const _e=N;async function ve(){let e=A;if(me(),!e)return;let t=M(e.revocationEndpoint??e.tokenEndpoint);e.revocationEndpoint===void 0&&(t.pathname=t.pathname.replace(/\/token$/,`/revoke`)),await fetch(t,{method:`POST`,headers:{"Content-Type":`application/x-www-form-urlencoded`},body:new URLSearchParams({client_id:e.clientId,token:e.token,token_type_hint:`refresh_token`})})}function P(){return r.endpoints.auth||`https://auth.vertesia.io/`}function ye(e){return window.AUTH_MODE===`firebase`}function F(e){return!ye()}function I(){let e=new URL(document.baseURI),t=new URL(window.location.href),n=t.pathname.startsWith(e.pathname)?t:e;return n.hash=``,n}function be(){let e=new URL(document.baseURI);return e.hash=``,e.search=``,e}function xe(e,t,n,r,i={}){let a=new URL(n);i.projectId&&a.searchParams.set(`p`,i.projectId),i.accountId&&a.searchParams.set(`a`,i.accountId);let o=new URL(e);return o.searchParams.set(`sts`,t),o.searchParams.set(`redirect_uri`,a.toString()),o.searchParams.set(`state`,r),o}function L(e={}){if(j()){N().catch(e=>r.logger.error(`Application OAuth sign-in failed`,e));return}if(D()){window.location.replace(ie());return}let t=xe(P(),r.endpoints.sts??`https://sts.vertesia.io`,I(),T(),e);ne(),location.replace(t.toString())}function Se(){if(D()||j()||!F()||r.authTokenProvider||r.isLocalDev&&r.devAuthToken)return!1;let e=new URLSearchParams(window.location.hash.substring(1));return!(e.get(`token`)&&e.get(`state`))}let Ce=null,we=null,R=null;function Te(){if(!Ce)try{if(!r.firebase)throw Error(`Firebase configuration is not available in the environment`);Ce=s(r.firebase)}catch(e){throw console.error(`Failed to initialize Firebase app:`,e),Error(`Firebase initialization failed - environment may not be properly initialized`,{cause:e})}return Ce}function Ee(){return we||=a(Te()),we}function z(){return R||(R=c(Te()),R.tenantId=r.firebase?.tenantId??null),R}async function De(e){if(r.firebase?.tenantId)return z().tenantId=r.firebase.tenantId,{firebaseTenantId:r.firebase.tenantId,provider:r.firebase.providerType??`oidc`,name:``,label:``};if(!e){console.log(`No tenant name or email specified, skipping tenant setup`);return}if(!r.firebase){console.log(`Firebase configuration is not available in the environment`);return}try{e&&console.log(`Resolving tenant ID from email: ${e}`);let t=3,n=250;for(;t>0;)try{let t=await fetch(`/api/resolve-tenant`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({tenantEmail:e}),signal:AbortSignal.timeout(5e3)});if(!t)throw Error(`No response received from tenant API`);if(!t.ok){try{let e=await t.json();console.error(`Failed to resolve tenant ID:`,e.error)}catch{console.error(`Failed to resolve tenant ID: HTTP ${t.status}`)}if(t.status===404){console.warn(`Tenant not found for ${e}`);return}throw Error(`HTTP error ${t.status}`)}let n=await t.json();if(n?.firebaseTenantId){let e=z();return e.tenantId=n.firebaseTenantId,r.firebase.providerType=n.provider??`oidc`,console.log(`Tenant ID set to ${e.tenantId}`),n}console.error(`Invalid response format, missing tenantId for ${e}`);return}catch(e){if(t>1)console.warn(`Tenant resolution failed, retrying in ${n}ms...`,e),await new Promise(e=>setTimeout(e,n)),n*=2,t--;else throw e}}catch(e){console.error(`Error setting Firebase tenant:`,e instanceof Error?e.message:`Unknown error`)}}async function Oe(e){let t=z().currentUser;return t?t.getIdToken(e).then(n=>(r.logger.debug(`Got Firebase token`,{vertesia:{user_email:t.email,user_name:t.displayName,user_id:t.uid,refresh:e}}),n)).catch(n=>(r.logger.error(`Failed to get Firebase token`,{vertesia:{user_email:t.email,user_name:t.displayName,user_id:t.uid,refresh:e,error:n}}),console.error(`Failed to get access token`,n),null)):(r.logger.warn(`No user found`),Promise.resolve(null))}let B,V,H=!1;const ke=`vt.centralAuthRenewalAt`;function Ae(){if(!H||!F())return!1;let e=0;try{e=Number(sessionStorage.getItem(ke)??`0`)}catch{}if(Number.isFinite(e)&&e>0&&Date.now()-e<6e4)return r.logger.warn(`Central Auth session renewal already attempted; surfacing the failure instead`,{vertesia:{last_attempt_ms_ago:Date.now()-e}}),!1;try{sessionStorage.setItem(ke,String(Date.now()))}catch{}r.logger.info(`Renewing an expired Central Auth session through the broker`);let t=xe(P(),r.endpoints.sts??`https://sts.vertesia.io`,I(),T());return location.replace(t.toString()),!0}function je(e,t){if(!e)return;let n=`${S}-${e}`;if(t){let r=localStorage.getItem(n)===t;r&&localStorage.removeItem(n),r&&localStorage.getItem(`composableai.lastSelectedAccountId`)===e&&localStorage.removeItem(x);return}localStorage.getItem(`composableai.lastSelectedAccountId`)===e&&(localStorage.removeItem(x),localStorage.removeItem(n))}function Me(e){try{let t=i(e);return typeof t.email!=`string`||!t.email?void 0:{email:t.email,name:typeof t.name==`string`&&t.name?t.name:void 0}}catch{return}}function Ne(e){let t=e.searchParams.has(`a`)||e.searchParams.has(`p`)?void 0:r.defaultAuthSelection,n=e.searchParams.get(`a`)??t?.accountId,i=e.searchParams.get(`p`)??t?.projectId,a=n??(i===void 0?localStorage.getItem(`composableai.lastSelectedAccountId`)??void 0:void 0);return{accountId:a,projectId:i??localStorage.getItem(`composableai.lastSelectedProjectId-${a}`)??void 0}}function U(e){return i(e)}function Pe(e){if(!e)return!1;try{return ce(U(e).iss,r.endpoints.sts)}catch{return!1}}function Fe(e,t,n){let r=U(e),i=`client_id`in r&&typeof r.client_id==`string`&&r.client_id.startsWith(`vertesia-app:`);return!(!r.exp||r.exp<=Date.now()/1e3+(i?60:300)||!(r.permissions?.length||r.account_roles?.length||r.project_roles?.length||r.apps?.length)||t&&r.account?.id!==t||n&&r.project?.id!==n)}async function W(a,o,s,c,l=0){r.logger.debug(`Getting/refreshing composable token`,{vertesia:{account_id:o,project_id:s,retry_count:l}});let u=await a();if(!u)throw Error(`No id token found`);let d=r.endpoints.sts;r.logger.debug(`Using STS for token generation`,{vertesia:{account_id:o,project_id:s,sts_url:d}});try{let f=new URL(`${d}/token/issue`),p={type:`user`,account_id:o,project_id:s,expires_at:c?Math.floor(Date.now()/1e3)+c:void 0},m=await fetch(f,{method:`POST`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${u}`},body:JSON.stringify(p)}).catch(e=>{throw console.error(`Failed to call STS endpoint`,e),r.logger.error(`Failed to call STS endpoint`,{vertesia:{account_id:o,project_id:s,error:e}}),new Z(`The authentication service could not be reached`,d,{cause:e})});if(u&&m?.status===404){r.logger.debug(`404: User not found - calling ensure-user endpoint`,{vertesia:{account_id:o,project_id:s,status:m?.status}});let e=await fetch(`${r.endpoints.studio}/auth/ensure-user`,{method:`POST`,headers:{Authorization:`Bearer ${u}`,"Content-Type":`application/json`}});if(e.status===412){r.logger.debug(`412: No invite found - signup required`,{vertesia:{account_id:o,project_id:s}});let e=i(u);throw e?.email?new K(`User not found - signup required`,e.email):(r.logger.error(`No email found in id token`),Error(`No email found in id token`))}if(e.status===403)throw r.logger.warn(`403: Customer-domain user requires an invite to join`,{vertesia:{account_id:o,project_id:s}}),Error(`Customer-domain user requires an invite to join`);if(!e.ok)throw console.error(`Failed to ensure user exists`,e.status),r.logger.error(`Failed to ensure user exists`,{vertesia:{account_id:o,project_id:s,status:e.status}}),Error(`Failed to ensure user exists`);return r.logger.debug(`User ensured - retrying token generation`,{vertesia:{account_id:o,project_id:s}}),W(a,o,s,c,l)}if(u&&m?.status===412){r.logger.info(`412: auth succeeded but user doesn't exist - signup required`,{vertesia:{account_id:o,project_id:s,status:m?.status}});let e=i(u);throw e?.email?(r.logger.info(`User not found`,{vertesia:{account_id:o,project_id:s,email:e.email}}),new K(`User not found`,e.email)):(r.logger.error(`No email found in id token`),Error(`No email found in id token`))}if(m.status===401)throw r.logger.warn(`STS rejected the identity credential`,{vertesia:{account_id:o,project_id:s,status:m.status}}),new X(`Your sign-in credentials could not be verified`,d,{status:m.status});if(m.status===403){let i=await m.json().catch(()=>void 0),a=Me(u);throw i?.errorCode===n?(r.logger.warn(`403: User lacks early-access for this restricted environment`,{vertesia:{account_id:o,project_id:s}}),new Q(i.message??`You don't have sufficient permission to visit unstable environments`)):i?.errorCode===e?(r.logger.warn(`STS identity has no accessible account`,{vertesia:{error_code:i.errorCode,status:m.status}}),new Y(d,i.message,a)):!i?.errorCode||i.errorCode===t?(r.logger.warn(`STS rejected the requested account or project`,{vertesia:{account_id:o,project_id:s,status:m.status,error_code:i?.errorCode??t}}),new J(d,o,s,i?.errorCode?i.message:void 0,a)):(r.logger.error(`STS returned an unrecognized forbidden response`,{vertesia:{account_id:o,project_id:s,status:m.status,error_code:i.errorCode}}),new Z(`The authentication service rejected the request`,d,{status:m.status,errorCode:i.errorCode,cause:i}))}if(!m.ok){let e=await m.text();throw console.error(`STS token generation failed:`,m.status,e),r.logger.error(`STS token generation failed`,{vertesia:{status:m.status,error:e,account_id:o,project_id:s}}),new Z(`The authentication service could not complete sign-in`,d,{status:m.status,cause:e})}let{token:h}=await m.json();return r.logger.debug(`Successfully got token from STS`),h}catch(e){throw e instanceof K||e instanceof q||e instanceof Q||e instanceof Error&&e.message===`Customer-domain user requires an invite to join`?e:(console.error(`Failed to get composable token from STS`,e),r.logger.error(`Failed to get composable token from STS`,{vertesia:{account_id:o,project_id:s,error:e}}),new Z(`The authentication service could not complete sign-in`,d,{cause:e}))}}async function Ie(e,t,n){return W(Oe,e,t,n)}async function Le(e,t,n,r){return W(()=>Promise.resolve(e),t,n,r)}function Re(){return B}async function G(e,t,n,i=!1,a=!1){let o=e??(t===void 0?localStorage.getItem(`composableai.lastSelectedAccountId`)??void 0:void 0),s=t??localStorage.getItem(`composableai.lastSelectedProjectId-${o}`)??void 0,c=r.isLocalDev?r.devAuthToken:void 0,l=c??n??B,u=(!o||V?.account?.id===o)&&(!s||V?.project?.id===s);if(!i&&B&&V&&u&&V.exp>Date.now()/1e3+300)return H=!0,{rawToken:B,token:V,error:!1};if(!i&&Pe(l)&&Fe(l,o,s)){if(B=l,V=U(B),!V.exp)throw Error(`Invalid composable token`);return H=!0,{rawToken:B,token:V,error:!1}}try{if(!c&&!a&&z().currentUser)B=await Ie(o,s);else if(c)c&&(B=c);else{let e=await r.authTokenProvider?.(),t=e??n??B;B=(!i||e)&&t&&Pe(t)&&Fe(t,o,s)?t:t?await W(()=>Promise.resolve(t),o,s):void 0}}catch(e){throw(e instanceof J||e instanceof Y||e instanceof X)&&(B=void 0,V=void 0,e instanceof J&&je(o,s)),e instanceof X&&Ae(),e}if(!B)throw r.logger.error(`Cannot acquire a composable token`,{vertesia:{account_id:o,project_id:s}}),Ae(),Error(`Cannot acquire a composable token`);if(V=U(B),!V?.exp||!B)throw console.error(`Invalid composable token`,V),r.logger.error(`Invalid composable token`,{vertesia:{account_id:o,project_id:s}}),Error(`Invalid composable token`);return H=!0,{rawToken:B,token:V,error:!1}}var K=class extends Error{email;constructor(e,t){super(e),this.name=`UserNotFoundError`,this.email=t}},q=class extends Error{stsURL;status;errorCode;constructor(e,t,n){super(e,n),this.name=`STSError`,this.stsURL=t,this.status=n?.status,this.errorCode=n?.errorCode}},J=class extends q{accountId;projectId;identity;requestedScope;selectorSource;recoveryUrl;constructor(e,n,r,i,a){super(i??`The requested account or project is not available.`,e,{status:403,errorCode:t}),this.accountId=n,this.projectId=r,this.identity=a,this.name=`RequestedScopeUnavailableError`,this.requestedScope=r?`project`:`account`}};const ze=J;var Y=class extends q{identity;constructor(t,n,r){super(n??`No accessible account is available for this user.`,t,{status:403,errorCode:e}),this.identity=r,this.name=`NoAccessibleAccountError`}},X=class extends q{constructor(e,t,n){super(e,t,n),this.name=`CredentialError`}},Z=class extends q{constructor(e,t,n){super(e,t,n),this.name=`AuthenticationServiceError`}};function Be(e){return e instanceof J}function Ve(e){return e instanceof Y}function He(e){return e instanceof X}function Ue(e){return e instanceof Z}var Q=class extends Error{constructor(e){super(e),this.name=`RestrictedEnvironmentError`}};function We(){return{generateState:d(()=>T(),[]),verifyState:d(e=>E(e),[]),clearState:d(()=>ee(),[])}}var Ge=class e{authMethod=`token`;isLoading=!0;client;authError;authToken;setSession;lastSelectedAccount;lastSelectedProject;onboardingComplete;constructor(e,t){this.client=e||new y({serverUrl:D()?`${window.location.origin}/__appgen/session/studio`:r.endpoints.studio,storeUrl:D()?`${window.location.origin}/__appgen/session/store`:r.endpoints.zeno,tokenServerUrl:r.endpoints.sts,fetch:D()?ae:void 0}),t&&(this.setSession=t),this.logout=this.logout.bind(this),this.signOut=this.signOut.bind(this)}get store(){return this.client.store}get user(){return this.authToken}get account(){return this.authToken?.account}get project(){return this.authToken?.project}get accounts(){return this.authToken?.accounts}get authCallback(){return this.rawAuthToken.then(e=>`Bearer ${e}`)}get rawAuthToken(){return this.authMethod===`oauth`?N():D()?Promise.reject(Error(`Gateway session credentials are not available to application JavaScript`)):G().then(e=>{let t=e?.rawToken;if(!t)throw Error(`No token available`);return this.authToken=i(t),t})}async refreshAuthToken(){if(D()){let e=await this.loginGatewaySession();return this.setSession?.(this.clone()),e}if(this.authMethod===`oauth`)return this.authToken=i(await N(!0)),this.setSession?.(this.clone()),this.authToken;let e=(await G(void 0,void 0,void 0,!0))?.rawToken;if(!e)throw Error(`No token available`);return this.authToken=i(e),this.setSession?.(this.clone()),this.authToken}signOut(){this.logout()}getAccount(){return this.authToken?.account}async login(e,t={}){return this.authMethod=t.authMethod??`token`,this.authError=void 0,this.isLoading=!1,this.client.withAuthCallback(()=>this.authCallback),this.authToken=i(e),console.log(`Logging in as ${this.authToken?.name} with account ${this.authToken?.account.name} (${this.authToken?.account.id}, and project ${this.authToken?.project?.name} (${this.authToken?.project?.id})`),localStorage.setItem(x,this.authToken.account.id),localStorage.setItem(`${S}-${this.authToken.account.id}`,this.authToken.project?.id??``),r.onLogin?.(this.authToken),t.loadOnboardingStatus&&await this.fetchOnboardingStatus(),Promise.resolve()}async loginGatewaySession(){return this.authToken=await oe(),this.client.withAuthCallback(void 0),this.authError=void 0,this.isLoading=!1,r.onLogin?.(this.authToken),this.authToken}isLoggedIn(){return!!this.authToken}logout(){if(console.log(`Logging out`),D()){se().then(()=>{this.authToken=void 0,this.authError=void 0,this.isLoading=!1,r.onLogout?.(),this.setSession?.(this.clone())}).catch(e=>{this.authError=e instanceof Error?e:Error(String(e)),this.setSession?.(this.clone())});return}if(this.authMethod===`oauth`){ve().catch(()=>void 0).finally(()=>{let e=new URL(P());e.pathname=`/logout`,e.searchParams.set(`redirect_uri`,I().toString()),location.replace(e.toString())}),this.client.withAuthCallback(void 0),this.authToken=void 0,this.authError=void 0,this.isLoading=!1,r.onLogout?.(),this.setSession?.(this.clone());return}if(F()){console.log(`Using central auth logout`),this.authError=void 0,this.isLoading=!1,this.authToken=void 0,this.setSession=void 0,this.client.withAuthCallback(void 0);let e=new URL(P()),t=I();e.pathname=`/logout`,e.searchParams.set(`redirect_uri`,t.toString()),location.replace(e.toString())}else{console.log(`Using Firebase logout`);let e=!!this.authToken;this.authToken&&z().signOut(),this.authError=void 0,this.isLoading=!1,this.authToken=void 0,this.setSession=void 0,this.client.withAuthCallback(void 0),e&&location.replace(be().toString())}}async switchAccount(e){localStorage.setItem(x,e),this&&(this.account&&this.project?localStorage.setItem(`${S}-${this.account.id}`,this.project.id):this.account&&localStorage.removeItem(`${S}-${this.account.id}`));let t=be();t.searchParams.set(`a`,e),window.location.replace(t.toString())}async switchProject(e){this.account&&localStorage.setItem(`${S}-${this.account.id}`,e);let t=be();this.account?.id&&t.searchParams.set(`a`,this.account.id),t.searchParams.set(`p`,e),window.location.replace(t.toString())}async fetchAccounts(){return this.client.accounts.list().then(e=>{if(!this.authToken)throw Error(`No token available`);this.authToken.accounts=e,this.setSession?.(this.clone())}).catch(e=>{throw console.error(`Failed to fetch accounts`,e),e})}async fetchProjects(e){return this.client.projects.list([e]).then(t=>{if(!this.authToken)throw Error(`No token available`);this.authToken={...this.authToken,accounts:this.authToken.accounts?.map(n=>n.id===e?{...n,projects:t.filter(t=>t.account===e)}:n)},this.setSession?.(this.clone())}).catch(e=>{throw console.error(`Failed to fetch projects`,e),e})}async fetchOnboardingStatus(){if(!this.project?.id)return!1;if(this.onboardingComplete)return console.log(`Onboarding already completed`),!1;let e=this.onboardingComplete;try{let t=await this.client.account.onboardingProgress();return this.onboardingComplete=Object.values(t).every(e=>e===!0),e!==this.onboardingComplete&&this.setSession?.(this.clone()),e===!1&&this.onboardingComplete}catch(t){console.error(`Error fetching onboarding status:`,t),this.onboardingComplete=!1,e!==this.onboardingComplete&&this.setSession?.(this.clone())}return!1}clone(){let t=new e(this.client);return t.isLoading=this.isLoading,t.authError=this.authError,t.authToken=this.authToken,t.authMethod=this.authMethod,t.setSession=this.setSession,t.lastSelectedAccount=this.lastSelectedAccount,t.switchAccount=this.switchAccount,t.onboardingComplete=this.onboardingComplete,t}};const $=u(void 0);function Ke(){let e=f($);if(!e)throw Error(`useUserSession must be used within a UserSessionProvider`);return e}function qe(){let{user:e}=Ke(),[t,n]=g(null),[r,i]=g(!0),[a,o]=g(null);return p(()=>{(async()=>{if(!e?.email){n(null),i(!1);return}try{let t=await fetch(`/api/resolve-tenant`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({tenantEmail:e.email})});if(t.ok){let e=await t.json();n(e?{tenantKey:e.name||`unknown`,name:e.label||e.name||`Unknown`,domain:e.domain||[],firebaseTenantId:e.firebaseTenantId,provider:e.provider,logo:e.logo}:null)}else n(null)}catch(e){console.error(`Error loading current tenant:`,e),o(v.getFixedT(null,_)(`errors.failedToLoadTenantConfig`)),n(null)}finally{i(!1)}})()},[e?.email]),{currentTenant:t,isLoading:r,error:a}}function Je(e){let[,t]=e.split(`.`);if(!t)throw Error(`Invalid Vertesia auth token`);let n=t.replace(/-/g,`+`).replace(/_/g,`/`).padEnd(Math.ceil(t.length/4)*4,`=`);return JSON.parse(atob(n))}function Ye({children:e,token:t}){let n=m(()=>{let e=new Ge;e.isLoading=!1;try{e.authToken=Je(t),e.client.withAuthCallback(()=>Promise.resolve(`Bearer ${t}`)),localStorage.setItem(x,e.authToken.account.id),localStorage.setItem(`${S}-${e.authToken.account.id}`,e.authToken.project?.id??``)}catch(t){e.authError=t instanceof Error?t:Error(String(t))}return e.clone()},[t]);return b($.Provider,{value:n,children:e})}function Xe(){let e=new URL(window.location.href);e.hash=``,window.history.replaceState(window.history.state,``,`${e.pathname}${e.search}`)}function Ze(e,t,n=!1){let r=new URL(e),i=r.searchParams.get(`a`)??void 0,a=r.searchParams.get(`p`)??void 0;return i&&a&&i===t.accountId&&a===t.projectId?(r.searchParams.delete(`a`),r.searchParams.delete(`p`),t.requestedScope=`project`,t.selectorSource=`url`):a&&a===t.projectId?(r.searchParams.delete(`p`),t.requestedScope=`project`,t.selectorSource=`url`):i&&i===t.accountId?(r.searchParams.delete(`a`),t.requestedScope=`account`,t.selectorSource=`url`):(t.requestedScope=t.projectId?`project`:`account`,t.selectorSource=`persisted`),n&&(r.hash=``),t.recoveryUrl=r.toString(),r}function Qe({children:e,loadOnboardingStatus:n=!1}){let i=new URLSearchParams(location.hash.substring(1)),a=i.get(`token`),o=i.get(`state`),[s,c]=g(new Ge),{verifyState:u,clearState:d}=We(),f=h(!1),m=h(void 0),_=(e,n=!1)=>{let i=Ze(new URL(window.location.href),e,n);window.history.replaceState(window.history.state,``,i),r.logger.warn(`Sanitized an unavailable authentication scope`,{vertesia:{account_id:e.accountId,project_id:e.projectId,error_code:t,selector_source:e.selectorSource,requested_scope:e.requestedScope,recovery_action:`url_sanitized`}})},v=(e,t=!1)=>e instanceof J||e instanceof Y||e instanceof X||e instanceof Z||e instanceof K||e instanceof Q?(e instanceof J?_(e,t):t&&Xe(),s.isLoading=!1,s.authError=e,c(s.clone()),!0):!1;return m.current=()=>{if(f.current){r.logger.debug(`Skipping duplicate auth flow initiation`);return}f.current=!0,r.logger.debug(`Starting auth flow`);let{accountId:e,projectId:t}=Ne(new URL(window.location.href));if(r.logger.debug(`Selected account and project`,{vertesia:{account_id:e,project_id:t}}),r.isLocalDev&&r.devAuthToken){s.setSession=c,G(e,t,r.devAuthToken).then(e=>s.login(e.rawToken).then(()=>c(s.clone()))).catch(n=>{v(n)||(console.error(`Failed to initialize dev auth token`,n),r.logger.error(`Failed to initialize dev auth token`,{vertesia:{account_id:e,project_id:t,error:n}}),s.isLoading=!1,s.authError=n instanceof Error?n:Error(String(n)),c(s.clone()))});return}if(D()||j()){let e=!1;return s.setSession=c,(D()?s.loginGatewaySession():N().then(e=>s.login(e,{loadOnboardingStatus:n,authMethod:`oauth`}))).then(()=>{e||c(s.clone())}).catch(t=>{e||v(t)||(s.isLoading=!1,s.authError=t instanceof Error?t:Error(String(t)),c(s.clone()))}),()=>{e=!0,f.current=!1}}if(a&&o){s.setSession=c;let i=u(o);if(i){console.error(`Auth: invalid state: ${i}`),r.logger.error(`Invalid state: ${i}`,{vertesia:{state:o}}),d(),Xe(),L({accountId:e,projectId:t});return}d(),G(e,t,a,!1,F()).then(e=>s.login(e.rawToken,{loadOnboardingStatus:n}).then(()=>{c(s.clone()),Xe()})).catch(n=>{v(n,!0)||(console.error(`Failed to fetch user token from studio, redirecting to central auth`,n),r.logger.error(`Failed to fetch user token from studio, redirecting to central auth`,{vertesia:{error:n}}),L({accountId:e,projectId:t}))});return}let i=!1,p,m=()=>{if(!i){if(window.parent!==window&&!r.allowLegacyIframeAuth){s.isLoading=!1,s.authError=Error(`Embedded authentication requires a valid token from the host.`),c(s.clone());return}if(!s.isLoggedIn()){if(r.logger.debug(`Not logged in & no token/state`,{vertesia:{account_id:e,project_id:t}}),F()){r.logger.debug(`Redirecting to central auth with selection`,{vertesia:{account_id:e,project_id:t}}),L({accountId:e,projectId:t});return}r.logger.debug(`Host is in Firebase auth allowlist`,{vertesia:{account_id:e,project_id:t}})}p=l(z(),async i=>{i?(r.logger.debug(`Successful login with firebase`,{vertesia:{account_id:e,project_id:t}}),s.setSession=c,await G(e,t,void 0,!1,F()).then(e=>s.login(e.rawToken,{loadOnboardingStatus:n}).then(()=>c(s.clone()))).catch(n=>{v(n)||(console.error(`Unexpected failure while fetching a user token`,n),r.logger.error(`Unexpected failure while fetching a user token`,{vertesia:{account_id:e,project_id:t,error:n}}),s.logout(),s.isLoading=!1,s.authError=n,c(s.clone()))})):(r.logger.debug(`Using anonymous user`,{vertesia:{account_id:e,project_id:t}}),s.client.withAuthCallback(void 0),s.logout(),c(s.clone()))})}};return r.authTokenProvider?(s.setSession=c,r.authTokenProvider().then(async r=>{if(i)return;if(!r){m();return}let a=await G(e,t,r,!1,F());await s.login(a.rawToken,{loadOnboardingStatus:n}),i||c(s.clone())}).catch(n=>{i||v(n)||(console.warn(`Auth: failed to initialize injected auth token`,n),r.logger.warn(`Failed to initialize injected auth token`,{vertesia:{account_id:e,project_id:t,error:n}}),s.isLoading=!1,s.authError=n instanceof Error?n:Error(String(n)),c(s.clone()))}),()=>{i=!0,f.current=!1,p?.()}):(m(),()=>{i=!0,f.current=!1,p?.()})},p(()=>m.current?.(),[]),b($.Provider,{value:s,children:e})}function $e(){return{tagUserSession:async e=>{let t=window.localStorage.getItem(`composableSignupData`);if(!e){console.error(`No user found -- skipping tagging`);return}t&&window.localStorage.removeItem(`composableSignupData`)},trackEvent:(e,t)=>{r.isProd||console.debug(`track event`,e,t),r.firebase?.apiKey&&o(Ee(),e,{...t,debug_mode:!r.isProd})}}}export{Z as AuthenticationServiceError,X as CredentialError,Ye as DevSessionProvider,x as LastSelectedAccountId_KEY,S as LastSelectedProjectId_KEY,Y as NoAccessibleAccountError,J as RequestedScopeUnavailableError,Q as RestrictedEnvironmentError,q as STSError,ze as TokenAuthorizationError,K as UserNotFoundError,Ge as UserSession,$ as UserSessionContext,Qe as UserSessionProvider,xe as buildCentralAuthRedirectUrl,re as clearCentralAuthRoundTripMarker,W as fetchComposableToken,Ie as fetchComposableTokenFromFirebaseToken,Le as fetchComposableTokenFromVertesiaToken,G as getComposableToken,Re as getCurrentVertesiaToken,Ee as getFirebaseAnalytics,Te as getFirebaseApp,z as getFirebaseAuth,Oe as getFirebaseAuthToken,ge as isAppOAuthLoginPending,Ue as isAuthenticationServiceError,Se as isCentralAuthRedirectPending,He as isCredentialError,Ve as isNoAccessibleAccountError,Be as isRequestedScopeUnavailableError,L as redirectToCentralAuth,Ne as resolveAuthSelection,Ze as sanitizeRejectedScopeUrl,De as setFirebaseTenant,_e as startAppOAuthLogin,We as useAuthState,qe as useCurrentTenant,$e as useUXTracking,Ke as useUserSession};
|
|
2
2
|
//# sourceMappingURL=vertesia-ui-session.js.map
|