@vertesia/ui 1.6.0-dev.20261009.095813Z → 1.6.0-dev.20261014.015055Z
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/index.d.ts +12 -1
- package/lib/boot/index.d.ts.map +1 -1
- package/lib/boot/index.js +65 -10
- package/lib/boot/index.js.map +1 -1
- package/lib/boot/text.d.ts +13 -0
- package/lib/boot/text.d.ts.map +1 -0
- package/lib/boot/text.js +68 -0
- package/lib/boot/text.js.map +1 -0
- package/lib/features/agent/PayloadBuilder.d.ts +6 -0
- package/lib/features/agent/PayloadBuilder.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentConversation.js +6 -4
- package/lib/features/agent/chat/ModernAgentConversation.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/SummaryConversation.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/SummaryConversation.js +58 -0
- package/lib/features/agent/chat/ModernAgentOutput/SummaryConversation.js.map +1 -1
- package/lib/features/agent/chat/SkillWidgetProvider.d.ts.map +1 -1
- package/lib/features/agent/chat/SkillWidgetProvider.js +3 -2
- package/lib/features/agent/chat/SkillWidgetProvider.js.map +1 -1
- package/lib/i18n/LanguageProvider.d.ts +9 -1
- package/lib/i18n/LanguageProvider.d.ts.map +1 -1
- package/lib/i18n/LanguageProvider.js +7 -4
- package/lib/i18n/LanguageProvider.js.map +1 -1
- package/lib/i18n/locales/ar.json +5 -1
- package/lib/i18n/locales/de.json +5 -1
- package/lib/i18n/locales/en.json +5 -1
- package/lib/i18n/locales/es.json +5 -1
- package/lib/i18n/locales/fr.json +5 -1
- package/lib/i18n/locales/it.json +5 -1
- package/lib/i18n/locales/ja.json +5 -1
- package/lib/i18n/locales/ko.json +5 -1
- package/lib/i18n/locales/pt.json +5 -1
- package/lib/i18n/locales/ru.json +5 -1
- package/lib/i18n/locales/tr.json +5 -1
- package/lib/i18n/locales/zh-TW.json +5 -1
- package/lib/i18n/locales/zh.json +5 -1
- package/lib/i18n/rtl.d.ts +4 -2
- package/lib/i18n/rtl.d.ts.map +1 -1
- package/lib/i18n/rtl.js +4 -2
- package/lib/i18n/rtl.js.map +1 -1
- package/lib/session/UserSessionProvider.d.ts.map +1 -1
- package/lib/session/UserSessionProvider.js +10 -4
- package/lib/session/UserSessionProvider.js.map +1 -1
- package/lib/session/auth/oauth.d.ts.map +1 -1
- package/lib/session/auth/oauth.js +15 -11
- package/lib/session/auth/oauth.js.map +1 -1
- package/lib/shell/VertesiaShell.d.ts +7 -2
- package/lib/shell/VertesiaShell.d.ts.map +1 -1
- package/lib/shell/VertesiaShell.js +2 -2
- package/lib/shell/VertesiaShell.js.map +1 -1
- package/lib/shell/login/InviteAcceptModal.d.ts.map +1 -1
- package/lib/shell/login/InviteAcceptModal.js +83 -42
- package/lib/shell/login/InviteAcceptModal.js.map +1 -1
- package/lib/vertesia-ui-boot.js +52 -15
- package/lib/vertesia-ui-boot.js.map +1 -1
- package/lib/vertesia-ui-core.js +43 -43
- package/lib/vertesia-ui-core.js.map +1 -1
- package/lib/vertesia-ui-features.js +334 -334
- package/lib/vertesia-ui-features.js.map +1 -1
- package/lib/vertesia-ui-i18n.B1Nd8-dE.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.B1Nd8-dE.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.B2Z7mx1x.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.B2Z7mx1x.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.B756-YtS.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.B756-YtS.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.BICdgAEn.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.BICdgAEn.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.B_yx0c2A.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.B_yx0c2A.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.BwPrGiQn.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.BwPrGiQn.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.CfQbOHm3.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.CfQbOHm3.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.DMISlF16.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.DMISlF16.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.D_WA36Yq.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.D_WA36Yq.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.Dp3KuMs-.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.Dp3KuMs-.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.DsioKoQ3.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.DsioKoQ3.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.QEIqEPlv.chunk.js +5 -0
- package/lib/vertesia-ui-i18n.QEIqEPlv.chunk.js.map +1 -0
- package/lib/vertesia-ui-i18n.js +2 -2
- 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 +51 -51
- 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 +20 -20
- package/src/boot/index.ts +74 -11
- package/src/boot/text.ts +80 -0
- package/src/features/agent/chat/ModernAgentConversation.tsx +7 -4
- package/src/features/agent/chat/ModernAgentOutput/SummaryConversation.ts +60 -0
- package/src/features/agent/chat/SkillWidgetProvider.tsx +3 -2
- package/src/i18n/LanguageProvider.tsx +16 -4
- package/src/i18n/locales/ar.json +5 -1
- package/src/i18n/locales/de.json +5 -1
- package/src/i18n/locales/en.json +5 -1
- package/src/i18n/locales/es.json +5 -1
- package/src/i18n/locales/fr.json +5 -1
- package/src/i18n/locales/it.json +5 -1
- package/src/i18n/locales/ja.json +5 -1
- package/src/i18n/locales/ko.json +5 -1
- package/src/i18n/locales/pt.json +5 -1
- package/src/i18n/locales/ru.json +5 -1
- package/src/i18n/locales/tr.json +5 -1
- package/src/i18n/locales/zh-TW.json +5 -1
- package/src/i18n/locales/zh.json +5 -1
- package/src/i18n/rtl.ts +5 -2
- package/src/session/UserSessionProvider.tsx +11 -4
- package/src/session/auth/oauth.ts +26 -12
- package/src/shell/VertesiaShell.tsx +8 -2
- package/src/shell/login/InviteAcceptModal.tsx +112 -65
- package/lib/vertesia-ui-i18n.1NWiB6fw.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.1NWiB6fw.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.6Ozlf6Ks.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.6Ozlf6Ks.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.AttJpg8U.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.AttJpg8U.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.BI_xdp49.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.BI_xdp49.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.C-2EEX6w.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.C-2EEX6w.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.CAmo54FO.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.CAmo54FO.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.CbBzmHNP.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.CbBzmHNP.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.DZgTzkIg.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.DZgTzkIg.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.DZsITxq5.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.DZsITxq5.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.Dbf2GHth.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.Dbf2GHth.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.lleWnH5n.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.lleWnH5n.chunk.js.map +0 -1
- package/lib/vertesia-ui-i18n.wG_XSkbr.chunk.js +0 -5
- package/lib/vertesia-ui-i18n.wG_XSkbr.chunk.js.map +0 -1
|
@@ -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 ee}from"@vertesia/client";import{jsx as te}from"react/jsx-runtime";const y=`composableai.lastSelectedAccountId`,b=`composableai.lastSelectedProjectId`,x=`composableai.tabAccountId`,S=`composableai.tabProjectId`;function C(e){try{return sessionStorage.getItem(e)??void 0}catch{return}}function w(e,t){try{t?sessionStorage.setItem(e,t):sessionStorage.removeItem(e)}catch{}}function T(e){let t=C(x),n=e??t??localStorage.getItem(`composableai.lastSelectedAccountId`)??void 0;return{accountId:n,projectId:(t&&t===n?C(S):localStorage.getItem(`composableai.lastSelectedProjectId-${n}`)??void 0)||void 0}}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=i===void 0?T(n):void 0;return{accountId:n??a?.accountId,projectId:i??a?.projectId}}function E(e,t){w(x,e),w(S,t),localStorage.setItem(y,e),localStorage.setItem(`${b}-${e}`,t??``)}function D(){w(x,void 0),w(S,void 0)}function re(e,t){C(x)===e&&(!t||C(S)===t)&&D();let n=`${b}-${e}`;if(t){let r=localStorage.getItem(n)===t;r&&localStorage.removeItem(n),r&&localStorage.getItem(`composableai.lastSelectedAccountId`)===e&&localStorage.removeItem(y);return}localStorage.getItem(`composableai.lastSelectedAccountId`)===e&&(localStorage.removeItem(y),localStorage.removeItem(n))}const O=`auth_state`,k=`auth_state_expiry`;function ie(){let e=crypto.randomUUID();return sessionStorage.setItem(O,e),sessionStorage.setItem(k,String(Date.now()+3e5)),e}function ae(e){if(!e)return`Missing state`;let t=sessionStorage.getItem(O),n=parseInt(sessionStorage.getItem(k)||`0`,10);if(t!==e)return`State mismatched (${t} !== ${e})`;if(Date.now()>n)return`State expired`}function oe(){sessionStorage.removeItem(O),sessionStorage.removeItem(k)}function se(e,t){return`vtsauth=${e}; Path=/; Max-Age=${t}; SameSite=Lax${window.location.protocol===`https:`?`; Secure`:``}`}function ce(){document.cookie=se(`1`,300)}function le(){document.cookie=se(``,0)}function A(){if(typeof window>`u`||window.parent!==window)return!1;let e=window.__VERTESIA_RUNTIME_CONFIG__;return e?.authMode===`central`&&e.gatewaySession===!0}function ue(){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 de(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(ue()),new Promise(()=>{})):i}async function fe(){let e=await de(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 pe(){let e=await de(new URL(`/__appgen/session/logout`,window.location.origin).toString(),{method:`POST`});if(!e.ok)throw Error(`Application sign-out failed (${e.status})`)}function me(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 j=`vertesia.oauth.transaction`,M=`vertesia.oauth.access`;let he,N;var ge=class extends Error{};function _e(){try{let e=new URLSearchParams(window.location.hash.slice(1)),t=e.get(`token`);return!t||ae(e.get(`state`))?!1:me(i(t).iss,r.endpoints.sts)}catch{return!1}}function ve(){return!(!r.oauth||window.parent!==window||window.AUTH_MODE===`firebase`||A()||_e())}function ye(e){return btoa(String.fromCharCode(...e)).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=+$/,``)}function be(){return ye(crypto.getRandomValues(/* @__PURE__ */ new Uint8Array(32)))}function P(e){let t=new URL(e);if(t.protocol!==`https:`||t.username||t.password)throw Error(`OAuth endpoint must use HTTPS`);return t}function xe(){N=void 0,sessionStorage.removeItem(M),sessionStorage.removeItem(j)}async function Se(e=!1){let n=r.oauth;if(!n)throw Error(`Application OAuth is not configured`);let a=n.clientId.trim();if(!a)throw Error(`OAuth client ID is required`);let o=new URL(n.redirectUri),s=o.hostname===`localhost`||o.hostname.endsWith(`.localhost`)||o.hostname===`[::1]`||/^127\.\d+\.\d+\.\d+$/.test(o.hostname);if(o.protocol!==`https:`&&!(s&&o.protocol===`http:`))throw Error(`OAuth callback must use HTTPS or loopback HTTP`);let c=o.toString();if(new URL(c).origin!==window.location.origin)throw Error(`OAuth callback must be same-origin`);let l=(n.issuer?P(n.issuer).toString():r.endpoints.sts).replace(/\/+$/,``),u=new URL(window.location.href),{accountId:d,projectId:f}=ne(u),p=u.origin+u.pathname===new URL(c).origin+new URL(c).pathname,m=p?u.searchParams.get(`state`):null,h=p?u.searchParams.get(`code`):null,g=p?u.searchParams.get(`error`):null,_,v;if(m||h||g){let e=sessionStorage.getItem(j);if(sessionStorage.removeItem(j),v=e?JSON.parse(e):void 0,!v||v.state!==m||v.clientId!==a||v.redirectUri!==c||v.issuer!==l||Date.now()-v.created>6e5||v.created>Date.now())throw Error(`Invalid or expired OAuth login state`);if(g===t&&v.rememberedScope?.accountId){let e=new URL(v.target);if(e.origin!==window.location.origin)throw Error(`Invalid OAuth return target`);re(v.rememberedScope.accountId,v.rememberedScope.projectId),xe(),u=e,window.history.replaceState(window.history.state,``,u),d=v.retryScope?.accountId,f=void 0,v=void 0}else if(g||!h)throw Error(`Application sign-in was not completed (${g||`missing code`})`)}else{let t=sessionStorage.getItem(M);if(t){let r=JSON.parse(t),o=i(r.token);if(n.offlineAccess&&r.clientId===a&&r.issuer===l&&(!f||o.project?.id===f)&&(!d||o.account?.id===d)&&(_=N?.clientId===a&&N.issuer===l?N.token:void 0),r.refreshToken&&sessionStorage.removeItem(M),r.clientId===a&&r.issuer===l&&!e&&o.exp>Date.now()/1e3+(n.offlineAccess?300:30)&&(!f||o.project?.id===f)&&(!d||o.account?.id===d))return r.token}}let ee=new URL(l),te=new URL(`/.well-known/oauth-authorization-server${ee.pathname.replace(/\/$/,``)}`,ee.origin),y=await fetch(te);if(!y.ok)throw Error(`OAuth discovery failed (${y.status})`);let b=await y.json();if(b.issuer.replace(/\/+$/,``)!==l)throw Error(`OAuth issuer mismatch`);let x=P(b.authorization_endpoint),S=P(b.token_endpoint),C=b.revocation_endpoint===void 0?void 0:P(b.revocation_endpoint).toString(),w=n.resource?P(n.resource).toString():new URL(b.issuer).toString();if(_){try{let e=await fetch(S,{method:`POST`,headers:{"Content-Type":`application/x-www-form-urlencoded`},body:new URLSearchParams({grant_type:`refresh_token`,client_id:a,refresh_token:_,resource:w})});if(e.ok){let t=await e.json();if(!t.access_token||t.token_type?.toLowerCase()!==`bearer`)throw new ge(`Invalid OAuth refresh grant`);let n=i(t.access_token);if(n.iss.replace(/\/+$/,``)!==l||n.client_id!==a||n.exp<=Date.now()/1e3||d&&n.account?.id!==d||f&&n.project?.id!==f)throw new ge(`Invalid OAuth refresh identity`);return sessionStorage.setItem(M,JSON.stringify({token:t.access_token,clientId:a,issuer:l})),N={token:t.refresh_token??_,clientId:a,issuer:l,tokenEndpoint:S.toString(),revocationEndpoint:C},t.access_token}}catch{}N=void 0,sessionStorage.removeItem(M)}if(v&&h){let e=await fetch(S,{method:`POST`,headers:{"Content-Type":`application/x-www-form-urlencoded`},body:new URLSearchParams({grant_type:`authorization_code`,resource:w,code:h,client_id:a,redirect_uri:c,code_verifier:v.verifier})});if(!e.ok)throw Error(`OAuth code exchange failed (${e.status})`);let t=await e.json();if(!t.access_token||t.token_type?.toLowerCase()!==`bearer`)throw Error(`Invalid OAuth grant`);let r=i(t.access_token);if(r.iss.replace(/\/+$/,``)!==l||r.client_id!==a||r.exp<=Date.now()/1e3)throw Error(`OAuth grant does not match this application`);sessionStorage.setItem(M,JSON.stringify({token:t.access_token,clientId:a,issuer:l})),N=n.offlineAccess&&t.refresh_token?{token:t.refresh_token,clientId:a,issuer:l,tokenEndpoint:S.toString(),revocationEndpoint:C}:void 0;let o=new URL(v.target);if(o.origin!==window.location.origin)throw Error(`Invalid OAuth return target`);return r.account?.id?o.searchParams.set(`a`,r.account.id):o.searchParams.delete(`a`),r.project?.id?o.searchParams.set(`p`,r.project.id):o.searchParams.delete(`p`),o.pathname===`/auth/callback`&&(o.pathname=`/`),window.history.replaceState(window.history.state,``,o),t.access_token}let T=n.scopes??[`openid`,`profile`];if(a.startsWith(`https://`)){let e=await fetch(P(a),{cache:`no-store`});if(!e.ok)throw Error(`Application CIMD unavailable (${e.status})`);let t=await e.json();if(!t.redirect_uris?.includes(c))throw Error(`Application CIMD does not allow this callback`);!n.scopes&&t.scope&&(T=t.scope.split(/\s+/))}let E=u.searchParams.has(`a`)||u.searchParams.has(`p`)?{accountId:u.searchParams.get(`a`)??void 0,projectId:u.searchParams.get(`p`)??void 0}:r.defaultAuthSelection,D=be(),O={state:be(),verifier:D,clientId:a,redirectUri:c,issuer:l,target:u.toString(),rememberedScope:d&&E?.projectId===void 0&&(!E?.accountId||f)?{accountId:d,projectId:f}:void 0,retryScope:E?.accountId?{accountId:E.accountId}:void 0,created:Date.now()},k=await crypto.subtle.digest(`SHA-256`,new TextEncoder().encode(D));return x.searchParams.set(`client_id`,a),x.searchParams.set(`redirect_uri`,c),x.searchParams.set(`response_type`,`code`),x.searchParams.set(`resource`,w),x.searchParams.set(`state`,O.state),x.searchParams.set(`code_challenge_method`,`S256`),x.searchParams.set(`code_challenge`,ye(new Uint8Array(k))),x.searchParams.set(`scope`,(n.offlineAccess?[.../* @__PURE__ */ new Set([...T,`offline_access`])]:T.filter(e=>e!==`offline_access`)).join(` `)),d&&x.searchParams.set(`account_id`,d),f&&x.searchParams.set(`project_id`,f),sessionStorage.setItem(j,JSON.stringify(O)),ce(),window.location.replace(x.toString()),new Promise(()=>{})}function F(e=!1){return he??=Se(e).finally(()=>{he=void 0}),he}function Ce(){return ve()}const we=F;async function Te(){let e=N;if(xe(),!e)return;let t=P(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 I(){return r.endpoints.auth||`https://auth.vertesia.io/`}function Ee(e){return window.AUTH_MODE===`firebase`}function L(e){return!Ee()}function R(){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 De(){let e=new URL(document.baseURI);return e.hash=``,e.search=``,e}function Oe(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 z(e={}){if(ve()){F().catch(e=>r.logger.error(`Application OAuth sign-in failed`,e));return}if(A()){window.location.replace(ue());return}let t=Oe(I(),r.endpoints.sts??`https://sts.vertesia.io`,R(),ie(),e);ce(),location.replace(t.toString())}function ke(){if(A()||ve()||!L()||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 Ae=null,je=null,B=null;function Me(){if(!Ae)try{if(!r.firebase)throw Error(`Firebase configuration is not available in the environment`);Ae=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 Ae}function Ne(){return je||=a(Me()),je}function V(){return B||(B=c(Me()),B.tenantId=r.firebase?.tenantId??null),B}async function Pe(e){if(r.firebase?.tenantId)return V().tenantId=r.firebase.tenantId,{firebaseTenantId:r.firebase.tenantId,provider:r.firebase.providerType??`oidc`,name:``,label:``};if(!e){r.logger.debug(`Skipping Firebase tenant setup because no tenant identity was provided`);return}if(!r.firebase){r.logger.debug(`Skipping Firebase tenant setup because Firebase is not configured`);return}try{r.logger.debug(`Resolving Firebase tenant`);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){if(t.status===404){r.logger.debug(`No Firebase tenant for this address; using the default tenant`);return}let e=await t.json().catch(()=>void 0);throw Error(e?.error??`HTTP error ${t.status}`)}let n=await t.json();if(n===null){r.logger.debug(`No Firebase tenant for this address; using the default tenant`);return}if(n.firebaseTenantId){let e=V();return e.tenantId=n.firebaseTenantId,r.firebase.providerType=n.provider??`oidc`,r.logger.debug(`Firebase tenant resolved`),n}r.logger.warn(`Firebase tenant response did not include a tenant ID`);return}catch(e){if(t>1)r.logger.debug(`Firebase tenant resolution failed; retrying`,{vertesia:{retry_delay_ms:n,attempts_remaining:t-1,error:e}}),await new Promise(e=>setTimeout(e,n)),n*=2,t--;else throw e}}catch(e){r.logger.warn(`Firebase tenant resolution failed; continuing with the default tenant`,{vertesia:{error:e}})}}async function Fe(e){let t=V().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.warn(`Failed to get Firebase token`,{vertesia:{user_email:t.email,user_name:t.displayName,user_id:t.uid,refresh:e,error:n}}),null)):(r.logger.warn(`No user found`),Promise.resolve(null))}let H,U,W=!1;const Ie=`vt.centralAuthRenewalAt`;function Le(){if(!W||!L())return!1;let e=0;try{e=Number(sessionStorage.getItem(Ie)??`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(Ie,String(Date.now()))}catch{}r.logger.info(`Renewing an expired Central Auth session through the broker`);let t=Oe(I(),r.endpoints.sts??`https://sts.vertesia.io`,R(),ie());return location.replace(t.toString()),!0}function Re(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 G(e){return i(e)}function ze(e){if(!e)return!1;try{return me(G(e).iss,r.endpoints.sts)}catch{return!1}}function Be(e,t,n){let r=G(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 K(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 $(`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 J(`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}}),K(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 J(`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 Q(`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=Re(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 Xe(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 Z(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 X(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 $(`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 $(`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 J||e instanceof Y||e instanceof Xe||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 $(`The authentication service could not complete sign-in`,d,{cause:e}))}}async function Ve(e,t,n){return K(Fe,e,t,n)}async function He(e,t,n,r){return K(()=>Promise.resolve(e),t,n,r)}function Ue(){return H}function We(e){return U?.account?.id&&(!e||U.account.id===e)?{accountId:U.account.id,projectId:U.project?.id}:T(e)}async function q(e,t,n,i=!1,a=!1){let o=t===void 0?We(e):void 0,s=e??o?.accountId,c=t??o?.projectId,l=r.isLocalDev?r.devAuthToken:void 0,u=l??n??H,d=(!s||U?.account?.id===s)&&(!c||U?.project?.id===c);if(!i&&H&&U&&d&&U.exp>Date.now()/1e3+300)return W=!0,{rawToken:H,token:U,error:!1};if(!i&&ze(u)&&Be(u,s,c)){if(H=u,U=G(H),!U.exp)throw Error(`Invalid composable token`);return W=!0,{rawToken:H,token:U,error:!1}}try{if(!l&&!a&&V().currentUser)H=await Ve(s,c);else if(l)l&&(H=l);else{let e=await r.authTokenProvider?.(),t=e??n??H;H=(!i||e)&&t&&ze(t)&&Be(t,s,c)?t:t?await K(()=>Promise.resolve(t),s,c):void 0}}catch(e){throw(e instanceof X||e instanceof Z||e instanceof Q)&&(H=void 0,U=void 0,e instanceof X&&s&&re(s,c)),e instanceof Q&&Le(),e}if(!H)throw r.logger.error(`Cannot acquire a composable token`,{vertesia:{account_id:s,project_id:c}}),Le(),Error(`Cannot acquire a composable token`);if(U=G(H),!U?.exp||!H)throw console.error(`Invalid composable token`,U),r.logger.error(`Invalid composable token`,{vertesia:{account_id:s,project_id:c}}),Error(`Invalid composable token`);return W=!0,{rawToken:H,token:U,error:!1}}var J=class extends Error{email;constructor(e,t){super(e),this.name=`UserNotFoundError`,this.email=t}},Y=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}},X=class extends Y{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 Ge=X;var Z=class extends Y{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`}},Q=class extends Y{constructor(e,t,n){super(e,t,n),this.name=`CredentialError`}},$=class extends Y{constructor(e,t,n){super(e,t,n),this.name=`AuthenticationServiceError`}};function Ke(e){return e instanceof X}function qe(e){return e instanceof Z}function Je(e){return e instanceof Q}function Ye(e){return e instanceof $}var Xe=class extends Error{constructor(e){super(e),this.name=`RestrictedEnvironmentError`}};function Ze(){return{generateState:d(()=>ie(),[]),verifyState:d(e=>ae(e),[]),clearState:d(()=>oe(),[])}}var Qe=class e{authMethod=`token`;isLoading=!0;client;authError;authToken;setSession;lastSelectedAccount;lastSelectedProject;onboardingComplete;constructor(e,t){this.client=e||new ee({serverUrl:A()?`${window.location.origin}/__appgen/session/studio`:r.endpoints.studio,storeUrl:A()?`${window.location.origin}/__appgen/session/store`:r.endpoints.zeno,tokenServerUrl:r.endpoints.sts,fetch:A()?de: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`?F():A()?Promise.reject(/* @__PURE__ */ Error(`Gateway session credentials are not available to application JavaScript`)):q().then(e=>{let t=e?.rawToken;if(!t)throw Error(`No token available`);return this.adoptToken(t),t})}adoptToken(e){let t=i(e),n=this.authToken,a=!!n?.project&&n.project.id!==t.project?.id;if(n&&(n.account?.id!==t.account?.id||a))throw r.logger.warn(`Auth token scope changed under the session; reloading`,{vertesia:{account_id:n.account?.id,project_id:n.project?.id,next_account_id:t.account?.id,next_project_id:t.project?.id}}),location.reload(),Error(`The session account or project changed; reloading`);return this.authToken=t,t}async refreshAuthToken(){if(A()){let e=await this.loginGatewaySession();return this.setSession?.(this.clone()),e}if(this.authMethod===`oauth`)return this.authToken=i(await F(!0)),this.setSession?.(this.clone()),this.authToken;let e=(await q(void 0,void 0,void 0,!0))?.rawToken;if(!e)throw Error(`No token available`);let t=this.adoptToken(e);return this.setSession?.(this.clone()),t}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})`),E(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 fe(),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`),A()){pe().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`){Te().catch(()=>void 0).finally(()=>{let e=new URL(I());e.pathname=`/logout`,e.searchParams.set(`redirect_uri`,R().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(L()){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(I()),t=R();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&&V().signOut(),this.authError=void 0,this.isLoading=!1,this.authToken=void 0,this.setSession=void 0,this.client.withAuthCallback(void 0),e&&location.replace(De().toString())}}async switchAccount(e){localStorage.setItem(y,e),this&&(this.account&&this.project?localStorage.setItem(`${b}-${this.account.id}`,this.project.id):this.account&&localStorage.removeItem(`${b}-${this.account.id}`)),D();let t=De();t.searchParams.set(`a`,e),window.location.replace(t.toString())}async switchProject(e){this.account&&E(this.account.id,e);let t=De();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 $e=u(void 0);function et(){let e=f($e);if(!e)throw Error(`useUserSession must be used within a UserSessionProvider`);return e}function tt(){let{user:e}=et(),[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 nt(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 rt({children:e,token:t}){let n=m(()=>{let e=new Qe;e.isLoading=!1;try{e.authToken=nt(t),e.client.withAuthCallback(()=>Promise.resolve(`Bearer ${t}`)),E(e.authToken.account.id,e.authToken.project?.id)}catch(t){e.authError=t instanceof Error?t:Error(String(t))}return e.clone()},[t]);return te($e.Provider,{value:n,children:e})}function it(){let e=new URL(window.location.href);e.hash=``,window.history.replaceState(window.history.state,``,`${e.pathname}${e.search}`)}function at(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 ot({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 Qe),{verifyState:u,clearState:d}=Ze(),f=h(!1),m=h(void 0),_=(e,n=!1)=>{let i=at(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 X||e instanceof Z||e instanceof Q||e instanceof $||e instanceof J||e instanceof Xe?(e instanceof X?_(e,t):t&&it(),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,q(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()||ve()){let e=!1;return s.setSession=c,(A()?s.loginGatewaySession():F().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(),it(),z({accountId:e,projectId:t});return}d(),q(e,t,a,!1,L()).then(e=>s.login(e.rawToken,{loadOnboardingStatus:n}).then(()=>{c(s.clone()),it()})).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}}),z({accountId:e,projectId:t}))});return}let i=!1,p,m=()=>{if(!i){if(window.parent!==window&&!r.allowLegacyIframeAuth){s.isLoading=!1,s.authError=/* @__PURE__ */ 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}}),L()){r.logger.debug(`Redirecting to central auth with selection`,{vertesia:{account_id:e,project_id:t}}),z({accountId:e,projectId:t});return}r.logger.debug(`Host is in Firebase auth allowlist`,{vertesia:{account_id:e,project_id:t}})}p=l(V(),async i=>{i?(r.logger.debug(`Successful login with firebase`,{vertesia:{account_id:e,project_id:t}}),s.setSession=c,await q(e,t,void 0,!1,L()).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 q(e,t,r,!1,L());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?.(),[]),te($e.Provider,{value:s,children:e})}function st(){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(Ne(),e,{...t,debug_mode:!r.isProd})}}}export{$ as AuthenticationServiceError,Q as CredentialError,rt as DevSessionProvider,y as LastSelectedAccountId_KEY,b as LastSelectedProjectId_KEY,Z as NoAccessibleAccountError,X as RequestedScopeUnavailableError,Xe as RestrictedEnvironmentError,Y as STSError,Ge as TokenAuthorizationError,J as UserNotFoundError,Qe as UserSession,$e as UserSessionContext,ot as UserSessionProvider,Oe as buildCentralAuthRedirectUrl,le as clearCentralAuthRoundTripMarker,K as fetchComposableToken,Ve as fetchComposableTokenFromFirebaseToken,He as fetchComposableTokenFromVertesiaToken,q as getComposableToken,Ue as getCurrentVertesiaToken,Ne as getFirebaseAnalytics,Me as getFirebaseApp,V as getFirebaseAuth,Fe as getFirebaseAuthToken,Ce as isAppOAuthLoginPending,Ye as isAuthenticationServiceError,ke as isCentralAuthRedirectPending,Je as isCredentialError,qe as isNoAccessibleAccountError,Ke as isRequestedScopeUnavailableError,z as redirectToCentralAuth,E as rememberScopeSelection,ne as resolveAuthSelection,Te as revokeAppOAuthSession,at as sanitizeRejectedScopeUrl,Pe as setFirebaseTenant,we as startAppOAuthLogin,Ze as useAuthState,tt as useCurrentTenant,st as useUXTracking,et 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=`composableai.tabAccountId`,w=`composableai.tabProjectId`;function T(e){try{return sessionStorage.getItem(e)??void 0}catch{return}}function E(e,t){try{t?sessionStorage.setItem(e,t):sessionStorage.removeItem(e)}catch{}}function D(e){let t=T(C),n=e??t??localStorage.getItem(`composableai.lastSelectedAccountId`)??void 0;return{accountId:n,projectId:(t&&t===n?T(w):localStorage.getItem(`composableai.lastSelectedProjectId-${n}`)??void 0)||void 0}}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=i===void 0?D(n):void 0;return{accountId:n??a?.accountId,projectId:i??a?.projectId}}function O(e,t){E(C,e),E(w,t),localStorage.setItem(x,e),localStorage.setItem(`${S}-${e}`,t??``)}function k(){E(C,void 0),E(w,void 0)}function te(e,t){T(C)===e&&(!t||T(w)===t)&&k();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))}const A=`auth_state`,j=`auth_state_expiry`;function M(){let e=crypto.randomUUID();return sessionStorage.setItem(A,e),sessionStorage.setItem(j,String(Date.now()+3e5)),e}function ne(e){if(!e)return`Missing state`;let t=sessionStorage.getItem(A),n=parseInt(sessionStorage.getItem(j)||`0`,10);if(t!==e)return`State mismatched (${t} !== ${e})`;if(Date.now()>n)return`State expired`}function re(){sessionStorage.removeItem(A),sessionStorage.removeItem(j)}function ie(e,t){return`vtsauth=${e}; Path=/; Max-Age=${t}; SameSite=Lax${window.location.protocol===`https:`?`; Secure`:``}`}function ae(){document.cookie=ie(`1`,300)}function oe(){document.cookie=ie(``,0)}function N(){if(typeof window>`u`||window.parent!==window)return!1;let e=window.__VERTESIA_RUNTIME_CONFIG__;return e?.authMode===`central`&&e.gatewaySession===!0}function se(){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 ce(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(se()),new Promise(()=>{})):i}async function le(){let e=await ce(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 ue(){let e=await ce(new URL(`/__appgen/session/logout`,window.location.origin).toString(),{method:`POST`});if(!e.ok)throw Error(`Application sign-out failed (${e.status})`)}function de(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 P=`vertesia.oauth.transaction`,F=`vertesia.oauth.access`;let fe,I;var pe=class extends Error{};function me(){try{let e=new URLSearchParams(window.location.hash.slice(1)),t=e.get(`token`);return!t||ne(e.get(`state`))?!1:de(i(t).iss,r.endpoints.sts)}catch{return!1}}function L(){return!(!r.oauth||window.parent!==window||window.AUTH_MODE===`firebase`||N()||me())}function he(e){return btoa(String.fromCharCode(...e)).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=+$/,``)}function ge(){return he(crypto.getRandomValues(/* @__PURE__ */ new Uint8Array(32)))}function R(e){let t=new URL(e);if(t.protocol!==`https:`||t.username||t.password)throw Error(`OAuth endpoint must use HTTPS`);return t}function _e(){I=void 0,sessionStorage.removeItem(F),sessionStorage.removeItem(P)}async function ve(e=!1){let n=r.oauth;if(!n)throw Error(`Application OAuth is not configured`);let a=n.clientId.trim();if(!a)throw Error(`OAuth client ID is required`);let o=new URL(n.redirectUri),s=o.hostname===`localhost`||o.hostname.endsWith(`.localhost`)||o.hostname===`[::1]`||/^127\.\d+\.\d+\.\d+$/.test(o.hostname);if(o.protocol!==`https:`&&!(s&&o.protocol===`http:`))throw Error(`OAuth callback must use HTTPS or loopback HTTP`);let c=o.toString();if(new URL(c).origin!==window.location.origin)throw Error(`OAuth callback must be same-origin`);let l=(n.issuer?R(n.issuer).toString():r.endpoints.sts).replace(/\/+$/,``),u=n.resource?R(n.resource).toString():void 0,d=e=>e.clientId===a&&e.issuer===l&&e.resource===u,f=new URL(window.location.href),{accountId:p,projectId:m}=ee(f),h=f.origin+f.pathname===new URL(c).origin+new URL(c).pathname,g=h?f.searchParams.get(`state`):null,_=h?f.searchParams.get(`code`):null,v=h?f.searchParams.get(`error`):null,y,b;if(g||_||v){let e=sessionStorage.getItem(P);if(sessionStorage.removeItem(P),b=e?JSON.parse(e):void 0,!b||b.state!==g||!d(b)||b.redirectUri!==c||Date.now()-b.created>6e5||b.created>Date.now())throw Error(`Invalid or expired OAuth login state`);if(v===t&&b.rememberedScope?.accountId){let e=new URL(b.target);if(e.origin!==window.location.origin)throw Error(`Invalid OAuth return target`);te(b.rememberedScope.accountId,b.rememberedScope.projectId),_e(),f=e,window.history.replaceState(window.history.state,``,f),p=b.retryScope?.accountId,m=void 0,b=void 0}else if(v||!_)throw Error(`Application sign-in was not completed (${v||`missing code`})`)}else{let t=sessionStorage.getItem(F);if(t){let r=JSON.parse(t),a=i(r.token);if(n.offlineAccess&&d(r)&&(!m||a.project?.id===m)&&(!p||a.account?.id===p)&&(y=I&&d(I)?I.token:void 0),r.refreshToken&&sessionStorage.removeItem(F),d(r)&&!e&&a.exp>Date.now()/1e3+(n.offlineAccess?300:30)&&(!m||a.project?.id===m)&&(!p||a.account?.id===p))return r.token}}let x=new URL(l),S=new URL(`/.well-known/oauth-authorization-server${x.pathname.replace(/\/$/,``)}`,x.origin),C=await fetch(S);if(!C.ok)throw Error(`OAuth discovery failed (${C.status})`);let w=await C.json();if(w.issuer.replace(/\/+$/,``)!==l)throw Error(`OAuth issuer mismatch`);let T=R(w.authorization_endpoint),E=R(w.token_endpoint),D=w.revocation_endpoint===void 0?void 0:R(w.revocation_endpoint).toString(),O=u??new URL(w.issuer).toString();if(y){try{let e=await fetch(E,{method:`POST`,headers:{"Content-Type":`application/x-www-form-urlencoded`},body:new URLSearchParams({grant_type:`refresh_token`,client_id:a,refresh_token:y,resource:O})});if(e.ok){let t=await e.json();if(!t.access_token||t.token_type?.toLowerCase()!==`bearer`)throw new pe(`Invalid OAuth refresh grant`);let n=i(t.access_token);if(n.iss.replace(/\/+$/,``)!==l||n.client_id!==a||n.exp<=Date.now()/1e3||p&&n.account?.id!==p||m&&n.project?.id!==m)throw new pe(`Invalid OAuth refresh identity`);return sessionStorage.setItem(F,JSON.stringify({token:t.access_token,clientId:a,issuer:l,resource:u})),I={token:t.refresh_token??y,clientId:a,issuer:l,resource:u,tokenEndpoint:E.toString(),revocationEndpoint:D},t.access_token}}catch{}I=void 0,sessionStorage.removeItem(F)}if(b&&_){let e=await fetch(E,{method:`POST`,headers:{"Content-Type":`application/x-www-form-urlencoded`},body:new URLSearchParams({grant_type:`authorization_code`,resource:O,code:_,client_id:a,redirect_uri:c,code_verifier:b.verifier})});if(!e.ok)throw Error(`OAuth code exchange failed (${e.status})`);let t=await e.json();if(!t.access_token||t.token_type?.toLowerCase()!==`bearer`)throw Error(`Invalid OAuth grant`);let r=i(t.access_token);if(r.iss.replace(/\/+$/,``)!==l||r.client_id!==a||r.exp<=Date.now()/1e3)throw Error(`OAuth grant does not match this application`);sessionStorage.setItem(F,JSON.stringify({token:t.access_token,clientId:a,issuer:l,resource:u})),I=n.offlineAccess&&t.refresh_token?{token:t.refresh_token,clientId:a,issuer:l,resource:u,tokenEndpoint:E.toString(),revocationEndpoint:D}:void 0;let o=new URL(b.target);if(o.origin!==window.location.origin)throw Error(`Invalid OAuth return target`);return r.account?.id?o.searchParams.set(`a`,r.account.id):o.searchParams.delete(`a`),r.project?.id?o.searchParams.set(`p`,r.project.id):o.searchParams.delete(`p`),o.pathname===`/auth/callback`&&(o.pathname=`/`),window.history.replaceState(window.history.state,``,o),t.access_token}let k=n.scopes??[`openid`,`profile`];if(a.startsWith(`https://`)){let e=await fetch(R(a),{cache:`no-store`});if(!e.ok)throw Error(`Application CIMD unavailable (${e.status})`);let t=await e.json();if(!t.redirect_uris?.includes(c))throw Error(`Application CIMD does not allow this callback`);!n.scopes&&t.scope&&(k=t.scope.split(/\s+/))}let A=f.searchParams.has(`a`)||f.searchParams.has(`p`)?{accountId:f.searchParams.get(`a`)??void 0,projectId:f.searchParams.get(`p`)??void 0}:r.defaultAuthSelection,j=ge(),M={state:ge(),verifier:j,clientId:a,redirectUri:c,issuer:l,resource:u,target:f.toString(),rememberedScope:p&&A?.projectId===void 0&&(!A?.accountId||m)?{accountId:p,projectId:m}:void 0,retryScope:A?.accountId?{accountId:A.accountId}:void 0,created:Date.now()},ne=await crypto.subtle.digest(`SHA-256`,new TextEncoder().encode(j));return T.searchParams.set(`client_id`,a),T.searchParams.set(`redirect_uri`,c),T.searchParams.set(`response_type`,`code`),T.searchParams.set(`resource`,O),T.searchParams.set(`state`,M.state),T.searchParams.set(`code_challenge_method`,`S256`),T.searchParams.set(`code_challenge`,he(new Uint8Array(ne))),T.searchParams.set(`scope`,(n.offlineAccess?[.../* @__PURE__ */ new Set([...k,`offline_access`])]:k.filter(e=>e!==`offline_access`)).join(` `)),p&&T.searchParams.set(`account_id`,p),m&&T.searchParams.set(`project_id`,m),sessionStorage.setItem(P,JSON.stringify(M)),ae(),window.location.replace(T.toString()),new Promise(()=>{})}function z(e=!1){return fe??=ve(e).finally(()=>{fe=void 0}),fe}function ye(){return L()}const be=z;async function xe(){let e=I;if(_e(),!e)return;let t=R(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 B(){return r.endpoints.auth||`https://auth.vertesia.io/`}function Se(e){return window.AUTH_MODE===`firebase`}function V(e){return!Se()}function H(){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 Ce(){let e=new URL(document.baseURI);return e.hash=``,e.search=``,e}function we(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 Te(e={}){if(L()){z().catch(e=>r.logger.error(`Application OAuth sign-in failed`,e));return}if(N()){window.location.replace(se());return}let t=we(B(),r.endpoints.sts??`https://sts.vertesia.io`,H(),M(),e);ae(),location.replace(t.toString())}function Ee(){if(N()||L()||!V()||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 De=null,Oe=null,ke=null;function Ae(){if(!De)try{if(!r.firebase)throw Error(`Firebase configuration is not available in the environment`);De=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 De}function je(){return Oe||=a(Ae()),Oe}function U(){return ke||(ke=c(Ae()),ke.tenantId=r.firebase?.tenantId??null),ke}async function Me(e){if(r.firebase?.tenantId)return U().tenantId=r.firebase.tenantId,{firebaseTenantId:r.firebase.tenantId,provider:r.firebase.providerType??`oidc`,name:``,label:``};if(!e){r.logger.debug(`Skipping Firebase tenant setup because no tenant identity was provided`);return}if(!r.firebase){r.logger.debug(`Skipping Firebase tenant setup because Firebase is not configured`);return}try{r.logger.debug(`Resolving Firebase tenant`);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){if(t.status===404){r.logger.debug(`No Firebase tenant for this address; using the default tenant`);return}let e=await t.json().catch(()=>void 0);throw Error(e?.error??`HTTP error ${t.status}`)}let n=await t.json();if(n===null){r.logger.debug(`No Firebase tenant for this address; using the default tenant`);return}if(n.firebaseTenantId){let e=U();return e.tenantId=n.firebaseTenantId,r.firebase.providerType=n.provider??`oidc`,r.logger.debug(`Firebase tenant resolved`),n}r.logger.warn(`Firebase tenant response did not include a tenant ID`);return}catch(e){if(t>1)r.logger.debug(`Firebase tenant resolution failed; retrying`,{vertesia:{retry_delay_ms:n,attempts_remaining:t-1,error:e}}),await new Promise(e=>setTimeout(e,n)),n*=2,t--;else throw e}}catch(e){r.logger.warn(`Firebase tenant resolution failed; continuing with the default tenant`,{vertesia:{error:e}})}}async function Ne(e){let t=U().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.warn(`Failed to get Firebase token`,{vertesia:{user_email:t.email,user_name:t.displayName,user_id:t.uid,refresh:e,error:n}}),null)):(r.logger.warn(`No user found`),Promise.resolve(null))}let W,G,Pe=!1;const Fe=`vt.centralAuthRenewalAt`;function Ie(){if(!Pe||!V())return!1;let e=0;try{e=Number(sessionStorage.getItem(Fe)??`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(Fe,String(Date.now()))}catch{}r.logger.info(`Renewing an expired Central Auth session through the broker`);let t=we(B(),r.endpoints.sts??`https://sts.vertesia.io`,H(),M());return location.replace(t.toString()),!0}function Le(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 Re(e){return i(e)}function ze(e){if(!e)return!1;try{return de(Re(e).iss,r.endpoints.sts)}catch{return!1}}function Be(e,t,n){let r=Re(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 K(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 $(`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 J(`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}}),K(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 J(`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 Q(`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=Le(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 Xe(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 Z(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 X(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 $(`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 $(`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 J||e instanceof Y||e instanceof Xe||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 $(`The authentication service could not complete sign-in`,d,{cause:e}))}}async function Ve(e,t,n){return K(Ne,e,t,n)}async function He(e,t,n,r){return K(()=>Promise.resolve(e),t,n,r)}function Ue(){return W}function We(e){return G?.account?.id&&(!e||G.account.id===e)?{accountId:G.account.id,projectId:G.project?.id}:D(e)}async function q(e,t,n,i=!1,a=!1){let o=t===void 0?We(e):void 0,s=e??o?.accountId,c=t??o?.projectId,l=r.isLocalDev?r.devAuthToken:void 0,u=l??n??W,d=(!s||G?.account?.id===s)&&(!c||G?.project?.id===c);if(!i&&W&&G&&d&&G.exp>Date.now()/1e3+300)return Pe=!0,{rawToken:W,token:G,error:!1};if(!i&&ze(u)&&Be(u,s,c)){if(W=u,G=Re(W),!G.exp)throw Error(`Invalid composable token`);return Pe=!0,{rawToken:W,token:G,error:!1}}try{if(!l&&!a&&U().currentUser)W=await Ve(s,c);else if(l)l&&(W=l);else{let e=await r.authTokenProvider?.(),t=e??n??W;W=(!i||e)&&t&&ze(t)&&Be(t,s,c)?t:t?await K(()=>Promise.resolve(t),s,c):void 0}}catch(e){throw(e instanceof X||e instanceof Z||e instanceof Q)&&(W=void 0,G=void 0,e instanceof X&&s&&te(s,c)),e instanceof Q&&Ie(),e}if(!W)throw r.logger.error(`Cannot acquire a composable token`,{vertesia:{account_id:s,project_id:c}}),Ie(),Error(`Cannot acquire a composable token`);if(G=Re(W),!G?.exp||!W)throw console.error(`Invalid composable token`,G),r.logger.error(`Invalid composable token`,{vertesia:{account_id:s,project_id:c}}),Error(`Invalid composable token`);return Pe=!0,{rawToken:W,token:G,error:!1}}var J=class extends Error{email;constructor(e,t){super(e),this.name=`UserNotFoundError`,this.email=t}},Y=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}},X=class extends Y{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 Ge=X;var Z=class extends Y{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`}},Q=class extends Y{constructor(e,t,n){super(e,t,n),this.name=`CredentialError`}},$=class extends Y{constructor(e,t,n){super(e,t,n),this.name=`AuthenticationServiceError`}};function Ke(e){return e instanceof X}function qe(e){return e instanceof Z}function Je(e){return e instanceof Q}function Ye(e){return e instanceof $}var Xe=class extends Error{constructor(e){super(e),this.name=`RestrictedEnvironmentError`}};function Ze(){return{generateState:d(()=>M(),[]),verifyState:d(e=>ne(e),[]),clearState:d(()=>re(),[])}}var Qe=class e{authMethod=`token`;isLoading=!0;client;authError;authToken;setSession;lastSelectedAccount;lastSelectedProject;onboardingComplete;constructor(e,t){this.client=e||new y({serverUrl:N()?`${window.location.origin}/__appgen/session/studio`:r.endpoints.studio,storeUrl:N()?`${window.location.origin}/__appgen/session/store`:r.endpoints.zeno,tokenServerUrl:r.endpoints.sts,fetch:N()?ce: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`?z():N()?Promise.reject(/* @__PURE__ */ Error(`Gateway session credentials are not available to application JavaScript`)):q().then(e=>{let t=e?.rawToken;if(!t)throw Error(`No token available`);return this.adoptToken(t),t})}adoptToken(e){let t=i(e),n=this.authToken,a=!!n?.project&&n.project.id!==t.project?.id;if(n&&(n.account?.id!==t.account?.id||a))throw r.logger.warn(`Auth token scope changed under the session; reloading`,{vertesia:{account_id:n.account?.id,project_id:n.project?.id,next_account_id:t.account?.id,next_project_id:t.project?.id}}),location.reload(),Error(`The session account or project changed; reloading`);return this.authToken=t,t}async refreshAuthToken(){if(N()){let e=await this.loginGatewaySession();return this.setSession?.(this.clone()),e}if(this.authMethod===`oauth`)return this.authToken=i(await z(!0)),this.setSession?.(this.clone()),this.authToken;let e=(await q(void 0,void 0,void 0,!0))?.rawToken;if(!e)throw Error(`No token available`);let t=this.adoptToken(e);return this.setSession?.(this.clone()),t}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})`),O(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 le(),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`),N()){ue().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`){xe().catch(()=>void 0).finally(()=>{let e=new URL(B());e.pathname=`/logout`,e.searchParams.set(`redirect_uri`,H().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(V()){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(B()),t=H();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&&U().signOut(),this.authError=void 0,this.isLoading=!1,this.authToken=void 0,this.setSession=void 0,this.client.withAuthCallback(void 0),e&&location.replace(Ce().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}`)),k();let t=Ce();t.searchParams.set(`a`,e),window.location.replace(t.toString())}async switchProject(e){this.account&&O(this.account.id,e);let t=Ce();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 $e=u(void 0);function et(){let e=f($e);if(!e)throw Error(`useUserSession must be used within a UserSessionProvider`);return e}function tt(){let{user:e}=et(),[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 nt(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 rt({children:e,token:t}){let n=m(()=>{let e=new Qe;e.isLoading=!1;try{e.authToken=nt(t),e.client.withAuthCallback(()=>Promise.resolve(`Bearer ${t}`)),O(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($e.Provider,{value:n,children:e})}function it(){let e=new URL(window.location.href);e.hash=``,window.history.replaceState(window.history.state,``,`${e.pathname}${e.search}`)}function at(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 ot({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 Qe),{verifyState:u,clearState:d}=Ze(),f=h(!1),m=h(void 0),_=(e,n=!1)=>{let i=at(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 X||e instanceof Z||e instanceof Q||e instanceof $||e instanceof J||e instanceof Xe?(e instanceof X?_(e,t):t&&it(),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}}),r.isLocalDev&&r.devAuthToken){s.setSession=c,q(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(N()||L()){let e=!1;return s.setSession=c,(N()?s.loginGatewaySession():z().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(),it(),Te({accountId:e,projectId:t});return}d(),q(e,t,a,!1,V()).then(e=>s.login(e.rawToken,{loadOnboardingStatus:n}).then(()=>{c(s.clone()),it()})).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}}),Te({accountId:e,projectId:t}))});return}let i=!1,p,m=()=>{if(!i){if(window.parent!==window&&!r.allowLegacyIframeAuth){s.isLoading=!1,s.authError=/* @__PURE__ */ 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}}),V()){r.logger.debug(`Redirecting to central auth with selection`,{vertesia:{account_id:e,project_id:t}}),Te({accountId:e,projectId:t});return}r.logger.debug(`Host is in Firebase auth allowlist`,{vertesia:{account_id:e,project_id:t}})}p=l(U(),async i=>{i?(r.logger.debug(`Successful login with firebase`,{vertesia:{account_id:e,project_id:t}}),s.setSession=c,await q(e,t,void 0,!1,V()).then(e=>s.login(e.rawToken,{loadOnboardingStatus:n}).then(()=>c(s.clone()))).catch(n=>{v(n)||(n instanceof Error&&n.message===`Customer-domain user requires an invite to join`||(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 q(e,t,r,!1,V());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($e.Provider,{value:s,children:e})}function st(){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(je(),e,{...t,debug_mode:!r.isProd})}}}export{$ as AuthenticationServiceError,Q as CredentialError,rt as DevSessionProvider,x as LastSelectedAccountId_KEY,S as LastSelectedProjectId_KEY,Z as NoAccessibleAccountError,X as RequestedScopeUnavailableError,Xe as RestrictedEnvironmentError,Y as STSError,Ge as TokenAuthorizationError,J as UserNotFoundError,Qe as UserSession,$e as UserSessionContext,ot as UserSessionProvider,we as buildCentralAuthRedirectUrl,oe as clearCentralAuthRoundTripMarker,K as fetchComposableToken,Ve as fetchComposableTokenFromFirebaseToken,He as fetchComposableTokenFromVertesiaToken,q as getComposableToken,Ue as getCurrentVertesiaToken,je as getFirebaseAnalytics,Ae as getFirebaseApp,U as getFirebaseAuth,Ne as getFirebaseAuthToken,ye as isAppOAuthLoginPending,Ye as isAuthenticationServiceError,Ee as isCentralAuthRedirectPending,Je as isCredentialError,qe as isNoAccessibleAccountError,Ke as isRequestedScopeUnavailableError,Te as redirectToCentralAuth,O as rememberScopeSelection,ee as resolveAuthSelection,xe as revokeAppOAuthSession,at as sanitizeRejectedScopeUrl,Me as setFirebaseTenant,be as startAppOAuthLogin,Ze as useAuthState,tt as useCurrentTenant,st as useUXTracking,et as useUserSession};
|
|
2
2
|
//# sourceMappingURL=vertesia-ui-session.js.map
|