@xinosolutions/auth-sdk 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -27,10 +27,12 @@ __export(index_exports, {
27
27
  SessionBridgeError: () => SessionBridgeError,
28
28
  XSAuthDeniedError: () => XSAuthDeniedError,
29
29
  createPkcePair: () => createPkcePair,
30
+ idTokenIncludesMfa: () => idTokenIncludesMfa,
30
31
  isLoginRequiredError: () => isLoginRequiredError,
31
32
  isPrimaryAccountError: () => isPrimaryAccountError,
32
33
  loginWithXS: () => loginWithXS,
33
34
  openSessionBridge: () => openSessionBridge2,
35
+ parseIdTokenAmr: () => parseIdTokenAmr,
34
36
  signOutWithXS: () => signOutWithXS2
35
37
  });
36
38
  module.exports = __toCommonJS(index_exports);
@@ -441,7 +443,7 @@ async function loginWithXS(opts) {
441
443
  "loginWithXS requires a browser Window and explicit parentOrigin (or window.location)."
442
444
  );
443
445
  }
444
- const timeoutMs = opts.timeoutMs !== void 0 ? opts.timeoutMs : 12e4;
446
+ const timeoutMs = opts.timeoutMs !== void 0 ? opts.timeoutMs : 18e4;
445
447
  const state = randomBase64State();
446
448
  sessionStorage.setItem(STATE_KEY_STORAGE, state);
447
449
  const nonce = opts.useNonce ? randomBase64State() : void 0;
@@ -458,6 +460,7 @@ async function loginWithXS(opts) {
458
460
  if (nonce) params.set("nonce", nonce);
459
461
  const prompt = resolvePrompt(opts);
460
462
  if (prompt) params.set("prompt", prompt);
463
+ if (opts.mode === "signup") params.set("mode", "signup");
461
464
  if (opts.accountId?.trim()) params.set("account_id", opts.accountId.trim());
462
465
  maybeSetPublicPath(params, authBase);
463
466
  const authorizeUrl = `${normalizedBase.href.replace(/\/?$/u, "")}/authorize?${params.toString()}`;
@@ -529,7 +532,7 @@ async function loginWithXS(opts) {
529
532
  window.removeEventListener("message", handleMessage);
530
533
  clearInterval(closePoll);
531
534
  cleaned = true;
532
- resolve({ user, idToken });
535
+ resolve({ user, idToken, mfaVerified: idTokenIncludesMfa(idToken) });
533
536
  try {
534
537
  popup.close();
535
538
  } catch {
@@ -545,6 +548,31 @@ async function loginWithXS(opts) {
545
548
  }, 280);
546
549
  });
547
550
  }
551
+ function idTokenIncludesMfa(idToken) {
552
+ const amr = parseIdTokenAmr(idToken);
553
+ return Array.isArray(amr) && amr.includes("mfa");
554
+ }
555
+ function parseIdTokenAmr(idToken) {
556
+ const payload = parseJwtPayload(idToken);
557
+ if (!payload || !("amr" in payload)) return null;
558
+ const amr = payload.amr;
559
+ if (Array.isArray(amr)) {
560
+ return amr.filter((v) => typeof v === "string");
561
+ }
562
+ if (typeof amr === "string" && amr.trim()) return [amr.trim()];
563
+ return null;
564
+ }
565
+ function parseJwtPayload(token) {
566
+ const parts = token.split(".");
567
+ if (parts.length < 2) return null;
568
+ try {
569
+ const json = atob(parts[1].replace(/-/g, "+").replace(/_/g, "/"));
570
+ const parsed = JSON.parse(json);
571
+ return parsed && typeof parsed === "object" ? parsed : null;
572
+ } catch {
573
+ return null;
574
+ }
575
+ }
548
576
  function randomBase64State() {
549
577
  return base64UrlEncode(bytesBuffer(32));
550
578
  }
@@ -573,10 +601,12 @@ function isLoginRequiredError(error) {
573
601
  SessionBridgeError,
574
602
  XSAuthDeniedError,
575
603
  createPkcePair,
604
+ idTokenIncludesMfa,
576
605
  isLoginRequiredError,
577
606
  isPrimaryAccountError,
578
607
  loginWithXS,
579
608
  openSessionBridge,
609
+ parseIdTokenAmr,
580
610
  signOutWithXS
581
611
  });
