@xinosolutions/auth-sdk 0.3.1 → 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
@@ -460,6 +460,7 @@ async function loginWithXS(opts) {
460
460
  if (nonce) params.set("nonce", nonce);
461
461
  const prompt = resolvePrompt(opts);
462
462
  if (prompt) params.set("prompt", prompt);
463
+ if (opts.mode === "signup") params.set("mode", "signup");
463
464
  if (opts.accountId?.trim()) params.set("account_id", opts.accountId.trim());
464
465
  maybeSetPublicPath(params, authBase);
465
466
  const authorizeUrl = `${normalizedBase.href.replace(/\/?$/u, "")}/authorize?${params.toString()}`;
@@ -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 /**\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\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.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":"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","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":"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","names":["openSessionBridge","signOutWithXS","openSessionBridge","signOutWithXS","popupWindowFeatures"]}
package/dist/index.d.cts CHANGED
@@ -106,6 +106,12 @@ interface LoginWithXSOptions {
106
106
  preferPrimary?: boolean;
107
107
  /** Override Auth-Server base URL (e.g. same-origin `/xs-auth` proxy in local dev). */
108
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';
109
115
  }
110
116
  interface LoginWithXSResult {
111
117
  user: XSAuthUser;
package/dist/index.d.ts CHANGED
@@ -106,6 +106,12 @@ interface LoginWithXSOptions {
106
106
  preferPrimary?: boolean;
107
107
  /** Override Auth-Server base URL (e.g. same-origin `/xs-auth` proxy in local dev). */
108
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';
109
115
  }
110
116
  interface LoginWithXSResult {
111
117
  user: XSAuthUser;
package/dist/index.js CHANGED
@@ -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()}`;
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 /**\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\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.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"]}
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.1",
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",