582
612
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/session-bridge.ts","../src/sign-out.ts"],"sourcesContent":["import {\r\n LoginTimeoutError,\r\n PopupBlockedError,\r\n PopupClosedError,\r\n XSAuthDeniedError,\r\n} from './errors';\r\nimport {\r\n isPrimaryAccountError,\r\n openSessionBridge as openSessionBridgeInternal,\r\n SessionBridgeError,\r\n type OpenSessionBridgeOptions,\r\n type SessionBridge,\r\n type XSBrowserAccount,\r\n} from './session-bridge';\r\n\r\nimport {\r\n signOutWithXS as signOutWithXSInternal,\r\n type SignOutAction,\r\n type SignOutWithXSOptions,\r\n type SignOutWithXSResult,\r\n} from './sign-out';\r\n\r\nexport {\r\n LoginBridgeTimeoutError,\r\n LoginTimeoutError,\r\n PopupBlockedError,\r\n PopupClosedError,\r\n XSAuthDeniedError,\r\n} from './errors';\r\n\r\nexport {\r\n isPrimaryAccountError,\r\n SessionBridgeError,\r\n type OpenSessionBridgeOptions,\r\n type SessionBridge,\r\n type XSBrowserAccount,\r\n};\r\n\r\nexport {\r\n type SignOutAction,\r\n type SignOutWithXSOptions,\r\n type SignOutWithXSResult,\r\n};\r\n\r\n/** XS Auth server — baked in at build time (local vs production). */\r\nconst XS_AUTH_BASE_URL = __XS_AUTH_BASE_URL__;\r\n\r\n/** Opens the Auth-Server session bridge popup (multi-account sign-out). */\r\nexport function openSessionBridge(\r\n opts: OpenSessionBridgeOptions,\r\n): Promise<SessionBridge> {\r\n return openSessionBridgeInternal(opts, XS_AUTH_BASE_URL);\r\n}\r\n\r\n/** Google-style sign-out popup on the Auth-Server domain. */\r\nexport function signOutWithXS(opts: SignOutWithXSOptions): Promise<SignOutWithXSResult> {\r\n const authBase = opts.authBaseUrl?.trim() || XS_AUTH_BASE_URL;\r\n return signOutWithXSInternal(opts, authBase);\r\n}\r\n\r\n/** Signed-in user profile from XS Auth. */\r\nexport interface XSAuthUser {\r\n email: string;\r\n firstName?: string;\r\n lastName?: string;\r\n}\r\n\r\nexport interface LoginWithXSOptions {\r\n /** Your app's public client id from Xino Solutions. */\r\n clientId: string;\r\n /** Must be on your XS Auth client's allowed domains list (normally `window.location.origin`). */\r\n parentOrigin?: string;\r\n timeoutMs?: number;\r\n scope?: string;\r\n /**\r\n * Request a `nonce` inside `idToken` — your backend should verify it matches when validating the JWT.\r\n */\r\n useNonce?: boolean;\r\n /**\r\n * OAuth-style prompt for multi-account SSO on the Auth-Server domain.\r\n * - `none`: silent sign-in with the primary browser session (fails with `login_required` if absent)\r\n * - `select_account`: always show the account chooser when sessions exist\r\n * - `login`: force email/password (add another account)\r\n */\r\n prompt?: 'none' | 'select_account' | 'login';\r\n /** Prefer a specific XS Auth user id (`sub`) when continuing an existing browser session. */\r\n accountId?: string;\r\n /** When true and `prompt` is unset, defaults to `none` instead of account chooser. */\r\n preferPrimary?: boolean;\r\n /** Override Auth-Server base URL (e.g. same-origin `/xs-auth` proxy in local dev). */\r\n authBaseUrl?: string;\r\n}\r\n\r\nexport interface LoginWithXSResult {\r\n user: XSAuthUser;\r\n /** Short-lived signed JWT — send to your backend to create a session. */\r\n idToken: string;\r\n}\r\n\r\nfunction bytesBuffer(len: number): Uint8Array {\r\n const out = new Uint8Array(len);\r\n crypto.getRandomValues(out);\r\n return out;\r\n}\r\n\r\nfunction base64UrlEncode(buf: Uint8Array | ArrayBuffer): string {\r\n const bytes = buf instanceof Uint8Array ? buf : new Uint8Array(buf);\r\n let binary = '';\r\n const chunkSize = 0x8000;\r\n for (let i = 0; i < bytes.length; i += chunkSize) {\r\n binary += String.fromCharCode(...bytes.subarray(i, i + chunkSize));\r\n }\r\n const b64 = btoa(binary);\r\n return b64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/u, '');\r\n}\r\n\r\nasync function pkceVerifierAndChallenge(): Promise<{\r\n verifier: string;\r\n challenge: string;\r\n}> {\r\n const verifier = base64UrlEncode(bytesBuffer(64));\r\n const data = new TextEncoder().encode(verifier);\r\n const digest = await crypto.subtle.digest('SHA-256', data);\r\n const challenge = base64UrlEncode(digest);\r\n return { verifier, challenge };\r\n}\r\n\r\n/** PKCE helpers for tests / custom callers. */\r\nexport async function createPkcePair(): Promise<{\r\n verifier: string;\r\n challenge: string;\r\n}> {\r\n return pkceVerifierAndChallenge();\r\n}\r\n\r\nconst STATE_KEY_STORAGE = '__xs_login_state';\r\n\r\nfunction parseSdkUser(raw: unknown): XSAuthUser | null {\r\n if (!raw || typeof raw !== 'object') return null;\r\n const u = raw as Record<string, unknown>;\r\n const email = typeof u.email === 'string' ? u.email.trim() : '';\r\n if (!email) return null;\r\n const user: XSAuthUser = { email };\r\n const firstName =\r\n typeof u.firstName === 'string' ? u.firstName.trim() : '';\r\n const lastName = typeof u.lastName === 'string' ? u.lastName.trim() : '';\r\n if (firstName) user.firstName = firstName;\r\n if (lastName) user.lastName = lastName;\r\n return user;\r\n}\r\n\r\nfunction resolvePrompt(opts: LoginWithXSOptions): string | undefined {\r\n if (opts.prompt) return opts.prompt;\r\n if (opts.preferPrimary) return 'none';\r\n return undefined;\r\n}\r\n\r\nfunction authPublicPathFromBase(authBaseUrl: string): string {\r\n try {\r\n const pathname = new URL(authBaseUrl).pathname.replace(/\\/$/u, '');\r\n return pathname === '/' ? '' : pathname;\r\n } catch {\r\n return '';\r\n }\r\n}\r\n\r\nfunction maybeSetPublicPath(params: URLSearchParams, authBaseUrl: string): void {\r\n const publicPath = authPublicPathFromBase(authBaseUrl);\r\n if (publicPath) params.set('public_path', publicPath);\r\n}\r\n\r\n/**\r\n * Opens the XS Auth sign-in popup and returns the signed-in user plus a verifiable `idToken`.\r\n *\r\n * All Auth-Server HTTP calls happen inside the popup (same origin). The host app only\r\n * opens the popup and exchanges postMessages with the PKCE verifier — no fetch to Auth-Server.\r\n */\r\nexport async function loginWithXS(\r\n opts: LoginWithXSOptions,\r\n): Promise<LoginWithXSResult> {\r\n const authBase = opts.authBaseUrl?.trim() || XS_AUTH_BASE_URL;\r\n const normalizedBase = normalizeBaseUrl(authBase);\r\n const authOrigin = normalizedBase.origin;\r\n const parentOrigin = (opts.parentOrigin ?? globalThis.location?.origin) as\r\n | string\r\n | undefined;\r\n if (!parentOrigin || typeof window === 'undefined') {\r\n throw new Error(\r\n 'loginWithXS requires a browser Window and explicit parentOrigin (or window.location).',\r\n );\r\n }\r\n\r\n const timeoutMs =\r\n opts.timeoutMs !== undefined ? opts.timeoutMs : 120_000;\r\n\r\n const state = randomBase64State();\r\n sessionStorage.setItem(STATE_KEY_STORAGE, state);\r\n\r\n const nonce = opts.useNonce ? randomBase64State() : undefined;\r\n const pair = await pkceVerifierAndChallenge();\r\n\r\n const params = new URLSearchParams({\r\n client_id: opts.clientId,\r\n state,\r\n code_challenge: pair.challenge,\r\n code_challenge_method: 'S256',\r\n parent_origin: parentOrigin,\r\n response_mode: 'popup',\r\n });\r\n if (opts.scope?.trim()) params.set('scope', opts.scope.trim());\r\n if (nonce) params.set('nonce', nonce);\r\n const prompt = resolvePrompt(opts);\r\n if (prompt) params.set('prompt', prompt);\r\n if (opts.accountId?.trim()) params.set('account_id', opts.accountId.trim());\r\n maybeSetPublicPath(params, authBase);\r\n\r\n const authorizeUrl = `${normalizedBase.href.replace(/\\/?$/u, '')}/authorize?${params.toString()}`;\r\n\r\n const popupWidth = prompt === 'none' ? 420 : 480;\r\n const popupHeight = prompt === 'none' ? 120 : 640;\r\n const popup = window.open(\r\n authorizeUrl,\r\n `xs-auth-${crypto.randomUUID()}`,\r\n popupWindowFeatures(popupWidth, popupHeight),\r\n );\r\n if (!popup) throw new PopupBlockedError();\r\n\r\n return await new Promise<LoginWithXSResult>((resolve, reject) => {\r\n let cleaned = false;\r\n const teardown = (): void => {\r\n if (cleaned) return;\r\n cleaned = true;\r\n window.removeEventListener('message', handleMessage as EventListener);\r\n clearInterval(closePoll);\r\n clearTimeout(timer);\r\n try {\r\n popup.close();\r\n } catch {\r\n // ignore\r\n }\r\n };\r\n\r\n const fail = (e: unknown): void => {\r\n teardown();\r\n reject(e instanceof Error ? e : new Error(String(e)));\r\n };\r\n\r\n const timer = window.setTimeout(() => {\r\n fail(new LoginTimeoutError());\r\n }, timeoutMs);\r\n\r\n const handleMessage = (event: MessageEvent): void => {\r\n if (event.origin !== authOrigin) return;\r\n const d = event.data as Partial<Record<string, unknown>>;\r\n if (d?.source !== 'xs-auth') return;\r\n\r\n const st = typeof d.state === 'string' ? d.state : '';\r\n if (!st || st !== sessionStorage.getItem(STATE_KEY_STORAGE)) return;\r\n\r\n if (typeof d.error === 'string' && d.error.length > 0) {\r\n teardown();\r\n reject(\r\n new XSAuthDeniedError(\r\n String(d.error),\r\n typeof d.error_description === 'string'\r\n ? d.error_description\r\n : '',\r\n ),\r\n );\r\n return;\r\n }\r\n\r\n if (d.type === 'need_verifier') {\r\n try {\r\n popup.postMessage(\r\n {\r\n source: 'xs-auth-opener',\r\n state: st,\r\n code_verifier: pair.verifier,\r\n client_id: opts.clientId,\r\n },\r\n authOrigin,\r\n );\r\n } catch {\r\n fail(new XSAuthDeniedError('exchange_failed', 'Sign in could not be completed.'));\r\n }\r\n return;\r\n }\r\n\r\n const idToken =\r\n typeof d.id_token === 'string'\r\n ? d.id_token\r\n : typeof d.idToken === 'string'\r\n ? d.idToken\r\n : '';\r\n const user = parseSdkUser(d.user);\r\n if (!idToken || !user) return;\r\n\r\n sessionStorage.removeItem(STATE_KEY_STORAGE);\r\n clearTimeout(timer);\r\n window.removeEventListener('message', handleMessage as EventListener);\r\n clearInterval(closePoll);\r\n cleaned = true;\r\n\r\n resolve({ user, idToken });\r\n\r\n try {\r\n popup.close();\r\n } catch {\r\n // ignore\r\n }\r\n };\r\n\r\n window.addEventListener('message', handleMessage as EventListener);\r\n\r\n const closePoll = window.setInterval(() => {\r\n if (!popup.closed) return;\r\n if (cleaned) return;\r\n const pending = sessionStorage.getItem(STATE_KEY_STORAGE);\r\n if (!pending) return;\r\n fail(new PopupClosedError());\r\n }, 280);\r\n });\r\n}\r\n\r\nfunction randomBase64State(): string {\r\n return base64UrlEncode(bytesBuffer(32));\r\n}\r\n\r\nfunction normalizeBaseUrl(s: string): URL {\r\n return new URL(s);\r\n}\r\n\r\n/** Center popup over the opener window (falls back to screen center). */\r\nfunction popupWindowFeatures(width: number, height: number): string {\r\n const win = window;\r\n const outerW = win.outerWidth > 0 ? win.outerWidth : win.innerWidth;\r\n const outerH = win.outerHeight > 0 ? win.outerHeight : win.innerHeight;\r\n const screenX = win.screenX ?? win.screenLeft ?? 0;\r\n const screenY = win.screenY ?? win.screenTop ?? 0;\r\n const left = Math.round(screenX + Math.max(0, (outerW - width) / 2));\r\n const top = Math.round(screenY + Math.max(0, (outerH - height) / 2));\r\n return `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes`;\r\n}\r\n\r\n/** True when Auth-Server has no active browser session for silent sign-in. */\r\nexport function isLoginRequiredError(error: unknown): boolean {\r\n return error instanceof XSAuthDeniedError && error.errorCode === 'login_required';\r\n}\r\n","/** Popup was blocked by the browser or environment. */\r\nexport class PopupBlockedError extends Error {\r\n readonly name = 'PopupBlockedError';\r\n}\r\n\r\n/** User closed the popup before completing login. */\r\nexport class PopupClosedError extends Error {\r\n readonly name = 'PopupClosedError';\r\n}\r\n\r\n/** XS Auth popup did not complete within timeout. */\r\nexport class LoginTimeoutError extends Error {\r\n readonly name = 'LoginTimeoutError';\r\n}\r\n\r\n/** XS Auth returned an OAuth-style error inside postMessage. */\r\nexport class XSAuthDeniedError extends Error {\r\n readonly name = 'XSAuthDeniedError';\r\n readonly errorCode: string;\r\n readonly description: string;\r\n\r\n constructor(errorCode: string, description: string) {\r\n super(description || errorCode || 'xs_auth_denied');\r\n this.errorCode = errorCode;\r\n this.description = description;\r\n }\r\n}\r\n\r\n/** Session bridge did not respond within timeout. */\r\nexport class LoginBridgeTimeoutError extends Error {\r\n readonly name = 'LoginBridgeTimeoutError';\r\n}\r\n","import {\r\n LoginBridgeTimeoutError,\r\n PopupBlockedError,\r\n PopupClosedError,\r\n} from './errors';\r\n\r\n/** XS Auth browser session account (multi-account SSO on the Auth-Server domain). */\r\nexport interface XSBrowserAccount {\r\n sessionId: string;\r\n userId: string;\r\n email: string;\r\n name: string;\r\n isPrimary: boolean;\r\n}\r\n\r\nexport interface OpenSessionBridgeOptions {\r\n clientId: string;\r\n parentOrigin?: string;\r\n timeoutMs?: number;\r\n}\r\n\r\nexport interface SessionBridge {\r\n listAccounts(): Promise<XSBrowserAccount[]>;\r\n revokeAccount(sessionId: string): Promise<{ accounts: XSBrowserAccount[]; remainingCount: number }>;\r\n revokeAll(): Promise<void>;\r\n setPrimary(sessionId: string): Promise<XSBrowserAccount[]>;\r\n close(): void;\r\n}\r\n\r\nexport class SessionBridgeError extends Error {\r\n readonly name = 'SessionBridgeError';\r\n readonly errorCode: string;\r\n\r\n constructor(errorCode: string, message: string) {\r\n super(message || errorCode);\r\n this.errorCode = errorCode;\r\n }\r\n}\r\n\r\ntype BridgeMessage = Partial<Record<string, unknown>>;\r\n\r\nconst BRIDGE_STATE_KEY = '__xs_bridge_state';\r\n\r\nfunction parseAccounts(raw: unknown): XSBrowserAccount[] {\r\n if (!Array.isArray(raw)) return [];\r\n return raw\r\n .map((item) => {\r\n if (!item || typeof item !== 'object') return null;\r\n const row = item as Record<string, unknown>;\r\n const sessionId =\r\n typeof row.sessionId === 'string'\r\n ? row.sessionId\r\n : typeof row.session_id === 'string'\r\n ? row.session_id\r\n : '';\r\n const userId =\r\n typeof row.userId === 'string'\r\n ? row.userId\r\n : typeof row.user_id === 'string'\r\n ? row.user_id\r\n : '';\r\n const email = typeof row.email === 'string' ? row.email : '';\r\n const name = typeof row.name === 'string' ? row.name : email;\r\n if (!sessionId || !email) return null;\r\n return {\r\n sessionId,\r\n userId,\r\n email,\r\n name,\r\n isPrimary: row.isPrimary === true || row.is_primary === true,\r\n };\r\n })\r\n .filter((x): x is XSBrowserAccount => x !== null);\r\n}\r\n\r\nfunction hiddenBridgePopupFeatures(): string {\r\n return 'width=1,height=1,left=-10000,top=-10000,resizable=no,scrollbars=no';\r\n}\r\n\r\nfunction randomBridgeState(): string {\r\n const bytes = new Uint8Array(32);\r\n crypto.getRandomValues(bytes);\r\n let binary = '';\r\n for (let i = 0; i < bytes.length; i++) {\r\n binary += String.fromCharCode(bytes[i]!);\r\n }\r\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/u, '');\r\n}\r\n\r\n/**\r\n * Opens a same-origin Auth-Server popup bridge so the host app can list and revoke\r\n * browser SSO sessions without cross-origin cookie access.\r\n */\r\nexport async function openSessionBridge(\r\n opts: OpenSessionBridgeOptions,\r\n authBaseUrl: string,\r\n): Promise<SessionBridge> {\r\n const parentOrigin = (opts.parentOrigin ?? globalThis.location?.origin) as string | undefined;\r\n if (!parentOrigin || typeof window === 'undefined') {\r\n throw new Error(\r\n 'openSessionBridge requires a browser Window and explicit parentOrigin (or window.location).',\r\n );\r\n }\r\n\r\n const normalizedBase = new URL(authBaseUrl);\r\n const authOrigin = normalizedBase.origin;\r\n const state = randomBridgeState();\r\n sessionStorage.setItem(BRIDGE_STATE_KEY, state);\r\n\r\n const params = new URLSearchParams({\r\n client_id: opts.clientId,\r\n parent_origin: parentOrigin,\r\n state,\r\n });\r\n\r\n const bridgeUrl = `${normalizedBase.href.replace(/\\/?$/u, '')}/session/bridge?${params.toString()}`;\r\n const popup = window.open(\r\n bridgeUrl,\r\n `xs-auth-bridge-${crypto.randomUUID()}`,\r\n hiddenBridgePopupFeatures(),\r\n );\r\n if (!popup) throw new PopupBlockedError();\r\n\r\n const timeoutMs = opts.timeoutMs !== undefined ? opts.timeoutMs : 120_000;\r\n let cleaned = false;\r\n let closePoll: ReturnType<typeof setInterval> | undefined;\r\n\r\n const teardown = (): void => {\r\n if (cleaned) return;\r\n cleaned = true;\r\n window.removeEventListener('message', handleMessage as EventListener);\r\n if (closePoll !== undefined) clearInterval(closePoll);\r\n sessionStorage.removeItem(BRIDGE_STATE_KEY);\r\n try {\r\n popup.close();\r\n } catch {\r\n // ignore\r\n }\r\n };\r\n\r\n const pending = new Map<\r\n string,\r\n {\r\n resolve: (value: BridgeMessage) => void;\r\n reject: (error: Error) => void;\r\n }\r\n >();\r\n\r\n let bridgeReady = false;\r\n let readyResolve: (() => void) | null = null;\r\n let readyReject: ((error: Error) => void) | null = null;\r\n\r\n const readyPromise = new Promise<void>((resolve, reject) => {\r\n readyResolve = resolve;\r\n readyReject = reject;\r\n });\r\n\r\n const handleMessage = (event: MessageEvent): void => {\r\n if (event.origin !== authOrigin) return;\r\n const d = event.data as BridgeMessage;\r\n if (d?.source !== 'xs-auth') return;\r\n\r\n const st = typeof d.state === 'string' ? d.state : '';\r\n if (!st || st !== sessionStorage.getItem(BRIDGE_STATE_KEY)) return;\r\n\r\n if (d.type === 'bridge_ready') {\r\n bridgeReady = true;\r\n readyResolve?.();\r\n return;\r\n }\r\n\r\n const requestId = typeof d.requestId === 'string' ? d.requestId : '';\r\n if (!requestId) return;\r\n\r\n const entry = pending.get(requestId);\r\n if (!entry) return;\r\n\r\n pending.delete(requestId);\r\n\r\n if (typeof d.error === 'string' && d.error.length > 0) {\r\n entry.reject(\r\n new SessionBridgeError(\r\n String(d.error),\r\n typeof d.error_description === 'string' ? d.error_description : '',\r\n ),\r\n );\r\n return;\r\n }\r\n\r\n if (d.type === 'result') {\r\n entry.resolve(d);\r\n }\r\n };\r\n\r\n window.addEventListener('message', handleMessage as EventListener);\r\n\r\n closePoll = window.setInterval(() => {\r\n if (!popup.closed) return;\r\n if (cleaned) return;\r\n for (const [, entry] of pending) {\r\n entry.reject(new PopupClosedError());\r\n }\r\n pending.clear();\r\n readyReject?.(new PopupClosedError());\r\n teardown();\r\n }, 280);\r\n\r\n const readyTimer = window.setTimeout(() => {\r\n if (bridgeReady) return;\r\n readyReject?.(new LoginBridgeTimeoutError());\r\n teardown();\r\n }, timeoutMs);\r\n\r\n try {\r\n await readyPromise;\r\n } catch (error) {\r\n clearTimeout(readyTimer);\r\n throw error;\r\n }\r\n clearTimeout(readyTimer);\r\n\r\n const sendRequest = (type: string, extra: Record<string, unknown> = {}): Promise<BridgeMessage> => {\r\n if (popup.closed) {\r\n return Promise.reject(new PopupClosedError());\r\n }\r\n\r\n const requestId = crypto.randomUUID();\r\n return new Promise<BridgeMessage>((resolve, reject) => {\r\n const timer = window.setTimeout(() => {\r\n pending.delete(requestId);\r\n reject(new LoginBridgeTimeoutError());\r\n }, timeoutMs);\r\n\r\n pending.set(requestId, {\r\n resolve: (value) => {\r\n clearTimeout(timer);\r\n resolve(value);\r\n },\r\n reject: (error) => {\r\n clearTimeout(timer);\r\n reject(error);\r\n },\r\n });\r\n\r\n try {\r\n popup.postMessage(\r\n {\r\n source: 'xs-auth-opener',\r\n state,\r\n client_id: opts.clientId,\r\n requestId,\r\n type,\r\n ...extra,\r\n },\r\n authOrigin,\r\n );\r\n } catch {\r\n pending.delete(requestId);\r\n clearTimeout(timer);\r\n reject(new SessionBridgeError('post_message_failed', 'Could not reach the session bridge.'));\r\n }\r\n });\r\n };\r\n\r\n return {\r\n async listAccounts() {\r\n const result = await sendRequest('list_accounts');\r\n return parseAccounts(result.accounts);\r\n },\r\n\r\n async revokeAccount(sessionId: string) {\r\n const result = await sendRequest('revoke', { session_id: sessionId.trim() });\r\n const accounts = parseAccounts(result.accounts);\r\n const remainingCount =\r\n typeof result.remainingCount === 'number' ? result.remainingCount : accounts.length;\r\n return { accounts, remainingCount };\r\n },\r\n\r\n async revokeAll() {\r\n await sendRequest('revoke_all');\r\n },\r\n\r\n async setPrimary(sessionId: string) {\r\n const result = await sendRequest('set_primary', { session_id: sessionId.trim() });\r\n return parseAccounts(result.accounts);\r\n },\r\n\r\n close() {\r\n teardown();\r\n },\r\n };\r\n}\r\n\r\n/** True when the user must pick another primary account before signing out. */\r\nexport function isPrimaryAccountError(error: unknown): boolean {\r\n return error instanceof SessionBridgeError && error.errorCode === 'primary_account';\r\n}\r\n","import {\r\n LoginBridgeTimeoutError,\r\n PopupBlockedError,\r\n PopupClosedError,\r\n} from './errors';\r\n\r\nexport interface SignOutWithXSOptions {\r\n clientId: string;\r\n parentOrigin?: string;\r\n /** XS Auth user id (`sub`) for the account active in the host app. */\r\n activeUserId?: string;\r\n timeoutMs?: number;\r\n /** Override Auth-Server base URL (e.g. same-origin `/xs-auth` proxy in local dev). */\r\n authBaseUrl?: string;\r\n}\r\n\r\nexport type SignOutAction = 'revoked_one' | 'revoked_all' | 'cancelled';\r\n\r\nexport interface SignOutWithXSResult {\r\n action: SignOutAction;\r\n revokedCurrent: boolean;\r\n remainingCount: number;\r\n}\r\n\r\nconst SIGN_OUT_STATE_KEY = '__xs_sign_out_state';\r\n\r\nfunction popupWindowFeatures(width: number, height: number): string {\r\n const win = window;\r\n const outerW = win.outerWidth > 0 ? win.outerWidth : win.innerWidth;\r\n const outerH = win.outerHeight > 0 ? win.outerHeight : win.innerHeight;\r\n const screenX = win.screenX ?? win.screenLeft ?? 0;\r\n const screenY = win.screenY ?? win.screenTop ?? 0;\r\n const left = Math.round(screenX + Math.max(0, (outerW - width) / 2));\r\n const top = Math.round(screenY + Math.max(0, (outerH - height) / 2));\r\n return `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes`;\r\n}\r\n\r\nfunction randomState(): string {\r\n const bytes = new Uint8Array(32);\r\n crypto.getRandomValues(bytes);\r\n let binary = '';\r\n for (let i = 0; i < bytes.length; i++) {\r\n binary += String.fromCharCode(bytes[i]!);\r\n }\r\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/u, '');\r\n}\r\n\r\nfunction parseSignOutResult(raw: SignOutAction, data: Record<string, unknown>): SignOutWithXSResult {\r\n return {\r\n action: raw,\r\n revokedCurrent: data.revokedCurrent === true,\r\n remainingCount:\r\n typeof data.remainingCount === 'number' && Number.isFinite(data.remainingCount)\r\n ? Math.max(0, data.remainingCount)\r\n : 0,\r\n };\r\n}\r\n\r\n/**\r\n * Opens a centered XS Auth popup to sign out of one or all browser SSO accounts\r\n * (Google-style account manager on the Auth-Server domain).\r\n */\r\nexport async function signOutWithXS(\r\n opts: SignOutWithXSOptions,\r\n authBaseUrl: string,\r\n): Promise<SignOutWithXSResult> {\r\n const parentOrigin = (opts.parentOrigin ?? globalThis.location?.origin) as string | undefined;\r\n if (!parentOrigin || typeof window === 'undefined') {\r\n throw new Error(\r\n 'signOutWithXS requires a browser Window and explicit parentOrigin (or window.location).',\r\n );\r\n }\r\n\r\n const normalizedBase = new URL(authBaseUrl);\r\n const authOrigin = normalizedBase.origin;\r\n const state = randomState();\r\n sessionStorage.setItem(SIGN_OUT_STATE_KEY, state);\r\n\r\n const params = new URLSearchParams({\r\n client_id: opts.clientId,\r\n parent_origin: parentOrigin,\r\n state,\r\n });\r\n if (opts.activeUserId?.trim()) {\r\n params.set('active_user_id', opts.activeUserId.trim());\r\n }\r\n\r\n const url = `${normalizedBase.href.replace(/\\/?$/u, '')}/session/sign-out?${params.toString()}`;\r\n const popup = window.open(\r\n url,\r\n `xs-auth-signout-${crypto.randomUUID()}`,\r\n popupWindowFeatures(480, 640),\r\n );\r\n if (!popup) throw new PopupBlockedError();\r\n\r\n const timeoutMs = opts.timeoutMs !== undefined ? opts.timeoutMs : 120_000;\r\n\r\n return await new Promise<SignOutWithXSResult>((resolve, reject) => {\r\n let cleaned = false;\r\n\r\n const teardown = (): void => {\r\n if (cleaned) return;\r\n cleaned = true;\r\n window.removeEventListener('message', handleMessage as EventListener);\r\n clearInterval(closePoll);\r\n clearTimeout(timer);\r\n sessionStorage.removeItem(SIGN_OUT_STATE_KEY);\r\n try {\r\n popup.close();\r\n } catch {\r\n // ignore\r\n }\r\n };\r\n\r\n const fail = (error: Error): void => {\r\n teardown();\r\n reject(error);\r\n };\r\n\r\n const timer = window.setTimeout(() => {\r\n fail(new LoginBridgeTimeoutError());\r\n }, timeoutMs);\r\n\r\n const handleMessage = (event: MessageEvent): void => {\r\n if (event.origin !== authOrigin) return;\r\n const d = event.data as Partial<Record<string, unknown>>;\r\n if (d?.source !== 'xs-auth') return;\r\n\r\n const st = typeof d.state === 'string' ? d.state : '';\r\n if (!st || st !== sessionStorage.getItem(SIGN_OUT_STATE_KEY)) return;\r\n\r\n if (d.type === 'sign_out_cancelled') {\r\n teardown();\r\n resolve(parseSignOutResult('cancelled', d));\r\n return;\r\n }\r\n\r\n if (d.type === 'sign_out_complete') {\r\n teardown();\r\n const actionRaw = typeof d.action === 'string' ? d.action : 'revoked_one';\r\n const action: SignOutAction =\r\n actionRaw === 'revoked_all'\r\n ? 'revoked_all'\r\n : actionRaw === 'cancelled'\r\n ? 'cancelled'\r\n : 'revoked_one';\r\n resolve(parseSignOutResult(action, d));\r\n }\r\n };\r\n\r\n window.addEventListener('message', handleMessage as EventListener);\r\n\r\n const closePoll = window.setInterval(() => {\r\n if (!popup.closed) return;\r\n if (cleaned) return;\r\n if (!sessionStorage.getItem(SIGN_OUT_STATE_KEY)) return;\r\n fail(new PopupClosedError());\r\n }, 280);\r\n });\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,2BAAAA;AAAA,EAAA,qBAAAC;AAAA;AAAA;;;ACCO,IAAM,oBAAN,cAAgC,MAAM;AAAA,EAClC,OAAO;AAClB;AAGO,IAAM,mBAAN,cAA+B,MAAM;AAAA,EACjC,OAAO;AAClB;AAGO,IAAM,oBAAN,cAAgC,MAAM;AAAA,EAClC,OAAO;AAClB;AAGO,IAAM,oBAAN,cAAgC,MAAM;AAAA,EAClC,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EAET,YAAY,WAAmB,aAAqB;AAClD,UAAM,eAAe,aAAa,gBAAgB;AAClD,SAAK,YAAY;AACjB,SAAK,cAAc;AAAA,EACrB;AACF;AAGO,IAAM,0BAAN,cAAsC,MAAM;AAAA,EACxC,OAAO;AAClB;;;ACFO,IAAM,qBAAN,cAAiC,MAAM;AAAA,EACnC,OAAO;AAAA,EACP;AAAA,EAET,YAAY,WAAmB,SAAiB;AAC9C,UAAM,WAAW,SAAS;AAC1B,SAAK,YAAY;AAAA,EACnB;AACF;AAIA,IAAM,mBAAmB;AAEzB,SAAS,cAAc,KAAkC;AACvD,MAAI,CAAC,MAAM,QAAQ,GAAG,EAAG,QAAO,CAAC;AACjC,SAAO,IACJ,IAAI,CAAC,SAAS;AACb,QAAI,CAAC,QAAQ,OAAO,SAAS,SAAU,QAAO;AAC9C,UAAM,MAAM;AACZ,UAAM,YACJ,OAAO,IAAI,cAAc,WACrB,IAAI,YACJ,OAAO,IAAI,eAAe,WACxB,IAAI,aACJ;AACR,UAAM,SACJ,OAAO,IAAI,WAAW,WAClB,IAAI,SACJ,OAAO,IAAI,YAAY,WACrB,IAAI,UACJ;AACR,UAAM,QAAQ,OAAO,IAAI,UAAU,WAAW,IAAI,QAAQ;AAC1D,UAAM,OAAO,OAAO,IAAI,SAAS,WAAW,IAAI,OAAO;AACvD,QAAI,CAAC,aAAa,CAAC,MAAO,QAAO;AACjC,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW,IAAI,cAAc,QAAQ,IAAI,eAAe;AAAA,IAC1D;AAAA,EACF,CAAC,EACA,OAAO,CAAC,MAA6B,MAAM,IAAI;AACpD;AAEA,SAAS,4BAAoC;AAC3C,SAAO;AACT;AAEA,SAAS,oBAA4B;AACnC,QAAM,QAAQ,IAAI,WAAW,EAAE;AAC/B,SAAO,gBAAgB,KAAK;AAC5B,MAAI,SAAS;AACb,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,cAAU,OAAO,aAAa,MAAM,CAAC,CAAE;AAAA,EACzC;AACA,SAAO,KAAK,MAAM,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,QAAQ,EAAE;AAChF;AAMA,eAAsB,kBACpB,MACA,aACwB;AACxB,QAAM,eAAgB,KAAK,gBAAgB,WAAW,UAAU;AAChE,MAAI,CAAC,gBAAgB,OAAO,WAAW,aAAa;AAClD,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,iBAAiB,IAAI,IAAI,WAAW;AAC1C,QAAM,aAAa,eAAe;AAClC,QAAM,QAAQ,kBAAkB;AAChC,iBAAe,QAAQ,kBAAkB,KAAK;AAE9C,QAAM,SAAS,IAAI,gBAAgB;AAAA,IACjC,WAAW,KAAK;AAAA,IAChB,eAAe;AAAA,IACf;AAAA,EACF,CAAC;AAED,QAAM,YAAY,GAAG,eAAe,KAAK,QAAQ,SAAS,EAAE,CAAC,mBAAmB,OAAO,SAAS,CAAC;AACjG,QAAM,QAAQ,OAAO;AAAA,IACnB;AAAA,IACA,kBAAkB,OAAO,WAAW,CAAC;AAAA,IACrC,0BAA0B;AAAA,EAC5B;AACA,MAAI,CAAC,MAAO,OAAM,IAAI,kBAAkB;AAExC,QAAM,YAAY,KAAK,cAAc,SAAY,KAAK,YAAY;AAClE,MAAI,UAAU;AACd,MAAI;AAEJ,QAAM,WAAW,MAAY;AAC3B,QAAI,QAAS;AACb,cAAU;AACV,WAAO,oBAAoB,WAAW,aAA8B;AACpE,QAAI,cAAc,OAAW,eAAc,SAAS;AACpD,mBAAe,WAAW,gBAAgB;AAC1C,QAAI;AACF,YAAM,MAAM;AAAA,IACd,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,QAAM,UAAU,oBAAI,IAMlB;AAEF,MAAI,cAAc;AAClB,MAAI,eAAoC;AACxC,MAAI,cAA+C;AAEnD,QAAM,eAAe,IAAI,QAAc,CAAC,SAAS,WAAW;AAC1D,mBAAe;AACf,kBAAc;AAAA,EAChB,CAAC;AAED,QAAM,gBAAgB,CAAC,UAA8B;AACnD,QAAI,MAAM,WAAW,WAAY;AACjC,UAAM,IAAI,MAAM;AAChB,QAAI,GAAG,WAAW,UAAW;AAE7B,UAAM,KAAK,OAAO,EAAE,UAAU,WAAW,EAAE,QAAQ;AACnD,QAAI,CAAC,MAAM,OAAO,eAAe,QAAQ,gBAAgB,EAAG;AAE5D,QAAI,EAAE,SAAS,gBAAgB;AAC7B,oBAAc;AACd,qBAAe;AACf;AAAA,IACF;AAEA,UAAM,YAAY,OAAO,EAAE,cAAc,WAAW,EAAE,YAAY;AAClE,QAAI,CAAC,UAAW;AAEhB,UAAM,QAAQ,QAAQ,IAAI,SAAS;AACnC,QAAI,CAAC,MAAO;AAEZ,YAAQ,OAAO,SAAS;AAExB,QAAI,OAAO,EAAE,UAAU,YAAY,EAAE,MAAM,SAAS,GAAG;AACrD,YAAM;AAAA,QACJ,IAAI;AAAA,UACF,OAAO,EAAE,KAAK;AAAA,UACd,OAAO,EAAE,sBAAsB,WAAW,EAAE,oBAAoB;AAAA,QAClE;AAAA,MACF;AACA;AAAA,IACF;AAEA,QAAI,EAAE,SAAS,UAAU;AACvB,YAAM,QAAQ,CAAC;AAAA,IACjB;AAAA,EACF;AAEA,SAAO,iBAAiB,WAAW,aAA8B;AAEjE,cAAY,OAAO,YAAY,MAAM;AACnC,QAAI,CAAC,MAAM,OAAQ;AACnB,QAAI,QAAS;AACb,eAAW,CAAC,EAAE,KAAK,KAAK,SAAS;AAC/B,YAAM,OAAO,IAAI,iBAAiB,CAAC;AAAA,IACrC;AACA,YAAQ,MAAM;AACd,kBAAc,IAAI,iBAAiB,CAAC;AACpC,aAAS;AAAA,EACX,GAAG,GAAG;AAEN,QAAM,aAAa,OAAO,WAAW,MAAM;AACzC,QAAI,YAAa;AACjB,kBAAc,IAAI,wBAAwB,CAAC;AAC3C,aAAS;AAAA,EACX,GAAG,SAAS;AAEZ,MAAI;AACF,UAAM;AAAA,EACR,SAAS,OAAO;AACd,iBAAa,UAAU;AACvB,UAAM;AAAA,EACR;AACA,eAAa,UAAU;AAEvB,QAAM,cAAc,CAAC,MAAc,QAAiC,CAAC,MAA8B;AACjG,QAAI,MAAM,QAAQ;AAChB,aAAO,QAAQ,OAAO,IAAI,iBAAiB,CAAC;AAAA,IAC9C;AAEA,UAAM,YAAY,OAAO,WAAW;AACpC,WAAO,IAAI,QAAuB,CAAC,SAAS,WAAW;AACrD,YAAM,QAAQ,OAAO,WAAW,MAAM;AACpC,gBAAQ,OAAO,SAAS;AACxB,eAAO,IAAI,wBAAwB,CAAC;AAAA,MACtC,GAAG,SAAS;AAEZ,cAAQ,IAAI,WAAW;AAAA,QACrB,SAAS,CAAC,UAAU;AAClB,uBAAa,KAAK;AAClB,kBAAQ,KAAK;AAAA,QACf;AAAA,QACA,QAAQ,CAAC,UAAU;AACjB,uBAAa,KAAK;AAClB,iBAAO,KAAK;AAAA,QACd;AAAA,MACF,CAAC;AAED,UAAI;AACF,cAAM;AAAA,UACJ;AAAA,YACE,QAAQ;AAAA,YACR;AAAA,YACA,WAAW,KAAK;AAAA,YAChB;AAAA,YACA;AAAA,YACA,GAAG;AAAA,UACL;AAAA,UACA;AAAA,QACF;AAAA,MACF,QAAQ;AACN,gBAAQ,OAAO,SAAS;AACxB,qBAAa,KAAK;AAClB,eAAO,IAAI,mBAAmB,uBAAuB,qCAAqC,CAAC;AAAA,MAC7F;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL,MAAM,eAAe;AACnB,YAAM,SAAS,MAAM,YAAY,eAAe;AAChD,aAAO,cAAc,OAAO,QAAQ;AAAA,IACtC;AAAA,IAEA,MAAM,cAAc,WAAmB;AACrC,YAAM,SAAS,MAAM,YAAY,UAAU,EAAE,YAAY,UAAU,KAAK,EAAE,CAAC;AAC3E,YAAM,WAAW,cAAc,OAAO,QAAQ;AAC9C,YAAM,iBACJ,OAAO,OAAO,mBAAmB,WAAW,OAAO,iBAAiB,SAAS;AAC/E,aAAO,EAAE,UAAU,eAAe;AAAA,IACpC;AAAA,IAEA,MAAM,YAAY;AAChB,YAAM,YAAY,YAAY;AAAA,IAChC;AAAA,IAEA,MAAM,WAAW,WAAmB;AAClC,YAAM,SAAS,MAAM,YAAY,eAAe,EAAE,YAAY,UAAU,KAAK,EAAE,CAAC;AAChF,aAAO,cAAc,OAAO,QAAQ;AAAA,IACtC;AAAA,IAEA,QAAQ;AACN,eAAS;AAAA,IACX;AAAA,EACF;AACF;AAGO,SAAS,sBAAsB,OAAyB;AAC7D,SAAO,iBAAiB,sBAAsB,MAAM,cAAc;AACpE;;;AChRA,IAAM,qBAAqB;AAE3B,SAAS,oBAAoB,OAAe,QAAwB;AAClE,QAAM,MAAM;AACZ,QAAM,SAAS,IAAI,aAAa,IAAI,IAAI,aAAa,IAAI;AACzD,QAAM,SAAS,IAAI,cAAc,IAAI,IAAI,cAAc,IAAI;AAC3D,QAAM,UAAU,IAAI,WAAW,IAAI,cAAc;AACjD,QAAM,UAAU,IAAI,WAAW,IAAI,aAAa;AAChD,QAAM,OAAO,KAAK,MAAM,UAAU,KAAK,IAAI,IAAI,SAAS,SAAS,CAAC,CAAC;AACnE,QAAM,MAAM,KAAK,MAAM,UAAU,KAAK,IAAI,IAAI,SAAS,UAAU,CAAC,CAAC;AACnE,SAAO,SAAS,KAAK,WAAW,MAAM,SAAS,IAAI,QAAQ,GAAG;AAChE;AAEA,SAAS,cAAsB;AAC7B,QAAM,QAAQ,IAAI,WAAW,EAAE;AAC/B,SAAO,gBAAgB,KAAK;AAC5B,MAAI,SAAS;AACb,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,cAAU,OAAO,aAAa,MAAM,CAAC,CAAE;AAAA,EACzC;AACA,SAAO,KAAK,MAAM,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,QAAQ,EAAE;AAChF;AAEA,SAAS,mBAAmB,KAAoB,MAAoD;AAClG,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,gBAAgB,KAAK,mBAAmB;AAAA,IACxC,gBACE,OAAO,KAAK,mBAAmB,YAAY,OAAO,SAAS,KAAK,cAAc,IAC1E,KAAK,IAAI,GAAG,KAAK,cAAc,IAC/B;AAAA,EACR;AACF;AAMA,eAAsB,cACpB,MACA,aAC8B;AAC9B,QAAM,eAAgB,KAAK,gBAAgB,WAAW,UAAU;AAChE,MAAI,CAAC,gBAAgB,OAAO,WAAW,aAAa;AAClD,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,iBAAiB,IAAI,IAAI,WAAW;AAC1C,QAAM,aAAa,eAAe;AAClC,QAAM,QAAQ,YAAY;AAC1B,iBAAe,QAAQ,oBAAoB,KAAK;AAEhD,QAAM,SAAS,IAAI,gBAAgB;AAAA,IACjC,WAAW,KAAK;AAAA,IAChB,eAAe;AAAA,IACf;AAAA,EACF,CAAC;AACD,MAAI,KAAK,cAAc,KAAK,GAAG;AAC7B,WAAO,IAAI,kBAAkB,KAAK,aAAa,KAAK,CAAC;AAAA,EACvD;AAEA,QAAM,MAAM,GAAG,eAAe,KAAK,QAAQ,SAAS,EAAE,CAAC,qBAAqB,OAAO,SAAS,CAAC;AAC7F,QAAM,QAAQ,OAAO;AAAA,IACnB;AAAA,IACA,mBAAmB,OAAO,WAAW,CAAC;AAAA,IACtC,oBAAoB,KAAK,GAAG;AAAA,EAC9B;AACA,MAAI,CAAC,MAAO,OAAM,IAAI,kBAAkB;AAExC,QAAM,YAAY,KAAK,cAAc,SAAY,KAAK,YAAY;AAElE,SAAO,MAAM,IAAI,QAA6B,CAAC,SAAS,WAAW;AACjE,QAAI,UAAU;AAEd,UAAM,WAAW,MAAY;AAC3B,UAAI,QAAS;AACb,gBAAU;AACV,aAAO,oBAAoB,WAAW,aAA8B;AACpE,oBAAc,SAAS;AACvB,mBAAa,KAAK;AAClB,qBAAe,WAAW,kBAAkB;AAC5C,UAAI;AACF,cAAM,MAAM;AAAA,MACd,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,UAAM,OAAO,CAAC,UAAuB;AACnC,eAAS;AACT,aAAO,KAAK;AAAA,IACd;AAEA,UAAM,QAAQ,OAAO,WAAW,MAAM;AACpC,WAAK,IAAI,wBAAwB,CAAC;AAAA,IACpC,GAAG,SAAS;AAEZ,UAAM,gBAAgB,CAAC,UAA8B;AACnD,UAAI,MAAM,WAAW,WAAY;AACjC,YAAM,IAAI,MAAM;AAChB,UAAI,GAAG,WAAW,UAAW;AAE7B,YAAM,KAAK,OAAO,EAAE,UAAU,WAAW,EAAE,QAAQ;AACnD,UAAI,CAAC,MAAM,OAAO,eAAe,QAAQ,kBAAkB,EAAG;AAE9D,UAAI,EAAE,SAAS,sBAAsB;AACnC,iBAAS;AACT,gBAAQ,mBAAmB,aAAa,CAAC,CAAC;AAC1C;AAAA,MACF;AAEA,UAAI,EAAE,SAAS,qBAAqB;AAClC,iBAAS;AACT,cAAM,YAAY,OAAO,EAAE,WAAW,WAAW,EAAE,SAAS;AAC5D,cAAM,SACJ,cAAc,gBACV,gBACA,cAAc,cACZ,cACA;AACR,gBAAQ,mBAAmB,QAAQ,CAAC,CAAC;AAAA,MACvC;AAAA,IACF;AAEA,WAAO,iBAAiB,WAAW,aAA8B;AAEjE,UAAM,YAAY,OAAO,YAAY,MAAM;AACzC,UAAI,CAAC,MAAM,OAAQ;AACnB,UAAI,QAAS;AACb,UAAI,CAAC,eAAe,QAAQ,kBAAkB,EAAG;AACjD,WAAK,IAAI,iBAAiB,CAAC;AAAA,IAC7B,GAAG,GAAG;AAAA,EACR,CAAC;AACH;;;AHlHA,IAAM,mBAAmB;AAGlB,SAASC,mBACd,MACwB;AACxB,SAAO,kBAA0B,MAAM,gBAAgB;AACzD;AAGO,SAASC,eAAc,MAA0D;AACtF,QAAM,WAAW,KAAK,aAAa,KAAK,KAAK;AAC7C,SAAO,cAAsB,MAAM,QAAQ;AAC7C;AAyCA,SAAS,YAAY,KAAyB;AAC5C,QAAM,MAAM,IAAI,WAAW,GAAG;AAC9B,SAAO,gBAAgB,GAAG;AAC1B,SAAO;AACT;AAEA,SAAS,gBAAgB,KAAuC;AAC9D,QAAM,QAAQ,eAAe,aAAa,MAAM,IAAI,WAAW,GAAG;AAClE,MAAI,SAAS;AACb,QAAM,YAAY;AAClB,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,WAAW;AAChD,cAAU,OAAO,aAAa,GAAG,MAAM,SAAS,GAAG,IAAI,SAAS,CAAC;AAAA,EACnE;AACA,QAAM,MAAM,KAAK,MAAM;AACvB,SAAO,IAAI,QAAQ,OAAO,GAAG,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,QAAQ,EAAE;AACvE;AAEA,eAAe,2BAGZ;AACD,QAAM,WAAW,gBAAgB,YAAY,EAAE,CAAC;AAChD,QAAM,OAAO,IAAI,YAAY,EAAE,OAAO,QAAQ;AAC9C,QAAM,SAAS,MAAM,OAAO,OAAO,OAAO,WAAW,IAAI;AACzD,QAAM,YAAY,gBAAgB,MAAM;AACxC,SAAO,EAAE,UAAU,UAAU;AAC/B;AAGA,eAAsB,iBAGnB;AACD,SAAO,yBAAyB;AAClC;AAEA,IAAM,oBAAoB;AAE1B,SAAS,aAAa,KAAiC;AACrD,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO;AAC5C,QAAM,IAAI;AACV,QAAM,QAAQ,OAAO,EAAE,UAAU,WAAW,EAAE,MAAM,KAAK,IAAI;AAC7D,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,OAAmB,EAAE,MAAM;AACjC,QAAM,YACJ,OAAO,EAAE,cAAc,WAAW,EAAE,UAAU,KAAK,IAAI;AACzD,QAAM,WAAW,OAAO,EAAE,aAAa,WAAW,EAAE,SAAS,KAAK,IAAI;AACtE,MAAI,UAAW,MAAK,YAAY;AAChC,MAAI,SAAU,MAAK,WAAW;AAC9B,SAAO;AACT;AAEA,SAAS,cAAc,MAA8C;AACnE,MAAI,KAAK,OAAQ,QAAO,KAAK;AAC7B,MAAI,KAAK,cAAe,QAAO;AAC/B,SAAO;AACT;AAEA,SAAS,uBAAuB,aAA6B;AAC3D,MAAI;AACF,UAAM,WAAW,IAAI,IAAI,WAAW,EAAE,SAAS,QAAQ,QAAQ,EAAE;AACjE,WAAO,aAAa,MAAM,KAAK;AAAA,EACjC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,mBAAmB,QAAyB,aAA2B;AAC9E,QAAM,aAAa,uBAAuB,WAAW;AACrD,MAAI,WAAY,QAAO,IAAI,eAAe,UAAU;AACtD;AAQA,eAAsB,YACpB,MAC4B;AAC5B,QAAM,WAAW,KAAK,aAAa,KAAK,KAAK;AAC7C,QAAM,iBAAiB,iBAAiB,QAAQ;AAChD,QAAM,aAAa,eAAe;AAClC,QAAM,eAAgB,KAAK,gBAAgB,WAAW,UAAU;AAGhE,MAAI,CAAC,gBAAgB,OAAO,WAAW,aAAa;AAClD,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,YACJ,KAAK,cAAc,SAAY,KAAK,YAAY;AAElD,QAAM,QAAQ,kBAAkB;AAChC,iBAAe,QAAQ,mBAAmB,KAAK;AAE/C,QAAM,QAAQ,KAAK,WAAW,kBAAkB,IAAI;AACpD,QAAM,OAAO,MAAM,yBAAyB;AAE5C,QAAM,SAAS,IAAI,gBAAgB;AAAA,IACjC,WAAW,KAAK;AAAA,IAChB;AAAA,IACA,gBAAgB,KAAK;AAAA,IACrB,uBAAuB;AAAA,IACvB,eAAe;AAAA,IACf,eAAe;AAAA,EACjB,CAAC;AACD,MAAI,KAAK,OAAO,KAAK,EAAG,QAAO,IAAI,SAAS,KAAK,MAAM,KAAK,CAAC;AAC7D,MAAI,MAAO,QAAO,IAAI,SAAS,KAAK;AACpC,QAAM,SAAS,cAAc,IAAI;AACjC,MAAI,OAAQ,QAAO,IAAI,UAAU,MAAM;AACvC,MAAI,KAAK,WAAW,KAAK,EAAG,QAAO,IAAI,cAAc,KAAK,UAAU,KAAK,CAAC;AAC1E,qBAAmB,QAAQ,QAAQ;AAEnC,QAAM,eAAe,GAAG,eAAe,KAAK,QAAQ,SAAS,EAAE,CAAC,cAAc,OAAO,SAAS,CAAC;AAE/F,QAAM,aAAa,WAAW,SAAS,MAAM;AAC7C,QAAM,cAAc,WAAW,SAAS,MAAM;AAC9C,QAAM,QAAQ,OAAO;AAAA,IACnB;AAAA,IACA,WAAW,OAAO,WAAW,CAAC;AAAA,IAC9BC,qBAAoB,YAAY,WAAW;AAAA,EAC7C;AACA,MAAI,CAAC,MAAO,OAAM,IAAI,kBAAkB;AAExC,SAAO,MAAM,IAAI,QAA2B,CAAC,SAAS,WAAW;AAC/D,QAAI,UAAU;AACd,UAAM,WAAW,MAAY;AAC3B,UAAI,QAAS;AACb,gBAAU;AACV,aAAO,oBAAoB,WAAW,aAA8B;AACpE,oBAAc,SAAS;AACvB,mBAAa,KAAK;AAClB,UAAI;AACF,cAAM,MAAM;AAAA,MACd,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,UAAM,OAAO,CAAC,MAAqB;AACjC,eAAS;AACT,aAAO,aAAa,QAAQ,IAAI,IAAI,MAAM,OAAO,CAAC,CAAC,CAAC;AAAA,IACtD;AAEA,UAAM,QAAQ,OAAO,WAAW,MAAM;AACpC,WAAK,IAAI,kBAAkB,CAAC;AAAA,IAC9B,GAAG,SAAS;AAEZ,UAAM,gBAAgB,CAAC,UAA8B;AACnD,UAAI,MAAM,WAAW,WAAY;AACjC,YAAM,IAAI,MAAM;AAChB,UAAI,GAAG,WAAW,UAAW;AAE7B,YAAM,KAAK,OAAO,EAAE,UAAU,WAAW,EAAE,QAAQ;AACnD,UAAI,CAAC,MAAM,OAAO,eAAe,QAAQ,iBAAiB,EAAG;AAE7D,UAAI,OAAO,EAAE,UAAU,YAAY,EAAE,MAAM,SAAS,GAAG;AACrD,iBAAS;AACT;AAAA,UACE,IAAI;AAAA,YACF,OAAO,EAAE,KAAK;AAAA,YACd,OAAO,EAAE,sBAAsB,WAC3B,EAAE,oBACF;AAAA,UACN;AAAA,QACF;AACA;AAAA,MACF;AAEA,UAAI,EAAE,SAAS,iBAAiB;AAC9B,YAAI;AACF,gBAAM;AAAA,YACJ;AAAA,cACE,QAAQ;AAAA,cACR,OAAO;AAAA,cACP,eAAe,KAAK;AAAA,cACpB,WAAW,KAAK;AAAA,YAClB;AAAA,YACA;AAAA,UACF;AAAA,QACF,QAAQ;AACN,eAAK,IAAI,kBAAkB,mBAAmB,iCAAiC,CAAC;AAAA,QAClF;AACA;AAAA,MACF;AAEA,YAAM,UACJ,OAAO,EAAE,aAAa,WAClB,EAAE,WACF,OAAO,EAAE,YAAY,WACnB,EAAE,UACF;AACR,YAAM,OAAO,aAAa,EAAE,IAAI;AAChC,UAAI,CAAC,WAAW,CAAC,KAAM;AAEvB,qBAAe,WAAW,iBAAiB;AAC3C,mBAAa,KAAK;AAClB,aAAO,oBAAoB,WAAW,aAA8B;AACpE,oBAAc,SAAS;AACvB,gBAAU;AAEV,cAAQ,EAAE,MAAM,QAAQ,CAAC;AAEzB,UAAI;AACF,cAAM,MAAM;AAAA,MACd,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,WAAO,iBAAiB,WAAW,aAA8B;AAEjE,UAAM,YAAY,OAAO,YAAY,MAAM;AACzC,UAAI,CAAC,MAAM,OAAQ;AACnB,UAAI,QAAS;AACb,YAAM,UAAU,eAAe,QAAQ,iBAAiB;AACxD,UAAI,CAAC,QAAS;AACd,WAAK,IAAI,iBAAiB,CAAC;AAAA,IAC7B,GAAG,GAAG;AAAA,EACR,CAAC;AACH;AAEA,SAAS,oBAA4B;AACnC,SAAO,gBAAgB,YAAY,EAAE,CAAC;AACxC;AAEA,SAAS,iBAAiB,GAAgB;AACxC,SAAO,IAAI,IAAI,CAAC;AAClB;AAGA,SAASA,qBAAoB,OAAe,QAAwB;AAClE,QAAM,MAAM;AACZ,QAAM,SAAS,IAAI,aAAa,IAAI,IAAI,aAAa,IAAI;AACzD,QAAM,SAAS,IAAI,cAAc,IAAI,IAAI,cAAc,IAAI;AAC3D,QAAM,UAAU,IAAI,WAAW,IAAI,cAAc;AACjD,QAAM,UAAU,IAAI,WAAW,IAAI,aAAa;AAChD,QAAM,OAAO,KAAK,MAAM,UAAU,KAAK,IAAI,IAAI,SAAS,SAAS,CAAC,CAAC;AACnE,QAAM,MAAM,KAAK,MAAM,UAAU,KAAK,IAAI,IAAI,SAAS,UAAU,CAAC,CAAC;AACnE,SAAO,SAAS,KAAK,WAAW,MAAM,SAAS,IAAI,QAAQ,GAAG;AAChE;AAGO,SAAS,qBAAqB,OAAyB;AAC5D,SAAO,iBAAiB,qBAAqB,MAAM,cAAc;AACnE;","names":["openSessionBridge","signOutWithXS","openSessionBridge","signOutWithXS","popupWindowFeatures"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/session-bridge.ts","../src/sign-out.ts"],"sourcesContent":["import {\r\n LoginTimeoutError,\r\n PopupBlockedError,\r\n PopupClosedError,\r\n XSAuthDeniedError,\r\n} from './errors';\r\nimport {\r\n isPrimaryAccountError,\r\n openSessionBridge as openSessionBridgeInternal,\r\n SessionBridgeError,\r\n type OpenSessionBridgeOptions,\r\n type SessionBridge,\r\n type XSBrowserAccount,\r\n} from './session-bridge';\r\n\r\nimport {\r\n signOutWithXS as signOutWithXSInternal,\r\n type SignOutAction,\r\n type SignOutWithXSOptions,\r\n type SignOutWithXSResult,\r\n} from './sign-out';\r\n\r\nexport {\r\n LoginBridgeTimeoutError,\r\n LoginTimeoutError,\r\n PopupBlockedError,\r\n PopupClosedError,\r\n XSAuthDeniedError,\r\n} from './errors';\r\n\r\nexport {\r\n isPrimaryAccountError,\r\n SessionBridgeError,\r\n type OpenSessionBridgeOptions,\r\n type SessionBridge,\r\n type XSBrowserAccount,\r\n};\r\n\r\nexport {\r\n type SignOutAction,\r\n type SignOutWithXSOptions,\r\n type SignOutWithXSResult,\r\n};\r\n\r\n/** XS Auth server — baked in at build time (local vs production). */\r\nconst XS_AUTH_BASE_URL = __XS_AUTH_BASE_URL__;\r\n\r\n/** Opens the Auth-Server session bridge popup (multi-account sign-out). */\r\nexport function openSessionBridge(\r\n opts: OpenSessionBridgeOptions,\r\n): Promise<SessionBridge> {\r\n return openSessionBridgeInternal(opts, XS_AUTH_BASE_URL);\r\n}\r\n\r\n/** Google-style sign-out popup on the Auth-Server domain. */\r\nexport function signOutWithXS(opts: SignOutWithXSOptions): Promise<SignOutWithXSResult> {\r\n const authBase = opts.authBaseUrl?.trim() || XS_AUTH_BASE_URL;\r\n return signOutWithXSInternal(opts, authBase);\r\n}\r\n\r\n/** Signed-in user profile from XS Auth. */\r\nexport interface XSAuthUser {\r\n email: string;\r\n firstName?: string;\r\n lastName?: string;\r\n}\r\n\r\nexport interface LoginWithXSOptions {\r\n /** Your app's public client id from Xino Solutions. */\r\n clientId: string;\r\n /** Must be on your XS Auth client's allowed domains list (normally `window.location.origin`). */\r\n parentOrigin?: string;\r\n /**\r\n * Sign-in timeout in ms. Defaults to 180s to allow MFA verification in the Auth-Server popup.\r\n */\r\n timeoutMs?: number;\r\n scope?: string;\r\n /**\r\n * Request a `nonce` inside `idToken` — your backend should verify it matches when validating the JWT.\r\n */\r\n useNonce?: boolean;\r\n /**\r\n * OAuth-style prompt for multi-account SSO on the Auth-Server domain.\r\n * - `none`: silent sign-in with the primary browser session (fails with `login_required` if absent)\r\n * - `select_account`: always show the account chooser when sessions exist\r\n * - `login`: force email/password (add another account)\r\n */\r\n prompt?: 'none' | 'select_account' | 'login';\r\n /** Prefer a specific XS Auth user id (`sub`) when continuing an existing browser session. */\r\n accountId?: string;\r\n /** When true and `prompt` is unset, defaults to `none` instead of account chooser. */\r\n preferPrimary?: boolean;\r\n /** Override Auth-Server base URL (e.g. same-origin `/xs-auth` proxy in local dev). */\r\n authBaseUrl?: string;\r\n /**\r\n * Initial Auth-Server login page view.\r\n * - `signin`: email/password sign-in (default)\r\n * - `signup`: registration form (\"Create one\")\r\n */\r\n mode?: 'signin' | 'signup';\r\n}\r\n\r\nexport interface LoginWithXSResult {\r\n user: XSAuthUser;\r\n /** Short-lived signed JWT — send to your backend to create a session. */\r\n idToken: string;\r\n /** True when the user completed MFA during this sign-in (`amr` includes `mfa`). */\r\n mfaVerified: boolean;\r\n}\r\n\r\nfunction bytesBuffer(len: number): Uint8Array {\r\n const out = new Uint8Array(len);\r\n crypto.getRandomValues(out);\r\n return out;\r\n}\r\n\r\nfunction base64UrlEncode(buf: Uint8Array | ArrayBuffer): string {\r\n const bytes = buf instanceof Uint8Array ? buf : new Uint8Array(buf);\r\n let binary = '';\r\n const chunkSize = 0x8000;\r\n for (let i = 0; i < bytes.length; i += chunkSize) {\r\n binary += String.fromCharCode(...bytes.subarray(i, i + chunkSize));\r\n }\r\n const b64 = btoa(binary);\r\n return b64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/u, '');\r\n}\r\n\r\nasync function pkceVerifierAndChallenge(): Promise<{\r\n verifier: string;\r\n challenge: string;\r\n}> {\r\n const verifier = base64UrlEncode(bytesBuffer(64));\r\n const data = new TextEncoder().encode(verifier);\r\n const digest = await crypto.subtle.digest('SHA-256', data);\r\n const challenge = base64UrlEncode(digest);\r\n return { verifier, challenge };\r\n}\r\n\r\n/** PKCE helpers for tests / custom callers. */\r\nexport async function createPkcePair(): Promise<{\r\n verifier: string;\r\n challenge: string;\r\n}> {\r\n return pkceVerifierAndChallenge();\r\n}\r\n\r\nconst STATE_KEY_STORAGE = '__xs_login_state';\r\n\r\nfunction parseSdkUser(raw: unknown): XSAuthUser | null {\r\n if (!raw || typeof raw !== 'object') return null;\r\n const u = raw as Record<string, unknown>;\r\n const email = typeof u.email === 'string' ? u.email.trim() : '';\r\n if (!email) return null;\r\n const user: XSAuthUser = { email };\r\n const firstName =\r\n typeof u.firstName === 'string' ? u.firstName.trim() : '';\r\n const lastName = typeof u.lastName === 'string' ? u.lastName.trim() : '';\r\n if (firstName) user.firstName = firstName;\r\n if (lastName) user.lastName = lastName;\r\n return user;\r\n}\r\n\r\nfunction resolvePrompt(opts: LoginWithXSOptions): string | undefined {\r\n if (opts.prompt) return opts.prompt;\r\n if (opts.preferPrimary) return 'none';\r\n return undefined;\r\n}\r\n\r\nfunction authPublicPathFromBase(authBaseUrl: string): string {\r\n try {\r\n const pathname = new URL(authBaseUrl).pathname.replace(/\\/$/u, '');\r\n return pathname === '/' ? '' : pathname;\r\n } catch {\r\n return '';\r\n }\r\n}\r\n\r\nfunction maybeSetPublicPath(params: URLSearchParams, authBaseUrl: string): void {\r\n const publicPath = authPublicPathFromBase(authBaseUrl);\r\n if (publicPath) params.set('public_path', publicPath);\r\n}\r\n\r\n/**\r\n * Opens the XS Auth sign-in popup and returns the signed-in user plus a verifiable `idToken`.\r\n *\r\n * All Auth-Server HTTP calls happen inside the popup (same origin). The host app only\r\n * opens the popup and exchanges postMessages with the PKCE verifier — no fetch to Auth-Server.\r\n */\r\nexport async function loginWithXS(\r\n opts: LoginWithXSOptions,\r\n): Promise<LoginWithXSResult> {\r\n const authBase = opts.authBaseUrl?.trim() || XS_AUTH_BASE_URL;\r\n const normalizedBase = normalizeBaseUrl(authBase);\r\n const authOrigin = normalizedBase.origin;\r\n const parentOrigin = (opts.parentOrigin ?? globalThis.location?.origin) as\r\n | string\r\n | undefined;\r\n if (!parentOrigin || typeof window === 'undefined') {\r\n throw new Error(\r\n 'loginWithXS requires a browser Window and explicit parentOrigin (or window.location).',\r\n );\r\n }\r\n\r\n const timeoutMs =\r\n opts.timeoutMs !== undefined ? opts.timeoutMs : 180_000;\r\n\r\n const state = randomBase64State();\r\n sessionStorage.setItem(STATE_KEY_STORAGE, state);\r\n\r\n const nonce = opts.useNonce ? randomBase64State() : undefined;\r\n const pair = await pkceVerifierAndChallenge();\r\n\r\n const params = new URLSearchParams({\r\n client_id: opts.clientId,\r\n state,\r\n code_challenge: pair.challenge,\r\n code_challenge_method: 'S256',\r\n parent_origin: parentOrigin,\r\n response_mode: 'popup',\r\n });\r\n if (opts.scope?.trim()) params.set('scope', opts.scope.trim());\r\n if (nonce) params.set('nonce', nonce);\r\n const prompt = resolvePrompt(opts);\r\n if (prompt) params.set('prompt', prompt);\r\n if (opts.mode === 'signup') params.set('mode', 'signup');\r\n if (opts.accountId?.trim()) params.set('account_id', opts.accountId.trim());\r\n maybeSetPublicPath(params, authBase);\r\n\r\n const authorizeUrl = `${normalizedBase.href.replace(/\\/?$/u, '')}/authorize?${params.toString()}`;\r\n\r\n const popupWidth = prompt === 'none' ? 420 : 480;\r\n const popupHeight = prompt === 'none' ? 120 : 640;\r\n const popup = window.open(\r\n authorizeUrl,\r\n `xs-auth-${crypto.randomUUID()}`,\r\n popupWindowFeatures(popupWidth, popupHeight),\r\n );\r\n if (!popup) throw new PopupBlockedError();\r\n\r\n return await new Promise<LoginWithXSResult>((resolve, reject) => {\r\n let cleaned = false;\r\n const teardown = (): void => {\r\n if (cleaned) return;\r\n cleaned = true;\r\n window.removeEventListener('message', handleMessage as EventListener);\r\n clearInterval(closePoll);\r\n clearTimeout(timer);\r\n try {\r\n popup.close();\r\n } catch {\r\n // ignore\r\n }\r\n };\r\n\r\n const fail = (e: unknown): void => {\r\n teardown();\r\n reject(e instanceof Error ? e : new Error(String(e)));\r\n };\r\n\r\n const timer = window.setTimeout(() => {\r\n fail(new LoginTimeoutError());\r\n }, timeoutMs);\r\n\r\n const handleMessage = (event: MessageEvent): void => {\r\n if (event.origin !== authOrigin) return;\r\n const d = event.data as Partial<Record<string, unknown>>;\r\n if (d?.source !== 'xs-auth') return;\r\n\r\n const st = typeof d.state === 'string' ? d.state : '';\r\n if (!st || st !== sessionStorage.getItem(STATE_KEY_STORAGE)) return;\r\n\r\n if (typeof d.error === 'string' && d.error.length > 0) {\r\n teardown();\r\n reject(\r\n new XSAuthDeniedError(\r\n String(d.error),\r\n typeof d.error_description === 'string'\r\n ? d.error_description\r\n : '',\r\n ),\r\n );\r\n return;\r\n }\r\n\r\n if (d.type === 'need_verifier') {\r\n try {\r\n popup.postMessage(\r\n {\r\n source: 'xs-auth-opener',\r\n state: st,\r\n code_verifier: pair.verifier,\r\n client_id: opts.clientId,\r\n },\r\n authOrigin,\r\n );\r\n } catch {\r\n fail(new XSAuthDeniedError('exchange_failed', 'Sign in could not be completed.'));\r\n }\r\n return;\r\n }\r\n\r\n const idToken =\r\n typeof d.id_token === 'string'\r\n ? d.id_token\r\n : typeof d.idToken === 'string'\r\n ? d.idToken\r\n : '';\r\n const user = parseSdkUser(d.user);\r\n if (!idToken || !user) return;\r\n\r\n sessionStorage.removeItem(STATE_KEY_STORAGE);\r\n clearTimeout(timer);\r\n window.removeEventListener('message', handleMessage as EventListener);\r\n clearInterval(closePoll);\r\n cleaned = true;\r\n\r\n resolve({ user, idToken, mfaVerified: idTokenIncludesMfa(idToken) });\r\n\r\n try {\r\n popup.close();\r\n } catch {\r\n // ignore\r\n }\r\n };\r\n\r\n window.addEventListener('message', handleMessage as EventListener);\r\n\r\n const closePoll = window.setInterval(() => {\r\n if (!popup.closed) return;\r\n if (cleaned) return;\r\n const pending = sessionStorage.getItem(STATE_KEY_STORAGE);\r\n if (!pending) return;\r\n fail(new PopupClosedError());\r\n }, 280);\r\n });\r\n}\r\n\r\n/** True when an XS Auth idToken indicates MFA was completed at sign-in. */\r\nexport function idTokenIncludesMfa(idToken: string): boolean {\r\n const amr = parseIdTokenAmr(idToken);\r\n return Array.isArray(amr) && amr.includes('mfa');\r\n}\r\n\r\n/** Read the `amr` claim from an XS Auth idToken payload (no signature verification). */\r\nexport function parseIdTokenAmr(idToken: string): string[] | null {\r\n const payload = parseJwtPayload(idToken);\r\n if (!payload || !('amr' in payload)) return null;\r\n const amr = payload.amr;\r\n if (Array.isArray(amr)) {\r\n return amr.filter((v): v is string => typeof v === 'string');\r\n }\r\n if (typeof amr === 'string' && amr.trim()) return [amr.trim()];\r\n return null;\r\n}\r\n\r\nfunction parseJwtPayload(token: string): Record<string, unknown> | null {\r\n const parts = token.split('.');\r\n if (parts.length < 2) return null;\r\n try {\r\n const json = atob(parts[1].replace(/-/g, '+').replace(/_/g, '/'));\r\n const parsed: unknown = JSON.parse(json);\r\n return parsed && typeof parsed === 'object' ? (parsed as Record<string, unknown>) : null;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nfunction randomBase64State(): string {\r\n return base64UrlEncode(bytesBuffer(32));\r\n}\r\n\r\nfunction normalizeBaseUrl(s: string): URL {\r\n return new URL(s);\r\n}\r\n\r\n/** Center popup over the opener window (falls back to screen center). */\r\nfunction popupWindowFeatures(width: number, height: number): string {\r\n const win = window;\r\n const outerW = win.outerWidth > 0 ? win.outerWidth : win.innerWidth;\r\n const outerH = win.outerHeight > 0 ? win.outerHeight : win.innerHeight;\r\n const screenX = win.screenX ?? win.screenLeft ?? 0;\r\n const screenY = win.screenY ?? win.screenTop ?? 0;\r\n const left = Math.round(screenX + Math.max(0, (outerW - width) / 2));\r\n const top = Math.round(screenY + Math.max(0, (outerH - height) / 2));\r\n return `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes`;\r\n}\r\n\r\n/** True when Auth-Server has no active browser session for silent sign-in. */\r\nexport function isLoginRequiredError(error: unknown): boolean {\r\n return error instanceof XSAuthDeniedError && error.errorCode === 'login_required';\r\n}\r\n","/** Popup was blocked by the browser or environment. */\r\nexport class PopupBlockedError extends Error {\r\n readonly name = 'PopupBlockedError';\r\n}\r\n\r\n/** User closed the popup before completing login. */\r\nexport class PopupClosedError extends Error {\r\n readonly name = 'PopupClosedError';\r\n}\r\n\r\n/** XS Auth popup did not complete within timeout. */\r\nexport class LoginTimeoutError extends Error {\r\n readonly name = 'LoginTimeoutError';\r\n}\r\n\r\n/** XS Auth returned an OAuth-style error inside postMessage. */\r\nexport class XSAuthDeniedError extends Error {\r\n readonly name = 'XSAuthDeniedError';\r\n readonly errorCode: string;\r\n readonly description: string;\r\n\r\n constructor(errorCode: string, description: string) {\r\n super(description || errorCode || 'xs_auth_denied');\r\n this.errorCode = errorCode;\r\n this.description = description;\r\n }\r\n}\r\n\r\n/** Session bridge did not respond within timeout. */\r\nexport class LoginBridgeTimeoutError extends Error {\r\n readonly name = 'LoginBridgeTimeoutError';\r\n}\r\n","import {\r\n LoginBridgeTimeoutError,\r\n PopupBlockedError,\r\n PopupClosedError,\r\n} from './errors';\r\n\r\n/** XS Auth browser session account (multi-account SSO on the Auth-Server domain). */\r\nexport interface XSBrowserAccount {\r\n sessionId: string;\r\n userId: string;\r\n email: string;\r\n name: string;\r\n isPrimary: boolean;\r\n}\r\n\r\nexport interface OpenSessionBridgeOptions {\r\n clientId: string;\r\n parentOrigin?: string;\r\n timeoutMs?: number;\r\n}\r\n\r\nexport interface SessionBridge {\r\n listAccounts(): Promise<XSBrowserAccount[]>;\r\n revokeAccount(sessionId: string): Promise<{ accounts: XSBrowserAccount[]; remainingCount: number }>;\r\n revokeAll(): Promise<void>;\r\n setPrimary(sessionId: string): Promise<XSBrowserAccount[]>;\r\n close(): void;\r\n}\r\n\r\nexport class SessionBridgeError extends Error {\r\n readonly name = 'SessionBridgeError';\r\n readonly errorCode: string;\r\n\r\n constructor(errorCode: string, message: string) {\r\n super(message || errorCode);\r\n this.errorCode = errorCode;\r\n }\r\n}\r\n\r\ntype BridgeMessage = Partial<Record<string, unknown>>;\r\n\r\nconst BRIDGE_STATE_KEY = '__xs_bridge_state';\r\n\r\nfunction parseAccounts(raw: unknown): XSBrowserAccount[] {\r\n if (!Array.isArray(raw)) return [];\r\n return raw\r\n .map((item) => {\r\n if (!item || typeof item !== 'object') return null;\r\n const row = item as Record<string, unknown>;\r\n const sessionId =\r\n typeof row.sessionId === 'string'\r\n ? row.sessionId\r\n : typeof row.session_id === 'string'\r\n ? row.session_id\r\n : '';\r\n const userId =\r\n typeof row.userId === 'string'\r\n ? row.userId\r\n : typeof row.user_id === 'string'\r\n ? row.user_id\r\n : '';\r\n const email = typeof row.email === 'string' ? row.email : '';\r\n const name = typeof row.name === 'string' ? row.name : email;\r\n if (!sessionId || !email) return null;\r\n return {\r\n sessionId,\r\n userId,\r\n email,\r\n name,\r\n isPrimary: row.isPrimary === true || row.is_primary === true,\r\n };\r\n })\r\n .filter((x): x is XSBrowserAccount => x !== null);\r\n}\r\n\r\nfunction hiddenBridgePopupFeatures(): string {\r\n return 'width=1,height=1,left=-10000,top=-10000,resizable=no,scrollbars=no';\r\n}\r\n\r\nfunction randomBridgeState(): string {\r\n const bytes = new Uint8Array(32);\r\n crypto.getRandomValues(bytes);\r\n let binary = '';\r\n for (let i = 0; i < bytes.length; i++) {\r\n binary += String.fromCharCode(bytes[i]!);\r\n }\r\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/u, '');\r\n}\r\n\r\n/**\r\n * Opens a same-origin Auth-Server popup bridge so the host app can list and revoke\r\n * browser SSO sessions without cross-origin cookie access.\r\n */\r\nexport async function openSessionBridge(\r\n opts: OpenSessionBridgeOptions,\r\n authBaseUrl: string,\r\n): Promise<SessionBridge> {\r\n const parentOrigin = (opts.parentOrigin ?? globalThis.location?.origin) as string | undefined;\r\n if (!parentOrigin || typeof window === 'undefined') {\r\n throw new Error(\r\n 'openSessionBridge requires a browser Window and explicit parentOrigin (or window.location).',\r\n );\r\n }\r\n\r\n const normalizedBase = new URL(authBaseUrl);\r\n const authOrigin = normalizedBase.origin;\r\n const state = randomBridgeState();\r\n sessionStorage.setItem(BRIDGE_STATE_KEY, state);\r\n\r\n const params = new URLSearchParams({\r\n client_id: opts.clientId,\r\n parent_origin: parentOrigin,\r\n state,\r\n });\r\n\r\n const bridgeUrl = `${normalizedBase.href.replace(/\\/?$/u, '')}/session/bridge?${params.toString()}`;\r\n const popup = window.open(\r\n bridgeUrl,\r\n `xs-auth-bridge-${crypto.randomUUID()}`,\r\n hiddenBridgePopupFeatures(),\r\n );\r\n if (!popup) throw new PopupBlockedError();\r\n\r\n const timeoutMs = opts.timeoutMs !== undefined ? opts.timeoutMs : 120_000;\r\n let cleaned = false;\r\n let closePoll: ReturnType<typeof setInterval> | undefined;\r\n\r\n const teardown = (): void => {\r\n if (cleaned) return;\r\n cleaned = true;\r\n window.removeEventListener('message', handleMessage as EventListener);\r\n if (closePoll !== undefined) clearInterval(closePoll);\r\n sessionStorage.removeItem(BRIDGE_STATE_KEY);\r\n try {\r\n popup.close();\r\n } catch {\r\n // ignore\r\n }\r\n };\r\n\r\n const pending = new Map<\r\n string,\r\n {\r\n resolve: (value: BridgeMessage) => void;\r\n reject: (error: Error) => void;\r\n }\r\n >();\r\n\r\n let bridgeReady = false;\r\n let readyResolve: (() => void) | null = null;\r\n let readyReject: ((error: Error) => void) | null = null;\r\n\r\n const readyPromise = new Promise<void>((resolve, reject) => {\r\n readyResolve = resolve;\r\n readyReject = reject;\r\n });\r\n\r\n const handleMessage = (event: MessageEvent): void => {\r\n if (event.origin !== authOrigin) return;\r\n const d = event.data as BridgeMessage;\r\n if (d?.source !== 'xs-auth') return;\r\n\r\n const st = typeof d.state === 'string' ? d.state : '';\r\n if (!st || st !== sessionStorage.getItem(BRIDGE_STATE_KEY)) return;\r\n\r\n if (d.type === 'bridge_ready') {\r\n bridgeReady = true;\r\n readyResolve?.();\r\n return;\r\n }\r\n\r\n const requestId = typeof d.requestId === 'string' ? d.requestId : '';\r\n if (!requestId) return;\r\n\r\n const entry = pending.get(requestId);\r\n if (!entry) return;\r\n\r\n pending.delete(requestId);\r\n\r\n if (typeof d.error === 'string' && d.error.length > 0) {\r\n entry.reject(\r\n new SessionBridgeError(\r\n String(d.error),\r\n typeof d.error_description === 'string' ? d.error_description : '',\r\n ),\r\n );\r\n return;\r\n }\r\n\r\n if (d.type === 'result') {\r\n entry.resolve(d);\r\n }\r\n };\r\n\r\n window.addEventListener('message', handleMessage as EventListener);\r\n\r\n closePoll = window.setInterval(() => {\r\n if (!popup.closed) return;\r\n if (cleaned) return;\r\n for (const [, entry] of pending) {\r\n entry.reject(new PopupClosedError());\r\n }\r\n pending.clear();\r\n readyReject?.(new PopupClosedError());\r\n teardown();\r\n }, 280);\r\n\r\n const readyTimer = window.setTimeout(() => {\r\n if (bridgeReady) return;\r\n readyReject?.(new LoginBridgeTimeoutError());\r\n teardown();\r\n }, timeoutMs);\r\n\r\n try {\r\n await readyPromise;\r\n } catch (error) {\r\n clearTimeout(readyTimer);\r\n throw error;\r\n }\r\n clearTimeout(readyTimer);\r\n\r\n const sendRequest = (type: string, extra: Record<string, unknown> = {}): Promise<BridgeMessage> => {\r\n if (popup.closed) {\r\n return Promise.reject(new PopupClosedError());\r\n }\r\n\r\n const requestId = crypto.randomUUID();\r\n return new Promise<BridgeMessage>((resolve, reject) => {\r\n const timer = window.setTimeout(() => {\r\n pending.delete(requestId);\r\n reject(new LoginBridgeTimeoutError());\r\n }, timeoutMs);\r\n\r\n pending.set(requestId, {\r\n resolve: (value) => {\r\n clearTimeout(timer);\r\n resolve(value);\r\n },\r\n reject: (error) => {\r\n clearTimeout(timer);\r\n reject(error);\r\n },\r\n });\r\n\r\n try {\r\n popup.postMessage(\r\n {\r\n source: 'xs-auth-opener',\r\n state,\r\n client_id: opts.clientId,\r\n requestId,\r\n type,\r\n ...extra,\r\n },\r\n authOrigin,\r\n );\r\n } catch {\r\n pending.delete(requestId);\r\n clearTimeout(timer);\r\n reject(new SessionBridgeError('post_message_failed', 'Could not reach the session bridge.'));\r\n }\r\n });\r\n };\r\n\r\n return {\r\n async listAccounts() {\r\n const result = await sendRequest('list_accounts');\r\n return parseAccounts(result.accounts);\r\n },\r\n\r\n async revokeAccount(sessionId: string) {\r\n const result = await sendRequest('revoke', { session_id: sessionId.trim() });\r\n const accounts = parseAccounts(result.accounts);\r\n const remainingCount =\r\n typeof result.remainingCount === 'number' ? result.remainingCount : accounts.length;\r\n return { accounts, remainingCount };\r\n },\r\n\r\n async revokeAll() {\r\n await sendRequest('revoke_all');\r\n },\r\n\r\n async setPrimary(sessionId: string) {\r\n const result = await sendRequest('set_primary', { session_id: sessionId.trim() });\r\n return parseAccounts(result.accounts);\r\n },\r\n\r\n close() {\r\n teardown();\r\n },\r\n };\r\n}\r\n\r\n/** True when the user must pick another primary account before signing out. */\r\nexport function isPrimaryAccountError(error: unknown): boolean {\r\n return error instanceof SessionBridgeError && error.errorCode === 'primary_account';\r\n}\r\n","import {\r\n LoginBridgeTimeoutError,\r\n PopupBlockedError,\r\n PopupClosedError,\r\n} from './errors';\r\n\r\nexport interface SignOutWithXSOptions {\r\n clientId: string;\r\n parentOrigin?: string;\r\n /** XS Auth user id (`sub`) for the account active in the host app. */\r\n activeUserId?: string;\r\n timeoutMs?: number;\r\n /** Override Auth-Server base URL (e.g. same-origin `/xs-auth` proxy in local dev). */\r\n authBaseUrl?: string;\r\n}\r\n\r\nexport type SignOutAction = 'revoked_one' | 'revoked_all' | 'cancelled';\r\n\r\nexport interface SignOutWithXSResult {\r\n action: SignOutAction;\r\n revokedCurrent: boolean;\r\n remainingCount: number;\r\n}\r\n\r\nconst SIGN_OUT_STATE_KEY = '__xs_sign_out_state';\r\n\r\nfunction popupWindowFeatures(width: number, height: number): string {\r\n const win = window;\r\n const outerW = win.outerWidth > 0 ? win.outerWidth : win.innerWidth;\r\n const outerH = win.outerHeight > 0 ? win.outerHeight : win.innerHeight;\r\n const screenX = win.screenX ?? win.screenLeft ?? 0;\r\n const screenY = win.screenY ?? win.screenTop ?? 0;\r\n const left = Math.round(screenX + Math.max(0, (outerW - width) / 2));\r\n const top = Math.round(screenY + Math.max(0, (outerH - height) / 2));\r\n return `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes`;\r\n}\r\n\r\nfunction randomState(): string {\r\n const bytes = new Uint8Array(32);\r\n crypto.getRandomValues(bytes);\r\n let binary = '';\r\n for (let i = 0; i < bytes.length; i++) {\r\n binary += String.fromCharCode(bytes[i]!);\r\n }\r\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/u, '');\r\n}\r\n\r\nfunction parseSignOutResult(raw: SignOutAction, data: Record<string, unknown>): SignOutWithXSResult {\r\n return {\r\n action: raw,\r\n revokedCurrent: data.revokedCurrent === true,\r\n remainingCount:\r\n typeof data.remainingCount === 'number' && Number.isFinite(data.remainingCount)\r\n ? Math.max(0, data.remainingCount)\r\n : 0,\r\n };\r\n}\r\n\r\n/**\r\n * Opens a centered XS Auth popup to sign out of one or all browser SSO accounts\r\n * (Google-style account manager on the Auth-Server domain).\r\n */\r\nexport async function signOutWithXS(\r\n opts: SignOutWithXSOptions,\r\n authBaseUrl: string,\r\n): Promise<SignOutWithXSResult> {\r\n const parentOrigin = (opts.parentOrigin ?? globalThis.location?.origin) as string | undefined;\r\n if (!parentOrigin || typeof window === 'undefined') {\r\n throw new Error(\r\n 'signOutWithXS requires a browser Window and explicit parentOrigin (or window.location).',\r\n );\r\n }\r\n\r\n const normalizedBase = new URL(authBaseUrl);\r\n const authOrigin = normalizedBase.origin;\r\n const state = randomState();\r\n sessionStorage.setItem(SIGN_OUT_STATE_KEY, state);\r\n\r\n const params = new URLSearchParams({\r\n client_id: opts.clientId,\r\n parent_origin: parentOrigin,\r\n state,\r\n });\r\n if (opts.activeUserId?.trim()) {\r\n params.set('active_user_id', opts.activeUserId.trim());\r\n }\r\n\r\n const url = `${normalizedBase.href.replace(/\\/?$/u, '')}/session/sign-out?${params.toString()}`;\r\n const popup = window.open(\r\n url,\r\n `xs-auth-signout-${crypto.randomUUID()}`,\r\n popupWindowFeatures(480, 640),\r\n );\r\n if (!popup) throw new PopupBlockedError();\r\n\r\n const timeoutMs = opts.timeoutMs !== undefined ? opts.timeoutMs : 120_000;\r\n\r\n return await new Promise<SignOutWithXSResult>((resolve, reject) => {\r\n let cleaned = false;\r\n\r\n const teardown = (): void => {\r\n if (cleaned) return;\r\n cleaned = true;\r\n window.removeEventListener('message', handleMessage as EventListener);\r\n clearInterval(closePoll);\r\n clearTimeout(timer);\r\n sessionStorage.removeItem(SIGN_OUT_STATE_KEY);\r\n try {\r\n popup.close();\r\n } catch {\r\n // ignore\r\n }\r\n };\r\n\r\n const fail = (error: Error): void => {\r\n teardown();\r\n reject(error);\r\n };\r\n\r\n const timer = window.setTimeout(() => {\r\n fail(new LoginBridgeTimeoutError());\r\n }, timeoutMs);\r\n\r\n const handleMessage = (event: MessageEvent): void => {\r\n if (event.origin !== authOrigin) return;\r\n const d = event.data as Partial<Record<string, unknown>>;\r\n if (d?.source !== 'xs-auth') return;\r\n\r\n const st = typeof d.state === 'string' ? d.state : '';\r\n if (!st || st !== sessionStorage.getItem(SIGN_OUT_STATE_KEY)) return;\r\n\r\n if (d.type === 'sign_out_cancelled') {\r\n teardown();\r\n resolve(parseSignOutResult('cancelled', d));\r\n return;\r\n }\r\n\r\n if (d.type === 'sign_out_complete') {\r\n teardown();\r\n const actionRaw = typeof d.action === 'string' ? d.action : 'revoked_one';\r\n const action: SignOutAction =\r\n actionRaw === 'revoked_all'\r\n ? 'revoked_all'\r\n : actionRaw === 'cancelled'\r\n ? 'cancelled'\r\n : 'revoked_one';\r\n resolve(parseSignOutResult(action, d));\r\n }\r\n };\r\n\r\n window.addEventListener('message', handleMessage as EventListener);\r\n\r\n const closePoll = window.setInterval(() => {\r\n if (!popup.closed) return;\r\n if (cleaned) return;\r\n if (!sessionStorage.getItem(SIGN_OUT_STATE_KEY)) return;\r\n fail(new PopupClosedError());\r\n }, 280);\r\n });\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,2BAAAA;AAAA,EAAA;AAAA,uBAAAC;AAAA;AAAA;;;ACCO,IAAM,oBAAN,cAAgC,MAAM;AAAA,EAClC,OAAO;AAClB;AAGO,IAAM,mBAAN,cAA+B,MAAM;AAAA,EACjC,OAAO;AAClB;AAGO,IAAM,oBAAN,cAAgC,MAAM;AAAA,EAClC,OAAO;AAClB;AAGO,IAAM,oBAAN,cAAgC,MAAM;AAAA,EAClC,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EAET,YAAY,WAAmB,aAAqB;AAClD,UAAM,eAAe,aAAa,gBAAgB;AAClD,SAAK,YAAY;AACjB,SAAK,cAAc;AAAA,EACrB;AACF;AAGO,IAAM,0BAAN,cAAsC,MAAM;AAAA,EACxC,OAAO;AAClB;;;ACFO,IAAM,qBAAN,cAAiC,MAAM;AAAA,EACnC,OAAO;AAAA,EACP;AAAA,EAET,YAAY,WAAmB,SAAiB;AAC9C,UAAM,WAAW,SAAS;AAC1B,SAAK,YAAY;AAAA,EACnB;AACF;AAIA,IAAM,mBAAmB;AAEzB,SAAS,cAAc,KAAkC;AACvD,MAAI,CAAC,MAAM,QAAQ,GAAG,EAAG,QAAO,CAAC;AACjC,SAAO,IACJ,IAAI,CAAC,SAAS;AACb,QAAI,CAAC,QAAQ,OAAO,SAAS,SAAU,QAAO;AAC9C,UAAM,MAAM;AACZ,UAAM,YACJ,OAAO,IAAI,cAAc,WACrB,IAAI,YACJ,OAAO,IAAI,eAAe,WACxB,IAAI,aACJ;AACR,UAAM,SACJ,OAAO,IAAI,WAAW,WAClB,IAAI,SACJ,OAAO,IAAI,YAAY,WACrB,IAAI,UACJ;AACR,UAAM,QAAQ,OAAO,IAAI,UAAU,WAAW,IAAI,QAAQ;AAC1D,UAAM,OAAO,OAAO,IAAI,SAAS,WAAW,IAAI,OAAO;AACvD,QAAI,CAAC,aAAa,CAAC,MAAO,QAAO;AACjC,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW,IAAI,cAAc,QAAQ,IAAI,eAAe;AAAA,IAC1D;AAAA,EACF,CAAC,EACA,OAAO,CAAC,MAA6B,MAAM,IAAI;AACpD;AAEA,SAAS,4BAAoC;AAC3C,SAAO;AACT;AAEA,SAAS,oBAA4B;AACnC,QAAM,QAAQ,IAAI,WAAW,EAAE;AAC/B,SAAO,gBAAgB,KAAK;AAC5B,MAAI,SAAS;AACb,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,cAAU,OAAO,aAAa,MAAM,CAAC,CAAE;AAAA,EACzC;AACA,SAAO,KAAK,MAAM,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,QAAQ,EAAE;AAChF;AAMA,eAAsB,kBACpB,MACA,aACwB;AACxB,QAAM,eAAgB,KAAK,gBAAgB,WAAW,UAAU;AAChE,MAAI,CAAC,gBAAgB,OAAO,WAAW,aAAa;AAClD,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,iBAAiB,IAAI,IAAI,WAAW;AAC1C,QAAM,aAAa,eAAe;AAClC,QAAM,QAAQ,kBAAkB;AAChC,iBAAe,QAAQ,kBAAkB,KAAK;AAE9C,QAAM,SAAS,IAAI,gBAAgB;AAAA,IACjC,WAAW,KAAK;AAAA,IAChB,eAAe;AAAA,IACf;AAAA,EACF,CAAC;AAED,QAAM,YAAY,GAAG,eAAe,KAAK,QAAQ,SAAS,EAAE,CAAC,mBAAmB,OAAO,SAAS,CAAC;AACjG,QAAM,QAAQ,OAAO;AAAA,IACnB;AAAA,IACA,kBAAkB,OAAO,WAAW,CAAC;AAAA,IACrC,0BAA0B;AAAA,EAC5B;AACA,MAAI,CAAC,MAAO,OAAM,IAAI,kBAAkB;AAExC,QAAM,YAAY,KAAK,cAAc,SAAY,KAAK,YAAY;AAClE,MAAI,UAAU;AACd,MAAI;AAEJ,QAAM,WAAW,MAAY;AAC3B,QAAI,QAAS;AACb,cAAU;AACV,WAAO,oBAAoB,WAAW,aAA8B;AACpE,QAAI,cAAc,OAAW,eAAc,SAAS;AACpD,mBAAe,WAAW,gBAAgB;AAC1C,QAAI;AACF,YAAM,MAAM;AAAA,IACd,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,QAAM,UAAU,oBAAI,IAMlB;AAEF,MAAI,cAAc;AAClB,MAAI,eAAoC;AACxC,MAAI,cAA+C;AAEnD,QAAM,eAAe,IAAI,QAAc,CAAC,SAAS,WAAW;AAC1D,mBAAe;AACf,kBAAc;AAAA,EAChB,CAAC;AAED,QAAM,gBAAgB,CAAC,UAA8B;AACnD,QAAI,MAAM,WAAW,WAAY;AACjC,UAAM,IAAI,MAAM;AAChB,QAAI,GAAG,WAAW,UAAW;AAE7B,UAAM,KAAK,OAAO,EAAE,UAAU,WAAW,EAAE,QAAQ;AACnD,QAAI,CAAC,MAAM,OAAO,eAAe,QAAQ,gBAAgB,EAAG;AAE5D,QAAI,EAAE,SAAS,gBAAgB;AAC7B,oBAAc;AACd,qBAAe;AACf;AAAA,IACF;AAEA,UAAM,YAAY,OAAO,EAAE,cAAc,WAAW,EAAE,YAAY;AAClE,QAAI,CAAC,UAAW;AAEhB,UAAM,QAAQ,QAAQ,IAAI,SAAS;AACnC,QAAI,CAAC,MAAO;AAEZ,YAAQ,OAAO,SAAS;AAExB,QAAI,OAAO,EAAE,UAAU,YAAY,EAAE,MAAM,SAAS,GAAG;AACrD,YAAM;AAAA,QACJ,IAAI;AAAA,UACF,OAAO,EAAE,KAAK;AAAA,UACd,OAAO,EAAE,sBAAsB,WAAW,EAAE,oBAAoB;AAAA,QAClE;AAAA,MACF;AACA;AAAA,IACF;AAEA,QAAI,EAAE,SAAS,UAAU;AACvB,YAAM,QAAQ,CAAC;AAAA,IACjB;AAAA,EACF;AAEA,SAAO,iBAAiB,WAAW,aAA8B;AAEjE,cAAY,OAAO,YAAY,MAAM;AACnC,QAAI,CAAC,MAAM,OAAQ;AACnB,QAAI,QAAS;AACb,eAAW,CAAC,EAAE,KAAK,KAAK,SAAS;AAC/B,YAAM,OAAO,IAAI,iBAAiB,CAAC;AAAA,IACrC;AACA,YAAQ,MAAM;AACd,kBAAc,IAAI,iBAAiB,CAAC;AACpC,aAAS;AAAA,EACX,GAAG,GAAG;AAEN,QAAM,aAAa,OAAO,WAAW,MAAM;AACzC,QAAI,YAAa;AACjB,kBAAc,IAAI,wBAAwB,CAAC;AAC3C,aAAS;AAAA,EACX,GAAG,SAAS;AAEZ,MAAI;AACF,UAAM;AAAA,EACR,SAAS,OAAO;AACd,iBAAa,UAAU;AACvB,UAAM;AAAA,EACR;AACA,eAAa,UAAU;AAEvB,QAAM,cAAc,CAAC,MAAc,QAAiC,CAAC,MAA8B;AACjG,QAAI,MAAM,QAAQ;AAChB,aAAO,QAAQ,OAAO,IAAI,iBAAiB,CAAC;AAAA,IAC9C;AAEA,UAAM,YAAY,OAAO,WAAW;AACpC,WAAO,IAAI,QAAuB,CAAC,SAAS,WAAW;AACrD,YAAM,QAAQ,OAAO,WAAW,MAAM;AACpC,gBAAQ,OAAO,SAAS;AACxB,eAAO,IAAI,wBAAwB,CAAC;AAAA,MACtC,GAAG,SAAS;AAEZ,cAAQ,IAAI,WAAW;AAAA,QACrB,SAAS,CAAC,UAAU;AAClB,uBAAa,KAAK;AAClB,kBAAQ,KAAK;AAAA,QACf;AAAA,QACA,QAAQ,CAAC,UAAU;AACjB,uBAAa,KAAK;AAClB,iBAAO,KAAK;AAAA,QACd;AAAA,MACF,CAAC;AAED,UAAI;AACF,cAAM;AAAA,UACJ;AAAA,YACE,QAAQ;AAAA,YACR;AAAA,YACA,WAAW,KAAK;AAAA,YAChB;AAAA,YACA;AAAA,YACA,GAAG;AAAA,UACL;AAAA,UACA;AAAA,QACF;AAAA,MACF,QAAQ;AACN,gBAAQ,OAAO,SAAS;AACxB,qBAAa,KAAK;AAClB,eAAO,IAAI,mBAAmB,uBAAuB,qCAAqC,CAAC;AAAA,MAC7F;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL,MAAM,eAAe;AACnB,YAAM,SAAS,MAAM,YAAY,eAAe;AAChD,aAAO,cAAc,OAAO,QAAQ;AAAA,IACtC;AAAA,IAEA,MAAM,cAAc,WAAmB;AACrC,YAAM,SAAS,MAAM,YAAY,UAAU,EAAE,YAAY,UAAU,KAAK,EAAE,CAAC;AAC3E,YAAM,WAAW,cAAc,OAAO,QAAQ;AAC9C,YAAM,iBACJ,OAAO,OAAO,mBAAmB,WAAW,OAAO,iBAAiB,SAAS;AAC/E,aAAO,EAAE,UAAU,eAAe;AAAA,IACpC;AAAA,IAEA,MAAM,YAAY;AAChB,YAAM,YAAY,YAAY;AAAA,IAChC;AAAA,IAEA,MAAM,WAAW,WAAmB;AAClC,YAAM,SAAS,MAAM,YAAY,eAAe,EAAE,YAAY,UAAU,KAAK,EAAE,CAAC;AAChF,aAAO,cAAc,OAAO,QAAQ;AAAA,IACtC;AAAA,IAEA,QAAQ;AACN,eAAS;AAAA,IACX;AAAA,EACF;AACF;AAGO,SAAS,sBAAsB,OAAyB;AAC7D,SAAO,iBAAiB,sBAAsB,MAAM,cAAc;AACpE;;;AChRA,IAAM,qBAAqB;AAE3B,SAAS,oBAAoB,OAAe,QAAwB;AAClE,QAAM,MAAM;AACZ,QAAM,SAAS,IAAI,aAAa,IAAI,IAAI,aAAa,IAAI;AACzD,QAAM,SAAS,IAAI,cAAc,IAAI,IAAI,cAAc,IAAI;AAC3D,QAAM,UAAU,IAAI,WAAW,IAAI,cAAc;AACjD,QAAM,UAAU,IAAI,WAAW,IAAI,aAAa;AAChD,QAAM,OAAO,KAAK,MAAM,UAAU,KAAK,IAAI,IAAI,SAAS,SAAS,CAAC,CAAC;AACnE,QAAM,MAAM,KAAK,MAAM,UAAU,KAAK,IAAI,IAAI,SAAS,UAAU,CAAC,CAAC;AACnE,SAAO,SAAS,KAAK,WAAW,MAAM,SAAS,IAAI,QAAQ,GAAG;AAChE;AAEA,SAAS,cAAsB;AAC7B,QAAM,QAAQ,IAAI,WAAW,EAAE;AAC/B,SAAO,gBAAgB,KAAK;AAC5B,MAAI,SAAS;AACb,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,cAAU,OAAO,aAAa,MAAM,CAAC,CAAE;AAAA,EACzC;AACA,SAAO,KAAK,MAAM,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,QAAQ,EAAE;AAChF;AAEA,SAAS,mBAAmB,KAAoB,MAAoD;AAClG,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,gBAAgB,KAAK,mBAAmB;AAAA,IACxC,gBACE,OAAO,KAAK,mBAAmB,YAAY,OAAO,SAAS,KAAK,cAAc,IAC1E,KAAK,IAAI,GAAG,KAAK,cAAc,IAC/B;AAAA,EACR;AACF;AAMA,eAAsB,cACpB,MACA,aAC8B;AAC9B,QAAM,eAAgB,KAAK,gBAAgB,WAAW,UAAU;AAChE,MAAI,CAAC,gBAAgB,OAAO,WAAW,aAAa;AAClD,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,iBAAiB,IAAI,IAAI,WAAW;AAC1C,QAAM,aAAa,eAAe;AAClC,QAAM,QAAQ,YAAY;AAC1B,iBAAe,QAAQ,oBAAoB,KAAK;AAEhD,QAAM,SAAS,IAAI,gBAAgB;AAAA,IACjC,WAAW,KAAK;AAAA,IAChB,eAAe;AAAA,IACf;AAAA,EACF,CAAC;AACD,MAAI,KAAK,cAAc,KAAK,GAAG;AAC7B,WAAO,IAAI,kBAAkB,KAAK,aAAa,KAAK,CAAC;AAAA,EACvD;AAEA,QAAM,MAAM,GAAG,eAAe,KAAK,QAAQ,SAAS,EAAE,CAAC,qBAAqB,OAAO,SAAS,CAAC;AAC7F,QAAM,QAAQ,OAAO;AAAA,IACnB;AAAA,IACA,mBAAmB,OAAO,WAAW,CAAC;AAAA,IACtC,oBAAoB,KAAK,GAAG;AAAA,EAC9B;AACA,MAAI,CAAC,MAAO,OAAM,IAAI,kBAAkB;AAExC,QAAM,YAAY,KAAK,cAAc,SAAY,KAAK,YAAY;AAElE,SAAO,MAAM,IAAI,QAA6B,CAAC,SAAS,WAAW;AACjE,QAAI,UAAU;AAEd,UAAM,WAAW,MAAY;AAC3B,UAAI,QAAS;AACb,gBAAU;AACV,aAAO,oBAAoB,WAAW,aAA8B;AACpE,oBAAc,SAAS;AACvB,mBAAa,KAAK;AAClB,qBAAe,WAAW,kBAAkB;AAC5C,UAAI;AACF,cAAM,MAAM;AAAA,MACd,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,UAAM,OAAO,CAAC,UAAuB;AACnC,eAAS;AACT,aAAO,KAAK;AAAA,IACd;AAEA,UAAM,QAAQ,OAAO,WAAW,MAAM;AACpC,WAAK,IAAI,wBAAwB,CAAC;AAAA,IACpC,GAAG,SAAS;AAEZ,UAAM,gBAAgB,CAAC,UAA8B;AACnD,UAAI,MAAM,WAAW,WAAY;AACjC,YAAM,IAAI,MAAM;AAChB,UAAI,GAAG,WAAW,UAAW;AAE7B,YAAM,KAAK,OAAO,EAAE,UAAU,WAAW,EAAE,QAAQ;AACnD,UAAI,CAAC,MAAM,OAAO,eAAe,QAAQ,kBAAkB,EAAG;AAE9D,UAAI,EAAE,SAAS,sBAAsB;AACnC,iBAAS;AACT,gBAAQ,mBAAmB,aAAa,CAAC,CAAC;AAC1C;AAAA,MACF;AAEA,UAAI,EAAE,SAAS,qBAAqB;AAClC,iBAAS;AACT,cAAM,YAAY,OAAO,EAAE,WAAW,WAAW,EAAE,SAAS;AAC5D,cAAM,SACJ,cAAc,gBACV,gBACA,cAAc,cACZ,cACA;AACR,gBAAQ,mBAAmB,QAAQ,CAAC,CAAC;AAAA,MACvC;AAAA,IACF;AAEA,WAAO,iBAAiB,WAAW,aAA8B;AAEjE,UAAM,YAAY,OAAO,YAAY,MAAM;AACzC,UAAI,CAAC,MAAM,OAAQ;AACnB,UAAI,QAAS;AACb,UAAI,CAAC,eAAe,QAAQ,kBAAkB,EAAG;AACjD,WAAK,IAAI,iBAAiB,CAAC;AAAA,IAC7B,GAAG,GAAG;AAAA,EACR,CAAC;AACH;;;AHlHA,IAAM,mBAAmB;AAGlB,SAASC,mBACd,MACwB;AACxB,SAAO,kBAA0B,MAAM,gBAAgB;AACzD;AAGO,SAASC,eAAc,MAA0D;AACtF,QAAM,WAAW,KAAK,aAAa,KAAK,KAAK;AAC7C,SAAO,cAAsB,MAAM,QAAQ;AAC7C;AAoDA,SAAS,YAAY,KAAyB;AAC5C,QAAM,MAAM,IAAI,WAAW,GAAG;AAC9B,SAAO,gBAAgB,GAAG;AAC1B,SAAO;AACT;AAEA,SAAS,gBAAgB,KAAuC;AAC9D,QAAM,QAAQ,eAAe,aAAa,MAAM,IAAI,WAAW,GAAG;AAClE,MAAI,SAAS;AACb,QAAM,YAAY;AAClB,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,WAAW;AAChD,cAAU,OAAO,aAAa,GAAG,MAAM,SAAS,GAAG,IAAI,SAAS,CAAC;AAAA,EACnE;AACA,QAAM,MAAM,KAAK,MAAM;AACvB,SAAO,IAAI,QAAQ,OAAO,GAAG,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,QAAQ,EAAE;AACvE;AAEA,eAAe,2BAGZ;AACD,QAAM,WAAW,gBAAgB,YAAY,EAAE,CAAC;AAChD,QAAM,OAAO,IAAI,YAAY,EAAE,OAAO,QAAQ;AAC9C,QAAM,SAAS,MAAM,OAAO,OAAO,OAAO,WAAW,IAAI;AACzD,QAAM,YAAY,gBAAgB,MAAM;AACxC,SAAO,EAAE,UAAU,UAAU;AAC/B;AAGA,eAAsB,iBAGnB;AACD,SAAO,yBAAyB;AAClC;AAEA,IAAM,oBAAoB;AAE1B,SAAS,aAAa,KAAiC;AACrD,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO;AAC5C,QAAM,IAAI;AACV,QAAM,QAAQ,OAAO,EAAE,UAAU,WAAW,EAAE,MAAM,KAAK,IAAI;AAC7D,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,OAAmB,EAAE,MAAM;AACjC,QAAM,YACJ,OAAO,EAAE,cAAc,WAAW,EAAE,UAAU,KAAK,IAAI;AACzD,QAAM,WAAW,OAAO,EAAE,aAAa,WAAW,EAAE,SAAS,KAAK,IAAI;AACtE,MAAI,UAAW,MAAK,YAAY;AAChC,MAAI,SAAU,MAAK,WAAW;AAC9B,SAAO;AACT;AAEA,SAAS,cAAc,MAA8C;AACnE,MAAI,KAAK,OAAQ,QAAO,KAAK;AAC7B,MAAI,KAAK,cAAe,QAAO;AAC/B,SAAO;AACT;AAEA,SAAS,uBAAuB,aAA6B;AAC3D,MAAI;AACF,UAAM,WAAW,IAAI,IAAI,WAAW,EAAE,SAAS,QAAQ,QAAQ,EAAE;AACjE,WAAO,aAAa,MAAM,KAAK;AAAA,EACjC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,mBAAmB,QAAyB,aAA2B;AAC9E,QAAM,aAAa,uBAAuB,WAAW;AACrD,MAAI,WAAY,QAAO,IAAI,eAAe,UAAU;AACtD;AAQA,eAAsB,YACpB,MAC4B;AAC5B,QAAM,WAAW,KAAK,aAAa,KAAK,KAAK;AAC7C,QAAM,iBAAiB,iBAAiB,QAAQ;AAChD,QAAM,aAAa,eAAe;AAClC,QAAM,eAAgB,KAAK,gBAAgB,WAAW,UAAU;AAGhE,MAAI,CAAC,gBAAgB,OAAO,WAAW,aAAa;AAClD,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,YACJ,KAAK,cAAc,SAAY,KAAK,YAAY;AAElD,QAAM,QAAQ,kBAAkB;AAChC,iBAAe,QAAQ,mBAAmB,KAAK;AAE/C,QAAM,QAAQ,KAAK,WAAW,kBAAkB,IAAI;AACpD,QAAM,OAAO,MAAM,yBAAyB;AAE5C,QAAM,SAAS,IAAI,gBAAgB;AAAA,IACjC,WAAW,KAAK;AAAA,IAChB;AAAA,IACA,gBAAgB,KAAK;AAAA,IACrB,uBAAuB;AAAA,IACvB,eAAe;AAAA,IACf,eAAe;AAAA,EACjB,CAAC;AACD,MAAI,KAAK,OAAO,KAAK,EAAG,QAAO,IAAI,SAAS,KAAK,MAAM,KAAK,CAAC;AAC7D,MAAI,MAAO,QAAO,IAAI,SAAS,KAAK;AACpC,QAAM,SAAS,cAAc,IAAI;AACjC,MAAI,OAAQ,QAAO,IAAI,UAAU,MAAM;AACvC,MAAI,KAAK,SAAS,SAAU,QAAO,IAAI,QAAQ,QAAQ;AACvD,MAAI,KAAK,WAAW,KAAK,EAAG,QAAO,IAAI,cAAc,KAAK,UAAU,KAAK,CAAC;AAC1E,qBAAmB,QAAQ,QAAQ;AAEnC,QAAM,eAAe,GAAG,eAAe,KAAK,QAAQ,SAAS,EAAE,CAAC,cAAc,OAAO,SAAS,CAAC;AAE/F,QAAM,aAAa,WAAW,SAAS,MAAM;AAC7C,QAAM,cAAc,WAAW,SAAS,MAAM;AAC9C,QAAM,QAAQ,OAAO;AAAA,IACnB;AAAA,IACA,WAAW,OAAO,WAAW,CAAC;AAAA,IAC9BC,qBAAoB,YAAY,WAAW;AAAA,EAC7C;AACA,MAAI,CAAC,MAAO,OAAM,IAAI,kBAAkB;AAExC,SAAO,MAAM,IAAI,QAA2B,CAAC,SAAS,WAAW;AAC/D,QAAI,UAAU;AACd,UAAM,WAAW,MAAY;AAC3B,UAAI,QAAS;AACb,gBAAU;AACV,aAAO,oBAAoB,WAAW,aAA8B;AACpE,oBAAc,SAAS;AACvB,mBAAa,KAAK;AAClB,UAAI;AACF,cAAM,MAAM;AAAA,MACd,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,UAAM,OAAO,CAAC,MAAqB;AACjC,eAAS;AACT,aAAO,aAAa,QAAQ,IAAI,IAAI,MAAM,OAAO,CAAC,CAAC,CAAC;AAAA,IACtD;AAEA,UAAM,QAAQ,OAAO,WAAW,MAAM;AACpC,WAAK,IAAI,kBAAkB,CAAC;AAAA,IAC9B,GAAG,SAAS;AAEZ,UAAM,gBAAgB,CAAC,UAA8B;AACnD,UAAI,MAAM,WAAW,WAAY;AACjC,YAAM,IAAI,MAAM;AAChB,UAAI,GAAG,WAAW,UAAW;AAE7B,YAAM,KAAK,OAAO,EAAE,UAAU,WAAW,EAAE,QAAQ;AACnD,UAAI,CAAC,MAAM,OAAO,eAAe,QAAQ,iBAAiB,EAAG;AAE7D,UAAI,OAAO,EAAE,UAAU,YAAY,EAAE,MAAM,SAAS,GAAG;AACrD,iBAAS;AACT;AAAA,UACE,IAAI;AAAA,YACF,OAAO,EAAE,KAAK;AAAA,YACd,OAAO,EAAE,sBAAsB,WAC3B,EAAE,oBACF;AAAA,UACN;AAAA,QACF;AACA;AAAA,MACF;AAEA,UAAI,EAAE,SAAS,iBAAiB;AAC9B,YAAI;AACF,gBAAM;AAAA,YACJ;AAAA,cACE,QAAQ;AAAA,cACR,OAAO;AAAA,cACP,eAAe,KAAK;AAAA,cACpB,WAAW,KAAK;AAAA,YAClB;AAAA,YACA;AAAA,UACF;AAAA,QACF,QAAQ;AACN,eAAK,IAAI,kBAAkB,mBAAmB,iCAAiC,CAAC;AAAA,QAClF;AACA;AAAA,MACF;AAEA,YAAM,UACJ,OAAO,EAAE,aAAa,WAClB,EAAE,WACF,OAAO,EAAE,YAAY,WACnB,EAAE,UACF;AACR,YAAM,OAAO,aAAa,EAAE,IAAI;AAChC,UAAI,CAAC,WAAW,CAAC,KAAM;AAEvB,qBAAe,WAAW,iBAAiB;AAC3C,mBAAa,KAAK;AAClB,aAAO,oBAAoB,WAAW,aAA8B;AACpE,oBAAc,SAAS;AACvB,gBAAU;AAEV,cAAQ,EAAE,MAAM,SAAS,aAAa,mBAAmB,OAAO,EAAE,CAAC;AAEnE,UAAI;AACF,cAAM,MAAM;AAAA,MACd,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,WAAO,iBAAiB,WAAW,aAA8B;AAEjE,UAAM,YAAY,OAAO,YAAY,MAAM;AACzC,UAAI,CAAC,MAAM,OAAQ;AACnB,UAAI,QAAS;AACb,YAAM,UAAU,eAAe,QAAQ,iBAAiB;AACxD,UAAI,CAAC,QAAS;AACd,WAAK,IAAI,iBAAiB,CAAC;AAAA,IAC7B,GAAG,GAAG;AAAA,EACR,CAAC;AACH;AAGO,SAAS,mBAAmB,SAA0B;AAC3D,QAAM,MAAM,gBAAgB,OAAO;AACnC,SAAO,MAAM,QAAQ,GAAG,KAAK,IAAI,SAAS,KAAK;AACjD;AAGO,SAAS,gBAAgB,SAAkC;AAChE,QAAM,UAAU,gBAAgB,OAAO;AACvC,MAAI,CAAC,WAAW,EAAE,SAAS,SAAU,QAAO;AAC5C,QAAM,MAAM,QAAQ;AACpB,MAAI,MAAM,QAAQ,GAAG,GAAG;AACtB,WAAO,IAAI,OAAO,CAAC,MAAmB,OAAO,MAAM,QAAQ;AAAA,EAC7D;AACA,MAAI,OAAO,QAAQ,YAAY,IAAI,KAAK,EAAG,QAAO,CAAC,IAAI,KAAK,CAAC;AAC7D,SAAO;AACT;AAEA,SAAS,gBAAgB,OAA+C;AACtE,QAAM,QAAQ,MAAM,MAAM,GAAG;AAC7B,MAAI,MAAM,SAAS,EAAG,QAAO;AAC7B,MAAI;AACF,UAAM,OAAO,KAAK,MAAM,CAAC,EAAE,QAAQ,MAAM,GAAG,EAAE,QAAQ,MAAM,GAAG,CAAC;AAChE,UAAM,SAAkB,KAAK,MAAM,IAAI;AACvC,WAAO,UAAU,OAAO,WAAW,WAAY,SAAqC;AAAA,EACtF,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,oBAA4B;AACnC,SAAO,gBAAgB,YAAY,EAAE,CAAC;AACxC;AAEA,SAAS,iBAAiB,GAAgB;AACxC,SAAO,IAAI,IAAI,CAAC;AAClB;AAGA,SAASA,qBAAoB,OAAe,QAAwB;AAClE,QAAM,MAAM;AACZ,QAAM,SAAS,IAAI,aAAa,IAAI,IAAI,aAAa,IAAI;AACzD,QAAM,SAAS,IAAI,cAAc,IAAI,IAAI,cAAc,IAAI;AAC3D,QAAM,UAAU,IAAI,WAAW,IAAI,cAAc;AACjD,QAAM,UAAU,IAAI,WAAW,IAAI,aAAa;AAChD,QAAM,OAAO,KAAK,MAAM,UAAU,KAAK,IAAI,IAAI,SAAS,SAAS,CAAC,CAAC;AACnE,QAAM,MAAM,KAAK,MAAM,UAAU,KAAK,IAAI,IAAI,SAAS,UAAU,CAAC,CAAC;AACnE,SAAO,SAAS,KAAK,WAAW,MAAM,SAAS,IAAI,QAAQ,GAAG;AAChE;AAGO,SAAS,qBAAqB,OAAyB;AAC5D,SAAO,iBAAiB,qBAAqB,MAAM,cAAc;AACnE;","names":["openSessionBridge","signOutWithXS","openSessionBridge","signOutWithXS","popupWindowFeatures"]}
package/dist/index.d.cts CHANGED
@@ -84,6 +84,9 @@ interface LoginWithXSOptions {
84
84
  clientId: string;
85
85
  /** Must be on your XS Auth client's allowed domains list (normally `window.location.origin`). */
86
86
  parentOrigin?: string;
87
+ /**
88
+ * Sign-in timeout in ms. Defaults to 180s to allow MFA verification in the Auth-Server popup.
89
+ */
87
90
  timeoutMs?: number;
88
91
  scope?: string;
89
92
  /**
@@ -103,11 +106,19 @@ interface LoginWithXSOptions {
103
106
  preferPrimary?: boolean;
104
107
  /** Override Auth-Server base URL (e.g. same-origin `/xs-auth` proxy in local dev). */
105
108
  authBaseUrl?: string;
109
+ /**
110
+ * Initial Auth-Server login page view.
111
+ * - `signin`: email/password sign-in (default)
112
+ * - `signup`: registration form ("Create one")
113
+ */
114
+ mode?: 'signin' | 'signup';
106
115
  }
107
116
  interface LoginWithXSResult {
108
117
  user: XSAuthUser;
109
118
  /** Short-lived signed JWT — send to your backend to create a session. */
110
119
  idToken: string;
120
+ /** True when the user completed MFA during this sign-in (`amr` includes `mfa`). */
121
+ mfaVerified: boolean;
111
122
  }
112
123
  /** PKCE helpers for tests / custom callers. */
113
124
  declare function createPkcePair(): Promise<{
@@ -121,7 +132,11 @@ declare function createPkcePair(): Promise<{
121
132
  * opens the popup and exchanges postMessages with the PKCE verifier — no fetch to Auth-Server.
122
133
  */
123
134
  declare function loginWithXS(opts: LoginWithXSOptions): Promise<LoginWithXSResult>;
135
+ /** True when an XS Auth idToken indicates MFA was completed at sign-in. */
136
+ declare function idTokenIncludesMfa(idToken: string): boolean;
137
+ /** Read the `amr` claim from an XS Auth idToken payload (no signature verification). */
138
+ declare function parseIdTokenAmr(idToken: string): string[] | null;
124
139
  /** True when Auth-Server has no active browser session for silent sign-in. */
125
140
  declare function isLoginRequiredError(error: unknown): boolean;
126
141
 
127
- export { LoginBridgeTimeoutError, LoginTimeoutError, type LoginWithXSOptions, type LoginWithXSResult, type OpenSessionBridgeOptions, PopupBlockedError, PopupClosedError, type SessionBridge, SessionBridgeError, type SignOutAction, type SignOutWithXSOptions, type SignOutWithXSResult, XSAuthDeniedError, type XSAuthUser, type XSBrowserAccount, createPkcePair, isLoginRequiredError, isPrimaryAccountError, loginWithXS, openSessionBridge, signOutWithXS };
142
+ export { LoginBridgeTimeoutError, LoginTimeoutError, type LoginWithXSOptions, type LoginWithXSResult, type OpenSessionBridgeOptions, PopupBlockedError, PopupClosedError, type SessionBridge, SessionBridgeError, type SignOutAction, type SignOutWithXSOptions, type SignOutWithXSResult, XSAuthDeniedError, type XSAuthUser, type XSBrowserAccount, createPkcePair, idTokenIncludesMfa, isLoginRequiredError, isPrimaryAccountError, loginWithXS, openSessionBridge, parseIdTokenAmr, signOutWithXS };
package/dist/index.d.ts CHANGED
@@ -84,6 +84,9 @@ interface LoginWithXSOptions {
84
84
  clientId: string;
85
85
  /** Must be on your XS Auth client's allowed domains list (normally `window.location.origin`). */
86
86
  parentOrigin?: string;
87
+ /**
88
+ * Sign-in timeout in ms. Defaults to 180s to allow MFA verification in the Auth-Server popup.
89
+ */
87
90
  timeoutMs?: number;
88
91
  scope?: string;
89
92
  /**
@@ -103,11 +106,19 @@ interface LoginWithXSOptions {
103
106
  preferPrimary?: boolean;
104
107
  /** Override Auth-Server base URL (e.g. same-origin `/xs-auth` proxy in local dev). */
105
108
  authBaseUrl?: string;
109
+ /**
110
+ * Initial Auth-Server login page view.
111
+ * - `signin`: email/password sign-in (default)
112
+ * - `signup`: registration form ("Create one")
113
+ */
114
+ mode?: 'signin' | 'signup';
106
115
  }
107
116
  interface LoginWithXSResult {
108
117
  user: XSAuthUser;
109
118
  /** Short-lived signed JWT — send to your backend to create a session. */
110
119
  idToken: string;
120
+ /** True when the user completed MFA during this sign-in (`amr` includes `mfa`). */
121
+ mfaVerified: boolean;
111
122
  }
112
123
  /** PKCE helpers for tests / custom callers. */
113
124
  declare function createPkcePair(): Promise<{
@@ -121,7 +132,11 @@ declare function createPkcePair(): Promise<{
121
132
  * opens the popup and exchanges postMessages with the PKCE verifier — no fetch to Auth-Server.
122
133
  */
123
134
  declare function loginWithXS(opts: LoginWithXSOptions): Promise<LoginWithXSResult>;
135
+ /** True when an XS Auth idToken indicates MFA was completed at sign-in. */
136
+ declare function idTokenIncludesMfa(idToken: string): boolean;
137
+ /** Read the `amr` claim from an XS Auth idToken payload (no signature verification). */
138
+ declare function parseIdTokenAmr(idToken: string): string[] | null;
124
139
  /** True when Auth-Server has no active browser session for silent sign-in. */
125
140
  declare function isLoginRequiredError(error: unknown): boolean;
126
141
 
127
- export { LoginBridgeTimeoutError, LoginTimeoutError, type LoginWithXSOptions, type LoginWithXSResult, type OpenSessionBridgeOptions, PopupBlockedError, PopupClosedError, type SessionBridge, SessionBridgeError, type SignOutAction, type SignOutWithXSOptions, type SignOutWithXSResult, XSAuthDeniedError, type XSAuthUser, type XSBrowserAccount, createPkcePair, isLoginRequiredError, isPrimaryAccountError, loginWithXS, openSessionBridge, signOutWithXS };
142
+ export { LoginBridgeTimeoutError, LoginTimeoutError, type LoginWithXSOptions, type LoginWithXSResult, type OpenSessionBridgeOptions, PopupBlockedError, PopupClosedError, type SessionBridge, SessionBridgeError, type SignOutAction, type SignOutWithXSOptions, type SignOutWithXSResult, XSAuthDeniedError, type XSAuthUser, type XSBrowserAccount, createPkcePair, idTokenIncludesMfa, isLoginRequiredError, isPrimaryAccountError, loginWithXS, openSessionBridge, parseIdTokenAmr, signOutWithXS };
package/dist/index.js CHANGED
@@ -404,7 +404,7 @@ async function loginWithXS(opts) {
404
404
  "loginWithXS requires a browser Window and explicit parentOrigin (or window.location)."
405
405
  );
406
406
  }
407
- const timeoutMs = opts.timeoutMs !== void 0 ? opts.timeoutMs : 12e4;
407
+ const timeoutMs = opts.timeoutMs !== void 0 ? opts.timeoutMs : 18e4;
408
408
  const state = randomBase64State();
409
409
  sessionStorage.setItem(STATE_KEY_STORAGE, state);
410
410
  const nonce = opts.useNonce ? randomBase64State() : void 0;
@@ -421,6 +421,7 @@ async function loginWithXS(opts) {
421
421
  if (nonce) params.set("nonce", nonce);
422
422
  const prompt = resolvePrompt(opts);
423
423
  if (prompt) params.set("prompt", prompt);
424
+ if (opts.mode === "signup") params.set("mode", "signup");
424
425
  if (opts.accountId?.trim()) params.set("account_id", opts.accountId.trim());
425
426
  maybeSetPublicPath(params, authBase);
426
427
  const authorizeUrl = `${normalizedBase.href.replace(/\/?$/u, "")}/authorize?${params.toString()}`;
@@ -492,7 +493,7 @@ async function loginWithXS(opts) {
492
493
  window.removeEventListener("message", handleMessage);
493
494
  clearInterval(closePoll);
494
495
  cleaned = true;
495
- resolve({ user, idToken });
496
+ resolve({ user, idToken, mfaVerified: idTokenIncludesMfa(idToken) });
496
497
  try {
497
498
  popup.close();
498
499
  } catch {
@@ -508,6 +509,31 @@ async function loginWithXS(opts) {
508
509
  }, 280);
509
510
  });
510
511
  }
512
+ function idTokenIncludesMfa(idToken) {
513
+ const amr = parseIdTokenAmr(idToken);
514
+ return Array.isArray(amr) && amr.includes("mfa");
515
+ }
516
+ function parseIdTokenAmr(idToken) {
517
+ const payload = parseJwtPayload(idToken);
518
+ if (!payload || !("amr" in payload)) return null;
519
+ const amr = payload.amr;
520
+ if (Array.isArray(amr)) {
521
+ return amr.filter((v) => typeof v === "string");
522
+ }
523
+ if (typeof amr === "string" && amr.trim()) return [amr.trim()];
524
+ return null;
525
+ }
526
+ function parseJwtPayload(token) {
527
+ const parts = token.split(".");
528
+ if (parts.length < 2) return null;
529
+ try {
530
+ const json = atob(parts[1].replace(/-/g, "+").replace(/_/g, "/"));
531
+ const parsed = JSON.parse(json);
532
+ return parsed && typeof parsed === "object" ? parsed : null;
533
+ } catch {
534
+ return null;
535
+ }
536
+ }
511
537
  function randomBase64State() {
512
538
  return base64UrlEncode(bytesBuffer(32));
513
539
  }
@@ -535,10 +561,12 @@ export {
535
561
  SessionBridgeError,
536
562
  XSAuthDeniedError,
537
563
  createPkcePair,
564
+ idTokenIncludesMfa,
538
565
  isLoginRequiredError,
539
566
  isPrimaryAccountError,
540
567
  loginWithXS,
541
568
  openSessionBridge2 as openSessionBridge,
569
+ parseIdTokenAmr,
542
570
  signOutWithXS2 as signOutWithXS
543
571
  };
544
572
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/session-bridge.ts","../src/sign-out.ts","../src/index.ts"],"sourcesContent":["/** Popup was blocked by the browser or environment. */\r\nexport class PopupBlockedError extends Error {\r\n readonly name = 'PopupBlockedError';\r\n}\r\n\r\n/** User closed the popup before completing login. */\r\nexport class PopupClosedError extends Error {\r\n readonly name = 'PopupClosedError';\r\n}\r\n\r\n/** XS Auth popup did not complete within timeout. */\r\nexport class LoginTimeoutError extends Error {\r\n readonly name = 'LoginTimeoutError';\r\n}\r\n\r\n/** XS Auth returned an OAuth-style error inside postMessage. */\r\nexport class XSAuthDeniedError extends Error {\r\n readonly name = 'XSAuthDeniedError';\r\n readonly errorCode: string;\r\n readonly description: string;\r\n\r\n constructor(errorCode: string, description: string) {\r\n super(description || errorCode || 'xs_auth_denied');\r\n this.errorCode = errorCode;\r\n this.description = description;\r\n }\r\n}\r\n\r\n/** Session bridge did not respond within timeout. */\r\nexport class LoginBridgeTimeoutError extends Error {\r\n readonly name = 'LoginBridgeTimeoutError';\r\n}\r\n","import {\r\n LoginBridgeTimeoutError,\r\n PopupBlockedError,\r\n PopupClosedError,\r\n} from './errors';\r\n\r\n/** XS Auth browser session account (multi-account SSO on the Auth-Server domain). */\r\nexport interface XSBrowserAccount {\r\n sessionId: string;\r\n userId: string;\r\n email: string;\r\n name: string;\r\n isPrimary: boolean;\r\n}\r\n\r\nexport interface OpenSessionBridgeOptions {\r\n clientId: string;\r\n parentOrigin?: string;\r\n timeoutMs?: number;\r\n}\r\n\r\nexport interface SessionBridge {\r\n listAccounts(): Promise<XSBrowserAccount[]>;\r\n revokeAccount(sessionId: string): Promise<{ accounts: XSBrowserAccount[]; remainingCount: number }>;\r\n revokeAll(): Promise<void>;\r\n setPrimary(sessionId: string): Promise<XSBrowserAccount[]>;\r\n close(): void;\r\n}\r\n\r\nexport class SessionBridgeError extends Error {\r\n readonly name = 'SessionBridgeError';\r\n readonly errorCode: string;\r\n\r\n constructor(errorCode: string, message: string) {\r\n super(message || errorCode);\r\n this.errorCode = errorCode;\r\n }\r\n}\r\n\r\ntype BridgeMessage = Partial<Record<string, unknown>>;\r\n\r\nconst BRIDGE_STATE_KEY = '__xs_bridge_state';\r\n\r\nfunction parseAccounts(raw: unknown): XSBrowserAccount[] {\r\n if (!Array.isArray(raw)) return [];\r\n return raw\r\n .map((item) => {\r\n if (!item || typeof item !== 'object') return null;\r\n const row = item as Record<string, unknown>;\r\n const sessionId =\r\n typeof row.sessionId === 'string'\r\n ? row.sessionId\r\n : typeof row.session_id === 'string'\r\n ? row.session_id\r\n : '';\r\n const userId =\r\n typeof row.userId === 'string'\r\n ? row.userId\r\n : typeof row.user_id === 'string'\r\n ? row.user_id\r\n : '';\r\n const email = typeof row.email === 'string' ? row.email : '';\r\n const name = typeof row.name === 'string' ? row.name : email;\r\n if (!sessionId || !email) return null;\r\n return {\r\n sessionId,\r\n userId,\r\n email,\r\n name,\r\n isPrimary: row.isPrimary === true || row.is_primary === true,\r\n };\r\n })\r\n .filter((x): x is XSBrowserAccount => x !== null);\r\n}\r\n\r\nfunction hiddenBridgePopupFeatures(): string {\r\n return 'width=1,height=1,left=-10000,top=-10000,resizable=no,scrollbars=no';\r\n}\r\n\r\nfunction randomBridgeState(): string {\r\n const bytes = new Uint8Array(32);\r\n crypto.getRandomValues(bytes);\r\n let binary = '';\r\n for (let i = 0; i < bytes.length; i++) {\r\n binary += String.fromCharCode(bytes[i]!);\r\n }\r\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/u, '');\r\n}\r\n\r\n/**\r\n * Opens a same-origin Auth-Server popup bridge so the host app can list and revoke\r\n * browser SSO sessions without cross-origin cookie access.\r\n */\r\nexport async function openSessionBridge(\r\n opts: OpenSessionBridgeOptions,\r\n authBaseUrl: string,\r\n): Promise<SessionBridge> {\r\n const parentOrigin = (opts.parentOrigin ?? globalThis.location?.origin) as string | undefined;\r\n if (!parentOrigin || typeof window === 'undefined') {\r\n throw new Error(\r\n 'openSessionBridge requires a browser Window and explicit parentOrigin (or window.location).',\r\n );\r\n }\r\n\r\n const normalizedBase = new URL(authBaseUrl);\r\n const authOrigin = normalizedBase.origin;\r\n const state = randomBridgeState();\r\n sessionStorage.setItem(BRIDGE_STATE_KEY, state);\r\n\r\n const params = new URLSearchParams({\r\n client_id: opts.clientId,\r\n parent_origin: parentOrigin,\r\n state,\r\n });\r\n\r\n const bridgeUrl = `${normalizedBase.href.replace(/\\/?$/u, '')}/session/bridge?${params.toString()}`;\r\n const popup = window.open(\r\n bridgeUrl,\r\n `xs-auth-bridge-${crypto.randomUUID()}`,\r\n hiddenBridgePopupFeatures(),\r\n );\r\n if (!popup) throw new PopupBlockedError();\r\n\r\n const timeoutMs = opts.timeoutMs !== undefined ? opts.timeoutMs : 120_000;\r\n let cleaned = false;\r\n let closePoll: ReturnType<typeof setInterval> | undefined;\r\n\r\n const teardown = (): void => {\r\n if (cleaned) return;\r\n cleaned = true;\r\n window.removeEventListener('message', handleMessage as EventListener);\r\n if (closePoll !== undefined) clearInterval(closePoll);\r\n sessionStorage.removeItem(BRIDGE_STATE_KEY);\r\n try {\r\n popup.close();\r\n } catch {\r\n // ignore\r\n }\r\n };\r\n\r\n const pending = new Map<\r\n string,\r\n {\r\n resolve: (value: BridgeMessage) => void;\r\n reject: (error: Error) => void;\r\n }\r\n >();\r\n\r\n let bridgeReady = false;\r\n let readyResolve: (() => void) | null = null;\r\n let readyReject: ((error: Error) => void) | null = null;\r\n\r\n const readyPromise = new Promise<void>((resolve, reject) => {\r\n readyResolve = resolve;\r\n readyReject = reject;\r\n });\r\n\r\n const handleMessage = (event: MessageEvent): void => {\r\n if (event.origin !== authOrigin) return;\r\n const d = event.data as BridgeMessage;\r\n if (d?.source !== 'xs-auth') return;\r\n\r\n const st = typeof d.state === 'string' ? d.state : '';\r\n if (!st || st !== sessionStorage.getItem(BRIDGE_STATE_KEY)) return;\r\n\r\n if (d.type === 'bridge_ready') {\r\n bridgeReady = true;\r\n readyResolve?.();\r\n return;\r\n }\r\n\r\n const requestId = typeof d.requestId === 'string' ? d.requestId : '';\r\n if (!requestId) return;\r\n\r\n const entry = pending.get(requestId);\r\n if (!entry) return;\r\n\r\n pending.delete(requestId);\r\n\r\n if (typeof d.error === 'string' && d.error.length > 0) {\r\n entry.reject(\r\n new SessionBridgeError(\r\n String(d.error),\r\n typeof d.error_description === 'string' ? d.error_description : '',\r\n ),\r\n );\r\n return;\r\n }\r\n\r\n if (d.type === 'result') {\r\n entry.resolve(d);\r\n }\r\n };\r\n\r\n window.addEventListener('message', handleMessage as EventListener);\r\n\r\n closePoll = window.setInterval(() => {\r\n if (!popup.closed) return;\r\n if (cleaned) return;\r\n for (const [, entry] of pending) {\r\n entry.reject(new PopupClosedError());\r\n }\r\n pending.clear();\r\n readyReject?.(new PopupClosedError());\r\n teardown();\r\n }, 280);\r\n\r\n const readyTimer = window.setTimeout(() => {\r\n if (bridgeReady) return;\r\n readyReject?.(new LoginBridgeTimeoutError());\r\n teardown();\r\n }, timeoutMs);\r\n\r\n try {\r\n await readyPromise;\r\n } catch (error) {\r\n clearTimeout(readyTimer);\r\n throw error;\r\n }\r\n clearTimeout(readyTimer);\r\n\r\n const sendRequest = (type: string, extra: Record<string, unknown> = {}): Promise<BridgeMessage> => {\r\n if (popup.closed) {\r\n return Promise.reject(new PopupClosedError());\r\n }\r\n\r\n const requestId = crypto.randomUUID();\r\n return new Promise<BridgeMessage>((resolve, reject) => {\r\n const timer = window.setTimeout(() => {\r\n pending.delete(requestId);\r\n reject(new LoginBridgeTimeoutError());\r\n }, timeoutMs);\r\n\r\n pending.set(requestId, {\r\n resolve: (value) => {\r\n clearTimeout(timer);\r\n resolve(value);\r\n },\r\n reject: (error) => {\r\n clearTimeout(timer);\r\n reject(error);\r\n },\r\n });\r\n\r\n try {\r\n popup.postMessage(\r\n {\r\n source: 'xs-auth-opener',\r\n state,\r\n client_id: opts.clientId,\r\n requestId,\r\n type,\r\n ...extra,\r\n },\r\n authOrigin,\r\n );\r\n } catch {\r\n pending.delete(requestId);\r\n clearTimeout(timer);\r\n reject(new SessionBridgeError('post_message_failed', 'Could not reach the session bridge.'));\r\n }\r\n });\r\n };\r\n\r\n return {\r\n async listAccounts() {\r\n const result = await sendRequest('list_accounts');\r\n return parseAccounts(result.accounts);\r\n },\r\n\r\n async revokeAccount(sessionId: string) {\r\n const result = await sendRequest('revoke', { session_id: sessionId.trim() });\r\n const accounts = parseAccounts(result.accounts);\r\n const remainingCount =\r\n typeof result.remainingCount === 'number' ? result.remainingCount : accounts.length;\r\n return { accounts, remainingCount };\r\n },\r\n\r\n async revokeAll() {\r\n await sendRequest('revoke_all');\r\n },\r\n\r\n async setPrimary(sessionId: string) {\r\n const result = await sendRequest('set_primary', { session_id: sessionId.trim() });\r\n return parseAccounts(result.accounts);\r\n },\r\n\r\n close() {\r\n teardown();\r\n },\r\n };\r\n}\r\n\r\n/** True when the user must pick another primary account before signing out. */\r\nexport function isPrimaryAccountError(error: unknown): boolean {\r\n return error instanceof SessionBridgeError && error.errorCode === 'primary_account';\r\n}\r\n","import {\r\n LoginBridgeTimeoutError,\r\n PopupBlockedError,\r\n PopupClosedError,\r\n} from './errors';\r\n\r\nexport interface SignOutWithXSOptions {\r\n clientId: string;\r\n parentOrigin?: string;\r\n /** XS Auth user id (`sub`) for the account active in the host app. */\r\n activeUserId?: string;\r\n timeoutMs?: number;\r\n /** Override Auth-Server base URL (e.g. same-origin `/xs-auth` proxy in local dev). */\r\n authBaseUrl?: string;\r\n}\r\n\r\nexport type SignOutAction = 'revoked_one' | 'revoked_all' | 'cancelled';\r\n\r\nexport interface SignOutWithXSResult {\r\n action: SignOutAction;\r\n revokedCurrent: boolean;\r\n remainingCount: number;\r\n}\r\n\r\nconst SIGN_OUT_STATE_KEY = '__xs_sign_out_state';\r\n\r\nfunction popupWindowFeatures(width: number, height: number): string {\r\n const win = window;\r\n const outerW = win.outerWidth > 0 ? win.outerWidth : win.innerWidth;\r\n const outerH = win.outerHeight > 0 ? win.outerHeight : win.innerHeight;\r\n const screenX = win.screenX ?? win.screenLeft ?? 0;\r\n const screenY = win.screenY ?? win.screenTop ?? 0;\r\n const left = Math.round(screenX + Math.max(0, (outerW - width) / 2));\r\n const top = Math.round(screenY + Math.max(0, (outerH - height) / 2));\r\n return `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes`;\r\n}\r\n\r\nfunction randomState(): string {\r\n const bytes = new Uint8Array(32);\r\n crypto.getRandomValues(bytes);\r\n let binary = '';\r\n for (let i = 0; i < bytes.length; i++) {\r\n binary += String.fromCharCode(bytes[i]!);\r\n }\r\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/u, '');\r\n}\r\n\r\nfunction parseSignOutResult(raw: SignOutAction, data: Record<string, unknown>): SignOutWithXSResult {\r\n return {\r\n action: raw,\r\n revokedCurrent: data.revokedCurrent === true,\r\n remainingCount:\r\n typeof data.remainingCount === 'number' && Number.isFinite(data.remainingCount)\r\n ? Math.max(0, data.remainingCount)\r\n : 0,\r\n };\r\n}\r\n\r\n/**\r\n * Opens a centered XS Auth popup to sign out of one or all browser SSO accounts\r\n * (Google-style account manager on the Auth-Server domain).\r\n */\r\nexport async function signOutWithXS(\r\n opts: SignOutWithXSOptions,\r\n authBaseUrl: string,\r\n): Promise<SignOutWithXSResult> {\r\n const parentOrigin = (opts.parentOrigin ?? globalThis.location?.origin) as string | undefined;\r\n if (!parentOrigin || typeof window === 'undefined') {\r\n throw new Error(\r\n 'signOutWithXS requires a browser Window and explicit parentOrigin (or window.location).',\r\n );\r\n }\r\n\r\n const normalizedBase = new URL(authBaseUrl);\r\n const authOrigin = normalizedBase.origin;\r\n const state = randomState();\r\n sessionStorage.setItem(SIGN_OUT_STATE_KEY, state);\r\n\r\n const params = new URLSearchParams({\r\n client_id: opts.clientId,\r\n parent_origin: parentOrigin,\r\n state,\r\n });\r\n if (opts.activeUserId?.trim()) {\r\n params.set('active_user_id', opts.activeUserId.trim());\r\n }\r\n\r\n const url = `${normalizedBase.href.replace(/\\/?$/u, '')}/session/sign-out?${params.toString()}`;\r\n const popup = window.open(\r\n url,\r\n `xs-auth-signout-${crypto.randomUUID()}`,\r\n popupWindowFeatures(480, 640),\r\n );\r\n if (!popup) throw new PopupBlockedError();\r\n\r\n const timeoutMs = opts.timeoutMs !== undefined ? opts.timeoutMs : 120_000;\r\n\r\n return await new Promise<SignOutWithXSResult>((resolve, reject) => {\r\n let cleaned = false;\r\n\r\n const teardown = (): void => {\r\n if (cleaned) return;\r\n cleaned = true;\r\n window.removeEventListener('message', handleMessage as EventListener);\r\n clearInterval(closePoll);\r\n clearTimeout(timer);\r\n sessionStorage.removeItem(SIGN_OUT_STATE_KEY);\r\n try {\r\n popup.close();\r\n } catch {\r\n // ignore\r\n }\r\n };\r\n\r\n const fail = (error: Error): void => {\r\n teardown();\r\n reject(error);\r\n };\r\n\r\n const timer = window.setTimeout(() => {\r\n fail(new LoginBridgeTimeoutError());\r\n }, timeoutMs);\r\n\r\n const handleMessage = (event: MessageEvent): void => {\r\n if (event.origin !== authOrigin) return;\r\n const d = event.data as Partial<Record<string, unknown>>;\r\n if (d?.source !== 'xs-auth') return;\r\n\r\n const st = typeof d.state === 'string' ? d.state : '';\r\n if (!st || st !== sessionStorage.getItem(SIGN_OUT_STATE_KEY)) return;\r\n\r\n if (d.type === 'sign_out_cancelled') {\r\n teardown();\r\n resolve(parseSignOutResult('cancelled', d));\r\n return;\r\n }\r\n\r\n if (d.type === 'sign_out_complete') {\r\n teardown();\r\n const actionRaw = typeof d.action === 'string' ? d.action : 'revoked_one';\r\n const action: SignOutAction =\r\n actionRaw === 'revoked_all'\r\n ? 'revoked_all'\r\n : actionRaw === 'cancelled'\r\n ? 'cancelled'\r\n : 'revoked_one';\r\n resolve(parseSignOutResult(action, d));\r\n }\r\n };\r\n\r\n window.addEventListener('message', handleMessage as EventListener);\r\n\r\n const closePoll = window.setInterval(() => {\r\n if (!popup.closed) return;\r\n if (cleaned) return;\r\n if (!sessionStorage.getItem(SIGN_OUT_STATE_KEY)) return;\r\n fail(new PopupClosedError());\r\n }, 280);\r\n });\r\n}\r\n","import {\r\n LoginTimeoutError,\r\n PopupBlockedError,\r\n PopupClosedError,\r\n XSAuthDeniedError,\r\n} from './errors';\r\nimport {\r\n isPrimaryAccountError,\r\n openSessionBridge as openSessionBridgeInternal,\r\n SessionBridgeError,\r\n type OpenSessionBridgeOptions,\r\n type SessionBridge,\r\n type XSBrowserAccount,\r\n} from './session-bridge';\r\n\r\nimport {\r\n signOutWithXS as signOutWithXSInternal,\r\n type SignOutAction,\r\n type SignOutWithXSOptions,\r\n type SignOutWithXSResult,\r\n} from './sign-out';\r\n\r\nexport {\r\n LoginBridgeTimeoutError,\r\n LoginTimeoutError,\r\n PopupBlockedError,\r\n PopupClosedError,\r\n XSAuthDeniedError,\r\n} from './errors';\r\n\r\nexport {\r\n isPrimaryAccountError,\r\n SessionBridgeError,\r\n type OpenSessionBridgeOptions,\r\n type SessionBridge,\r\n type XSBrowserAccount,\r\n};\r\n\r\nexport {\r\n type SignOutAction,\r\n type SignOutWithXSOptions,\r\n type SignOutWithXSResult,\r\n};\r\n\r\n/** XS Auth server — baked in at build time (local vs production). */\r\nconst XS_AUTH_BASE_URL = __XS_AUTH_BASE_URL__;\r\n\r\n/** Opens the Auth-Server session bridge popup (multi-account sign-out). */\r\nexport function openSessionBridge(\r\n opts: OpenSessionBridgeOptions,\r\n): Promise<SessionBridge> {\r\n return openSessionBridgeInternal(opts, XS_AUTH_BASE_URL);\r\n}\r\n\r\n/** Google-style sign-out popup on the Auth-Server domain. */\r\nexport function signOutWithXS(opts: SignOutWithXSOptions): Promise<SignOutWithXSResult> {\r\n const authBase = opts.authBaseUrl?.trim() || XS_AUTH_BASE_URL;\r\n return signOutWithXSInternal(opts, authBase);\r\n}\r\n\r\n/** Signed-in user profile from XS Auth. */\r\nexport interface XSAuthUser {\r\n email: string;\r\n firstName?: string;\r\n lastName?: string;\r\n}\r\n\r\nexport interface LoginWithXSOptions {\r\n /** Your app's public client id from Xino Solutions. */\r\n clientId: string;\r\n /** Must be on your XS Auth client's allowed domains list (normally `window.location.origin`). */\r\n parentOrigin?: string;\r\n timeoutMs?: number;\r\n scope?: string;\r\n /**\r\n * Request a `nonce` inside `idToken` — your backend should verify it matches when validating the JWT.\r\n */\r\n useNonce?: boolean;\r\n /**\r\n * OAuth-style prompt for multi-account SSO on the Auth-Server domain.\r\n * - `none`: silent sign-in with the primary browser session (fails with `login_required` if absent)\r\n * - `select_account`: always show the account chooser when sessions exist\r\n * - `login`: force email/password (add another account)\r\n */\r\n prompt?: 'none' | 'select_account' | 'login';\r\n /** Prefer a specific XS Auth user id (`sub`) when continuing an existing browser session. */\r\n accountId?: string;\r\n /** When true and `prompt` is unset, defaults to `none` instead of account chooser. */\r\n preferPrimary?: boolean;\r\n /** Override Auth-Server base URL (e.g. same-origin `/xs-auth` proxy in local dev). */\r\n authBaseUrl?: string;\r\n}\r\n\r\nexport interface LoginWithXSResult {\r\n user: XSAuthUser;\r\n /** Short-lived signed JWT — send to your backend to create a session. */\r\n idToken: string;\r\n}\r\n\r\nfunction bytesBuffer(len: number): Uint8Array {\r\n const out = new Uint8Array(len);\r\n crypto.getRandomValues(out);\r\n return out;\r\n}\r\n\r\nfunction base64UrlEncode(buf: Uint8Array | ArrayBuffer): string {\r\n const bytes = buf instanceof Uint8Array ? buf : new Uint8Array(buf);\r\n let binary = '';\r\n const chunkSize = 0x8000;\r\n for (let i = 0; i < bytes.length; i += chunkSize) {\r\n binary += String.fromCharCode(...bytes.subarray(i, i + chunkSize));\r\n }\r\n const b64 = btoa(binary);\r\n return b64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/u, '');\r\n}\r\n\r\nasync function pkceVerifierAndChallenge(): Promise<{\r\n verifier: string;\r\n challenge: string;\r\n}> {\r\n const verifier = base64UrlEncode(bytesBuffer(64));\r\n const data = new TextEncoder().encode(verifier);\r\n const digest = await crypto.subtle.digest('SHA-256', data);\r\n const challenge = base64UrlEncode(digest);\r\n return { verifier, challenge };\r\n}\r\n\r\n/** PKCE helpers for tests / custom callers. */\r\nexport async function createPkcePair(): Promise<{\r\n verifier: string;\r\n challenge: string;\r\n}> {\r\n return pkceVerifierAndChallenge();\r\n}\r\n\r\nconst STATE_KEY_STORAGE = '__xs_login_state';\r\n\r\nfunction parseSdkUser(raw: unknown): XSAuthUser | null {\r\n if (!raw || typeof raw !== 'object') return null;\r\n const u = raw as Record<string, unknown>;\r\n const email = typeof u.email === 'string' ? u.email.trim() : '';\r\n if (!email) return null;\r\n const user: XSAuthUser = { email };\r\n const firstName =\r\n typeof u.firstName === 'string' ? u.firstName.trim() : '';\r\n const lastName = typeof u.lastName === 'string' ? u.lastName.trim() : '';\r\n if (firstName) user.firstName = firstName;\r\n if (lastName) user.lastName = lastName;\r\n return user;\r\n}\r\n\r\nfunction resolvePrompt(opts: LoginWithXSOptions): string | undefined {\r\n if (opts.prompt) return opts.prompt;\r\n if (opts.preferPrimary) return 'none';\r\n return undefined;\r\n}\r\n\r\nfunction authPublicPathFromBase(authBaseUrl: string): string {\r\n try {\r\n const pathname = new URL(authBaseUrl).pathname.replace(/\\/$/u, '');\r\n return pathname === '/' ? '' : pathname;\r\n } catch {\r\n return '';\r\n }\r\n}\r\n\r\nfunction maybeSetPublicPath(params: URLSearchParams, authBaseUrl: string): void {\r\n const publicPath = authPublicPathFromBase(authBaseUrl);\r\n if (publicPath) params.set('public_path', publicPath);\r\n}\r\n\r\n/**\r\n * Opens the XS Auth sign-in popup and returns the signed-in user plus a verifiable `idToken`.\r\n *\r\n * All Auth-Server HTTP calls happen inside the popup (same origin). The host app only\r\n * opens the popup and exchanges postMessages with the PKCE verifier — no fetch to Auth-Server.\r\n */\r\nexport async function loginWithXS(\r\n opts: LoginWithXSOptions,\r\n): Promise<LoginWithXSResult> {\r\n const authBase = opts.authBaseUrl?.trim() || XS_AUTH_BASE_URL;\r\n const normalizedBase = normalizeBaseUrl(authBase);\r\n const authOrigin = normalizedBase.origin;\r\n const parentOrigin = (opts.parentOrigin ?? globalThis.location?.origin) as\r\n | string\r\n | undefined;\r\n if (!parentOrigin || typeof window === 'undefined') {\r\n throw new Error(\r\n 'loginWithXS requires a browser Window and explicit parentOrigin (or window.location).',\r\n );\r\n }\r\n\r\n const timeoutMs =\r\n opts.timeoutMs !== undefined ? opts.timeoutMs : 120_000;\r\n\r\n const state = randomBase64State();\r\n sessionStorage.setItem(STATE_KEY_STORAGE, state);\r\n\r\n const nonce = opts.useNonce ? randomBase64State() : undefined;\r\n const pair = await pkceVerifierAndChallenge();\r\n\r\n const params = new URLSearchParams({\r\n client_id: opts.clientId,\r\n state,\r\n code_challenge: pair.challenge,\r\n code_challenge_method: 'S256',\r\n parent_origin: parentOrigin,\r\n response_mode: 'popup',\r\n });\r\n if (opts.scope?.trim()) params.set('scope', opts.scope.trim());\r\n if (nonce) params.set('nonce', nonce);\r\n const prompt = resolvePrompt(opts);\r\n if (prompt) params.set('prompt', prompt);\r\n if (opts.accountId?.trim()) params.set('account_id', opts.accountId.trim());\r\n maybeSetPublicPath(params, authBase);\r\n\r\n const authorizeUrl = `${normalizedBase.href.replace(/\\/?$/u, '')}/authorize?${params.toString()}`;\r\n\r\n const popupWidth = prompt === 'none' ? 420 : 480;\r\n const popupHeight = prompt === 'none' ? 120 : 640;\r\n const popup = window.open(\r\n authorizeUrl,\r\n `xs-auth-${crypto.randomUUID()}`,\r\n popupWindowFeatures(popupWidth, popupHeight),\r\n );\r\n if (!popup) throw new PopupBlockedError();\r\n\r\n return await new Promise<LoginWithXSResult>((resolve, reject) => {\r\n let cleaned = false;\r\n const teardown = (): void => {\r\n if (cleaned) return;\r\n cleaned = true;\r\n window.removeEventListener('message', handleMessage as EventListener);\r\n clearInterval(closePoll);\r\n clearTimeout(timer);\r\n try {\r\n popup.close();\r\n } catch {\r\n // ignore\r\n }\r\n };\r\n\r\n const fail = (e: unknown): void => {\r\n teardown();\r\n reject(e instanceof Error ? e : new Error(String(e)));\r\n };\r\n\r\n const timer = window.setTimeout(() => {\r\n fail(new LoginTimeoutError());\r\n }, timeoutMs);\r\n\r\n const handleMessage = (event: MessageEvent): void => {\r\n if (event.origin !== authOrigin) return;\r\n const d = event.data as Partial<Record<string, unknown>>;\r\n if (d?.source !== 'xs-auth') return;\r\n\r\n const st = typeof d.state === 'string' ? d.state : '';\r\n if (!st || st !== sessionStorage.getItem(STATE_KEY_STORAGE)) return;\r\n\r\n if (typeof d.error === 'string' && d.error.length > 0) {\r\n teardown();\r\n reject(\r\n new XSAuthDeniedError(\r\n String(d.error),\r\n typeof d.error_description === 'string'\r\n ? d.error_description\r\n : '',\r\n ),\r\n );\r\n return;\r\n }\r\n\r\n if (d.type === 'need_verifier') {\r\n try {\r\n popup.postMessage(\r\n {\r\n source: 'xs-auth-opener',\r\n state: st,\r\n code_verifier: pair.verifier,\r\n client_id: opts.clientId,\r\n },\r\n authOrigin,\r\n );\r\n } catch {\r\n fail(new XSAuthDeniedError('exchange_failed', 'Sign in could not be completed.'));\r\n }\r\n return;\r\n }\r\n\r\n const idToken =\r\n typeof d.id_token === 'string'\r\n ? d.id_token\r\n : typeof d.idToken === 'string'\r\n ? d.idToken\r\n : '';\r\n const user = parseSdkUser(d.user);\r\n if (!idToken || !user) return;\r\n\r\n sessionStorage.removeItem(STATE_KEY_STORAGE);\r\n clearTimeout(timer);\r\n window.removeEventListener('message', handleMessage as EventListener);\r\n clearInterval(closePoll);\r\n cleaned = true;\r\n\r\n resolve({ user, idToken });\r\n\r\n try {\r\n popup.close();\r\n } catch {\r\n // ignore\r\n }\r\n };\r\n\r\n window.addEventListener('message', handleMessage as EventListener);\r\n\r\n const closePoll = window.setInterval(() => {\r\n if (!popup.closed) return;\r\n if (cleaned) return;\r\n const pending = sessionStorage.getItem(STATE_KEY_STORAGE);\r\n if (!pending) return;\r\n fail(new PopupClosedError());\r\n }, 280);\r\n });\r\n}\r\n\r\nfunction randomBase64State(): string {\r\n return base64UrlEncode(bytesBuffer(32));\r\n}\r\n\r\nfunction normalizeBaseUrl(s: string): URL {\r\n return new URL(s);\r\n}\r\n\r\n/** Center popup over the opener window (falls back to screen center). */\r\nfunction popupWindowFeatures(width: number, height: number): string {\r\n const win = window;\r\n const outerW = win.outerWidth > 0 ? win.outerWidth : win.innerWidth;\r\n const outerH = win.outerHeight > 0 ? win.outerHeight : win.innerHeight;\r\n const screenX = win.screenX ?? win.screenLeft ?? 0;\r\n const screenY = win.screenY ?? win.screenTop ?? 0;\r\n const left = Math.round(screenX + Math.max(0, (outerW - width) / 2));\r\n const top = Math.round(screenY + Math.max(0, (outerH - height) / 2));\r\n return `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes`;\r\n}\r\n\r\n/** True when Auth-Server has no active browser session for silent sign-in. */\r\nexport function isLoginRequiredError(error: unknown): boolean {\r\n return error instanceof XSAuthDeniedError && error.errorCode === 'login_required';\r\n}\r\n"],"mappings":";AACO,IAAM,oBAAN,cAAgC,MAAM;AAAA,EAClC,OAAO;AAClB;AAGO,IAAM,mBAAN,cAA+B,MAAM;AAAA,EACjC,OAAO;AAClB;AAGO,IAAM,oBAAN,cAAgC,MAAM;AAAA,EAClC,OAAO;AAClB;AAGO,IAAM,oBAAN,cAAgC,MAAM;AAAA,EAClC,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EAET,YAAY,WAAmB,aAAqB;AAClD,UAAM,eAAe,aAAa,gBAAgB;AAClD,SAAK,YAAY;AACjB,SAAK,cAAc;AAAA,EACrB;AACF;AAGO,IAAM,0BAAN,cAAsC,MAAM;AAAA,EACxC,OAAO;AAClB;;;ACFO,IAAM,qBAAN,cAAiC,MAAM;AAAA,EACnC,OAAO;AAAA,EACP;AAAA,EAET,YAAY,WAAmB,SAAiB;AAC9C,UAAM,WAAW,SAAS;AAC1B,SAAK,YAAY;AAAA,EACnB;AACF;AAIA,IAAM,mBAAmB;AAEzB,SAAS,cAAc,KAAkC;AACvD,MAAI,CAAC,MAAM,QAAQ,GAAG,EAAG,QAAO,CAAC;AACjC,SAAO,IACJ,IAAI,CAAC,SAAS;AACb,QAAI,CAAC,QAAQ,OAAO,SAAS,SAAU,QAAO;AAC9C,UAAM,MAAM;AACZ,UAAM,YACJ,OAAO,IAAI,cAAc,WACrB,IAAI,YACJ,OAAO,IAAI,eAAe,WACxB,IAAI,aACJ;AACR,UAAM,SACJ,OAAO,IAAI,WAAW,WAClB,IAAI,SACJ,OAAO,IAAI,YAAY,WACrB,IAAI,UACJ;AACR,UAAM,QAAQ,OAAO,IAAI,UAAU,WAAW,IAAI,QAAQ;AAC1D,UAAM,OAAO,OAAO,IAAI,SAAS,WAAW,IAAI,OAAO;AACvD,QAAI,CAAC,aAAa,CAAC,MAAO,QAAO;AACjC,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW,IAAI,cAAc,QAAQ,IAAI,eAAe;AAAA,IAC1D;AAAA,EACF,CAAC,EACA,OAAO,CAAC,MAA6B,MAAM,IAAI;AACpD;AAEA,SAAS,4BAAoC;AAC3C,SAAO;AACT;AAEA,SAAS,oBAA4B;AACnC,QAAM,QAAQ,IAAI,WAAW,EAAE;AAC/B,SAAO,gBAAgB,KAAK;AAC5B,MAAI,SAAS;AACb,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,cAAU,OAAO,aAAa,MAAM,CAAC,CAAE;AAAA,EACzC;AACA,SAAO,KAAK,MAAM,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,QAAQ,EAAE;AAChF;AAMA,eAAsB,kBACpB,MACA,aACwB;AACxB,QAAM,eAAgB,KAAK,gBAAgB,WAAW,UAAU;AAChE,MAAI,CAAC,gBAAgB,OAAO,WAAW,aAAa;AAClD,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,iBAAiB,IAAI,IAAI,WAAW;AAC1C,QAAM,aAAa,eAAe;AAClC,QAAM,QAAQ,kBAAkB;AAChC,iBAAe,QAAQ,kBAAkB,KAAK;AAE9C,QAAM,SAAS,IAAI,gBAAgB;AAAA,IACjC,WAAW,KAAK;AAAA,IAChB,eAAe;AAAA,IACf;AAAA,EACF,CAAC;AAED,QAAM,YAAY,GAAG,eAAe,KAAK,QAAQ,SAAS,EAAE,CAAC,mBAAmB,OAAO,SAAS,CAAC;AACjG,QAAM,QAAQ,OAAO;AAAA,IACnB;AAAA,IACA,kBAAkB,OAAO,WAAW,CAAC;AAAA,IACrC,0BAA0B;AAAA,EAC5B;AACA,MAAI,CAAC,MAAO,OAAM,IAAI,kBAAkB;AAExC,QAAM,YAAY,KAAK,cAAc,SAAY,KAAK,YAAY;AAClE,MAAI,UAAU;AACd,MAAI;AAEJ,QAAM,WAAW,MAAY;AAC3B,QAAI,QAAS;AACb,cAAU;AACV,WAAO,oBAAoB,WAAW,aAA8B;AACpE,QAAI,cAAc,OAAW,eAAc,SAAS;AACpD,mBAAe,WAAW,gBAAgB;AAC1C,QAAI;AACF,YAAM,MAAM;AAAA,IACd,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,QAAM,UAAU,oBAAI,IAMlB;AAEF,MAAI,cAAc;AAClB,MAAI,eAAoC;AACxC,MAAI,cAA+C;AAEnD,QAAM,eAAe,IAAI,QAAc,CAAC,SAAS,WAAW;AAC1D,mBAAe;AACf,kBAAc;AAAA,EAChB,CAAC;AAED,QAAM,gBAAgB,CAAC,UAA8B;AACnD,QAAI,MAAM,WAAW,WAAY;AACjC,UAAM,IAAI,MAAM;AAChB,QAAI,GAAG,WAAW,UAAW;AAE7B,UAAM,KAAK,OAAO,EAAE,UAAU,WAAW,EAAE,QAAQ;AACnD,QAAI,CAAC,MAAM,OAAO,eAAe,QAAQ,gBAAgB,EAAG;AAE5D,QAAI,EAAE,SAAS,gBAAgB;AAC7B,oBAAc;AACd,qBAAe;AACf;AAAA,IACF;AAEA,UAAM,YAAY,OAAO,EAAE,cAAc,WAAW,EAAE,YAAY;AAClE,QAAI,CAAC,UAAW;AAEhB,UAAM,QAAQ,QAAQ,IAAI,SAAS;AACnC,QAAI,CAAC,MAAO;AAEZ,YAAQ,OAAO,SAAS;AAExB,QAAI,OAAO,EAAE,UAAU,YAAY,EAAE,MAAM,SAAS,GAAG;AACrD,YAAM;AAAA,QACJ,IAAI;AAAA,UACF,OAAO,EAAE,KAAK;AAAA,UACd,OAAO,EAAE,sBAAsB,WAAW,EAAE,oBAAoB;AAAA,QAClE;AAAA,MACF;AACA;AAAA,IACF;AAEA,QAAI,EAAE,SAAS,UAAU;AACvB,YAAM,QAAQ,CAAC;AAAA,IACjB;AAAA,EACF;AAEA,SAAO,iBAAiB,WAAW,aAA8B;AAEjE,cAAY,OAAO,YAAY,MAAM;AACnC,QAAI,CAAC,MAAM,OAAQ;AACnB,QAAI,QAAS;AACb,eAAW,CAAC,EAAE,KAAK,KAAK,SAAS;AAC/B,YAAM,OAAO,IAAI,iBAAiB,CAAC;AAAA,IACrC;AACA,YAAQ,MAAM;AACd,kBAAc,IAAI,iBAAiB,CAAC;AACpC,aAAS;AAAA,EACX,GAAG,GAAG;AAEN,QAAM,aAAa,OAAO,WAAW,MAAM;AACzC,QAAI,YAAa;AACjB,kBAAc,IAAI,wBAAwB,CAAC;AAC3C,aAAS;AAAA,EACX,GAAG,SAAS;AAEZ,MAAI;AACF,UAAM;AAAA,EACR,SAAS,OAAO;AACd,iBAAa,UAAU;AACvB,UAAM;AAAA,EACR;AACA,eAAa,UAAU;AAEvB,QAAM,cAAc,CAAC,MAAc,QAAiC,CAAC,MAA8B;AACjG,QAAI,MAAM,QAAQ;AAChB,aAAO,QAAQ,OAAO,IAAI,iBAAiB,CAAC;AAAA,IAC9C;AAEA,UAAM,YAAY,OAAO,WAAW;AACpC,WAAO,IAAI,QAAuB,CAAC,SAAS,WAAW;AACrD,YAAM,QAAQ,OAAO,WAAW,MAAM;AACpC,gBAAQ,OAAO,SAAS;AACxB,eAAO,IAAI,wBAAwB,CAAC;AAAA,MACtC,GAAG,SAAS;AAEZ,cAAQ,IAAI,WAAW;AAAA,QACrB,SAAS,CAAC,UAAU;AAClB,uBAAa,KAAK;AAClB,kBAAQ,KAAK;AAAA,QACf;AAAA,QACA,QAAQ,CAAC,UAAU;AACjB,uBAAa,KAAK;AAClB,iBAAO,KAAK;AAAA,QACd;AAAA,MACF,CAAC;AAED,UAAI;AACF,cAAM;AAAA,UACJ;AAAA,YACE,QAAQ;AAAA,YACR;AAAA,YACA,WAAW,KAAK;AAAA,YAChB;AAAA,YACA;AAAA,YACA,GAAG;AAAA,UACL;AAAA,UACA;AAAA,QACF;AAAA,MACF,QAAQ;AACN,gBAAQ,OAAO,SAAS;AACxB,qBAAa,KAAK;AAClB,eAAO,IAAI,mBAAmB,uBAAuB,qCAAqC,CAAC;AAAA,MAC7F;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL,MAAM,eAAe;AACnB,YAAM,SAAS,MAAM,YAAY,eAAe;AAChD,aAAO,cAAc,OAAO,QAAQ;AAAA,IACtC;AAAA,IAEA,MAAM,cAAc,WAAmB;AACrC,YAAM,SAAS,MAAM,YAAY,UAAU,EAAE,YAAY,UAAU,KAAK,EAAE,CAAC;AAC3E,YAAM,WAAW,cAAc,OAAO,QAAQ;AAC9C,YAAM,iBACJ,OAAO,OAAO,mBAAmB,WAAW,OAAO,iBAAiB,SAAS;AAC/E,aAAO,EAAE,UAAU,eAAe;AAAA,IACpC;AAAA,IAEA,MAAM,YAAY;AAChB,YAAM,YAAY,YAAY;AAAA,IAChC;AAAA,IAEA,MAAM,WAAW,WAAmB;AAClC,YAAM,SAAS,MAAM,YAAY,eAAe,EAAE,YAAY,UAAU,KAAK,EAAE,CAAC;AAChF,aAAO,cAAc,OAAO,QAAQ;AAAA,IACtC;AAAA,IAEA,QAAQ;AACN,eAAS;AAAA,IACX;AAAA,EACF;AACF;AAGO,SAAS,sBAAsB,OAAyB;AAC7D,SAAO,iBAAiB,sBAAsB,MAAM,cAAc;AACpE;;;AChRA,IAAM,qBAAqB;AAE3B,SAAS,oBAAoB,OAAe,QAAwB;AAClE,QAAM,MAAM;AACZ,QAAM,SAAS,IAAI,aAAa,IAAI,IAAI,aAAa,IAAI;AACzD,QAAM,SAAS,IAAI,cAAc,IAAI,IAAI,cAAc,IAAI;AAC3D,QAAM,UAAU,IAAI,WAAW,IAAI,cAAc;AACjD,QAAM,UAAU,IAAI,WAAW,IAAI,aAAa;AAChD,QAAM,OAAO,KAAK,MAAM,UAAU,KAAK,IAAI,IAAI,SAAS,SAAS,CAAC,CAAC;AACnE,QAAM,MAAM,KAAK,MAAM,UAAU,KAAK,IAAI,IAAI,SAAS,UAAU,CAAC,CAAC;AACnE,SAAO,SAAS,KAAK,WAAW,MAAM,SAAS,IAAI,QAAQ,GAAG;AAChE;AAEA,SAAS,cAAsB;AAC7B,QAAM,QAAQ,IAAI,WAAW,EAAE;AAC/B,SAAO,gBAAgB,KAAK;AAC5B,MAAI,SAAS;AACb,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,cAAU,OAAO,aAAa,MAAM,CAAC,CAAE;AAAA,EACzC;AACA,SAAO,KAAK,MAAM,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,QAAQ,EAAE;AAChF;AAEA,SAAS,mBAAmB,KAAoB,MAAoD;AAClG,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,gBAAgB,KAAK,mBAAmB;AAAA,IACxC,gBACE,OAAO,KAAK,mBAAmB,YAAY,OAAO,SAAS,KAAK,cAAc,IAC1E,KAAK,IAAI,GAAG,KAAK,cAAc,IAC/B;AAAA,EACR;AACF;AAMA,eAAsB,cACpB,MACA,aAC8B;AAC9B,QAAM,eAAgB,KAAK,gBAAgB,WAAW,UAAU;AAChE,MAAI,CAAC,gBAAgB,OAAO,WAAW,aAAa;AAClD,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,iBAAiB,IAAI,IAAI,WAAW;AAC1C,QAAM,aAAa,eAAe;AAClC,QAAM,QAAQ,YAAY;AAC1B,iBAAe,QAAQ,oBAAoB,KAAK;AAEhD,QAAM,SAAS,IAAI,gBAAgB;AAAA,IACjC,WAAW,KAAK;AAAA,IAChB,eAAe;AAAA,IACf;AAAA,EACF,CAAC;AACD,MAAI,KAAK,cAAc,KAAK,GAAG;AAC7B,WAAO,IAAI,kBAAkB,KAAK,aAAa,KAAK,CAAC;AAAA,EACvD;AAEA,QAAM,MAAM,GAAG,eAAe,KAAK,QAAQ,SAAS,EAAE,CAAC,qBAAqB,OAAO,SAAS,CAAC;AAC7F,QAAM,QAAQ,OAAO;AAAA,IACnB;AAAA,IACA,mBAAmB,OAAO,WAAW,CAAC;AAAA,IACtC,oBAAoB,KAAK,GAAG;AAAA,EAC9B;AACA,MAAI,CAAC,MAAO,OAAM,IAAI,kBAAkB;AAExC,QAAM,YAAY,KAAK,cAAc,SAAY,KAAK,YAAY;AAElE,SAAO,MAAM,IAAI,QAA6B,CAAC,SAAS,WAAW;AACjE,QAAI,UAAU;AAEd,UAAM,WAAW,MAAY;AAC3B,UAAI,QAAS;AACb,gBAAU;AACV,aAAO,oBAAoB,WAAW,aAA8B;AACpE,oBAAc,SAAS;AACvB,mBAAa,KAAK;AAClB,qBAAe,WAAW,kBAAkB;AAC5C,UAAI;AACF,cAAM,MAAM;AAAA,MACd,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,UAAM,OAAO,CAAC,UAAuB;AACnC,eAAS;AACT,aAAO,KAAK;AAAA,IACd;AAEA,UAAM,QAAQ,OAAO,WAAW,MAAM;AACpC,WAAK,IAAI,wBAAwB,CAAC;AAAA,IACpC,GAAG,SAAS;AAEZ,UAAM,gBAAgB,CAAC,UAA8B;AACnD,UAAI,MAAM,WAAW,WAAY;AACjC,YAAM,IAAI,MAAM;AAChB,UAAI,GAAG,WAAW,UAAW;AAE7B,YAAM,KAAK,OAAO,EAAE,UAAU,WAAW,EAAE,QAAQ;AACnD,UAAI,CAAC,MAAM,OAAO,eAAe,QAAQ,kBAAkB,EAAG;AAE9D,UAAI,EAAE,SAAS,sBAAsB;AACnC,iBAAS;AACT,gBAAQ,mBAAmB,aAAa,CAAC,CAAC;AAC1C;AAAA,MACF;AAEA,UAAI,EAAE,SAAS,qBAAqB;AAClC,iBAAS;AACT,cAAM,YAAY,OAAO,EAAE,WAAW,WAAW,EAAE,SAAS;AAC5D,cAAM,SACJ,cAAc,gBACV,gBACA,cAAc,cACZ,cACA;AACR,gBAAQ,mBAAmB,QAAQ,CAAC,CAAC;AAAA,MACvC;AAAA,IACF;AAEA,WAAO,iBAAiB,WAAW,aAA8B;AAEjE,UAAM,YAAY,OAAO,YAAY,MAAM;AACzC,UAAI,CAAC,MAAM,OAAQ;AACnB,UAAI,QAAS;AACb,UAAI,CAAC,eAAe,QAAQ,kBAAkB,EAAG;AACjD,WAAK,IAAI,iBAAiB,CAAC;AAAA,IAC7B,GAAG,GAAG;AAAA,EACR,CAAC;AACH;;;AClHA,IAAM,mBAAmB;AAGlB,SAASA,mBACd,MACwB;AACxB,SAAO,kBAA0B,MAAM,gBAAgB;AACzD;AAGO,SAASC,eAAc,MAA0D;AACtF,QAAM,WAAW,KAAK,aAAa,KAAK,KAAK;AAC7C,SAAO,cAAsB,MAAM,QAAQ;AAC7C;AAyCA,SAAS,YAAY,KAAyB;AAC5C,QAAM,MAAM,IAAI,WAAW,GAAG;AAC9B,SAAO,gBAAgB,GAAG;AAC1B,SAAO;AACT;AAEA,SAAS,gBAAgB,KAAuC;AAC9D,QAAM,QAAQ,eAAe,aAAa,MAAM,IAAI,WAAW,GAAG;AAClE,MAAI,SAAS;AACb,QAAM,YAAY;AAClB,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,WAAW;AAChD,cAAU,OAAO,aAAa,GAAG,MAAM,SAAS,GAAG,IAAI,SAAS,CAAC;AAAA,EACnE;AACA,QAAM,MAAM,KAAK,MAAM;AACvB,SAAO,IAAI,QAAQ,OAAO,GAAG,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,QAAQ,EAAE;AACvE;AAEA,eAAe,2BAGZ;AACD,QAAM,WAAW,gBAAgB,YAAY,EAAE,CAAC;AAChD,QAAM,OAAO,IAAI,YAAY,EAAE,OAAO,QAAQ;AAC9C,QAAM,SAAS,MAAM,OAAO,OAAO,OAAO,WAAW,IAAI;AACzD,QAAM,YAAY,gBAAgB,MAAM;AACxC,SAAO,EAAE,UAAU,UAAU;AAC/B;AAGA,eAAsB,iBAGnB;AACD,SAAO,yBAAyB;AAClC;AAEA,IAAM,oBAAoB;AAE1B,SAAS,aAAa,KAAiC;AACrD,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO;AAC5C,QAAM,IAAI;AACV,QAAM,QAAQ,OAAO,EAAE,UAAU,WAAW,EAAE,MAAM,KAAK,IAAI;AAC7D,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,OAAmB,EAAE,MAAM;AACjC,QAAM,YACJ,OAAO,EAAE,cAAc,WAAW,EAAE,UAAU,KAAK,IAAI;AACzD,QAAM,WAAW,OAAO,EAAE,aAAa,WAAW,EAAE,SAAS,KAAK,IAAI;AACtE,MAAI,UAAW,MAAK,YAAY;AAChC,MAAI,SAAU,MAAK,WAAW;AAC9B,SAAO;AACT;AAEA,SAAS,cAAc,MAA8C;AACnE,MAAI,KAAK,OAAQ,QAAO,KAAK;AAC7B,MAAI,KAAK,cAAe,QAAO;AAC/B,SAAO;AACT;AAEA,SAAS,uBAAuB,aAA6B;AAC3D,MAAI;AACF,UAAM,WAAW,IAAI,IAAI,WAAW,EAAE,SAAS,QAAQ,QAAQ,EAAE;AACjE,WAAO,aAAa,MAAM,KAAK;AAAA,EACjC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,mBAAmB,QAAyB,aAA2B;AAC9E,QAAM,aAAa,uBAAuB,WAAW;AACrD,MAAI,WAAY,QAAO,IAAI,eAAe,UAAU;AACtD;AAQA,eAAsB,YACpB,MAC4B;AAC5B,QAAM,WAAW,KAAK,aAAa,KAAK,KAAK;AAC7C,QAAM,iBAAiB,iBAAiB,QAAQ;AAChD,QAAM,aAAa,eAAe;AAClC,QAAM,eAAgB,KAAK,gBAAgB,WAAW,UAAU;AAGhE,MAAI,CAAC,gBAAgB,OAAO,WAAW,aAAa;AAClD,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,YACJ,KAAK,cAAc,SAAY,KAAK,YAAY;AAElD,QAAM,QAAQ,kBAAkB;AAChC,iBAAe,QAAQ,mBAAmB,KAAK;AAE/C,QAAM,QAAQ,KAAK,WAAW,kBAAkB,IAAI;AACpD,QAAM,OAAO,MAAM,yBAAyB;AAE5C,QAAM,SAAS,IAAI,gBAAgB;AAAA,IACjC,WAAW,KAAK;AAAA,IAChB;AAAA,IACA,gBAAgB,KAAK;AAAA,IACrB,uBAAuB;AAAA,IACvB,eAAe;AAAA,IACf,eAAe;AAAA,EACjB,CAAC;AACD,MAAI,KAAK,OAAO,KAAK,EAAG,QAAO,IAAI,SAAS,KAAK,MAAM,KAAK,CAAC;AAC7D,MAAI,MAAO,QAAO,IAAI,SAAS,KAAK;AACpC,QAAM,SAAS,cAAc,IAAI;AACjC,MAAI,OAAQ,QAAO,IAAI,UAAU,MAAM;AACvC,MAAI,KAAK,WAAW,KAAK,EAAG,QAAO,IAAI,cAAc,KAAK,UAAU,KAAK,CAAC;AAC1E,qBAAmB,QAAQ,QAAQ;AAEnC,QAAM,eAAe,GAAG,eAAe,KAAK,QAAQ,SAAS,EAAE,CAAC,cAAc,OAAO,SAAS,CAAC;AAE/F,QAAM,aAAa,WAAW,SAAS,MAAM;AAC7C,QAAM,cAAc,WAAW,SAAS,MAAM;AAC9C,QAAM,QAAQ,OAAO;AAAA,IACnB;AAAA,IACA,WAAW,OAAO,WAAW,CAAC;AAAA,IAC9BC,qBAAoB,YAAY,WAAW;AAAA,EAC7C;AACA,MAAI,CAAC,MAAO,OAAM,IAAI,kBAAkB;AAExC,SAAO,MAAM,IAAI,QAA2B,CAAC,SAAS,WAAW;AAC/D,QAAI,UAAU;AACd,UAAM,WAAW,MAAY;AAC3B,UAAI,QAAS;AACb,gBAAU;AACV,aAAO,oBAAoB,WAAW,aAA8B;AACpE,oBAAc,SAAS;AACvB,mBAAa,KAAK;AAClB,UAAI;AACF,cAAM,MAAM;AAAA,MACd,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,UAAM,OAAO,CAAC,MAAqB;AACjC,eAAS;AACT,aAAO,aAAa,QAAQ,IAAI,IAAI,MAAM,OAAO,CAAC,CAAC,CAAC;AAAA,IACtD;AAEA,UAAM,QAAQ,OAAO,WAAW,MAAM;AACpC,WAAK,IAAI,kBAAkB,CAAC;AAAA,IAC9B,GAAG,SAAS;AAEZ,UAAM,gBAAgB,CAAC,UAA8B;AACnD,UAAI,MAAM,WAAW,WAAY;AACjC,YAAM,IAAI,MAAM;AAChB,UAAI,GAAG,WAAW,UAAW;AAE7B,YAAM,KAAK,OAAO,EAAE,UAAU,WAAW,EAAE,QAAQ;AACnD,UAAI,CAAC,MAAM,OAAO,eAAe,QAAQ,iBAAiB,EAAG;AAE7D,UAAI,OAAO,EAAE,UAAU,YAAY,EAAE,MAAM,SAAS,GAAG;AACrD,iBAAS;AACT;AAAA,UACE,IAAI;AAAA,YACF,OAAO,EAAE,KAAK;AAAA,YACd,OAAO,EAAE,sBAAsB,WAC3B,EAAE,oBACF;AAAA,UACN;AAAA,QACF;AACA;AAAA,MACF;AAEA,UAAI,EAAE,SAAS,iBAAiB;AAC9B,YAAI;AACF,gBAAM;AAAA,YACJ;AAAA,cACE,QAAQ;AAAA,cACR,OAAO;AAAA,cACP,eAAe,KAAK;AAAA,cACpB,WAAW,KAAK;AAAA,YAClB;AAAA,YACA;AAAA,UACF;AAAA,QACF,QAAQ;AACN,eAAK,IAAI,kBAAkB,mBAAmB,iCAAiC,CAAC;AAAA,QAClF;AACA;AAAA,MACF;AAEA,YAAM,UACJ,OAAO,EAAE,aAAa,WAClB,EAAE,WACF,OAAO,EAAE,YAAY,WACnB,EAAE,UACF;AACR,YAAM,OAAO,aAAa,EAAE,IAAI;AAChC,UAAI,CAAC,WAAW,CAAC,KAAM;AAEvB,qBAAe,WAAW,iBAAiB;AAC3C,mBAAa,KAAK;AAClB,aAAO,oBAAoB,WAAW,aAA8B;AACpE,oBAAc,SAAS;AACvB,gBAAU;AAEV,cAAQ,EAAE,MAAM,QAAQ,CAAC;AAEzB,UAAI;AACF,cAAM,MAAM;AAAA,MACd,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,WAAO,iBAAiB,WAAW,aAA8B;AAEjE,UAAM,YAAY,OAAO,YAAY,MAAM;AACzC,UAAI,CAAC,MAAM,OAAQ;AACnB,UAAI,QAAS;AACb,YAAM,UAAU,eAAe,QAAQ,iBAAiB;AACxD,UAAI,CAAC,QAAS;AACd,WAAK,IAAI,iBAAiB,CAAC;AAAA,IAC7B,GAAG,GAAG;AAAA,EACR,CAAC;AACH;AAEA,SAAS,oBAA4B;AACnC,SAAO,gBAAgB,YAAY,EAAE,CAAC;AACxC;AAEA,SAAS,iBAAiB,GAAgB;AACxC,SAAO,IAAI,IAAI,CAAC;AAClB;AAGA,SAASA,qBAAoB,OAAe,QAAwB;AAClE,QAAM,MAAM;AACZ,QAAM,SAAS,IAAI,aAAa,IAAI,IAAI,aAAa,IAAI;AACzD,QAAM,SAAS,IAAI,cAAc,IAAI,IAAI,cAAc,IAAI;AAC3D,QAAM,UAAU,IAAI,WAAW,IAAI,cAAc;AACjD,QAAM,UAAU,IAAI,WAAW,IAAI,aAAa;AAChD,QAAM,OAAO,KAAK,MAAM,UAAU,KAAK,IAAI,IAAI,SAAS,SAAS,CAAC,CAAC;AACnE,QAAM,MAAM,KAAK,MAAM,UAAU,KAAK,IAAI,IAAI,SAAS,UAAU,CAAC,CAAC;AACnE,SAAO,SAAS,KAAK,WAAW,MAAM,SAAS,IAAI,QAAQ,GAAG;AAChE;AAGO,SAAS,qBAAqB,OAAyB;AAC5D,SAAO,iBAAiB,qBAAqB,MAAM,cAAc;AACnE;","names":["openSessionBridge","signOutWithXS","popupWindowFeatures"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/session-bridge.ts","../src/sign-out.ts","../src/index.ts"],"sourcesContent":["/** Popup was blocked by the browser or environment. */\r\nexport class PopupBlockedError extends Error {\r\n readonly name = 'PopupBlockedError';\r\n}\r\n\r\n/** User closed the popup before completing login. */\r\nexport class PopupClosedError extends Error {\r\n readonly name = 'PopupClosedError';\r\n}\r\n\r\n/** XS Auth popup did not complete within timeout. */\r\nexport class LoginTimeoutError extends Error {\r\n readonly name = 'LoginTimeoutError';\r\n}\r\n\r\n/** XS Auth returned an OAuth-style error inside postMessage. */\r\nexport class XSAuthDeniedError extends Error {\r\n readonly name = 'XSAuthDeniedError';\r\n readonly errorCode: string;\r\n readonly description: string;\r\n\r\n constructor(errorCode: string, description: string) {\r\n super(description || errorCode || 'xs_auth_denied');\r\n this.errorCode = errorCode;\r\n this.description = description;\r\n }\r\n}\r\n\r\n/** Session bridge did not respond within timeout. */\r\nexport class LoginBridgeTimeoutError extends Error {\r\n readonly name = 'LoginBridgeTimeoutError';\r\n}\r\n","import {\r\n LoginBridgeTimeoutError,\r\n PopupBlockedError,\r\n PopupClosedError,\r\n} from './errors';\r\n\r\n/** XS Auth browser session account (multi-account SSO on the Auth-Server domain). */\r\nexport interface XSBrowserAccount {\r\n sessionId: string;\r\n userId: string;\r\n email: string;\r\n name: string;\r\n isPrimary: boolean;\r\n}\r\n\r\nexport interface OpenSessionBridgeOptions {\r\n clientId: string;\r\n parentOrigin?: string;\r\n timeoutMs?: number;\r\n}\r\n\r\nexport interface SessionBridge {\r\n listAccounts(): Promise<XSBrowserAccount[]>;\r\n revokeAccount(sessionId: string): Promise<{ accounts: XSBrowserAccount[]; remainingCount: number }>;\r\n revokeAll(): Promise<void>;\r\n setPrimary(sessionId: string): Promise<XSBrowserAccount[]>;\r\n close(): void;\r\n}\r\n\r\nexport class SessionBridgeError extends Error {\r\n readonly name = 'SessionBridgeError';\r\n readonly errorCode: string;\r\n\r\n constructor(errorCode: string, message: string) {\r\n super(message || errorCode);\r\n this.errorCode = errorCode;\r\n }\r\n}\r\n\r\ntype BridgeMessage = Partial<Record<string, unknown>>;\r\n\r\nconst BRIDGE_STATE_KEY = '__xs_bridge_state';\r\n\r\nfunction parseAccounts(raw: unknown): XSBrowserAccount[] {\r\n if (!Array.isArray(raw)) return [];\r\n return raw\r\n .map((item) => {\r\n if (!item || typeof item !== 'object') return null;\r\n const row = item as Record<string, unknown>;\r\n const sessionId =\r\n typeof row.sessionId === 'string'\r\n ? row.sessionId\r\n : typeof row.session_id === 'string'\r\n ? row.session_id\r\n : '';\r\n const userId =\r\n typeof row.userId === 'string'\r\n ? row.userId\r\n : typeof row.user_id === 'string'\r\n ? row.user_id\r\n : '';\r\n const email = typeof row.email === 'string' ? row.email : '';\r\n const name = typeof row.name === 'string' ? row.name : email;\r\n if (!sessionId || !email) return null;\r\n return {\r\n sessionId,\r\n userId,\r\n email,\r\n name,\r\n isPrimary: row.isPrimary === true || row.is_primary === true,\r\n };\r\n })\r\n .filter((x): x is XSBrowserAccount => x !== null);\r\n}\r\n\r\nfunction hiddenBridgePopupFeatures(): string {\r\n return 'width=1,height=1,left=-10000,top=-10000,resizable=no,scrollbars=no';\r\n}\r\n\r\nfunction randomBridgeState(): string {\r\n const bytes = new Uint8Array(32);\r\n crypto.getRandomValues(bytes);\r\n let binary = '';\r\n for (let i = 0; i < bytes.length; i++) {\r\n binary += String.fromCharCode(bytes[i]!);\r\n }\r\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/u, '');\r\n}\r\n\r\n/**\r\n * Opens a same-origin Auth-Server popup bridge so the host app can list and revoke\r\n * browser SSO sessions without cross-origin cookie access.\r\n */\r\nexport async function openSessionBridge(\r\n opts: OpenSessionBridgeOptions,\r\n authBaseUrl: string,\r\n): Promise<SessionBridge> {\r\n const parentOrigin = (opts.parentOrigin ?? globalThis.location?.origin) as string | undefined;\r\n if (!parentOrigin || typeof window === 'undefined') {\r\n throw new Error(\r\n 'openSessionBridge requires a browser Window and explicit parentOrigin (or window.location).',\r\n );\r\n }\r\n\r\n const normalizedBase = new URL(authBaseUrl);\r\n const authOrigin = normalizedBase.origin;\r\n const state = randomBridgeState();\r\n sessionStorage.setItem(BRIDGE_STATE_KEY, state);\r\n\r\n const params = new URLSearchParams({\r\n client_id: opts.clientId,\r\n parent_origin: parentOrigin,\r\n state,\r\n });\r\n\r\n const bridgeUrl = `${normalizedBase.href.replace(/\\/?$/u, '')}/session/bridge?${params.toString()}`;\r\n const popup = window.open(\r\n bridgeUrl,\r\n `xs-auth-bridge-${crypto.randomUUID()}`,\r\n hiddenBridgePopupFeatures(),\r\n );\r\n if (!popup) throw new PopupBlockedError();\r\n\r\n const timeoutMs = opts.timeoutMs !== undefined ? opts.timeoutMs : 120_000;\r\n let cleaned = false;\r\n let closePoll: ReturnType<typeof setInterval> | undefined;\r\n\r\n const teardown = (): void => {\r\n if (cleaned) return;\r\n cleaned = true;\r\n window.removeEventListener('message', handleMessage as EventListener);\r\n if (closePoll !== undefined) clearInterval(closePoll);\r\n sessionStorage.removeItem(BRIDGE_STATE_KEY);\r\n try {\r\n popup.close();\r\n } catch {\r\n // ignore\r\n }\r\n };\r\n\r\n const pending = new Map<\r\n string,\r\n {\r\n resolve: (value: BridgeMessage) => void;\r\n reject: (error: Error) => void;\r\n }\r\n >();\r\n\r\n let bridgeReady = false;\r\n let readyResolve: (() => void) | null = null;\r\n let readyReject: ((error: Error) => void) | null = null;\r\n\r\n const readyPromise = new Promise<void>((resolve, reject) => {\r\n readyResolve = resolve;\r\n readyReject = reject;\r\n });\r\n\r\n const handleMessage = (event: MessageEvent): void => {\r\n if (event.origin !== authOrigin) return;\r\n const d = event.data as BridgeMessage;\r\n if (d?.source !== 'xs-auth') return;\r\n\r\n const st = typeof d.state === 'string' ? d.state : '';\r\n if (!st || st !== sessionStorage.getItem(BRIDGE_STATE_KEY)) return;\r\n\r\n if (d.type === 'bridge_ready') {\r\n bridgeReady = true;\r\n readyResolve?.();\r\n return;\r\n }\r\n\r\n const requestId = typeof d.requestId === 'string' ? d.requestId : '';\r\n if (!requestId) return;\r\n\r\n const entry = pending.get(requestId);\r\n if (!entry) return;\r\n\r\n pending.delete(requestId);\r\n\r\n if (typeof d.error === 'string' && d.error.length > 0) {\r\n entry.reject(\r\n new SessionBridgeError(\r\n String(d.error),\r\n typeof d.error_description === 'string' ? d.error_description : '',\r\n ),\r\n );\r\n return;\r\n }\r\n\r\n if (d.type === 'result') {\r\n entry.resolve(d);\r\n }\r\n };\r\n\r\n window.addEventListener('message', handleMessage as EventListener);\r\n\r\n closePoll = window.setInterval(() => {\r\n if (!popup.closed) return;\r\n if (cleaned) return;\r\n for (const [, entry] of pending) {\r\n entry.reject(new PopupClosedError());\r\n }\r\n pending.clear();\r\n readyReject?.(new PopupClosedError());\r\n teardown();\r\n }, 280);\r\n\r\n const readyTimer = window.setTimeout(() => {\r\n if (bridgeReady) return;\r\n readyReject?.(new LoginBridgeTimeoutError());\r\n teardown();\r\n }, timeoutMs);\r\n\r\n try {\r\n await readyPromise;\r\n } catch (error) {\r\n clearTimeout(readyTimer);\r\n throw error;\r\n }\r\n clearTimeout(readyTimer);\r\n\r\n const sendRequest = (type: string, extra: Record<string, unknown> = {}): Promise<BridgeMessage> => {\r\n if (popup.closed) {\r\n return Promise.reject(new PopupClosedError());\r\n }\r\n\r\n const requestId = crypto.randomUUID();\r\n return new Promise<BridgeMessage>((resolve, reject) => {\r\n const timer = window.setTimeout(() => {\r\n pending.delete(requestId);\r\n reject(new LoginBridgeTimeoutError());\r\n }, timeoutMs);\r\n\r\n pending.set(requestId, {\r\n resolve: (value) => {\r\n clearTimeout(timer);\r\n resolve(value);\r\n },\r\n reject: (error) => {\r\n clearTimeout(timer);\r\n reject(error);\r\n },\r\n });\r\n\r\n try {\r\n popup.postMessage(\r\n {\r\n source: 'xs-auth-opener',\r\n state,\r\n client_id: opts.clientId,\r\n requestId,\r\n type,\r\n ...extra,\r\n },\r\n authOrigin,\r\n );\r\n } catch {\r\n pending.delete(requestId);\r\n clearTimeout(timer);\r\n reject(new SessionBridgeError('post_message_failed', 'Could not reach the session bridge.'));\r\n }\r\n });\r\n };\r\n\r\n return {\r\n async listAccounts() {\r\n const result = await sendRequest('list_accounts');\r\n return parseAccounts(result.accounts);\r\n },\r\n\r\n async revokeAccount(sessionId: string) {\r\n const result = await sendRequest('revoke', { session_id: sessionId.trim() });\r\n const accounts = parseAccounts(result.accounts);\r\n const remainingCount =\r\n typeof result.remainingCount === 'number' ? result.remainingCount : accounts.length;\r\n return { accounts, remainingCount };\r\n },\r\n\r\n async revokeAll() {\r\n await sendRequest('revoke_all');\r\n },\r\n\r\n async setPrimary(sessionId: string) {\r\n const result = await sendRequest('set_primary', { session_id: sessionId.trim() });\r\n return parseAccounts(result.accounts);\r\n },\r\n\r\n close() {\r\n teardown();\r\n },\r\n };\r\n}\r\n\r\n/** True when the user must pick another primary account before signing out. */\r\nexport function isPrimaryAccountError(error: unknown): boolean {\r\n return error instanceof SessionBridgeError && error.errorCode === 'primary_account';\r\n}\r\n","import {\r\n LoginBridgeTimeoutError,\r\n PopupBlockedError,\r\n PopupClosedError,\r\n} from './errors';\r\n\r\nexport interface SignOutWithXSOptions {\r\n clientId: string;\r\n parentOrigin?: string;\r\n /** XS Auth user id (`sub`) for the account active in the host app. */\r\n activeUserId?: string;\r\n timeoutMs?: number;\r\n /** Override Auth-Server base URL (e.g. same-origin `/xs-auth` proxy in local dev). */\r\n authBaseUrl?: string;\r\n}\r\n\r\nexport type SignOutAction = 'revoked_one' | 'revoked_all' | 'cancelled';\r\n\r\nexport interface SignOutWithXSResult {\r\n action: SignOutAction;\r\n revokedCurrent: boolean;\r\n remainingCount: number;\r\n}\r\n\r\nconst SIGN_OUT_STATE_KEY = '__xs_sign_out_state';\r\n\r\nfunction popupWindowFeatures(width: number, height: number): string {\r\n const win = window;\r\n const outerW = win.outerWidth > 0 ? win.outerWidth : win.innerWidth;\r\n const outerH = win.outerHeight > 0 ? win.outerHeight : win.innerHeight;\r\n const screenX = win.screenX ?? win.screenLeft ?? 0;\r\n const screenY = win.screenY ?? win.screenTop ?? 0;\r\n const left = Math.round(screenX + Math.max(0, (outerW - width) / 2));\r\n const top = Math.round(screenY + Math.max(0, (outerH - height) / 2));\r\n return `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes`;\r\n}\r\n\r\nfunction randomState(): string {\r\n const bytes = new Uint8Array(32);\r\n crypto.getRandomValues(bytes);\r\n let binary = '';\r\n for (let i = 0; i < bytes.length; i++) {\r\n binary += String.fromCharCode(bytes[i]!);\r\n }\r\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/u, '');\r\n}\r\n\r\nfunction parseSignOutResult(raw: SignOutAction, data: Record<string, unknown>): SignOutWithXSResult {\r\n return {\r\n action: raw,\r\n revokedCurrent: data.revokedCurrent === true,\r\n remainingCount:\r\n typeof data.remainingCount === 'number' && Number.isFinite(data.remainingCount)\r\n ? Math.max(0, data.remainingCount)\r\n : 0,\r\n };\r\n}\r\n\r\n/**\r\n * Opens a centered XS Auth popup to sign out of one or all browser SSO accounts\r\n * (Google-style account manager on the Auth-Server domain).\r\n */\r\nexport async function signOutWithXS(\r\n opts: SignOutWithXSOptions,\r\n authBaseUrl: string,\r\n): Promise<SignOutWithXSResult> {\r\n const parentOrigin = (opts.parentOrigin ?? globalThis.location?.origin) as string | undefined;\r\n if (!parentOrigin || typeof window === 'undefined') {\r\n throw new Error(\r\n 'signOutWithXS requires a browser Window and explicit parentOrigin (or window.location).',\r\n );\r\n }\r\n\r\n const normalizedBase = new URL(authBaseUrl);\r\n const authOrigin = normalizedBase.origin;\r\n const state = randomState();\r\n sessionStorage.setItem(SIGN_OUT_STATE_KEY, state);\r\n\r\n const params = new URLSearchParams({\r\n client_id: opts.clientId,\r\n parent_origin: parentOrigin,\r\n state,\r\n });\r\n if (opts.activeUserId?.trim()) {\r\n params.set('active_user_id', opts.activeUserId.trim());\r\n }\r\n\r\n const url = `${normalizedBase.href.replace(/\\/?$/u, '')}/session/sign-out?${params.toString()}`;\r\n const popup = window.open(\r\n url,\r\n `xs-auth-signout-${crypto.randomUUID()}`,\r\n popupWindowFeatures(480, 640),\r\n );\r\n if (!popup) throw new PopupBlockedError();\r\n\r\n const timeoutMs = opts.timeoutMs !== undefined ? opts.timeoutMs : 120_000;\r\n\r\n return await new Promise<SignOutWithXSResult>((resolve, reject) => {\r\n let cleaned = false;\r\n\r\n const teardown = (): void => {\r\n if (cleaned) return;\r\n cleaned = true;\r\n window.removeEventListener('message', handleMessage as EventListener);\r\n clearInterval(closePoll);\r\n clearTimeout(timer);\r\n sessionStorage.removeItem(SIGN_OUT_STATE_KEY);\r\n try {\r\n popup.close();\r\n } catch {\r\n // ignore\r\n }\r\n };\r\n\r\n const fail = (error: Error): void => {\r\n teardown();\r\n reject(error);\r\n };\r\n\r\n const timer = window.setTimeout(() => {\r\n fail(new LoginBridgeTimeoutError());\r\n }, timeoutMs);\r\n\r\n const handleMessage = (event: MessageEvent): void => {\r\n if (event.origin !== authOrigin) return;\r\n const d = event.data as Partial<Record<string, unknown>>;\r\n if (d?.source !== 'xs-auth') return;\r\n\r\n const st = typeof d.state === 'string' ? d.state : '';\r\n if (!st || st !== sessionStorage.getItem(SIGN_OUT_STATE_KEY)) return;\r\n\r\n if (d.type === 'sign_out_cancelled') {\r\n teardown();\r\n resolve(parseSignOutResult('cancelled', d));\r\n return;\r\n }\r\n\r\n if (d.type === 'sign_out_complete') {\r\n teardown();\r\n const actionRaw = typeof d.action === 'string' ? d.action : 'revoked_one';\r\n const action: SignOutAction =\r\n actionRaw === 'revoked_all'\r\n ? 'revoked_all'\r\n : actionRaw === 'cancelled'\r\n ? 'cancelled'\r\n : 'revoked_one';\r\n resolve(parseSignOutResult(action, d));\r\n }\r\n };\r\n\r\n window.addEventListener('message', handleMessage as EventListener);\r\n\r\n const closePoll = window.setInterval(() => {\r\n if (!popup.closed) return;\r\n if (cleaned) return;\r\n if (!sessionStorage.getItem(SIGN_OUT_STATE_KEY)) return;\r\n fail(new PopupClosedError());\r\n }, 280);\r\n });\r\n}\r\n","import {\r\n LoginTimeoutError,\r\n PopupBlockedError,\r\n PopupClosedError,\r\n XSAuthDeniedError,\r\n} from './errors';\r\nimport {\r\n isPrimaryAccountError,\r\n openSessionBridge as openSessionBridgeInternal,\r\n SessionBridgeError,\r\n type OpenSessionBridgeOptions,\r\n type SessionBridge,\r\n type XSBrowserAccount,\r\n} from './session-bridge';\r\n\r\nimport {\r\n signOutWithXS as signOutWithXSInternal,\r\n type SignOutAction,\r\n type SignOutWithXSOptions,\r\n type SignOutWithXSResult,\r\n} from './sign-out';\r\n\r\nexport {\r\n LoginBridgeTimeoutError,\r\n LoginTimeoutError,\r\n PopupBlockedError,\r\n PopupClosedError,\r\n XSAuthDeniedError,\r\n} from './errors';\r\n\r\nexport {\r\n isPrimaryAccountError,\r\n SessionBridgeError,\r\n type OpenSessionBridgeOptions,\r\n type SessionBridge,\r\n type XSBrowserAccount,\r\n};\r\n\r\nexport {\r\n type SignOutAction,\r\n type SignOutWithXSOptions,\r\n type SignOutWithXSResult,\r\n};\r\n\r\n/** XS Auth server — baked in at build time (local vs production). */\r\nconst XS_AUTH_BASE_URL = __XS_AUTH_BASE_URL__;\r\n\r\n/** Opens the Auth-Server session bridge popup (multi-account sign-out). */\r\nexport function openSessionBridge(\r\n opts: OpenSessionBridgeOptions,\r\n): Promise<SessionBridge> {\r\n return openSessionBridgeInternal(opts, XS_AUTH_BASE_URL);\r\n}\r\n\r\n/** Google-style sign-out popup on the Auth-Server domain. */\r\nexport function signOutWithXS(opts: SignOutWithXSOptions): Promise<SignOutWithXSResult> {\r\n const authBase = opts.authBaseUrl?.trim() || XS_AUTH_BASE_URL;\r\n return signOutWithXSInternal(opts, authBase);\r\n}\r\n\r\n/** Signed-in user profile from XS Auth. */\r\nexport interface XSAuthUser {\r\n email: string;\r\n firstName?: string;\r\n lastName?: string;\r\n}\r\n\r\nexport interface LoginWithXSOptions {\r\n /** Your app's public client id from Xino Solutions. */\r\n clientId: string;\r\n /** Must be on your XS Auth client's allowed domains list (normally `window.location.origin`). */\r\n parentOrigin?: string;\r\n /**\r\n * Sign-in timeout in ms. Defaults to 180s to allow MFA verification in the Auth-Server popup.\r\n */\r\n timeoutMs?: number;\r\n scope?: string;\r\n /**\r\n * Request a `nonce` inside `idToken` — your backend should verify it matches when validating the JWT.\r\n */\r\n useNonce?: boolean;\r\n /**\r\n * OAuth-style prompt for multi-account SSO on the Auth-Server domain.\r\n * - `none`: silent sign-in with the primary browser session (fails with `login_required` if absent)\r\n * - `select_account`: always show the account chooser when sessions exist\r\n * - `login`: force email/password (add another account)\r\n */\r\n prompt?: 'none' | 'select_account' | 'login';\r\n /** Prefer a specific XS Auth user id (`sub`) when continuing an existing browser session. */\r\n accountId?: string;\r\n /** When true and `prompt` is unset, defaults to `none` instead of account chooser. */\r\n preferPrimary?: boolean;\r\n /** Override Auth-Server base URL (e.g. same-origin `/xs-auth` proxy in local dev). */\r\n authBaseUrl?: string;\r\n /**\r\n * Initial Auth-Server login page view.\r\n * - `signin`: email/password sign-in (default)\r\n * - `signup`: registration form (\"Create one\")\r\n */\r\n mode?: 'signin' | 'signup';\r\n}\r\n\r\nexport interface LoginWithXSResult {\r\n user: XSAuthUser;\r\n /** Short-lived signed JWT — send to your backend to create a session. */\r\n idToken: string;\r\n /** True when the user completed MFA during this sign-in (`amr` includes `mfa`). */\r\n mfaVerified: boolean;\r\n}\r\n\r\nfunction bytesBuffer(len: number): Uint8Array {\r\n const out = new Uint8Array(len);\r\n crypto.getRandomValues(out);\r\n return out;\r\n}\r\n\r\nfunction base64UrlEncode(buf: Uint8Array | ArrayBuffer): string {\r\n const bytes = buf instanceof Uint8Array ? buf : new Uint8Array(buf);\r\n let binary = '';\r\n const chunkSize = 0x8000;\r\n for (let i = 0; i < bytes.length; i += chunkSize) {\r\n binary += String.fromCharCode(...bytes.subarray(i, i + chunkSize));\r\n }\r\n const b64 = btoa(binary);\r\n return b64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/u, '');\r\n}\r\n\r\nasync function pkceVerifierAndChallenge(): Promise<{\r\n verifier: string;\r\n challenge: string;\r\n}> {\r\n const verifier = base64UrlEncode(bytesBuffer(64));\r\n const data = new TextEncoder().encode(verifier);\r\n const digest = await crypto.subtle.digest('SHA-256', data);\r\n const challenge = base64UrlEncode(digest);\r\n return { verifier, challenge };\r\n}\r\n\r\n/** PKCE helpers for tests / custom callers. */\r\nexport async function createPkcePair(): Promise<{\r\n verifier: string;\r\n challenge: string;\r\n}> {\r\n return pkceVerifierAndChallenge();\r\n}\r\n\r\nconst STATE_KEY_STORAGE = '__xs_login_state';\r\n\r\nfunction parseSdkUser(raw: unknown): XSAuthUser | null {\r\n if (!raw || typeof raw !== 'object') return null;\r\n const u = raw as Record<string, unknown>;\r\n const email = typeof u.email === 'string' ? u.email.trim() : '';\r\n if (!email) return null;\r\n const user: XSAuthUser = { email };\r\n const firstName =\r\n typeof u.firstName === 'string' ? u.firstName.trim() : '';\r\n const lastName = typeof u.lastName === 'string' ? u.lastName.trim() : '';\r\n if (firstName) user.firstName = firstName;\r\n if (lastName) user.lastName = lastName;\r\n return user;\r\n}\r\n\r\nfunction resolvePrompt(opts: LoginWithXSOptions): string | undefined {\r\n if (opts.prompt) return opts.prompt;\r\n if (opts.preferPrimary) return 'none';\r\n return undefined;\r\n}\r\n\r\nfunction authPublicPathFromBase(authBaseUrl: string): string {\r\n try {\r\n const pathname = new URL(authBaseUrl).pathname.replace(/\\/$/u, '');\r\n return pathname === '/' ? '' : pathname;\r\n } catch {\r\n return '';\r\n }\r\n}\r\n\r\nfunction maybeSetPublicPath(params: URLSearchParams, authBaseUrl: string): void {\r\n const publicPath = authPublicPathFromBase(authBaseUrl);\r\n if (publicPath) params.set('public_path', publicPath);\r\n}\r\n\r\n/**\r\n * Opens the XS Auth sign-in popup and returns the signed-in user plus a verifiable `idToken`.\r\n *\r\n * All Auth-Server HTTP calls happen inside the popup (same origin). The host app only\r\n * opens the popup and exchanges postMessages with the PKCE verifier — no fetch to Auth-Server.\r\n */\r\nexport async function loginWithXS(\r\n opts: LoginWithXSOptions,\r\n): Promise<LoginWithXSResult> {\r\n const authBase = opts.authBaseUrl?.trim() || XS_AUTH_BASE_URL;\r\n const normalizedBase = normalizeBaseUrl(authBase);\r\n const authOrigin = normalizedBase.origin;\r\n const parentOrigin = (opts.parentOrigin ?? globalThis.location?.origin) as\r\n | string\r\n | undefined;\r\n if (!parentOrigin || typeof window === 'undefined') {\r\n throw new Error(\r\n 'loginWithXS requires a browser Window and explicit parentOrigin (or window.location).',\r\n );\r\n }\r\n\r\n const timeoutMs =\r\n opts.timeoutMs !== undefined ? opts.timeoutMs : 180_000;\r\n\r\n const state = randomBase64State();\r\n sessionStorage.setItem(STATE_KEY_STORAGE, state);\r\n\r\n const nonce = opts.useNonce ? randomBase64State() : undefined;\r\n const pair = await pkceVerifierAndChallenge();\r\n\r\n const params = new URLSearchParams({\r\n client_id: opts.clientId,\r\n state,\r\n code_challenge: pair.challenge,\r\n code_challenge_method: 'S256',\r\n parent_origin: parentOrigin,\r\n response_mode: 'popup',\r\n });\r\n if (opts.scope?.trim()) params.set('scope', opts.scope.trim());\r\n if (nonce) params.set('nonce', nonce);\r\n const prompt = resolvePrompt(opts);\r\n if (prompt) params.set('prompt', prompt);\r\n if (opts.mode === 'signup') params.set('mode', 'signup');\r\n if (opts.accountId?.trim()) params.set('account_id', opts.accountId.trim());\r\n maybeSetPublicPath(params, authBase);\r\n\r\n const authorizeUrl = `${normalizedBase.href.replace(/\\/?$/u, '')}/authorize?${params.toString()}`;\r\n\r\n const popupWidth = prompt === 'none' ? 420 : 480;\r\n const popupHeight = prompt === 'none' ? 120 : 640;\r\n const popup = window.open(\r\n authorizeUrl,\r\n `xs-auth-${crypto.randomUUID()}`,\r\n popupWindowFeatures(popupWidth, popupHeight),\r\n );\r\n if (!popup) throw new PopupBlockedError();\r\n\r\n return await new Promise<LoginWithXSResult>((resolve, reject) => {\r\n let cleaned = false;\r\n const teardown = (): void => {\r\n if (cleaned) return;\r\n cleaned = true;\r\n window.removeEventListener('message', handleMessage as EventListener);\r\n clearInterval(closePoll);\r\n clearTimeout(timer);\r\n try {\r\n popup.close();\r\n } catch {\r\n // ignore\r\n }\r\n };\r\n\r\n const fail = (e: unknown): void => {\r\n teardown();\r\n reject(e instanceof Error ? e : new Error(String(e)));\r\n };\r\n\r\n const timer = window.setTimeout(() => {\r\n fail(new LoginTimeoutError());\r\n }, timeoutMs);\r\n\r\n const handleMessage = (event: MessageEvent): void => {\r\n if (event.origin !== authOrigin) return;\r\n const d = event.data as Partial<Record<string, unknown>>;\r\n if (d?.source !== 'xs-auth') return;\r\n\r\n const st = typeof d.state === 'string' ? d.state : '';\r\n if (!st || st !== sessionStorage.getItem(STATE_KEY_STORAGE)) return;\r\n\r\n if (typeof d.error === 'string' && d.error.length > 0) {\r\n teardown();\r\n reject(\r\n new XSAuthDeniedError(\r\n String(d.error),\r\n typeof d.error_description === 'string'\r\n ? d.error_description\r\n : '',\r\n ),\r\n );\r\n return;\r\n }\r\n\r\n if (d.type === 'need_verifier') {\r\n try {\r\n popup.postMessage(\r\n {\r\n source: 'xs-auth-opener',\r\n state: st,\r\n code_verifier: pair.verifier,\r\n client_id: opts.clientId,\r\n },\r\n authOrigin,\r\n );\r\n } catch {\r\n fail(new XSAuthDeniedError('exchange_failed', 'Sign in could not be completed.'));\r\n }\r\n return;\r\n }\r\n\r\n const idToken =\r\n typeof d.id_token === 'string'\r\n ? d.id_token\r\n : typeof d.idToken === 'string'\r\n ? d.idToken\r\n : '';\r\n const user = parseSdkUser(d.user);\r\n if (!idToken || !user) return;\r\n\r\n sessionStorage.removeItem(STATE_KEY_STORAGE);\r\n clearTimeout(timer);\r\n window.removeEventListener('message', handleMessage as EventListener);\r\n clearInterval(closePoll);\r\n cleaned = true;\r\n\r\n resolve({ user, idToken, mfaVerified: idTokenIncludesMfa(idToken) });\r\n\r\n try {\r\n popup.close();\r\n } catch {\r\n // ignore\r\n }\r\n };\r\n\r\n window.addEventListener('message', handleMessage as EventListener);\r\n\r\n const closePoll = window.setInterval(() => {\r\n if (!popup.closed) return;\r\n if (cleaned) return;\r\n const pending = sessionStorage.getItem(STATE_KEY_STORAGE);\r\n if (!pending) return;\r\n fail(new PopupClosedError());\r\n }, 280);\r\n });\r\n}\r\n\r\n/** True when an XS Auth idToken indicates MFA was completed at sign-in. */\r\nexport function idTokenIncludesMfa(idToken: string): boolean {\r\n const amr = parseIdTokenAmr(idToken);\r\n return Array.isArray(amr) && amr.includes('mfa');\r\n}\r\n\r\n/** Read the `amr` claim from an XS Auth idToken payload (no signature verification). */\r\nexport function parseIdTokenAmr(idToken: string): string[] | null {\r\n const payload = parseJwtPayload(idToken);\r\n if (!payload || !('amr' in payload)) return null;\r\n const amr = payload.amr;\r\n if (Array.isArray(amr)) {\r\n return amr.filter((v): v is string => typeof v === 'string');\r\n }\r\n if (typeof amr === 'string' && amr.trim()) return [amr.trim()];\r\n return null;\r\n}\r\n\r\nfunction parseJwtPayload(token: string): Record<string, unknown> | null {\r\n const parts = token.split('.');\r\n if (parts.length < 2) return null;\r\n try {\r\n const json = atob(parts[1].replace(/-/g, '+').replace(/_/g, '/'));\r\n const parsed: unknown = JSON.parse(json);\r\n return parsed && typeof parsed === 'object' ? (parsed as Record<string, unknown>) : null;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nfunction randomBase64State(): string {\r\n return base64UrlEncode(bytesBuffer(32));\r\n}\r\n\r\nfunction normalizeBaseUrl(s: string): URL {\r\n return new URL(s);\r\n}\r\n\r\n/** Center popup over the opener window (falls back to screen center). */\r\nfunction popupWindowFeatures(width: number, height: number): string {\r\n const win = window;\r\n const outerW = win.outerWidth > 0 ? win.outerWidth : win.innerWidth;\r\n const outerH = win.outerHeight > 0 ? win.outerHeight : win.innerHeight;\r\n const screenX = win.screenX ?? win.screenLeft ?? 0;\r\n const screenY = win.screenY ?? win.screenTop ?? 0;\r\n const left = Math.round(screenX + Math.max(0, (outerW - width) / 2));\r\n const top = Math.round(screenY + Math.max(0, (outerH - height) / 2));\r\n return `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes`;\r\n}\r\n\r\n/** True when Auth-Server has no active browser session for silent sign-in. */\r\nexport function isLoginRequiredError(error: unknown): boolean {\r\n return error instanceof XSAuthDeniedError && error.errorCode === 'login_required';\r\n}\r\n"],"mappings":"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","names":["openSessionBridge","signOutWithXS","popupWindowFeatures"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xinosolutions/auth-sdk",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "private": false,
5
5
  "description": "Login with XS Auth — popup sign-in returning user profile and signed idToken.",
6
6
  "type": "module",