@authon/js 0.1.14 → 0.1.15

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
@@ -700,12 +700,17 @@ var Authon = class {
700
700
  }
701
701
  let resolved = false;
702
702
  let cleaned = false;
703
+ const storageKey = `authon-oauth-${state}`;
703
704
  const resolve = (tokens) => {
704
705
  if (resolved) return;
705
706
  resolved = true;
706
707
  cleanup();
707
708
  try {
708
- if (!popup.closed) popup.close();
709
+ if (popup && !popup.closed) popup.close();
710
+ } catch {
711
+ }
712
+ try {
713
+ localStorage.removeItem(storageKey);
709
714
  } catch {
710
715
  }
711
716
  this.session.setSession(tokens);
@@ -719,10 +724,31 @@ var Authon = class {
719
724
  this.modal?.showError(msg);
720
725
  this.emit("error", new Error(msg));
721
726
  };
727
+ const pollApi = async () => {
728
+ if (resolved || cleaned) return;
729
+ try {
730
+ const result = await this.apiGet(
731
+ `/v1/auth/oauth/poll?state=${encodeURIComponent(state)}`
732
+ );
733
+ if (result.status === "completed" && result.accessToken) {
734
+ resolve({
735
+ accessToken: result.accessToken,
736
+ refreshToken: result.refreshToken,
737
+ expiresIn: result.expiresIn,
738
+ user: result.user
739
+ });
740
+ } else if (result.status === "error") {
741
+ handleError(result.message || "Authentication failed");
742
+ }
743
+ } catch {
744
+ }
745
+ };
722
746
  const cleanup = () => {
723
747
  if (cleaned) return;
724
748
  cleaned = true;
725
749
  window.removeEventListener("message", messageHandler);
750
+ window.removeEventListener("storage", storageHandler);
751
+ document.removeEventListener("visibilitychange", visibilityHandler);
726
752
  if (apiPollTimer) clearInterval(apiPollTimer);
727
753
  if (closePollTimer) clearInterval(closePollTimer);
728
754
  if (maxTimer) clearTimeout(maxTimer);
@@ -734,34 +760,47 @@ var Authon = class {
734
760
  }
735
761
  };
736
762
  window.addEventListener("message", messageHandler);
737
- const apiPollTimer = setInterval(async () => {
738
- if (resolved || cleaned) return;
763
+ const storageHandler = (e) => {
764
+ if (e.key !== storageKey || !e.newValue) return;
739
765
  try {
740
- const result = await this.apiGet(
741
- `/v1/auth/oauth/poll?state=${encodeURIComponent(state)}`
742
- );
743
- if (result.status === "completed" && result.accessToken) {
744
- resolve({
745
- accessToken: result.accessToken,
746
- refreshToken: result.refreshToken,
747
- expiresIn: result.expiresIn,
748
- user: result.user
749
- });
750
- } else if (result.status === "error") {
751
- handleError(result.message || "Authentication failed");
752
- }
766
+ const data = JSON.parse(e.newValue);
767
+ if (data.tokens) resolve(data.tokens);
768
+ else if (data.error) handleError(data.error);
753
769
  } catch {
754
770
  }
755
- }, 1500);
771
+ };
772
+ window.addEventListener("storage", storageHandler);
773
+ try {
774
+ const existing = localStorage.getItem(storageKey);
775
+ if (existing) {
776
+ const data = JSON.parse(existing);
777
+ if (data.tokens) {
778
+ resolve(data.tokens);
779
+ return;
780
+ }
781
+ }
782
+ } catch {
783
+ }
784
+ const apiPollTimer = setInterval(pollApi, 1500);
785
+ const visibilityHandler = () => {
786
+ if (document.visibilityState === "visible" && !resolved && !cleaned) {
787
+ pollApi();
788
+ }
789
+ };
790
+ document.addEventListener("visibilitychange", visibilityHandler);
756
791
  const closePollTimer = setInterval(() => {
757
792
  if (resolved || cleaned) return;
758
793
  try {
759
- if (popup.closed) {
794
+ if (popup && popup.closed) {
760
795
  clearInterval(closePollTimer);
796
+ pollApi();
761
797
  setTimeout(() => {
762
798
  if (resolved || cleaned) return;
763
- cleanup();
764
- this.modal?.hideLoading();
799
+ pollApi().then(() => {
800
+ if (resolved || cleaned) return;
801
+ cleanup();
802
+ this.modal?.hideLoading();
803
+ });
765
804
  }, 3e3);
766
805
  }
767
806
  } catch {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/modal.ts","../src/providers.ts","../src/session.ts","../src/authon.ts"],"sourcesContent":["export { Authon } from './authon';\nexport type { AuthonConfig, AuthonEvents, AuthonEventType } from './types';\nexport { getProviderButtonConfig } from './providers';\nexport type { ProviderButtonConfig } from './providers';\n","import type { BrandingConfig, OAuthProviderType } from '@authon/shared';\nimport { DEFAULT_BRANDING } from '@authon/shared';\nimport { getProviderButtonConfig } from './providers';\n\nexport class ModalRenderer {\n private shadowRoot: ShadowRoot | null = null;\n private hostElement: HTMLDivElement | null = null;\n private containerElement: HTMLElement | null = null;\n private mode: 'popup' | 'embedded';\n private theme: 'light' | 'dark' | 'auto';\n private branding: BrandingConfig;\n private enabledProviders: OAuthProviderType[] = [];\n private currentView: 'signIn' | 'signUp' = 'signIn';\n private onProviderClick: (provider: OAuthProviderType) => void;\n private onEmailSubmit: (email: string, password: string, isSignUp: boolean) => void;\n private onClose: () => void;\n private escHandler: ((e: KeyboardEvent) => void) | null = null;\n\n constructor(options: {\n mode: 'popup' | 'embedded';\n theme?: 'light' | 'dark' | 'auto';\n containerId?: string;\n branding?: BrandingConfig;\n onProviderClick: (provider: OAuthProviderType) => void;\n onEmailSubmit: (email: string, password: string, isSignUp: boolean) => void;\n onClose: () => void;\n }) {\n this.mode = options.mode;\n this.theme = options.theme || 'auto';\n this.branding = { ...DEFAULT_BRANDING, ...options.branding };\n this.onProviderClick = options.onProviderClick;\n this.onEmailSubmit = options.onEmailSubmit;\n this.onClose = options.onClose;\n\n if (options.mode === 'embedded' && options.containerId) {\n this.containerElement = document.getElementById(options.containerId);\n }\n }\n\n setProviders(providers: OAuthProviderType[]): void {\n this.enabledProviders = providers;\n }\n\n setBranding(branding: BrandingConfig): void {\n this.branding = { ...DEFAULT_BRANDING, ...branding };\n }\n\n open(view: 'signIn' | 'signUp' = 'signIn'): void {\n if (this.shadowRoot && this.hostElement) {\n // Modal already open — smooth in-place view switch\n this.switchView(view);\n } else {\n this.currentView = view;\n this.render(view);\n }\n }\n\n close(): void {\n if (this.escHandler) {\n document.removeEventListener('keydown', this.escHandler);\n this.escHandler = null;\n }\n if (this.hostElement) {\n this.hostElement.remove();\n this.hostElement = null;\n this.shadowRoot = null;\n }\n if (this.containerElement) {\n this.containerElement.innerHTML = '';\n }\n }\n\n showError(message: string): void {\n if (!this.shadowRoot) return;\n this.clearError();\n const errorEl = this.shadowRoot.getElementById('email-form');\n if (errorEl) {\n const errDiv = document.createElement('div');\n errDiv.id = 'authon-error-msg';\n errDiv.className = 'error-msg';\n errDiv.textContent = message;\n errorEl.appendChild(errDiv);\n }\n }\n\n showBanner(message: string, type: 'error' | 'warning' = 'error'): void {\n if (!this.shadowRoot) return;\n this.clearBanner();\n const inner = this.shadowRoot.getElementById('modal-inner');\n if (!inner) return;\n const banner = document.createElement('div');\n banner.id = 'authon-banner';\n banner.className = type === 'warning' ? 'banner-warning' : 'error-msg';\n banner.textContent = message;\n inner.insertBefore(banner, inner.firstChild);\n }\n\n clearBanner(): void {\n if (!this.shadowRoot) return;\n this.shadowRoot.getElementById('authon-banner')?.remove();\n }\n\n clearError(): void {\n if (!this.shadowRoot) return;\n this.shadowRoot.getElementById('authon-error-msg')?.remove();\n }\n\n showLoading(): void {\n if (!this.shadowRoot) return;\n this.hideLoading();\n const overlay = document.createElement('div');\n overlay.id = 'authon-loading-overlay';\n overlay.innerHTML = `\n <div class=\"loading-spinner\">\n <div class=\"loading-ring\"></div>\n <div class=\"loading-ring\"></div>\n <div class=\"loading-ring\"></div>\n </div>\n <div class=\"loading-text\">Signing in<span class=\"loading-dots\"><span></span><span></span><span></span></span></div>\n `;\n this.shadowRoot.querySelector('.modal-container')?.appendChild(overlay);\n }\n\n hideLoading(): void {\n if (!this.shadowRoot) return;\n this.shadowRoot.getElementById('authon-loading-overlay')?.remove();\n }\n\n // ── Smooth view switch (no flicker) ──\n\n private switchView(view: 'signIn' | 'signUp'): void {\n if (!this.shadowRoot || view === this.currentView) return;\n this.currentView = view;\n\n const inner = this.shadowRoot.getElementById('modal-inner');\n if (!inner) return;\n\n // Cross-fade: fade out → update → fade in\n inner.style.opacity = '0';\n inner.style.transform = 'translateY(-4px)';\n\n setTimeout(() => {\n inner.innerHTML = this.buildInnerContent(view);\n this.attachInnerEvents(view);\n // Trigger reflow, then animate in\n void inner.offsetHeight;\n inner.style.opacity = '1';\n inner.style.transform = 'translateY(0)';\n }, 140);\n }\n\n // ── Render ──\n\n private render(view: 'signIn' | 'signUp'): void {\n const host = document.createElement('div');\n host.setAttribute('data-authon-modal', '');\n this.hostElement = host;\n\n if (this.mode === 'popup') {\n document.body.appendChild(host);\n } else if (this.containerElement) {\n this.containerElement.appendChild(host);\n }\n\n this.shadowRoot = host.attachShadow({ mode: 'open' });\n this.shadowRoot.innerHTML = this.buildShell(view);\n this.attachInnerEvents(view);\n this.attachShellEvents();\n }\n\n // ── HTML builders ──\n\n /** Shell = style + backdrop + modal-container (stable across view switches) */\n private buildShell(view: 'signIn' | 'signUp'): string {\n const popupWrapper =\n this.mode === 'popup'\n ? `<div class=\"backdrop\" id=\"backdrop\"></div>`\n : '';\n\n return `\n <style>${this.buildCSS()}</style>\n ${popupWrapper}\n <div class=\"modal-container\" role=\"dialog\" aria-modal=\"true\">\n <div id=\"modal-inner\" class=\"modal-inner\">\n ${this.buildInnerContent(view)}\n </div>\n </div>\n `;\n }\n\n /** Inner content = everything inside the modal that changes per view */\n private buildInnerContent(view: 'signIn' | 'signUp'): string {\n const b = this.branding;\n const isSignUp = view === 'signUp';\n const title = isSignUp ? 'Create your account' : 'Welcome back';\n const subtitle = isSignUp ? 'Already have an account?' : \"Don't have an account?\";\n const subtitleLink = isSignUp ? 'Sign in' : 'Sign up';\n\n const dark = this.isDark();\n\n // SignUp view: hide providers, show only email form\n const showProviders = !isSignUp;\n\n const providerButtons = showProviders\n ? this.enabledProviders\n .filter((p) => !b.hiddenProviders?.includes(p))\n .map((p) => {\n const config = getProviderButtonConfig(p);\n const isWhiteBg = config.bgColor === '#ffffff';\n const btnBg = dark && isWhiteBg ? '#f8fafc' : config.bgColor;\n const btnBorder = isWhiteBg ? (dark ? '#475569' : '#e5e7eb') : config.bgColor;\n return `<button class=\"provider-btn\" data-provider=\"${p}\" style=\"background:${btnBg};color:${config.textColor};border:1px solid ${btnBorder}\">\n <span class=\"provider-icon\">${config.iconSvg}</span>\n <span>${config.label}</span>\n </button>`;\n })\n .join('')\n : '';\n\n const divider =\n showProviders && b.showDivider !== false && b.showEmailPassword !== false\n ? `<div class=\"divider\"><span>or</span></div>`\n : '';\n\n const emailForm =\n b.showEmailPassword !== false\n ? `<form class=\"email-form\" id=\"email-form\">\n <input type=\"email\" placeholder=\"Email address\" name=\"email\" required class=\"input\" autocomplete=\"email\" />\n <input type=\"password\" placeholder=\"Password\" name=\"password\" required class=\"input\" autocomplete=\"${isSignUp ? 'new-password' : 'current-password'}\" />\n ${isSignUp ? '<p class=\"password-hint\">Must contain uppercase, lowercase, and a number (min 8 chars)</p>' : ''}\n <button type=\"submit\" class=\"submit-btn\">${isSignUp ? 'Sign up' : 'Sign in'}</button>\n </form>`\n : '';\n\n const footer =\n b.termsUrl || b.privacyUrl\n ? `<div class=\"footer\">\n ${b.termsUrl ? `<a href=\"${b.termsUrl}\" target=\"_blank\">Terms of Service</a>` : ''}\n ${b.termsUrl && b.privacyUrl ? ' · ' : ''}\n ${b.privacyUrl ? `<a href=\"${b.privacyUrl}\" target=\"_blank\">Privacy Policy</a>` : ''}\n </div>`\n : '';\n\n const titleHtml = isSignUp\n ? `<div class=\"title-row\">\n <button class=\"back-btn\" id=\"back-btn\" type=\"button\" aria-label=\"Back to sign in\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M19 12H5\"/><path d=\"m12 19-7-7 7-7\"/></svg>\n </button>\n <h2 class=\"title\">${title}</h2>\n </div>`\n : `<h2 class=\"title\">${title}</h2>`;\n\n return `\n ${b.logoDataUrl ? `<img src=\"${b.logoDataUrl}\" alt=\"Logo\" class=\"logo\" />` : ''}\n ${titleHtml}\n ${b.brandName ? `<p class=\"brand-name\">${b.brandName}</p>` : ''}\n ${showProviders ? `<div class=\"providers\">${providerButtons}</div>` : ''}\n ${divider}\n ${emailForm}\n <p class=\"switch-view\">${subtitle} <a href=\"#\" id=\"switch-link\">${subtitleLink}</a></p>\n ${footer}\n ${b.showSecuredBy !== false ? `<div class=\"secured-by\">Secured by <a href=\"https://authon.dev\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"secured-link\">Authon</a></div>` : ''}\n `;\n }\n\n private isDark(): boolean {\n if (this.theme === 'dark') return true;\n if (this.theme === 'light') return false;\n return typeof window !== 'undefined' && window.matchMedia('(prefers-color-scheme: dark)').matches;\n }\n\n private buildCSS(): string {\n const b = this.branding;\n const dark = this.isDark();\n const bg = dark ? (b.darkBg || '#0f172a') : (b.lightBg || '#ffffff');\n const text = dark ? (b.darkText || '#f1f5f9') : (b.lightText || '#111827');\n const mutedText = dark ? '#94a3b8' : '#6b7280';\n const dimText = dark ? '#64748b' : '#9ca3af';\n const borderColor = dark ? '#334155' : '#d1d5db';\n const dividerColor = dark ? '#334155' : '#e5e7eb';\n const inputBg = dark ? '#1e293b' : '#ffffff';\n\n return `\n :host {\n --authon-primary-start: ${b.primaryColorStart || '#7c3aed'};\n --authon-primary-end: ${b.primaryColorEnd || '#4f46e5'};\n --authon-bg: ${bg};\n --authon-text: ${text};\n --authon-muted: ${mutedText};\n --authon-dim: ${dimText};\n --authon-border: ${borderColor};\n --authon-divider: ${dividerColor};\n --authon-input-bg: ${inputBg};\n --authon-radius: ${b.borderRadius ?? 12}px;\n --authon-font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n font-family: var(--authon-font);\n color: var(--authon-text);\n }\n * { box-sizing: border-box; margin: 0; padding: 0; }\n .backdrop {\n position: fixed; inset: 0; z-index: 99998;\n background: rgba(0,0,0,${dark ? '0.7' : '0.5'}); backdrop-filter: blur(4px);\n animation: fadeIn 0.2s ease;\n }\n .modal-container {\n ${this.mode === 'popup' ? 'position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 99999; max-height: 90vh; overflow-y: auto;' : ''}\n background: var(--authon-bg);\n color: var(--authon-text);\n border: 1px solid var(--authon-border);\n border-radius: var(--authon-radius);\n padding: 32px;\n width: 400px; max-width: 100%;\n position: ${this.mode === 'popup' ? 'fixed' : 'relative'};\n ${this.mode === 'popup' ? `box-shadow: 0 25px 50px -12px rgba(0,0,0,${dark ? '0.5' : '0.25'}); animation: slideIn 0.3s ease;` : ''}\n }\n .modal-inner {\n transition: opacity 0.14s ease, transform 0.14s ease;\n }\n .logo { display: block; margin: 0 auto 16px; max-height: 48px; }\n .title-row { display: flex; align-items: center; position: relative; margin-bottom: 8px; }\n .title-row .title { flex: 1; margin-bottom: 0; }\n .back-btn {\n position: absolute; left: 0; top: 50%; transform: translateY(-50%);\n background: none; border: none; color: var(--authon-muted);\n cursor: pointer; padding: 4px; border-radius: 6px; display: flex; align-items: center; justify-content: center;\n transition: color 0.15s, background 0.15s;\n }\n .back-btn:hover { color: var(--authon-text); background: var(--authon-divider); }\n .password-hint { font-size: 11px; color: var(--authon-dim); margin: -4px 0 2px; }\n .title { text-align: center; font-size: 24px; font-weight: 700; margin-bottom: 8px; color: var(--authon-text); }\n .brand-name { text-align: center; font-size: 14px; color: var(--authon-muted); margin-bottom: 24px; }\n .providers { display: flex; flex-direction: column; gap: 8px; margin-bottom: 16px; }\n .provider-btn {\n display: flex; align-items: center; gap: 12px;\n width: 100%; padding: 10px 16px; border-radius: calc(var(--authon-radius) * 0.67);\n font-size: 14px; font-weight: 500; cursor: pointer;\n transition: opacity 0.15s, transform 0.1s;\n font-family: var(--authon-font);\n }\n .provider-btn:hover { opacity: 0.9; }\n .provider-btn:active { transform: scale(0.98); }\n .provider-icon { display: flex; align-items: center; flex-shrink: 0; }\n .divider {\n display: flex; align-items: center; gap: 12px;\n margin: 16px 0; color: var(--authon-dim); font-size: 13px;\n }\n .divider::before, .divider::after {\n content: ''; flex: 1; height: 1px; background: var(--authon-divider);\n }\n .email-form { display: flex; flex-direction: column; gap: 10px; }\n .input {\n width: 100%; padding: 10px 14px;\n background: var(--authon-input-bg);\n color: var(--authon-text);\n border: 1px solid var(--authon-border); border-radius: calc(var(--authon-radius) * 0.5);\n font-size: 14px; font-family: var(--authon-font);\n outline: none; transition: border-color 0.15s;\n }\n .input::placeholder { color: var(--authon-dim); }\n .input:focus { border-color: var(--authon-primary-start); box-shadow: 0 0 0 3px rgba(124,58,237,0.15); }\n .submit-btn {\n width: 100%; padding: 10px;\n background: linear-gradient(135deg, var(--authon-primary-start), var(--authon-primary-end));\n color: #fff; border: none; border-radius: calc(var(--authon-radius) * 0.5);\n font-size: 14px; font-weight: 600; cursor: pointer;\n font-family: var(--authon-font); transition: opacity 0.15s;\n }\n .submit-btn:hover { opacity: 0.9; }\n .submit-btn:disabled { opacity: 0.6; cursor: not-allowed; }\n .error-msg {\n margin-top: 8px; padding: 8px 12px;\n background: rgba(239,68,68,0.1); border: 1px solid rgba(239,68,68,0.3);\n border-radius: calc(var(--authon-radius) * 0.33);\n font-size: 13px; color: #ef4444; text-align: center;\n animation: fadeIn 0.15s ease;\n }\n .banner-warning {\n margin-bottom: 16px; padding: 10px 14px;\n background: rgba(245,158,11,0.1); border: 1px solid rgba(245,158,11,0.3);\n border-radius: calc(var(--authon-radius) * 0.33);\n font-size: 13px; color: #f59e0b; text-align: center;\n animation: fadeIn 0.15s ease;\n }\n .switch-view { text-align: center; margin-top: 16px; font-size: 13px; color: var(--authon-muted); }\n .switch-view a { color: var(--authon-primary-start); text-decoration: none; font-weight: 500; }\n .switch-view a:hover { text-decoration: underline; }\n .footer { text-align: center; margin-top: 12px; font-size: 12px; color: var(--authon-dim); }\n .footer a { color: var(--authon-dim); text-decoration: none; }\n .footer a:hover { text-decoration: underline; }\n .secured-by {\n text-align: center; margin-top: 16px;\n font-size: 11px; color: var(--authon-dim);\n }\n .secured-link { font-weight: 600; color: var(--authon-muted); text-decoration: none; }\n .secured-link:hover { text-decoration: underline; }\n /* Loading overlay */\n #authon-loading-overlay {\n position: absolute; inset: 0; z-index: 10;\n background: ${dark ? 'rgba(15,23,42,0.92)' : 'rgba(255,255,255,0.92)'};\n backdrop-filter: blur(2px);\n border-radius: var(--authon-radius);\n display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 20px;\n animation: fadeIn 0.15s ease;\n }\n .loading-spinner { position: relative; width: 48px; height: 48px; }\n .loading-ring {\n position: absolute; inset: 0;\n border: 2.5px solid transparent; border-top-color: var(--authon-primary-start);\n border-radius: 50%; animation: spin 1s cubic-bezier(.55,.15,.45,.85) infinite;\n }\n .loading-ring:nth-child(2) {\n inset: 5px; border-top-color: transparent; border-right-color: var(--authon-primary-end);\n animation-duration: 1.2s; animation-direction: reverse; opacity: .7;\n }\n .loading-ring:nth-child(3) {\n inset: 10px; border-top-color: transparent; border-bottom-color: var(--authon-primary-start);\n animation-duration: .8s; opacity: .4;\n }\n .loading-text { font-size: 14px; font-weight: 500; color: var(--authon-muted); }\n .loading-dots { display: inline-flex; gap: 2px; margin-left: 2px; }\n .loading-dots span {\n width: 3px; height: 3px; border-radius: 50%;\n background: var(--authon-muted); animation: blink 1.4s infinite both;\n }\n .loading-dots span:nth-child(2) { animation-delay: .2s; }\n .loading-dots span:nth-child(3) { animation-delay: .4s; }\n @keyframes spin { to { transform: rotate(360deg); } }\n @keyframes blink { 0%,80%,100% { opacity: .2; } 40% { opacity: 1; } }\n @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }\n @keyframes slideIn { from { opacity: 0; transform: translate(-50%, -48%); } to { opacity: 1; transform: translate(-50%, -50%); } }\n ${b.customCss || ''}\n `;\n }\n\n // ── Event binding ──\n\n /** Attach events to shell elements (backdrop, ESC) — called once */\n private attachShellEvents(): void {\n if (!this.shadowRoot) return;\n\n const backdrop = this.shadowRoot.getElementById('backdrop');\n if (backdrop) {\n backdrop.addEventListener('click', () => this.onClose());\n }\n\n if (this.escHandler) {\n document.removeEventListener('keydown', this.escHandler);\n }\n if (this.mode === 'popup') {\n this.escHandler = (e: KeyboardEvent) => {\n if (e.key === 'Escape') this.onClose();\n };\n document.addEventListener('keydown', this.escHandler);\n }\n }\n\n /** Attach events to inner content (buttons, form, switch link) — called on each view */\n private attachInnerEvents(view: 'signIn' | 'signUp'): void {\n if (!this.shadowRoot) return;\n\n // Provider buttons\n this.shadowRoot.querySelectorAll('.provider-btn').forEach((btn) => {\n btn.addEventListener('click', () => {\n const provider = (btn as HTMLElement).dataset.provider as OAuthProviderType;\n this.onProviderClick(provider);\n });\n });\n\n // Email form\n const form = this.shadowRoot.getElementById('email-form') as HTMLFormElement | null;\n if (form) {\n form.addEventListener('submit', (e) => {\n e.preventDefault();\n const formData = new FormData(form);\n this.onEmailSubmit(\n formData.get('email') as string,\n formData.get('password') as string,\n view === 'signUp',\n );\n });\n }\n\n // Back button (signUp → signIn)\n const backBtn = this.shadowRoot.getElementById('back-btn');\n if (backBtn) {\n backBtn.addEventListener('click', () => {\n this.open('signIn');\n });\n }\n\n // Switch view link\n const switchLink = this.shadowRoot.getElementById('switch-link');\n if (switchLink) {\n switchLink.addEventListener('click', (e) => {\n e.preventDefault();\n this.open(view === 'signIn' ? 'signUp' : 'signIn');\n });\n }\n }\n}\n","import { PROVIDER_COLORS, PROVIDER_DISPLAY_NAMES, type OAuthProviderType } from '@authon/shared';\n\nexport interface ProviderButtonConfig {\n provider: OAuthProviderType;\n label: string;\n bgColor: string;\n textColor: string;\n iconSvg: string;\n}\n\nconst PROVIDER_ICONS: Record<OAuthProviderType, string> = {\n google: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\"><path fill=\"#4285F4\" d=\"M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 01-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z\"/><path fill=\"#34A853\" d=\"M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z\"/><path fill=\"#FBBC05\" d=\"M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z\"/><path fill=\"#EA4335\" d=\"M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z\"/></svg>`,\n apple: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"currentColor\"><path d=\"M17.05 20.28c-.98.95-2.05.88-3.08.4-1.09-.5-2.08-.48-3.24 0-1.44.62-2.2.44-3.06-.4C2.79 15.25 3.51 7.59 9.05 7.31c1.35.07 2.29.74 3.08.8 1.18-.24 2.31-.93 3.57-.84 1.51.12 2.65.72 3.4 1.8-3.12 1.87-2.38 5.98.48 7.13-.57 1.5-1.31 2.99-2.54 4.09zM12.03 7.25c-.15-2.23 1.66-4.07 3.74-4.25.29 2.58-2.34 4.5-3.74 4.25z\"/></svg>`,\n kakao: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\"><path fill=\"#191919\" d=\"M12 3C6.48 3 2 6.36 2 10.43c0 2.62 1.75 4.93 4.37 6.23l-1.12 4.14c-.1.36.31.65.62.44l4.93-3.26c.39.04.79.06 1.2.06 5.52 0 10-3.36 10-7.61C22 6.36 17.52 3 12 3z\"/></svg>`,\n naver: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\"><path fill=\"#fff\" d=\"M16.27 3H7.73A4.73 4.73 0 003 7.73v8.54A4.73 4.73 0 007.73 21h8.54A4.73 4.73 0 0021 16.27V7.73A4.73 4.73 0 0016.27 3zm-1.84 12.44h-2.1l-2.86-4.15v4.15H7.38V8.56h2.1l2.86 4.15V8.56h2.09v6.88z\"/></svg>`,\n facebook: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\"><path fill=\"#fff\" d=\"M24 12.07C24 5.41 18.63 0 12 0S0 5.4 0 12.07C0 18.1 4.39 23.1 10.13 24v-8.44H7.08v-3.49h3.04V9.41c0-3.02 1.8-4.7 4.54-4.7 1.31 0 2.68.24 2.68.24v2.97h-1.5c-1.5 0-1.96.93-1.96 1.89v2.26h3.33l-.53 3.49h-2.8V24C19.62 23.1 24 18.1 24 12.07z\"/></svg>`,\n github: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"#fff\"><path d=\"M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z\"/></svg>`,\n discord: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"#fff\"><path d=\"M20.32 4.37a19.8 19.8 0 00-4.89-1.52.07.07 0 00-.08.04c-.21.38-.44.87-.61 1.26a18.27 18.27 0 00-5.49 0 12.64 12.64 0 00-.62-1.26.07.07 0 00-.08-.04 19.74 19.74 0 00-4.89 1.52.07.07 0 00-.03.03C1.11 8.39.34 12.28.73 16.12a.08.08 0 00.03.06 19.9 19.9 0 005.99 3.03.08.08 0 00.08-.03c.46-.63.87-1.3 1.22-2a.08.08 0 00-.04-.11 13.1 13.1 0 01-1.87-.9.08.08 0 01-.01-.13c.13-.09.25-.19.37-.29a.07.07 0 01.08-.01c3.93 1.8 8.18 1.8 12.07 0a.07.07 0 01.08 0c.12.1.25.2.37.3a.08.08 0 01-.01.12c-.6.35-1.22.65-1.87.9a.08.08 0 00-.04.1c.36.7.77 1.37 1.22 2a.08.08 0 00.08.03 19.83 19.83 0 006-3.03.08.08 0 00.03-.05c.47-4.87-.78-9.09-3.3-12.84a.06.06 0 00-.03-.03zM8.02 13.62c-1.11 0-2.03-1.02-2.03-2.28 0-1.26.9-2.28 2.03-2.28 1.14 0 2.04 1.03 2.03 2.28 0 1.26-.9 2.28-2.03 2.28zm7.5 0c-1.11 0-2.03-1.02-2.03-2.28 0-1.26.9-2.28 2.03-2.28 1.14 0 2.04 1.03 2.03 2.28 0 1.26-.89 2.28-2.03 2.28z\"/></svg>`,\n x: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"#fff\"><path d=\"M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z\"/></svg>`,\n line: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"#fff\"><path d=\"M19.365 9.863c.349 0 .63.285.63.631 0 .345-.281.63-.63.63H17.61v1.125h1.755c.349 0 .63.283.63.63 0 .344-.281.629-.63.629h-2.386c-.345 0-.627-.285-.627-.629V8.108c0-.345.282-.63.63-.63h2.386c.346 0 .627.285.627.63 0 .349-.281.63-.63.63H17.61v1.125h1.755zm-3.855 3.016c0 .27-.174.51-.432.596-.064.021-.133.031-.199.031-.211 0-.391-.09-.51-.25l-2.443-3.317v2.94c0 .344-.279.629-.631.629-.346 0-.626-.285-.626-.629V8.108c0-.27.173-.51.43-.595.06-.023.136-.033.194-.033.195 0 .375.104.495.254l2.462 3.33V8.108c0-.345.282-.63.63-.63.345 0 .63.285.63.63v4.771zm-5.741 0c0 .344-.282.629-.631.629-.345 0-.627-.285-.627-.629V8.108c0-.345.282-.63.63-.63.346 0 .628.285.628.63v4.771zm-2.466.629H4.917c-.345 0-.63-.285-.63-.629V8.108c0-.345.285-.63.63-.63.348 0 .63.285.63.63v4.141h1.756c.348 0 .629.283.629.63 0 .344-.282.629-.629.629M24 10.314C24 4.943 18.615.572 12 .572S0 4.943 0 10.314c0 4.811 4.27 8.842 10.035 9.608.391.082.923.258 1.058.59.12.301.079.766.038 1.08l-.164 1.02c-.045.301-.24 1.186 1.049.645 1.291-.539 6.916-4.078 9.436-6.975C23.176 14.393 24 12.458 24 10.314\"/></svg>`,\n microsoft: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\"><rect fill=\"#F25022\" x=\"1\" y=\"1\" width=\"10\" height=\"10\"/><rect fill=\"#7FBA00\" x=\"13\" y=\"1\" width=\"10\" height=\"10\"/><rect fill=\"#00A4EF\" x=\"1\" y=\"13\" width=\"10\" height=\"10\"/><rect fill=\"#FFB900\" x=\"13\" y=\"13\" width=\"10\" height=\"10\"/></svg>`,\n};\n\nexport function getProviderButtonConfig(provider: OAuthProviderType): ProviderButtonConfig {\n const colors = PROVIDER_COLORS[provider];\n return {\n provider,\n label: `Continue with ${PROVIDER_DISPLAY_NAMES[provider]}`,\n bgColor: colors.bg,\n textColor: colors.text,\n iconSvg: PROVIDER_ICONS[provider],\n };\n}\n","import type { AuthonUser, AuthTokens } from '@authon/shared';\n\nexport class SessionManager {\n private accessToken: string | null = null;\n private refreshToken: string | null = null;\n private user: AuthonUser | null = null;\n private refreshTimer: ReturnType<typeof setTimeout> | null = null;\n private apiUrl: string;\n private publishableKey: string;\n\n constructor(publishableKey: string, apiUrl: string) {\n this.publishableKey = publishableKey;\n this.apiUrl = apiUrl;\n }\n\n getToken(): string | null {\n return this.accessToken;\n }\n\n getUser(): AuthonUser | null {\n return this.user;\n }\n\n setSession(tokens: AuthTokens): void {\n this.accessToken = tokens.accessToken;\n this.refreshToken = tokens.refreshToken;\n this.user = tokens.user;\n if (tokens.expiresIn && tokens.expiresIn > 0) {\n this.scheduleRefresh(tokens.expiresIn);\n }\n }\n\n clearSession(): void {\n this.accessToken = null;\n this.refreshToken = null;\n this.user = null;\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n this.refreshTimer = null;\n }\n }\n\n private scheduleRefresh(expiresIn: number): void {\n if (this.refreshTimer) clearTimeout(this.refreshTimer);\n // Refresh 60 seconds before expiry\n const refreshIn = Math.max((expiresIn - 60) * 1000, 30000);\n this.refreshTimer = setTimeout(() => this.refresh(), refreshIn);\n }\n\n async refresh(): Promise<AuthTokens | null> {\n if (!this.refreshToken) {\n this.clearSession();\n return null;\n }\n try {\n const res = await fetch(`${this.apiUrl}/v1/auth/token/refresh`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': this.publishableKey,\n },\n credentials: 'include',\n body: JSON.stringify({ refreshToken: this.refreshToken }),\n });\n if (!res.ok) {\n this.clearSession();\n return null;\n }\n const tokens: AuthTokens = await res.json();\n this.setSession(tokens);\n return tokens;\n } catch {\n this.clearSession();\n return null;\n }\n }\n\n async signOut(): Promise<void> {\n try {\n await fetch(`${this.apiUrl}/v1/auth/signout`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': this.publishableKey,\n ...(this.accessToken ? { Authorization: `Bearer ${this.accessToken}` } : {}),\n },\n credentials: 'include',\n });\n } catch {\n // ignore\n }\n this.clearSession();\n }\n\n destroy(): void {\n this.clearSession();\n }\n}\n","import type { AuthonUser, AuthTokens, BrandingConfig, OAuthProviderType } from '@authon/shared';\nimport type { AuthonConfig, AuthonEventType, AuthonEvents } from './types';\nimport { ModalRenderer } from './modal';\nimport { SessionManager } from './session';\n\nexport class Authon {\n private publishableKey: string;\n private config: Required<Omit<AuthonConfig, 'containerId' | 'appearance'>> & {\n containerId?: string;\n appearance?: Partial<BrandingConfig>;\n };\n private session: SessionManager;\n private modal: ModalRenderer | null = null;\n private listeners: Map<string, Set<(...args: unknown[]) => void>> = new Map();\n private branding: BrandingConfig | null = null;\n private providers: OAuthProviderType[] = [];\n private initialized = false;\n\n constructor(publishableKey: string, config?: AuthonConfig) {\n this.publishableKey = publishableKey;\n this.config = {\n apiUrl: config?.apiUrl || 'https://api.authon.dev',\n mode: config?.mode || 'popup',\n theme: config?.theme || 'auto',\n locale: config?.locale || 'en',\n containerId: config?.containerId,\n appearance: config?.appearance,\n };\n this.session = new SessionManager(publishableKey, this.config.apiUrl);\n }\n\n // ── Public API ──\n\n async openSignIn(): Promise<void> {\n await this.ensureInitialized();\n this.getModal().open('signIn');\n }\n\n async openSignUp(): Promise<void> {\n await this.ensureInitialized();\n this.getModal().open('signUp');\n }\n\n async signInWithOAuth(provider: OAuthProviderType): Promise<void> {\n await this.ensureInitialized();\n await this.startOAuthFlow(provider);\n }\n\n async signInWithEmail(email: string, password: string): Promise<AuthonUser> {\n const tokens = await this.apiPost<AuthTokens>('/v1/auth/signin', { email, password });\n this.session.setSession(tokens);\n this.emit('signedIn', tokens.user);\n return tokens.user;\n }\n\n async signUpWithEmail(\n email: string,\n password: string,\n meta?: { displayName?: string },\n ): Promise<AuthonUser> {\n const tokens = await this.apiPost<AuthTokens>('/v1/auth/signup', {\n email,\n password,\n ...meta,\n });\n this.session.setSession(tokens);\n this.emit('signedIn', tokens.user);\n return tokens.user;\n }\n\n async signOut(): Promise<void> {\n await this.session.signOut();\n this.emit('signedOut');\n }\n\n getUser(): AuthonUser | null {\n return this.session.getUser();\n }\n\n getToken(): string | null {\n return this.session.getToken();\n }\n\n on<K extends AuthonEventType>(event: K, listener: AuthonEvents[K]): () => void {\n if (!this.listeners.has(event)) this.listeners.set(event, new Set());\n const set = this.listeners.get(event)!;\n set.add(listener as (...args: unknown[]) => void);\n return () => set.delete(listener as (...args: unknown[]) => void);\n }\n\n destroy(): void {\n this.modal?.close();\n this.session.destroy();\n this.listeners.clear();\n }\n\n // ── Internal ──\n\n private emit(event: string, ...args: unknown[]): void {\n this.listeners.get(event)?.forEach((fn) => fn(...args));\n }\n\n private async ensureInitialized(): Promise<void> {\n if (this.initialized) return;\n try {\n const [branding, providersRes] = await Promise.all([\n this.apiGet<BrandingConfig>('/v1/auth/branding'),\n this.apiGet<{ providers: OAuthProviderType[] }>('/v1/auth/providers'),\n ]);\n this.branding = { ...branding, ...this.config.appearance };\n this.providers = providersRes.providers;\n this.initialized = true;\n } catch (err) {\n this.emit('error', err instanceof Error ? err : new Error(String(err)));\n throw err;\n }\n }\n\n private getModal(): ModalRenderer {\n if (!this.modal) {\n this.modal = new ModalRenderer({\n mode: this.config.mode,\n theme: this.config.theme,\n containerId: this.config.containerId,\n branding: this.branding || undefined,\n onProviderClick: (provider) => this.startOAuthFlow(provider),\n onEmailSubmit: (email, password, isSignUp) => {\n this.modal?.clearError();\n const promise = isSignUp\n ? this.signUpWithEmail(email, password)\n : this.signInWithEmail(email, password);\n promise\n .then(() => this.modal?.close())\n .catch((err) => {\n const msg = err instanceof Error ? err.message : String(err);\n this.modal?.showError(msg || 'Authentication failed');\n this.emit('error', err instanceof Error ? err : new Error(msg));\n });\n },\n onClose: () => this.modal?.close(),\n });\n }\n if (this.branding) this.modal.setBranding(this.branding);\n this.modal.setProviders(this.providers);\n return this.modal;\n }\n\n private async startOAuthFlow(provider: OAuthProviderType): Promise<void> {\n try {\n const redirectUri = `${this.config.apiUrl}/v1/auth/oauth/redirect`;\n const { url, state } = await this.apiGet<{ url: string; state: string }>(\n `/v1/auth/oauth/${provider}/url?redirectUri=${encodeURIComponent(redirectUri)}`,\n );\n\n this.modal?.showLoading();\n\n // Open popup\n const width = 500;\n const height = 700;\n const left = window.screenX + (window.outerWidth - width) / 2;\n const top = window.screenY + (window.outerHeight - height) / 2;\n const popup = window.open(\n url,\n 'authon-oauth',\n `width=${width},height=${height},left=${left},top=${top},toolbar=no,menubar=no`,\n );\n\n if (!popup || popup.closed) {\n this.modal?.hideLoading();\n this.modal?.showBanner(\n 'Pop-up blocked. Please allow pop-ups for this site and try again.',\n 'warning',\n );\n this.emit('error', new Error('Popup was blocked by the browser'));\n return;\n }\n\n let resolved = false;\n let cleaned = false;\n\n const resolve = (tokens: AuthTokens) => {\n if (resolved) return;\n resolved = true;\n cleanup();\n try { if (!popup.closed) popup.close(); } catch { /* ignore */ }\n this.session.setSession(tokens);\n this.modal?.close();\n this.emit('signedIn', tokens.user);\n };\n\n const handleError = (msg: string) => {\n if (resolved) return;\n cleanup();\n this.modal?.hideLoading();\n this.modal?.showError(msg);\n this.emit('error', new Error(msg));\n };\n\n const cleanup = () => {\n if (cleaned) return;\n cleaned = true;\n window.removeEventListener('message', messageHandler);\n if (apiPollTimer) clearInterval(apiPollTimer);\n if (closePollTimer) clearInterval(closePollTimer);\n if (maxTimer) clearTimeout(maxTimer);\n };\n\n // 1. postMessage handler (fast path — Chrome/Firefox)\n const messageHandler = (e: MessageEvent) => {\n if (e.data?.type !== 'authon-oauth-callback') return;\n if (e.data.tokens) {\n resolve(e.data.tokens as AuthTokens);\n }\n };\n window.addEventListener('message', messageHandler);\n\n // 2. API polling (Safari fallback — window.opener severed by COOP)\n const apiPollTimer = setInterval(async () => {\n if (resolved || cleaned) return;\n try {\n const result = await this.apiGet<{ status: string; accessToken?: string; refreshToken?: string; expiresIn?: number; user?: AuthonUser; message?: string }>(\n `/v1/auth/oauth/poll?state=${encodeURIComponent(state)}`,\n );\n if (result.status === 'completed' && result.accessToken) {\n resolve({\n accessToken: result.accessToken,\n refreshToken: result.refreshToken!,\n expiresIn: result.expiresIn!,\n user: result.user!,\n });\n } else if (result.status === 'error') {\n handleError(result.message || 'Authentication failed');\n }\n } catch {\n // Network error — keep polling\n }\n }, 1500);\n\n // 3. Popup close detection\n const closePollTimer = setInterval(() => {\n if (resolved || cleaned) return;\n try {\n if (popup.closed) {\n clearInterval(closePollTimer);\n // Give polling a few more seconds to pick up the result\n setTimeout(() => {\n if (resolved || cleaned) return;\n cleanup();\n this.modal?.hideLoading();\n }, 3000);\n }\n } catch {\n // Cross-origin access error — popup still open\n }\n }, 500);\n\n // 4. Max timeout (3 minutes)\n const maxTimer = setTimeout(() => {\n if (resolved || cleaned) return;\n cleanup();\n this.modal?.hideLoading();\n }, 180_000);\n } catch (err) {\n this.modal?.hideLoading();\n this.emit('error', err instanceof Error ? err : new Error(String(err)));\n }\n }\n\n private async apiGet<T>(path: string): Promise<T> {\n const res = await fetch(`${this.config.apiUrl}${path}`, {\n headers: { 'x-api-key': this.publishableKey },\n credentials: 'include',\n });\n if (!res.ok) throw new Error(await this.parseApiError(res, path));\n return res.json();\n }\n\n private async apiPost<T>(path: string, body?: unknown): Promise<T> {\n const res = await fetch(`${this.config.apiUrl}${path}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': this.publishableKey,\n },\n credentials: 'include',\n body: body ? JSON.stringify(body) : undefined,\n });\n if (!res.ok) throw new Error(await this.parseApiError(res, path));\n return res.json();\n }\n\n private async parseApiError(res: Response, path: string): Promise<string> {\n try {\n const body = await res.json();\n if (Array.isArray(body.message) && body.message.length > 0) {\n return body.message[0];\n }\n if (typeof body.message === 'string' && body.message !== 'Bad Request') {\n return body.message;\n }\n } catch { /* ignore */ }\n return `API ${path}: ${res.status}`;\n }\n}\n"],"mappings":"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","names":["import_shared"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/modal.ts","../src/providers.ts","../src/session.ts","../src/authon.ts"],"sourcesContent":["export { Authon } from './authon';\nexport type { AuthonConfig, AuthonEvents, AuthonEventType } from './types';\nexport { getProviderButtonConfig } from './providers';\nexport type { ProviderButtonConfig } from './providers';\n","import type { BrandingConfig, OAuthProviderType } from '@authon/shared';\nimport { DEFAULT_BRANDING } from '@authon/shared';\nimport { getProviderButtonConfig } from './providers';\n\nexport class ModalRenderer {\n private shadowRoot: ShadowRoot | null = null;\n private hostElement: HTMLDivElement | null = null;\n private containerElement: HTMLElement | null = null;\n private mode: 'popup' | 'embedded';\n private theme: 'light' | 'dark' | 'auto';\n private branding: BrandingConfig;\n private enabledProviders: OAuthProviderType[] = [];\n private currentView: 'signIn' | 'signUp' = 'signIn';\n private onProviderClick: (provider: OAuthProviderType) => void;\n private onEmailSubmit: (email: string, password: string, isSignUp: boolean) => void;\n private onClose: () => void;\n private escHandler: ((e: KeyboardEvent) => void) | null = null;\n\n constructor(options: {\n mode: 'popup' | 'embedded';\n theme?: 'light' | 'dark' | 'auto';\n containerId?: string;\n branding?: BrandingConfig;\n onProviderClick: (provider: OAuthProviderType) => void;\n onEmailSubmit: (email: string, password: string, isSignUp: boolean) => void;\n onClose: () => void;\n }) {\n this.mode = options.mode;\n this.theme = options.theme || 'auto';\n this.branding = { ...DEFAULT_BRANDING, ...options.branding };\n this.onProviderClick = options.onProviderClick;\n this.onEmailSubmit = options.onEmailSubmit;\n this.onClose = options.onClose;\n\n if (options.mode === 'embedded' && options.containerId) {\n this.containerElement = document.getElementById(options.containerId);\n }\n }\n\n setProviders(providers: OAuthProviderType[]): void {\n this.enabledProviders = providers;\n }\n\n setBranding(branding: BrandingConfig): void {\n this.branding = { ...DEFAULT_BRANDING, ...branding };\n }\n\n open(view: 'signIn' | 'signUp' = 'signIn'): void {\n if (this.shadowRoot && this.hostElement) {\n // Modal already open — smooth in-place view switch\n this.switchView(view);\n } else {\n this.currentView = view;\n this.render(view);\n }\n }\n\n close(): void {\n if (this.escHandler) {\n document.removeEventListener('keydown', this.escHandler);\n this.escHandler = null;\n }\n if (this.hostElement) {\n this.hostElement.remove();\n this.hostElement = null;\n this.shadowRoot = null;\n }\n if (this.containerElement) {\n this.containerElement.innerHTML = '';\n }\n }\n\n showError(message: string): void {\n if (!this.shadowRoot) return;\n this.clearError();\n const errorEl = this.shadowRoot.getElementById('email-form');\n if (errorEl) {\n const errDiv = document.createElement('div');\n errDiv.id = 'authon-error-msg';\n errDiv.className = 'error-msg';\n errDiv.textContent = message;\n errorEl.appendChild(errDiv);\n }\n }\n\n showBanner(message: string, type: 'error' | 'warning' = 'error'): void {\n if (!this.shadowRoot) return;\n this.clearBanner();\n const inner = this.shadowRoot.getElementById('modal-inner');\n if (!inner) return;\n const banner = document.createElement('div');\n banner.id = 'authon-banner';\n banner.className = type === 'warning' ? 'banner-warning' : 'error-msg';\n banner.textContent = message;\n inner.insertBefore(banner, inner.firstChild);\n }\n\n clearBanner(): void {\n if (!this.shadowRoot) return;\n this.shadowRoot.getElementById('authon-banner')?.remove();\n }\n\n clearError(): void {\n if (!this.shadowRoot) return;\n this.shadowRoot.getElementById('authon-error-msg')?.remove();\n }\n\n showLoading(): void {\n if (!this.shadowRoot) return;\n this.hideLoading();\n const overlay = document.createElement('div');\n overlay.id = 'authon-loading-overlay';\n overlay.innerHTML = `\n <div class=\"loading-spinner\">\n <div class=\"loading-ring\"></div>\n <div class=\"loading-ring\"></div>\n <div class=\"loading-ring\"></div>\n </div>\n <div class=\"loading-text\">Signing in<span class=\"loading-dots\"><span></span><span></span><span></span></span></div>\n `;\n this.shadowRoot.querySelector('.modal-container')?.appendChild(overlay);\n }\n\n hideLoading(): void {\n if (!this.shadowRoot) return;\n this.shadowRoot.getElementById('authon-loading-overlay')?.remove();\n }\n\n // ── Smooth view switch (no flicker) ──\n\n private switchView(view: 'signIn' | 'signUp'): void {\n if (!this.shadowRoot || view === this.currentView) return;\n this.currentView = view;\n\n const inner = this.shadowRoot.getElementById('modal-inner');\n if (!inner) return;\n\n // Cross-fade: fade out → update → fade in\n inner.style.opacity = '0';\n inner.style.transform = 'translateY(-4px)';\n\n setTimeout(() => {\n inner.innerHTML = this.buildInnerContent(view);\n this.attachInnerEvents(view);\n // Trigger reflow, then animate in\n void inner.offsetHeight;\n inner.style.opacity = '1';\n inner.style.transform = 'translateY(0)';\n }, 140);\n }\n\n // ── Render ──\n\n private render(view: 'signIn' | 'signUp'): void {\n const host = document.createElement('div');\n host.setAttribute('data-authon-modal', '');\n this.hostElement = host;\n\n if (this.mode === 'popup') {\n document.body.appendChild(host);\n } else if (this.containerElement) {\n this.containerElement.appendChild(host);\n }\n\n this.shadowRoot = host.attachShadow({ mode: 'open' });\n this.shadowRoot.innerHTML = this.buildShell(view);\n this.attachInnerEvents(view);\n this.attachShellEvents();\n }\n\n // ── HTML builders ──\n\n /** Shell = style + backdrop + modal-container (stable across view switches) */\n private buildShell(view: 'signIn' | 'signUp'): string {\n const popupWrapper =\n this.mode === 'popup'\n ? `<div class=\"backdrop\" id=\"backdrop\"></div>`\n : '';\n\n return `\n <style>${this.buildCSS()}</style>\n ${popupWrapper}\n <div class=\"modal-container\" role=\"dialog\" aria-modal=\"true\">\n <div id=\"modal-inner\" class=\"modal-inner\">\n ${this.buildInnerContent(view)}\n </div>\n </div>\n `;\n }\n\n /** Inner content = everything inside the modal that changes per view */\n private buildInnerContent(view: 'signIn' | 'signUp'): string {\n const b = this.branding;\n const isSignUp = view === 'signUp';\n const title = isSignUp ? 'Create your account' : 'Welcome back';\n const subtitle = isSignUp ? 'Already have an account?' : \"Don't have an account?\";\n const subtitleLink = isSignUp ? 'Sign in' : 'Sign up';\n\n const dark = this.isDark();\n\n // SignUp view: hide providers, show only email form\n const showProviders = !isSignUp;\n\n const providerButtons = showProviders\n ? this.enabledProviders\n .filter((p) => !b.hiddenProviders?.includes(p))\n .map((p) => {\n const config = getProviderButtonConfig(p);\n const isWhiteBg = config.bgColor === '#ffffff';\n const btnBg = dark && isWhiteBg ? '#f8fafc' : config.bgColor;\n const btnBorder = isWhiteBg ? (dark ? '#475569' : '#e5e7eb') : config.bgColor;\n return `<button class=\"provider-btn\" data-provider=\"${p}\" style=\"background:${btnBg};color:${config.textColor};border:1px solid ${btnBorder}\">\n <span class=\"provider-icon\">${config.iconSvg}</span>\n <span>${config.label}</span>\n </button>`;\n })\n .join('')\n : '';\n\n const divider =\n showProviders && b.showDivider !== false && b.showEmailPassword !== false\n ? `<div class=\"divider\"><span>or</span></div>`\n : '';\n\n const emailForm =\n b.showEmailPassword !== false\n ? `<form class=\"email-form\" id=\"email-form\">\n <input type=\"email\" placeholder=\"Email address\" name=\"email\" required class=\"input\" autocomplete=\"email\" />\n <input type=\"password\" placeholder=\"Password\" name=\"password\" required class=\"input\" autocomplete=\"${isSignUp ? 'new-password' : 'current-password'}\" />\n ${isSignUp ? '<p class=\"password-hint\">Must contain uppercase, lowercase, and a number (min 8 chars)</p>' : ''}\n <button type=\"submit\" class=\"submit-btn\">${isSignUp ? 'Sign up' : 'Sign in'}</button>\n </form>`\n : '';\n\n const footer =\n b.termsUrl || b.privacyUrl\n ? `<div class=\"footer\">\n ${b.termsUrl ? `<a href=\"${b.termsUrl}\" target=\"_blank\">Terms of Service</a>` : ''}\n ${b.termsUrl && b.privacyUrl ? ' · ' : ''}\n ${b.privacyUrl ? `<a href=\"${b.privacyUrl}\" target=\"_blank\">Privacy Policy</a>` : ''}\n </div>`\n : '';\n\n const titleHtml = isSignUp\n ? `<div class=\"title-row\">\n <button class=\"back-btn\" id=\"back-btn\" type=\"button\" aria-label=\"Back to sign in\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M19 12H5\"/><path d=\"m12 19-7-7 7-7\"/></svg>\n </button>\n <h2 class=\"title\">${title}</h2>\n </div>`\n : `<h2 class=\"title\">${title}</h2>`;\n\n return `\n ${b.logoDataUrl ? `<img src=\"${b.logoDataUrl}\" alt=\"Logo\" class=\"logo\" />` : ''}\n ${titleHtml}\n ${b.brandName ? `<p class=\"brand-name\">${b.brandName}</p>` : ''}\n ${showProviders ? `<div class=\"providers\">${providerButtons}</div>` : ''}\n ${divider}\n ${emailForm}\n <p class=\"switch-view\">${subtitle} <a href=\"#\" id=\"switch-link\">${subtitleLink}</a></p>\n ${footer}\n ${b.showSecuredBy !== false ? `<div class=\"secured-by\">Secured by <a href=\"https://authon.dev\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"secured-link\">Authon</a></div>` : ''}\n `;\n }\n\n private isDark(): boolean {\n if (this.theme === 'dark') return true;\n if (this.theme === 'light') return false;\n return typeof window !== 'undefined' && window.matchMedia('(prefers-color-scheme: dark)').matches;\n }\n\n private buildCSS(): string {\n const b = this.branding;\n const dark = this.isDark();\n const bg = dark ? (b.darkBg || '#0f172a') : (b.lightBg || '#ffffff');\n const text = dark ? (b.darkText || '#f1f5f9') : (b.lightText || '#111827');\n const mutedText = dark ? '#94a3b8' : '#6b7280';\n const dimText = dark ? '#64748b' : '#9ca3af';\n const borderColor = dark ? '#334155' : '#d1d5db';\n const dividerColor = dark ? '#334155' : '#e5e7eb';\n const inputBg = dark ? '#1e293b' : '#ffffff';\n\n return `\n :host {\n --authon-primary-start: ${b.primaryColorStart || '#7c3aed'};\n --authon-primary-end: ${b.primaryColorEnd || '#4f46e5'};\n --authon-bg: ${bg};\n --authon-text: ${text};\n --authon-muted: ${mutedText};\n --authon-dim: ${dimText};\n --authon-border: ${borderColor};\n --authon-divider: ${dividerColor};\n --authon-input-bg: ${inputBg};\n --authon-radius: ${b.borderRadius ?? 12}px;\n --authon-font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n font-family: var(--authon-font);\n color: var(--authon-text);\n }\n * { box-sizing: border-box; margin: 0; padding: 0; }\n .backdrop {\n position: fixed; inset: 0; z-index: 99998;\n background: rgba(0,0,0,${dark ? '0.7' : '0.5'}); backdrop-filter: blur(4px);\n animation: fadeIn 0.2s ease;\n }\n .modal-container {\n ${this.mode === 'popup' ? 'position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 99999; max-height: 90vh; overflow-y: auto;' : ''}\n background: var(--authon-bg);\n color: var(--authon-text);\n border: 1px solid var(--authon-border);\n border-radius: var(--authon-radius);\n padding: 32px;\n width: 400px; max-width: 100%;\n position: ${this.mode === 'popup' ? 'fixed' : 'relative'};\n ${this.mode === 'popup' ? `box-shadow: 0 25px 50px -12px rgba(0,0,0,${dark ? '0.5' : '0.25'}); animation: slideIn 0.3s ease;` : ''}\n }\n .modal-inner {\n transition: opacity 0.14s ease, transform 0.14s ease;\n }\n .logo { display: block; margin: 0 auto 16px; max-height: 48px; }\n .title-row { display: flex; align-items: center; position: relative; margin-bottom: 8px; }\n .title-row .title { flex: 1; margin-bottom: 0; }\n .back-btn {\n position: absolute; left: 0; top: 50%; transform: translateY(-50%);\n background: none; border: none; color: var(--authon-muted);\n cursor: pointer; padding: 4px; border-radius: 6px; display: flex; align-items: center; justify-content: center;\n transition: color 0.15s, background 0.15s;\n }\n .back-btn:hover { color: var(--authon-text); background: var(--authon-divider); }\n .password-hint { font-size: 11px; color: var(--authon-dim); margin: -4px 0 2px; }\n .title { text-align: center; font-size: 24px; font-weight: 700; margin-bottom: 8px; color: var(--authon-text); }\n .brand-name { text-align: center; font-size: 14px; color: var(--authon-muted); margin-bottom: 24px; }\n .providers { display: flex; flex-direction: column; gap: 8px; margin-bottom: 16px; }\n .provider-btn {\n display: flex; align-items: center; gap: 12px;\n width: 100%; padding: 10px 16px; border-radius: calc(var(--authon-radius) * 0.67);\n font-size: 14px; font-weight: 500; cursor: pointer;\n transition: opacity 0.15s, transform 0.1s;\n font-family: var(--authon-font);\n }\n .provider-btn:hover { opacity: 0.9; }\n .provider-btn:active { transform: scale(0.98); }\n .provider-icon { display: flex; align-items: center; flex-shrink: 0; }\n .divider {\n display: flex; align-items: center; gap: 12px;\n margin: 16px 0; color: var(--authon-dim); font-size: 13px;\n }\n .divider::before, .divider::after {\n content: ''; flex: 1; height: 1px; background: var(--authon-divider);\n }\n .email-form { display: flex; flex-direction: column; gap: 10px; }\n .input {\n width: 100%; padding: 10px 14px;\n background: var(--authon-input-bg);\n color: var(--authon-text);\n border: 1px solid var(--authon-border); border-radius: calc(var(--authon-radius) * 0.5);\n font-size: 14px; font-family: var(--authon-font);\n outline: none; transition: border-color 0.15s;\n }\n .input::placeholder { color: var(--authon-dim); }\n .input:focus { border-color: var(--authon-primary-start); box-shadow: 0 0 0 3px rgba(124,58,237,0.15); }\n .submit-btn {\n width: 100%; padding: 10px;\n background: linear-gradient(135deg, var(--authon-primary-start), var(--authon-primary-end));\n color: #fff; border: none; border-radius: calc(var(--authon-radius) * 0.5);\n font-size: 14px; font-weight: 600; cursor: pointer;\n font-family: var(--authon-font); transition: opacity 0.15s;\n }\n .submit-btn:hover { opacity: 0.9; }\n .submit-btn:disabled { opacity: 0.6; cursor: not-allowed; }\n .error-msg {\n margin-top: 8px; padding: 8px 12px;\n background: rgba(239,68,68,0.1); border: 1px solid rgba(239,68,68,0.3);\n border-radius: calc(var(--authon-radius) * 0.33);\n font-size: 13px; color: #ef4444; text-align: center;\n animation: fadeIn 0.15s ease;\n }\n .banner-warning {\n margin-bottom: 16px; padding: 10px 14px;\n background: rgba(245,158,11,0.1); border: 1px solid rgba(245,158,11,0.3);\n border-radius: calc(var(--authon-radius) * 0.33);\n font-size: 13px; color: #f59e0b; text-align: center;\n animation: fadeIn 0.15s ease;\n }\n .switch-view { text-align: center; margin-top: 16px; font-size: 13px; color: var(--authon-muted); }\n .switch-view a { color: var(--authon-primary-start); text-decoration: none; font-weight: 500; }\n .switch-view a:hover { text-decoration: underline; }\n .footer { text-align: center; margin-top: 12px; font-size: 12px; color: var(--authon-dim); }\n .footer a { color: var(--authon-dim); text-decoration: none; }\n .footer a:hover { text-decoration: underline; }\n .secured-by {\n text-align: center; margin-top: 16px;\n font-size: 11px; color: var(--authon-dim);\n }\n .secured-link { font-weight: 600; color: var(--authon-muted); text-decoration: none; }\n .secured-link:hover { text-decoration: underline; }\n /* Loading overlay */\n #authon-loading-overlay {\n position: absolute; inset: 0; z-index: 10;\n background: ${dark ? 'rgba(15,23,42,0.92)' : 'rgba(255,255,255,0.92)'};\n backdrop-filter: blur(2px);\n border-radius: var(--authon-radius);\n display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 20px;\n animation: fadeIn 0.15s ease;\n }\n .loading-spinner { position: relative; width: 48px; height: 48px; }\n .loading-ring {\n position: absolute; inset: 0;\n border: 2.5px solid transparent; border-top-color: var(--authon-primary-start);\n border-radius: 50%; animation: spin 1s cubic-bezier(.55,.15,.45,.85) infinite;\n }\n .loading-ring:nth-child(2) {\n inset: 5px; border-top-color: transparent; border-right-color: var(--authon-primary-end);\n animation-duration: 1.2s; animation-direction: reverse; opacity: .7;\n }\n .loading-ring:nth-child(3) {\n inset: 10px; border-top-color: transparent; border-bottom-color: var(--authon-primary-start);\n animation-duration: .8s; opacity: .4;\n }\n .loading-text { font-size: 14px; font-weight: 500; color: var(--authon-muted); }\n .loading-dots { display: inline-flex; gap: 2px; margin-left: 2px; }\n .loading-dots span {\n width: 3px; height: 3px; border-radius: 50%;\n background: var(--authon-muted); animation: blink 1.4s infinite both;\n }\n .loading-dots span:nth-child(2) { animation-delay: .2s; }\n .loading-dots span:nth-child(3) { animation-delay: .4s; }\n @keyframes spin { to { transform: rotate(360deg); } }\n @keyframes blink { 0%,80%,100% { opacity: .2; } 40% { opacity: 1; } }\n @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }\n @keyframes slideIn { from { opacity: 0; transform: translate(-50%, -48%); } to { opacity: 1; transform: translate(-50%, -50%); } }\n ${b.customCss || ''}\n `;\n }\n\n // ── Event binding ──\n\n /** Attach events to shell elements (backdrop, ESC) — called once */\n private attachShellEvents(): void {\n if (!this.shadowRoot) return;\n\n const backdrop = this.shadowRoot.getElementById('backdrop');\n if (backdrop) {\n backdrop.addEventListener('click', () => this.onClose());\n }\n\n if (this.escHandler) {\n document.removeEventListener('keydown', this.escHandler);\n }\n if (this.mode === 'popup') {\n this.escHandler = (e: KeyboardEvent) => {\n if (e.key === 'Escape') this.onClose();\n };\n document.addEventListener('keydown', this.escHandler);\n }\n }\n\n /** Attach events to inner content (buttons, form, switch link) — called on each view */\n private attachInnerEvents(view: 'signIn' | 'signUp'): void {\n if (!this.shadowRoot) return;\n\n // Provider buttons\n this.shadowRoot.querySelectorAll('.provider-btn').forEach((btn) => {\n btn.addEventListener('click', () => {\n const provider = (btn as HTMLElement).dataset.provider as OAuthProviderType;\n this.onProviderClick(provider);\n });\n });\n\n // Email form\n const form = this.shadowRoot.getElementById('email-form') as HTMLFormElement | null;\n if (form) {\n form.addEventListener('submit', (e) => {\n e.preventDefault();\n const formData = new FormData(form);\n this.onEmailSubmit(\n formData.get('email') as string,\n formData.get('password') as string,\n view === 'signUp',\n );\n });\n }\n\n // Back button (signUp → signIn)\n const backBtn = this.shadowRoot.getElementById('back-btn');\n if (backBtn) {\n backBtn.addEventListener('click', () => {\n this.open('signIn');\n });\n }\n\n // Switch view link\n const switchLink = this.shadowRoot.getElementById('switch-link');\n if (switchLink) {\n switchLink.addEventListener('click', (e) => {\n e.preventDefault();\n this.open(view === 'signIn' ? 'signUp' : 'signIn');\n });\n }\n }\n}\n","import { PROVIDER_COLORS, PROVIDER_DISPLAY_NAMES, type OAuthProviderType } from '@authon/shared';\n\nexport interface ProviderButtonConfig {\n provider: OAuthProviderType;\n label: string;\n bgColor: string;\n textColor: string;\n iconSvg: string;\n}\n\nconst PROVIDER_ICONS: Record<OAuthProviderType, string> = {\n google: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\"><path fill=\"#4285F4\" d=\"M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 01-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z\"/><path fill=\"#34A853\" d=\"M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z\"/><path fill=\"#FBBC05\" d=\"M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z\"/><path fill=\"#EA4335\" d=\"M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z\"/></svg>`,\n apple: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"currentColor\"><path d=\"M17.05 20.28c-.98.95-2.05.88-3.08.4-1.09-.5-2.08-.48-3.24 0-1.44.62-2.2.44-3.06-.4C2.79 15.25 3.51 7.59 9.05 7.31c1.35.07 2.29.74 3.08.8 1.18-.24 2.31-.93 3.57-.84 1.51.12 2.65.72 3.4 1.8-3.12 1.87-2.38 5.98.48 7.13-.57 1.5-1.31 2.99-2.54 4.09zM12.03 7.25c-.15-2.23 1.66-4.07 3.74-4.25.29 2.58-2.34 4.5-3.74 4.25z\"/></svg>`,\n kakao: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\"><path fill=\"#191919\" d=\"M12 3C6.48 3 2 6.36 2 10.43c0 2.62 1.75 4.93 4.37 6.23l-1.12 4.14c-.1.36.31.65.62.44l4.93-3.26c.39.04.79.06 1.2.06 5.52 0 10-3.36 10-7.61C22 6.36 17.52 3 12 3z\"/></svg>`,\n naver: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\"><path fill=\"#fff\" d=\"M16.27 3H7.73A4.73 4.73 0 003 7.73v8.54A4.73 4.73 0 007.73 21h8.54A4.73 4.73 0 0021 16.27V7.73A4.73 4.73 0 0016.27 3zm-1.84 12.44h-2.1l-2.86-4.15v4.15H7.38V8.56h2.1l2.86 4.15V8.56h2.09v6.88z\"/></svg>`,\n facebook: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\"><path fill=\"#fff\" d=\"M24 12.07C24 5.41 18.63 0 12 0S0 5.4 0 12.07C0 18.1 4.39 23.1 10.13 24v-8.44H7.08v-3.49h3.04V9.41c0-3.02 1.8-4.7 4.54-4.7 1.31 0 2.68.24 2.68.24v2.97h-1.5c-1.5 0-1.96.93-1.96 1.89v2.26h3.33l-.53 3.49h-2.8V24C19.62 23.1 24 18.1 24 12.07z\"/></svg>`,\n github: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"#fff\"><path d=\"M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z\"/></svg>`,\n discord: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"#fff\"><path d=\"M20.32 4.37a19.8 19.8 0 00-4.89-1.52.07.07 0 00-.08.04c-.21.38-.44.87-.61 1.26a18.27 18.27 0 00-5.49 0 12.64 12.64 0 00-.62-1.26.07.07 0 00-.08-.04 19.74 19.74 0 00-4.89 1.52.07.07 0 00-.03.03C1.11 8.39.34 12.28.73 16.12a.08.08 0 00.03.06 19.9 19.9 0 005.99 3.03.08.08 0 00.08-.03c.46-.63.87-1.3 1.22-2a.08.08 0 00-.04-.11 13.1 13.1 0 01-1.87-.9.08.08 0 01-.01-.13c.13-.09.25-.19.37-.29a.07.07 0 01.08-.01c3.93 1.8 8.18 1.8 12.07 0a.07.07 0 01.08 0c.12.1.25.2.37.3a.08.08 0 01-.01.12c-.6.35-1.22.65-1.87.9a.08.08 0 00-.04.1c.36.7.77 1.37 1.22 2a.08.08 0 00.08.03 19.83 19.83 0 006-3.03.08.08 0 00.03-.05c.47-4.87-.78-9.09-3.3-12.84a.06.06 0 00-.03-.03zM8.02 13.62c-1.11 0-2.03-1.02-2.03-2.28 0-1.26.9-2.28 2.03-2.28 1.14 0 2.04 1.03 2.03 2.28 0 1.26-.9 2.28-2.03 2.28zm7.5 0c-1.11 0-2.03-1.02-2.03-2.28 0-1.26.9-2.28 2.03-2.28 1.14 0 2.04 1.03 2.03 2.28 0 1.26-.89 2.28-2.03 2.28z\"/></svg>`,\n x: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"#fff\"><path d=\"M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z\"/></svg>`,\n line: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"#fff\"><path d=\"M19.365 9.863c.349 0 .63.285.63.631 0 .345-.281.63-.63.63H17.61v1.125h1.755c.349 0 .63.283.63.63 0 .344-.281.629-.63.629h-2.386c-.345 0-.627-.285-.627-.629V8.108c0-.345.282-.63.63-.63h2.386c.346 0 .627.285.627.63 0 .349-.281.63-.63.63H17.61v1.125h1.755zm-3.855 3.016c0 .27-.174.51-.432.596-.064.021-.133.031-.199.031-.211 0-.391-.09-.51-.25l-2.443-3.317v2.94c0 .344-.279.629-.631.629-.346 0-.626-.285-.626-.629V8.108c0-.27.173-.51.43-.595.06-.023.136-.033.194-.033.195 0 .375.104.495.254l2.462 3.33V8.108c0-.345.282-.63.63-.63.345 0 .63.285.63.63v4.771zm-5.741 0c0 .344-.282.629-.631.629-.345 0-.627-.285-.627-.629V8.108c0-.345.282-.63.63-.63.346 0 .628.285.628.63v4.771zm-2.466.629H4.917c-.345 0-.63-.285-.63-.629V8.108c0-.345.285-.63.63-.63.348 0 .63.285.63.63v4.141h1.756c.348 0 .629.283.629.63 0 .344-.282.629-.629.629M24 10.314C24 4.943 18.615.572 12 .572S0 4.943 0 10.314c0 4.811 4.27 8.842 10.035 9.608.391.082.923.258 1.058.59.12.301.079.766.038 1.08l-.164 1.02c-.045.301-.24 1.186 1.049.645 1.291-.539 6.916-4.078 9.436-6.975C23.176 14.393 24 12.458 24 10.314\"/></svg>`,\n microsoft: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\"><rect fill=\"#F25022\" x=\"1\" y=\"1\" width=\"10\" height=\"10\"/><rect fill=\"#7FBA00\" x=\"13\" y=\"1\" width=\"10\" height=\"10\"/><rect fill=\"#00A4EF\" x=\"1\" y=\"13\" width=\"10\" height=\"10\"/><rect fill=\"#FFB900\" x=\"13\" y=\"13\" width=\"10\" height=\"10\"/></svg>`,\n};\n\nexport function getProviderButtonConfig(provider: OAuthProviderType): ProviderButtonConfig {\n const colors = PROVIDER_COLORS[provider];\n return {\n provider,\n label: `Continue with ${PROVIDER_DISPLAY_NAMES[provider]}`,\n bgColor: colors.bg,\n textColor: colors.text,\n iconSvg: PROVIDER_ICONS[provider],\n };\n}\n","import type { AuthonUser, AuthTokens } from '@authon/shared';\n\nexport class SessionManager {\n private accessToken: string | null = null;\n private refreshToken: string | null = null;\n private user: AuthonUser | null = null;\n private refreshTimer: ReturnType<typeof setTimeout> | null = null;\n private apiUrl: string;\n private publishableKey: string;\n\n constructor(publishableKey: string, apiUrl: string) {\n this.publishableKey = publishableKey;\n this.apiUrl = apiUrl;\n }\n\n getToken(): string | null {\n return this.accessToken;\n }\n\n getUser(): AuthonUser | null {\n return this.user;\n }\n\n setSession(tokens: AuthTokens): void {\n this.accessToken = tokens.accessToken;\n this.refreshToken = tokens.refreshToken;\n this.user = tokens.user;\n if (tokens.expiresIn && tokens.expiresIn > 0) {\n this.scheduleRefresh(tokens.expiresIn);\n }\n }\n\n clearSession(): void {\n this.accessToken = null;\n this.refreshToken = null;\n this.user = null;\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n this.refreshTimer = null;\n }\n }\n\n private scheduleRefresh(expiresIn: number): void {\n if (this.refreshTimer) clearTimeout(this.refreshTimer);\n // Refresh 60 seconds before expiry\n const refreshIn = Math.max((expiresIn - 60) * 1000, 30000);\n this.refreshTimer = setTimeout(() => this.refresh(), refreshIn);\n }\n\n async refresh(): Promise<AuthTokens | null> {\n if (!this.refreshToken) {\n this.clearSession();\n return null;\n }\n try {\n const res = await fetch(`${this.apiUrl}/v1/auth/token/refresh`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': this.publishableKey,\n },\n credentials: 'include',\n body: JSON.stringify({ refreshToken: this.refreshToken }),\n });\n if (!res.ok) {\n this.clearSession();\n return null;\n }\n const tokens: AuthTokens = await res.json();\n this.setSession(tokens);\n return tokens;\n } catch {\n this.clearSession();\n return null;\n }\n }\n\n async signOut(): Promise<void> {\n try {\n await fetch(`${this.apiUrl}/v1/auth/signout`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': this.publishableKey,\n ...(this.accessToken ? { Authorization: `Bearer ${this.accessToken}` } : {}),\n },\n credentials: 'include',\n });\n } catch {\n // ignore\n }\n this.clearSession();\n }\n\n destroy(): void {\n this.clearSession();\n }\n}\n","import type { AuthonUser, AuthTokens, BrandingConfig, OAuthProviderType } from '@authon/shared';\nimport type { AuthonConfig, AuthonEventType, AuthonEvents } from './types';\nimport { ModalRenderer } from './modal';\nimport { SessionManager } from './session';\n\nexport class Authon {\n private publishableKey: string;\n private config: Required<Omit<AuthonConfig, 'containerId' | 'appearance'>> & {\n containerId?: string;\n appearance?: Partial<BrandingConfig>;\n };\n private session: SessionManager;\n private modal: ModalRenderer | null = null;\n private listeners: Map<string, Set<(...args: unknown[]) => void>> = new Map();\n private branding: BrandingConfig | null = null;\n private providers: OAuthProviderType[] = [];\n private initialized = false;\n\n constructor(publishableKey: string, config?: AuthonConfig) {\n this.publishableKey = publishableKey;\n this.config = {\n apiUrl: config?.apiUrl || 'https://api.authon.dev',\n mode: config?.mode || 'popup',\n theme: config?.theme || 'auto',\n locale: config?.locale || 'en',\n containerId: config?.containerId,\n appearance: config?.appearance,\n };\n this.session = new SessionManager(publishableKey, this.config.apiUrl);\n }\n\n // ── Public API ──\n\n async openSignIn(): Promise<void> {\n await this.ensureInitialized();\n this.getModal().open('signIn');\n }\n\n async openSignUp(): Promise<void> {\n await this.ensureInitialized();\n this.getModal().open('signUp');\n }\n\n async signInWithOAuth(provider: OAuthProviderType): Promise<void> {\n await this.ensureInitialized();\n await this.startOAuthFlow(provider);\n }\n\n async signInWithEmail(email: string, password: string): Promise<AuthonUser> {\n const tokens = await this.apiPost<AuthTokens>('/v1/auth/signin', { email, password });\n this.session.setSession(tokens);\n this.emit('signedIn', tokens.user);\n return tokens.user;\n }\n\n async signUpWithEmail(\n email: string,\n password: string,\n meta?: { displayName?: string },\n ): Promise<AuthonUser> {\n const tokens = await this.apiPost<AuthTokens>('/v1/auth/signup', {\n email,\n password,\n ...meta,\n });\n this.session.setSession(tokens);\n this.emit('signedIn', tokens.user);\n return tokens.user;\n }\n\n async signOut(): Promise<void> {\n await this.session.signOut();\n this.emit('signedOut');\n }\n\n getUser(): AuthonUser | null {\n return this.session.getUser();\n }\n\n getToken(): string | null {\n return this.session.getToken();\n }\n\n on<K extends AuthonEventType>(event: K, listener: AuthonEvents[K]): () => void {\n if (!this.listeners.has(event)) this.listeners.set(event, new Set());\n const set = this.listeners.get(event)!;\n set.add(listener as (...args: unknown[]) => void);\n return () => set.delete(listener as (...args: unknown[]) => void);\n }\n\n destroy(): void {\n this.modal?.close();\n this.session.destroy();\n this.listeners.clear();\n }\n\n // ── Internal ──\n\n private emit(event: string, ...args: unknown[]): void {\n this.listeners.get(event)?.forEach((fn) => fn(...args));\n }\n\n private async ensureInitialized(): Promise<void> {\n if (this.initialized) return;\n try {\n const [branding, providersRes] = await Promise.all([\n this.apiGet<BrandingConfig>('/v1/auth/branding'),\n this.apiGet<{ providers: OAuthProviderType[] }>('/v1/auth/providers'),\n ]);\n this.branding = { ...branding, ...this.config.appearance };\n this.providers = providersRes.providers;\n this.initialized = true;\n } catch (err) {\n this.emit('error', err instanceof Error ? err : new Error(String(err)));\n throw err;\n }\n }\n\n private getModal(): ModalRenderer {\n if (!this.modal) {\n this.modal = new ModalRenderer({\n mode: this.config.mode,\n theme: this.config.theme,\n containerId: this.config.containerId,\n branding: this.branding || undefined,\n onProviderClick: (provider) => this.startOAuthFlow(provider),\n onEmailSubmit: (email, password, isSignUp) => {\n this.modal?.clearError();\n const promise = isSignUp\n ? this.signUpWithEmail(email, password)\n : this.signInWithEmail(email, password);\n promise\n .then(() => this.modal?.close())\n .catch((err) => {\n const msg = err instanceof Error ? err.message : String(err);\n this.modal?.showError(msg || 'Authentication failed');\n this.emit('error', err instanceof Error ? err : new Error(msg));\n });\n },\n onClose: () => this.modal?.close(),\n });\n }\n if (this.branding) this.modal.setBranding(this.branding);\n this.modal.setProviders(this.providers);\n return this.modal;\n }\n\n private async startOAuthFlow(provider: OAuthProviderType): Promise<void> {\n try {\n const redirectUri = `${this.config.apiUrl}/v1/auth/oauth/redirect`;\n const { url, state } = await this.apiGet<{ url: string; state: string }>(\n `/v1/auth/oauth/${provider}/url?redirectUri=${encodeURIComponent(redirectUri)}`,\n );\n\n this.modal?.showLoading();\n\n // Open popup\n const width = 500;\n const height = 700;\n const left = window.screenX + (window.outerWidth - width) / 2;\n const top = window.screenY + (window.outerHeight - height) / 2;\n const popup = window.open(\n url,\n 'authon-oauth',\n `width=${width},height=${height},left=${left},top=${top},toolbar=no,menubar=no`,\n );\n\n if (!popup || popup.closed) {\n this.modal?.hideLoading();\n this.modal?.showBanner(\n 'Pop-up blocked. Please allow pop-ups for this site and try again.',\n 'warning',\n );\n this.emit('error', new Error('Popup was blocked by the browser'));\n return;\n }\n\n let resolved = false;\n let cleaned = false;\n const storageKey = `authon-oauth-${state}`;\n\n const resolve = (tokens: AuthTokens) => {\n if (resolved) return;\n resolved = true;\n cleanup();\n try { if (popup && !popup.closed) popup.close(); } catch { /* ignore */ }\n try { localStorage.removeItem(storageKey); } catch { /* ignore */ }\n this.session.setSession(tokens);\n this.modal?.close();\n this.emit('signedIn', tokens.user);\n };\n\n const handleError = (msg: string) => {\n if (resolved) return;\n cleanup();\n this.modal?.hideLoading();\n this.modal?.showError(msg);\n this.emit('error', new Error(msg));\n };\n\n const pollApi = async () => {\n if (resolved || cleaned) return;\n try {\n const result = await this.apiGet<{ status: string; accessToken?: string; refreshToken?: string; expiresIn?: number; user?: AuthonUser; message?: string }>(\n `/v1/auth/oauth/poll?state=${encodeURIComponent(state)}`,\n );\n if (result.status === 'completed' && result.accessToken) {\n resolve({\n accessToken: result.accessToken,\n refreshToken: result.refreshToken!,\n expiresIn: result.expiresIn!,\n user: result.user!,\n });\n } else if (result.status === 'error') {\n handleError(result.message || 'Authentication failed');\n }\n } catch {\n // Network error — keep polling\n }\n };\n\n const cleanup = () => {\n if (cleaned) return;\n cleaned = true;\n window.removeEventListener('message', messageHandler);\n window.removeEventListener('storage', storageHandler);\n document.removeEventListener('visibilitychange', visibilityHandler);\n if (apiPollTimer) clearInterval(apiPollTimer);\n if (closePollTimer) clearInterval(closePollTimer);\n if (maxTimer) clearTimeout(maxTimer);\n };\n\n // 1. postMessage handler (fast path — Chrome/Firefox desktop)\n const messageHandler = (e: MessageEvent) => {\n if (e.data?.type !== 'authon-oauth-callback') return;\n if (e.data.tokens) {\n resolve(e.data.tokens as AuthTokens);\n }\n };\n window.addEventListener('message', messageHandler);\n\n // 2. localStorage handler (mobile fallback — cross-tab communication)\n const storageHandler = (e: StorageEvent) => {\n if (e.key !== storageKey || !e.newValue) return;\n try {\n const data = JSON.parse(e.newValue);\n if (data.tokens) resolve(data.tokens as AuthTokens);\n else if (data.error) handleError(data.error);\n } catch { /* ignore */ }\n };\n window.addEventListener('storage', storageHandler);\n\n // Also check localStorage immediately in case it was set before listener\n try {\n const existing = localStorage.getItem(storageKey);\n if (existing) {\n const data = JSON.parse(existing);\n if (data.tokens) { resolve(data.tokens as AuthTokens); return; }\n }\n } catch { /* ignore */ }\n\n // 3. API polling (fallback for all browsers)\n const apiPollTimer = setInterval(pollApi, 1500);\n\n // 4. visibilitychange — poll immediately when tab regains focus (mobile)\n const visibilityHandler = () => {\n if (document.visibilityState === 'visible' && !resolved && !cleaned) {\n pollApi();\n }\n };\n document.addEventListener('visibilitychange', visibilityHandler);\n\n // 5. Popup close detection\n const closePollTimer = setInterval(() => {\n if (resolved || cleaned) return;\n try {\n if (popup && popup.closed) {\n clearInterval(closePollTimer);\n // Poll immediately + give a few more seconds\n pollApi();\n setTimeout(() => {\n if (resolved || cleaned) return;\n pollApi().then(() => {\n if (resolved || cleaned) return;\n cleanup();\n this.modal?.hideLoading();\n });\n }, 3000);\n }\n } catch {\n // Cross-origin access error — popup still open\n }\n }, 500);\n\n // 6. Max timeout (3 minutes)\n const maxTimer = setTimeout(() => {\n if (resolved || cleaned) return;\n cleanup();\n this.modal?.hideLoading();\n }, 180_000);\n } catch (err) {\n this.modal?.hideLoading();\n this.emit('error', err instanceof Error ? err : new Error(String(err)));\n }\n }\n\n private async apiGet<T>(path: string): Promise<T> {\n const res = await fetch(`${this.config.apiUrl}${path}`, {\n headers: { 'x-api-key': this.publishableKey },\n credentials: 'include',\n });\n if (!res.ok) throw new Error(await this.parseApiError(res, path));\n return res.json();\n }\n\n private async apiPost<T>(path: string, body?: unknown): Promise<T> {\n const res = await fetch(`${this.config.apiUrl}${path}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': this.publishableKey,\n },\n credentials: 'include',\n body: body ? JSON.stringify(body) : undefined,\n });\n if (!res.ok) throw new Error(await this.parseApiError(res, path));\n return res.json();\n }\n\n private async parseApiError(res: Response, path: string): Promise<string> {\n try {\n const body = await res.json();\n if (Array.isArray(body.message) && body.message.length > 0) {\n return body.message[0];\n }\n if (typeof body.message === 'string' && body.message !== 'Bad Request') {\n return body.message;\n }\n } catch { /* ignore */ }\n return `API ${path}: ${res.status}`;\n }\n}\n"],"mappings":"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","names":["import_shared"]}
package/dist/index.js CHANGED
@@ -673,12 +673,17 @@ var Authon = class {
673
673
  }
674
674
  let resolved = false;
675
675
  let cleaned = false;
676
+ const storageKey = `authon-oauth-${state}`;
676
677
  const resolve = (tokens) => {
677
678
  if (resolved) return;
678
679
  resolved = true;
679
680
  cleanup();
680
681
  try {
681
- if (!popup.closed) popup.close();
682
+ if (popup && !popup.closed) popup.close();
683
+ } catch {
684
+ }
685
+ try {
686
+ localStorage.removeItem(storageKey);
682
687
  } catch {
683
688
  }
684
689
  this.session.setSession(tokens);
@@ -692,10 +697,31 @@ var Authon = class {
692
697
  this.modal?.showError(msg);
693
698
  this.emit("error", new Error(msg));
694
699
  };
700
+ const pollApi = async () => {
701
+ if (resolved || cleaned) return;
702
+ try {
703
+ const result = await this.apiGet(
704
+ `/v1/auth/oauth/poll?state=${encodeURIComponent(state)}`
705
+ );
706
+ if (result.status === "completed" && result.accessToken) {
707
+ resolve({
708
+ accessToken: result.accessToken,
709
+ refreshToken: result.refreshToken,
710
+ expiresIn: result.expiresIn,
711
+ user: result.user
712
+ });
713
+ } else if (result.status === "error") {
714
+ handleError(result.message || "Authentication failed");
715
+ }
716
+ } catch {
717
+ }
718
+ };
695
719
  const cleanup = () => {
696
720
  if (cleaned) return;
697
721
  cleaned = true;
698
722
  window.removeEventListener("message", messageHandler);
723
+ window.removeEventListener("storage", storageHandler);
724
+ document.removeEventListener("visibilitychange", visibilityHandler);
699
725
  if (apiPollTimer) clearInterval(apiPollTimer);
700
726
  if (closePollTimer) clearInterval(closePollTimer);
701
727
  if (maxTimer) clearTimeout(maxTimer);
@@ -707,34 +733,47 @@ var Authon = class {
707
733
  }
708
734
  };
709
735
  window.addEventListener("message", messageHandler);
710
- const apiPollTimer = setInterval(async () => {
711
- if (resolved || cleaned) return;
736
+ const storageHandler = (e) => {
737
+ if (e.key !== storageKey || !e.newValue) return;
712
738
  try {
713
- const result = await this.apiGet(
714
- `/v1/auth/oauth/poll?state=${encodeURIComponent(state)}`
715
- );
716
- if (result.status === "completed" && result.accessToken) {
717
- resolve({
718
- accessToken: result.accessToken,
719
- refreshToken: result.refreshToken,
720
- expiresIn: result.expiresIn,
721
- user: result.user
722
- });
723
- } else if (result.status === "error") {
724
- handleError(result.message || "Authentication failed");
725
- }
739
+ const data = JSON.parse(e.newValue);
740
+ if (data.tokens) resolve(data.tokens);
741
+ else if (data.error) handleError(data.error);
726
742
  } catch {
727
743
  }
728
- }, 1500);
744
+ };
745
+ window.addEventListener("storage", storageHandler);
746
+ try {
747
+ const existing = localStorage.getItem(storageKey);
748
+ if (existing) {
749
+ const data = JSON.parse(existing);
750
+ if (data.tokens) {
751
+ resolve(data.tokens);
752
+ return;
753
+ }
754
+ }
755
+ } catch {
756
+ }
757
+ const apiPollTimer = setInterval(pollApi, 1500);
758
+ const visibilityHandler = () => {
759
+ if (document.visibilityState === "visible" && !resolved && !cleaned) {
760
+ pollApi();
761
+ }
762
+ };
763
+ document.addEventListener("visibilitychange", visibilityHandler);
729
764
  const closePollTimer = setInterval(() => {
730
765
  if (resolved || cleaned) return;
731
766
  try {
732
- if (popup.closed) {
767
+ if (popup && popup.closed) {
733
768
  clearInterval(closePollTimer);
769
+ pollApi();
734
770
  setTimeout(() => {
735
771
  if (resolved || cleaned) return;
736
- cleanup();
737
- this.modal?.hideLoading();
772
+ pollApi().then(() => {
773
+ if (resolved || cleaned) return;
774
+ cleanup();
775
+ this.modal?.hideLoading();
776
+ });
738
777
  }, 3e3);
739
778
  }
740
779
  } catch {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/modal.ts","../src/providers.ts","../src/session.ts","../src/authon.ts"],"sourcesContent":["import type { BrandingConfig, OAuthProviderType } from '@authon/shared';\nimport { DEFAULT_BRANDING } from '@authon/shared';\nimport { getProviderButtonConfig } from './providers';\n\nexport class ModalRenderer {\n private shadowRoot: ShadowRoot | null = null;\n private hostElement: HTMLDivElement | null = null;\n private containerElement: HTMLElement | null = null;\n private mode: 'popup' | 'embedded';\n private theme: 'light' | 'dark' | 'auto';\n private branding: BrandingConfig;\n private enabledProviders: OAuthProviderType[] = [];\n private currentView: 'signIn' | 'signUp' = 'signIn';\n private onProviderClick: (provider: OAuthProviderType) => void;\n private onEmailSubmit: (email: string, password: string, isSignUp: boolean) => void;\n private onClose: () => void;\n private escHandler: ((e: KeyboardEvent) => void) | null = null;\n\n constructor(options: {\n mode: 'popup' | 'embedded';\n theme?: 'light' | 'dark' | 'auto';\n containerId?: string;\n branding?: BrandingConfig;\n onProviderClick: (provider: OAuthProviderType) => void;\n onEmailSubmit: (email: string, password: string, isSignUp: boolean) => void;\n onClose: () => void;\n }) {\n this.mode = options.mode;\n this.theme = options.theme || 'auto';\n this.branding = { ...DEFAULT_BRANDING, ...options.branding };\n this.onProviderClick = options.onProviderClick;\n this.onEmailSubmit = options.onEmailSubmit;\n this.onClose = options.onClose;\n\n if (options.mode === 'embedded' && options.containerId) {\n this.containerElement = document.getElementById(options.containerId);\n }\n }\n\n setProviders(providers: OAuthProviderType[]): void {\n this.enabledProviders = providers;\n }\n\n setBranding(branding: BrandingConfig): void {\n this.branding = { ...DEFAULT_BRANDING, ...branding };\n }\n\n open(view: 'signIn' | 'signUp' = 'signIn'): void {\n if (this.shadowRoot && this.hostElement) {\n // Modal already open — smooth in-place view switch\n this.switchView(view);\n } else {\n this.currentView = view;\n this.render(view);\n }\n }\n\n close(): void {\n if (this.escHandler) {\n document.removeEventListener('keydown', this.escHandler);\n this.escHandler = null;\n }\n if (this.hostElement) {\n this.hostElement.remove();\n this.hostElement = null;\n this.shadowRoot = null;\n }\n if (this.containerElement) {\n this.containerElement.innerHTML = '';\n }\n }\n\n showError(message: string): void {\n if (!this.shadowRoot) return;\n this.clearError();\n const errorEl = this.shadowRoot.getElementById('email-form');\n if (errorEl) {\n const errDiv = document.createElement('div');\n errDiv.id = 'authon-error-msg';\n errDiv.className = 'error-msg';\n errDiv.textContent = message;\n errorEl.appendChild(errDiv);\n }\n }\n\n showBanner(message: string, type: 'error' | 'warning' = 'error'): void {\n if (!this.shadowRoot) return;\n this.clearBanner();\n const inner = this.shadowRoot.getElementById('modal-inner');\n if (!inner) return;\n const banner = document.createElement('div');\n banner.id = 'authon-banner';\n banner.className = type === 'warning' ? 'banner-warning' : 'error-msg';\n banner.textContent = message;\n inner.insertBefore(banner, inner.firstChild);\n }\n\n clearBanner(): void {\n if (!this.shadowRoot) return;\n this.shadowRoot.getElementById('authon-banner')?.remove();\n }\n\n clearError(): void {\n if (!this.shadowRoot) return;\n this.shadowRoot.getElementById('authon-error-msg')?.remove();\n }\n\n showLoading(): void {\n if (!this.shadowRoot) return;\n this.hideLoading();\n const overlay = document.createElement('div');\n overlay.id = 'authon-loading-overlay';\n overlay.innerHTML = `\n <div class=\"loading-spinner\">\n <div class=\"loading-ring\"></div>\n <div class=\"loading-ring\"></div>\n <div class=\"loading-ring\"></div>\n </div>\n <div class=\"loading-text\">Signing in<span class=\"loading-dots\"><span></span><span></span><span></span></span></div>\n `;\n this.shadowRoot.querySelector('.modal-container')?.appendChild(overlay);\n }\n\n hideLoading(): void {\n if (!this.shadowRoot) return;\n this.shadowRoot.getElementById('authon-loading-overlay')?.remove();\n }\n\n // ── Smooth view switch (no flicker) ──\n\n private switchView(view: 'signIn' | 'signUp'): void {\n if (!this.shadowRoot || view === this.currentView) return;\n this.currentView = view;\n\n const inner = this.shadowRoot.getElementById('modal-inner');\n if (!inner) return;\n\n // Cross-fade: fade out → update → fade in\n inner.style.opacity = '0';\n inner.style.transform = 'translateY(-4px)';\n\n setTimeout(() => {\n inner.innerHTML = this.buildInnerContent(view);\n this.attachInnerEvents(view);\n // Trigger reflow, then animate in\n void inner.offsetHeight;\n inner.style.opacity = '1';\n inner.style.transform = 'translateY(0)';\n }, 140);\n }\n\n // ── Render ──\n\n private render(view: 'signIn' | 'signUp'): void {\n const host = document.createElement('div');\n host.setAttribute('data-authon-modal', '');\n this.hostElement = host;\n\n if (this.mode === 'popup') {\n document.body.appendChild(host);\n } else if (this.containerElement) {\n this.containerElement.appendChild(host);\n }\n\n this.shadowRoot = host.attachShadow({ mode: 'open' });\n this.shadowRoot.innerHTML = this.buildShell(view);\n this.attachInnerEvents(view);\n this.attachShellEvents();\n }\n\n // ── HTML builders ──\n\n /** Shell = style + backdrop + modal-container (stable across view switches) */\n private buildShell(view: 'signIn' | 'signUp'): string {\n const popupWrapper =\n this.mode === 'popup'\n ? `<div class=\"backdrop\" id=\"backdrop\"></div>`\n : '';\n\n return `\n <style>${this.buildCSS()}</style>\n ${popupWrapper}\n <div class=\"modal-container\" role=\"dialog\" aria-modal=\"true\">\n <div id=\"modal-inner\" class=\"modal-inner\">\n ${this.buildInnerContent(view)}\n </div>\n </div>\n `;\n }\n\n /** Inner content = everything inside the modal that changes per view */\n private buildInnerContent(view: 'signIn' | 'signUp'): string {\n const b = this.branding;\n const isSignUp = view === 'signUp';\n const title = isSignUp ? 'Create your account' : 'Welcome back';\n const subtitle = isSignUp ? 'Already have an account?' : \"Don't have an account?\";\n const subtitleLink = isSignUp ? 'Sign in' : 'Sign up';\n\n const dark = this.isDark();\n\n // SignUp view: hide providers, show only email form\n const showProviders = !isSignUp;\n\n const providerButtons = showProviders\n ? this.enabledProviders\n .filter((p) => !b.hiddenProviders?.includes(p))\n .map((p) => {\n const config = getProviderButtonConfig(p);\n const isWhiteBg = config.bgColor === '#ffffff';\n const btnBg = dark && isWhiteBg ? '#f8fafc' : config.bgColor;\n const btnBorder = isWhiteBg ? (dark ? '#475569' : '#e5e7eb') : config.bgColor;\n return `<button class=\"provider-btn\" data-provider=\"${p}\" style=\"background:${btnBg};color:${config.textColor};border:1px solid ${btnBorder}\">\n <span class=\"provider-icon\">${config.iconSvg}</span>\n <span>${config.label}</span>\n </button>`;\n })\n .join('')\n : '';\n\n const divider =\n showProviders && b.showDivider !== false && b.showEmailPassword !== false\n ? `<div class=\"divider\"><span>or</span></div>`\n : '';\n\n const emailForm =\n b.showEmailPassword !== false\n ? `<form class=\"email-form\" id=\"email-form\">\n <input type=\"email\" placeholder=\"Email address\" name=\"email\" required class=\"input\" autocomplete=\"email\" />\n <input type=\"password\" placeholder=\"Password\" name=\"password\" required class=\"input\" autocomplete=\"${isSignUp ? 'new-password' : 'current-password'}\" />\n ${isSignUp ? '<p class=\"password-hint\">Must contain uppercase, lowercase, and a number (min 8 chars)</p>' : ''}\n <button type=\"submit\" class=\"submit-btn\">${isSignUp ? 'Sign up' : 'Sign in'}</button>\n </form>`\n : '';\n\n const footer =\n b.termsUrl || b.privacyUrl\n ? `<div class=\"footer\">\n ${b.termsUrl ? `<a href=\"${b.termsUrl}\" target=\"_blank\">Terms of Service</a>` : ''}\n ${b.termsUrl && b.privacyUrl ? ' · ' : ''}\n ${b.privacyUrl ? `<a href=\"${b.privacyUrl}\" target=\"_blank\">Privacy Policy</a>` : ''}\n </div>`\n : '';\n\n const titleHtml = isSignUp\n ? `<div class=\"title-row\">\n <button class=\"back-btn\" id=\"back-btn\" type=\"button\" aria-label=\"Back to sign in\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M19 12H5\"/><path d=\"m12 19-7-7 7-7\"/></svg>\n </button>\n <h2 class=\"title\">${title}</h2>\n </div>`\n : `<h2 class=\"title\">${title}</h2>`;\n\n return `\n ${b.logoDataUrl ? `<img src=\"${b.logoDataUrl}\" alt=\"Logo\" class=\"logo\" />` : ''}\n ${titleHtml}\n ${b.brandName ? `<p class=\"brand-name\">${b.brandName}</p>` : ''}\n ${showProviders ? `<div class=\"providers\">${providerButtons}</div>` : ''}\n ${divider}\n ${emailForm}\n <p class=\"switch-view\">${subtitle} <a href=\"#\" id=\"switch-link\">${subtitleLink}</a></p>\n ${footer}\n ${b.showSecuredBy !== false ? `<div class=\"secured-by\">Secured by <a href=\"https://authon.dev\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"secured-link\">Authon</a></div>` : ''}\n `;\n }\n\n private isDark(): boolean {\n if (this.theme === 'dark') return true;\n if (this.theme === 'light') return false;\n return typeof window !== 'undefined' && window.matchMedia('(prefers-color-scheme: dark)').matches;\n }\n\n private buildCSS(): string {\n const b = this.branding;\n const dark = this.isDark();\n const bg = dark ? (b.darkBg || '#0f172a') : (b.lightBg || '#ffffff');\n const text = dark ? (b.darkText || '#f1f5f9') : (b.lightText || '#111827');\n const mutedText = dark ? '#94a3b8' : '#6b7280';\n const dimText = dark ? '#64748b' : '#9ca3af';\n const borderColor = dark ? '#334155' : '#d1d5db';\n const dividerColor = dark ? '#334155' : '#e5e7eb';\n const inputBg = dark ? '#1e293b' : '#ffffff';\n\n return `\n :host {\n --authon-primary-start: ${b.primaryColorStart || '#7c3aed'};\n --authon-primary-end: ${b.primaryColorEnd || '#4f46e5'};\n --authon-bg: ${bg};\n --authon-text: ${text};\n --authon-muted: ${mutedText};\n --authon-dim: ${dimText};\n --authon-border: ${borderColor};\n --authon-divider: ${dividerColor};\n --authon-input-bg: ${inputBg};\n --authon-radius: ${b.borderRadius ?? 12}px;\n --authon-font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n font-family: var(--authon-font);\n color: var(--authon-text);\n }\n * { box-sizing: border-box; margin: 0; padding: 0; }\n .backdrop {\n position: fixed; inset: 0; z-index: 99998;\n background: rgba(0,0,0,${dark ? '0.7' : '0.5'}); backdrop-filter: blur(4px);\n animation: fadeIn 0.2s ease;\n }\n .modal-container {\n ${this.mode === 'popup' ? 'position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 99999; max-height: 90vh; overflow-y: auto;' : ''}\n background: var(--authon-bg);\n color: var(--authon-text);\n border: 1px solid var(--authon-border);\n border-radius: var(--authon-radius);\n padding: 32px;\n width: 400px; max-width: 100%;\n position: ${this.mode === 'popup' ? 'fixed' : 'relative'};\n ${this.mode === 'popup' ? `box-shadow: 0 25px 50px -12px rgba(0,0,0,${dark ? '0.5' : '0.25'}); animation: slideIn 0.3s ease;` : ''}\n }\n .modal-inner {\n transition: opacity 0.14s ease, transform 0.14s ease;\n }\n .logo { display: block; margin: 0 auto 16px; max-height: 48px; }\n .title-row { display: flex; align-items: center; position: relative; margin-bottom: 8px; }\n .title-row .title { flex: 1; margin-bottom: 0; }\n .back-btn {\n position: absolute; left: 0; top: 50%; transform: translateY(-50%);\n background: none; border: none; color: var(--authon-muted);\n cursor: pointer; padding: 4px; border-radius: 6px; display: flex; align-items: center; justify-content: center;\n transition: color 0.15s, background 0.15s;\n }\n .back-btn:hover { color: var(--authon-text); background: var(--authon-divider); }\n .password-hint { font-size: 11px; color: var(--authon-dim); margin: -4px 0 2px; }\n .title { text-align: center; font-size: 24px; font-weight: 700; margin-bottom: 8px; color: var(--authon-text); }\n .brand-name { text-align: center; font-size: 14px; color: var(--authon-muted); margin-bottom: 24px; }\n .providers { display: flex; flex-direction: column; gap: 8px; margin-bottom: 16px; }\n .provider-btn {\n display: flex; align-items: center; gap: 12px;\n width: 100%; padding: 10px 16px; border-radius: calc(var(--authon-radius) * 0.67);\n font-size: 14px; font-weight: 500; cursor: pointer;\n transition: opacity 0.15s, transform 0.1s;\n font-family: var(--authon-font);\n }\n .provider-btn:hover { opacity: 0.9; }\n .provider-btn:active { transform: scale(0.98); }\n .provider-icon { display: flex; align-items: center; flex-shrink: 0; }\n .divider {\n display: flex; align-items: center; gap: 12px;\n margin: 16px 0; color: var(--authon-dim); font-size: 13px;\n }\n .divider::before, .divider::after {\n content: ''; flex: 1; height: 1px; background: var(--authon-divider);\n }\n .email-form { display: flex; flex-direction: column; gap: 10px; }\n .input {\n width: 100%; padding: 10px 14px;\n background: var(--authon-input-bg);\n color: var(--authon-text);\n border: 1px solid var(--authon-border); border-radius: calc(var(--authon-radius) * 0.5);\n font-size: 14px; font-family: var(--authon-font);\n outline: none; transition: border-color 0.15s;\n }\n .input::placeholder { color: var(--authon-dim); }\n .input:focus { border-color: var(--authon-primary-start); box-shadow: 0 0 0 3px rgba(124,58,237,0.15); }\n .submit-btn {\n width: 100%; padding: 10px;\n background: linear-gradient(135deg, var(--authon-primary-start), var(--authon-primary-end));\n color: #fff; border: none; border-radius: calc(var(--authon-radius) * 0.5);\n font-size: 14px; font-weight: 600; cursor: pointer;\n font-family: var(--authon-font); transition: opacity 0.15s;\n }\n .submit-btn:hover { opacity: 0.9; }\n .submit-btn:disabled { opacity: 0.6; cursor: not-allowed; }\n .error-msg {\n margin-top: 8px; padding: 8px 12px;\n background: rgba(239,68,68,0.1); border: 1px solid rgba(239,68,68,0.3);\n border-radius: calc(var(--authon-radius) * 0.33);\n font-size: 13px; color: #ef4444; text-align: center;\n animation: fadeIn 0.15s ease;\n }\n .banner-warning {\n margin-bottom: 16px; padding: 10px 14px;\n background: rgba(245,158,11,0.1); border: 1px solid rgba(245,158,11,0.3);\n border-radius: calc(var(--authon-radius) * 0.33);\n font-size: 13px; color: #f59e0b; text-align: center;\n animation: fadeIn 0.15s ease;\n }\n .switch-view { text-align: center; margin-top: 16px; font-size: 13px; color: var(--authon-muted); }\n .switch-view a { color: var(--authon-primary-start); text-decoration: none; font-weight: 500; }\n .switch-view a:hover { text-decoration: underline; }\n .footer { text-align: center; margin-top: 12px; font-size: 12px; color: var(--authon-dim); }\n .footer a { color: var(--authon-dim); text-decoration: none; }\n .footer a:hover { text-decoration: underline; }\n .secured-by {\n text-align: center; margin-top: 16px;\n font-size: 11px; color: var(--authon-dim);\n }\n .secured-link { font-weight: 600; color: var(--authon-muted); text-decoration: none; }\n .secured-link:hover { text-decoration: underline; }\n /* Loading overlay */\n #authon-loading-overlay {\n position: absolute; inset: 0; z-index: 10;\n background: ${dark ? 'rgba(15,23,42,0.92)' : 'rgba(255,255,255,0.92)'};\n backdrop-filter: blur(2px);\n border-radius: var(--authon-radius);\n display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 20px;\n animation: fadeIn 0.15s ease;\n }\n .loading-spinner { position: relative; width: 48px; height: 48px; }\n .loading-ring {\n position: absolute; inset: 0;\n border: 2.5px solid transparent; border-top-color: var(--authon-primary-start);\n border-radius: 50%; animation: spin 1s cubic-bezier(.55,.15,.45,.85) infinite;\n }\n .loading-ring:nth-child(2) {\n inset: 5px; border-top-color: transparent; border-right-color: var(--authon-primary-end);\n animation-duration: 1.2s; animation-direction: reverse; opacity: .7;\n }\n .loading-ring:nth-child(3) {\n inset: 10px; border-top-color: transparent; border-bottom-color: var(--authon-primary-start);\n animation-duration: .8s; opacity: .4;\n }\n .loading-text { font-size: 14px; font-weight: 500; color: var(--authon-muted); }\n .loading-dots { display: inline-flex; gap: 2px; margin-left: 2px; }\n .loading-dots span {\n width: 3px; height: 3px; border-radius: 50%;\n background: var(--authon-muted); animation: blink 1.4s infinite both;\n }\n .loading-dots span:nth-child(2) { animation-delay: .2s; }\n .loading-dots span:nth-child(3) { animation-delay: .4s; }\n @keyframes spin { to { transform: rotate(360deg); } }\n @keyframes blink { 0%,80%,100% { opacity: .2; } 40% { opacity: 1; } }\n @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }\n @keyframes slideIn { from { opacity: 0; transform: translate(-50%, -48%); } to { opacity: 1; transform: translate(-50%, -50%); } }\n ${b.customCss || ''}\n `;\n }\n\n // ── Event binding ──\n\n /** Attach events to shell elements (backdrop, ESC) — called once */\n private attachShellEvents(): void {\n if (!this.shadowRoot) return;\n\n const backdrop = this.shadowRoot.getElementById('backdrop');\n if (backdrop) {\n backdrop.addEventListener('click', () => this.onClose());\n }\n\n if (this.escHandler) {\n document.removeEventListener('keydown', this.escHandler);\n }\n if (this.mode === 'popup') {\n this.escHandler = (e: KeyboardEvent) => {\n if (e.key === 'Escape') this.onClose();\n };\n document.addEventListener('keydown', this.escHandler);\n }\n }\n\n /** Attach events to inner content (buttons, form, switch link) — called on each view */\n private attachInnerEvents(view: 'signIn' | 'signUp'): void {\n if (!this.shadowRoot) return;\n\n // Provider buttons\n this.shadowRoot.querySelectorAll('.provider-btn').forEach((btn) => {\n btn.addEventListener('click', () => {\n const provider = (btn as HTMLElement).dataset.provider as OAuthProviderType;\n this.onProviderClick(provider);\n });\n });\n\n // Email form\n const form = this.shadowRoot.getElementById('email-form') as HTMLFormElement | null;\n if (form) {\n form.addEventListener('submit', (e) => {\n e.preventDefault();\n const formData = new FormData(form);\n this.onEmailSubmit(\n formData.get('email') as string,\n formData.get('password') as string,\n view === 'signUp',\n );\n });\n }\n\n // Back button (signUp → signIn)\n const backBtn = this.shadowRoot.getElementById('back-btn');\n if (backBtn) {\n backBtn.addEventListener('click', () => {\n this.open('signIn');\n });\n }\n\n // Switch view link\n const switchLink = this.shadowRoot.getElementById('switch-link');\n if (switchLink) {\n switchLink.addEventListener('click', (e) => {\n e.preventDefault();\n this.open(view === 'signIn' ? 'signUp' : 'signIn');\n });\n }\n }\n}\n","import { PROVIDER_COLORS, PROVIDER_DISPLAY_NAMES, type OAuthProviderType } from '@authon/shared';\n\nexport interface ProviderButtonConfig {\n provider: OAuthProviderType;\n label: string;\n bgColor: string;\n textColor: string;\n iconSvg: string;\n}\n\nconst PROVIDER_ICONS: Record<OAuthProviderType, string> = {\n google: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\"><path fill=\"#4285F4\" d=\"M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 01-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z\"/><path fill=\"#34A853\" d=\"M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z\"/><path fill=\"#FBBC05\" d=\"M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z\"/><path fill=\"#EA4335\" d=\"M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z\"/></svg>`,\n apple: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"currentColor\"><path d=\"M17.05 20.28c-.98.95-2.05.88-3.08.4-1.09-.5-2.08-.48-3.24 0-1.44.62-2.2.44-3.06-.4C2.79 15.25 3.51 7.59 9.05 7.31c1.35.07 2.29.74 3.08.8 1.18-.24 2.31-.93 3.57-.84 1.51.12 2.65.72 3.4 1.8-3.12 1.87-2.38 5.98.48 7.13-.57 1.5-1.31 2.99-2.54 4.09zM12.03 7.25c-.15-2.23 1.66-4.07 3.74-4.25.29 2.58-2.34 4.5-3.74 4.25z\"/></svg>`,\n kakao: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\"><path fill=\"#191919\" d=\"M12 3C6.48 3 2 6.36 2 10.43c0 2.62 1.75 4.93 4.37 6.23l-1.12 4.14c-.1.36.31.65.62.44l4.93-3.26c.39.04.79.06 1.2.06 5.52 0 10-3.36 10-7.61C22 6.36 17.52 3 12 3z\"/></svg>`,\n naver: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\"><path fill=\"#fff\" d=\"M16.27 3H7.73A4.73 4.73 0 003 7.73v8.54A4.73 4.73 0 007.73 21h8.54A4.73 4.73 0 0021 16.27V7.73A4.73 4.73 0 0016.27 3zm-1.84 12.44h-2.1l-2.86-4.15v4.15H7.38V8.56h2.1l2.86 4.15V8.56h2.09v6.88z\"/></svg>`,\n facebook: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\"><path fill=\"#fff\" d=\"M24 12.07C24 5.41 18.63 0 12 0S0 5.4 0 12.07C0 18.1 4.39 23.1 10.13 24v-8.44H7.08v-3.49h3.04V9.41c0-3.02 1.8-4.7 4.54-4.7 1.31 0 2.68.24 2.68.24v2.97h-1.5c-1.5 0-1.96.93-1.96 1.89v2.26h3.33l-.53 3.49h-2.8V24C19.62 23.1 24 18.1 24 12.07z\"/></svg>`,\n github: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"#fff\"><path d=\"M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z\"/></svg>`,\n discord: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"#fff\"><path d=\"M20.32 4.37a19.8 19.8 0 00-4.89-1.52.07.07 0 00-.08.04c-.21.38-.44.87-.61 1.26a18.27 18.27 0 00-5.49 0 12.64 12.64 0 00-.62-1.26.07.07 0 00-.08-.04 19.74 19.74 0 00-4.89 1.52.07.07 0 00-.03.03C1.11 8.39.34 12.28.73 16.12a.08.08 0 00.03.06 19.9 19.9 0 005.99 3.03.08.08 0 00.08-.03c.46-.63.87-1.3 1.22-2a.08.08 0 00-.04-.11 13.1 13.1 0 01-1.87-.9.08.08 0 01-.01-.13c.13-.09.25-.19.37-.29a.07.07 0 01.08-.01c3.93 1.8 8.18 1.8 12.07 0a.07.07 0 01.08 0c.12.1.25.2.37.3a.08.08 0 01-.01.12c-.6.35-1.22.65-1.87.9a.08.08 0 00-.04.1c.36.7.77 1.37 1.22 2a.08.08 0 00.08.03 19.83 19.83 0 006-3.03.08.08 0 00.03-.05c.47-4.87-.78-9.09-3.3-12.84a.06.06 0 00-.03-.03zM8.02 13.62c-1.11 0-2.03-1.02-2.03-2.28 0-1.26.9-2.28 2.03-2.28 1.14 0 2.04 1.03 2.03 2.28 0 1.26-.9 2.28-2.03 2.28zm7.5 0c-1.11 0-2.03-1.02-2.03-2.28 0-1.26.9-2.28 2.03-2.28 1.14 0 2.04 1.03 2.03 2.28 0 1.26-.89 2.28-2.03 2.28z\"/></svg>`,\n x: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"#fff\"><path d=\"M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z\"/></svg>`,\n line: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"#fff\"><path d=\"M19.365 9.863c.349 0 .63.285.63.631 0 .345-.281.63-.63.63H17.61v1.125h1.755c.349 0 .63.283.63.63 0 .344-.281.629-.63.629h-2.386c-.345 0-.627-.285-.627-.629V8.108c0-.345.282-.63.63-.63h2.386c.346 0 .627.285.627.63 0 .349-.281.63-.63.63H17.61v1.125h1.755zm-3.855 3.016c0 .27-.174.51-.432.596-.064.021-.133.031-.199.031-.211 0-.391-.09-.51-.25l-2.443-3.317v2.94c0 .344-.279.629-.631.629-.346 0-.626-.285-.626-.629V8.108c0-.27.173-.51.43-.595.06-.023.136-.033.194-.033.195 0 .375.104.495.254l2.462 3.33V8.108c0-.345.282-.63.63-.63.345 0 .63.285.63.63v4.771zm-5.741 0c0 .344-.282.629-.631.629-.345 0-.627-.285-.627-.629V8.108c0-.345.282-.63.63-.63.346 0 .628.285.628.63v4.771zm-2.466.629H4.917c-.345 0-.63-.285-.63-.629V8.108c0-.345.285-.63.63-.63.348 0 .63.285.63.63v4.141h1.756c.348 0 .629.283.629.63 0 .344-.282.629-.629.629M24 10.314C24 4.943 18.615.572 12 .572S0 4.943 0 10.314c0 4.811 4.27 8.842 10.035 9.608.391.082.923.258 1.058.59.12.301.079.766.038 1.08l-.164 1.02c-.045.301-.24 1.186 1.049.645 1.291-.539 6.916-4.078 9.436-6.975C23.176 14.393 24 12.458 24 10.314\"/></svg>`,\n microsoft: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\"><rect fill=\"#F25022\" x=\"1\" y=\"1\" width=\"10\" height=\"10\"/><rect fill=\"#7FBA00\" x=\"13\" y=\"1\" width=\"10\" height=\"10\"/><rect fill=\"#00A4EF\" x=\"1\" y=\"13\" width=\"10\" height=\"10\"/><rect fill=\"#FFB900\" x=\"13\" y=\"13\" width=\"10\" height=\"10\"/></svg>`,\n};\n\nexport function getProviderButtonConfig(provider: OAuthProviderType): ProviderButtonConfig {\n const colors = PROVIDER_COLORS[provider];\n return {\n provider,\n label: `Continue with ${PROVIDER_DISPLAY_NAMES[provider]}`,\n bgColor: colors.bg,\n textColor: colors.text,\n iconSvg: PROVIDER_ICONS[provider],\n };\n}\n","import type { AuthonUser, AuthTokens } from '@authon/shared';\n\nexport class SessionManager {\n private accessToken: string | null = null;\n private refreshToken: string | null = null;\n private user: AuthonUser | null = null;\n private refreshTimer: ReturnType<typeof setTimeout> | null = null;\n private apiUrl: string;\n private publishableKey: string;\n\n constructor(publishableKey: string, apiUrl: string) {\n this.publishableKey = publishableKey;\n this.apiUrl = apiUrl;\n }\n\n getToken(): string | null {\n return this.accessToken;\n }\n\n getUser(): AuthonUser | null {\n return this.user;\n }\n\n setSession(tokens: AuthTokens): void {\n this.accessToken = tokens.accessToken;\n this.refreshToken = tokens.refreshToken;\n this.user = tokens.user;\n if (tokens.expiresIn && tokens.expiresIn > 0) {\n this.scheduleRefresh(tokens.expiresIn);\n }\n }\n\n clearSession(): void {\n this.accessToken = null;\n this.refreshToken = null;\n this.user = null;\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n this.refreshTimer = null;\n }\n }\n\n private scheduleRefresh(expiresIn: number): void {\n if (this.refreshTimer) clearTimeout(this.refreshTimer);\n // Refresh 60 seconds before expiry\n const refreshIn = Math.max((expiresIn - 60) * 1000, 30000);\n this.refreshTimer = setTimeout(() => this.refresh(), refreshIn);\n }\n\n async refresh(): Promise<AuthTokens | null> {\n if (!this.refreshToken) {\n this.clearSession();\n return null;\n }\n try {\n const res = await fetch(`${this.apiUrl}/v1/auth/token/refresh`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': this.publishableKey,\n },\n credentials: 'include',\n body: JSON.stringify({ refreshToken: this.refreshToken }),\n });\n if (!res.ok) {\n this.clearSession();\n return null;\n }\n const tokens: AuthTokens = await res.json();\n this.setSession(tokens);\n return tokens;\n } catch {\n this.clearSession();\n return null;\n }\n }\n\n async signOut(): Promise<void> {\n try {\n await fetch(`${this.apiUrl}/v1/auth/signout`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': this.publishableKey,\n ...(this.accessToken ? { Authorization: `Bearer ${this.accessToken}` } : {}),\n },\n credentials: 'include',\n });\n } catch {\n // ignore\n }\n this.clearSession();\n }\n\n destroy(): void {\n this.clearSession();\n }\n}\n","import type { AuthonUser, AuthTokens, BrandingConfig, OAuthProviderType } from '@authon/shared';\nimport type { AuthonConfig, AuthonEventType, AuthonEvents } from './types';\nimport { ModalRenderer } from './modal';\nimport { SessionManager } from './session';\n\nexport class Authon {\n private publishableKey: string;\n private config: Required<Omit<AuthonConfig, 'containerId' | 'appearance'>> & {\n containerId?: string;\n appearance?: Partial<BrandingConfig>;\n };\n private session: SessionManager;\n private modal: ModalRenderer | null = null;\n private listeners: Map<string, Set<(...args: unknown[]) => void>> = new Map();\n private branding: BrandingConfig | null = null;\n private providers: OAuthProviderType[] = [];\n private initialized = false;\n\n constructor(publishableKey: string, config?: AuthonConfig) {\n this.publishableKey = publishableKey;\n this.config = {\n apiUrl: config?.apiUrl || 'https://api.authon.dev',\n mode: config?.mode || 'popup',\n theme: config?.theme || 'auto',\n locale: config?.locale || 'en',\n containerId: config?.containerId,\n appearance: config?.appearance,\n };\n this.session = new SessionManager(publishableKey, this.config.apiUrl);\n }\n\n // ── Public API ──\n\n async openSignIn(): Promise<void> {\n await this.ensureInitialized();\n this.getModal().open('signIn');\n }\n\n async openSignUp(): Promise<void> {\n await this.ensureInitialized();\n this.getModal().open('signUp');\n }\n\n async signInWithOAuth(provider: OAuthProviderType): Promise<void> {\n await this.ensureInitialized();\n await this.startOAuthFlow(provider);\n }\n\n async signInWithEmail(email: string, password: string): Promise<AuthonUser> {\n const tokens = await this.apiPost<AuthTokens>('/v1/auth/signin', { email, password });\n this.session.setSession(tokens);\n this.emit('signedIn', tokens.user);\n return tokens.user;\n }\n\n async signUpWithEmail(\n email: string,\n password: string,\n meta?: { displayName?: string },\n ): Promise<AuthonUser> {\n const tokens = await this.apiPost<AuthTokens>('/v1/auth/signup', {\n email,\n password,\n ...meta,\n });\n this.session.setSession(tokens);\n this.emit('signedIn', tokens.user);\n return tokens.user;\n }\n\n async signOut(): Promise<void> {\n await this.session.signOut();\n this.emit('signedOut');\n }\n\n getUser(): AuthonUser | null {\n return this.session.getUser();\n }\n\n getToken(): string | null {\n return this.session.getToken();\n }\n\n on<K extends AuthonEventType>(event: K, listener: AuthonEvents[K]): () => void {\n if (!this.listeners.has(event)) this.listeners.set(event, new Set());\n const set = this.listeners.get(event)!;\n set.add(listener as (...args: unknown[]) => void);\n return () => set.delete(listener as (...args: unknown[]) => void);\n }\n\n destroy(): void {\n this.modal?.close();\n this.session.destroy();\n this.listeners.clear();\n }\n\n // ── Internal ──\n\n private emit(event: string, ...args: unknown[]): void {\n this.listeners.get(event)?.forEach((fn) => fn(...args));\n }\n\n private async ensureInitialized(): Promise<void> {\n if (this.initialized) return;\n try {\n const [branding, providersRes] = await Promise.all([\n this.apiGet<BrandingConfig>('/v1/auth/branding'),\n this.apiGet<{ providers: OAuthProviderType[] }>('/v1/auth/providers'),\n ]);\n this.branding = { ...branding, ...this.config.appearance };\n this.providers = providersRes.providers;\n this.initialized = true;\n } catch (err) {\n this.emit('error', err instanceof Error ? err : new Error(String(err)));\n throw err;\n }\n }\n\n private getModal(): ModalRenderer {\n if (!this.modal) {\n this.modal = new ModalRenderer({\n mode: this.config.mode,\n theme: this.config.theme,\n containerId: this.config.containerId,\n branding: this.branding || undefined,\n onProviderClick: (provider) => this.startOAuthFlow(provider),\n onEmailSubmit: (email, password, isSignUp) => {\n this.modal?.clearError();\n const promise = isSignUp\n ? this.signUpWithEmail(email, password)\n : this.signInWithEmail(email, password);\n promise\n .then(() => this.modal?.close())\n .catch((err) => {\n const msg = err instanceof Error ? err.message : String(err);\n this.modal?.showError(msg || 'Authentication failed');\n this.emit('error', err instanceof Error ? err : new Error(msg));\n });\n },\n onClose: () => this.modal?.close(),\n });\n }\n if (this.branding) this.modal.setBranding(this.branding);\n this.modal.setProviders(this.providers);\n return this.modal;\n }\n\n private async startOAuthFlow(provider: OAuthProviderType): Promise<void> {\n try {\n const redirectUri = `${this.config.apiUrl}/v1/auth/oauth/redirect`;\n const { url, state } = await this.apiGet<{ url: string; state: string }>(\n `/v1/auth/oauth/${provider}/url?redirectUri=${encodeURIComponent(redirectUri)}`,\n );\n\n this.modal?.showLoading();\n\n // Open popup\n const width = 500;\n const height = 700;\n const left = window.screenX + (window.outerWidth - width) / 2;\n const top = window.screenY + (window.outerHeight - height) / 2;\n const popup = window.open(\n url,\n 'authon-oauth',\n `width=${width},height=${height},left=${left},top=${top},toolbar=no,menubar=no`,\n );\n\n if (!popup || popup.closed) {\n this.modal?.hideLoading();\n this.modal?.showBanner(\n 'Pop-up blocked. Please allow pop-ups for this site and try again.',\n 'warning',\n );\n this.emit('error', new Error('Popup was blocked by the browser'));\n return;\n }\n\n let resolved = false;\n let cleaned = false;\n\n const resolve = (tokens: AuthTokens) => {\n if (resolved) return;\n resolved = true;\n cleanup();\n try { if (!popup.closed) popup.close(); } catch { /* ignore */ }\n this.session.setSession(tokens);\n this.modal?.close();\n this.emit('signedIn', tokens.user);\n };\n\n const handleError = (msg: string) => {\n if (resolved) return;\n cleanup();\n this.modal?.hideLoading();\n this.modal?.showError(msg);\n this.emit('error', new Error(msg));\n };\n\n const cleanup = () => {\n if (cleaned) return;\n cleaned = true;\n window.removeEventListener('message', messageHandler);\n if (apiPollTimer) clearInterval(apiPollTimer);\n if (closePollTimer) clearInterval(closePollTimer);\n if (maxTimer) clearTimeout(maxTimer);\n };\n\n // 1. postMessage handler (fast path — Chrome/Firefox)\n const messageHandler = (e: MessageEvent) => {\n if (e.data?.type !== 'authon-oauth-callback') return;\n if (e.data.tokens) {\n resolve(e.data.tokens as AuthTokens);\n }\n };\n window.addEventListener('message', messageHandler);\n\n // 2. API polling (Safari fallback — window.opener severed by COOP)\n const apiPollTimer = setInterval(async () => {\n if (resolved || cleaned) return;\n try {\n const result = await this.apiGet<{ status: string; accessToken?: string; refreshToken?: string; expiresIn?: number; user?: AuthonUser; message?: string }>(\n `/v1/auth/oauth/poll?state=${encodeURIComponent(state)}`,\n );\n if (result.status === 'completed' && result.accessToken) {\n resolve({\n accessToken: result.accessToken,\n refreshToken: result.refreshToken!,\n expiresIn: result.expiresIn!,\n user: result.user!,\n });\n } else if (result.status === 'error') {\n handleError(result.message || 'Authentication failed');\n }\n } catch {\n // Network error — keep polling\n }\n }, 1500);\n\n // 3. Popup close detection\n const closePollTimer = setInterval(() => {\n if (resolved || cleaned) return;\n try {\n if (popup.closed) {\n clearInterval(closePollTimer);\n // Give polling a few more seconds to pick up the result\n setTimeout(() => {\n if (resolved || cleaned) return;\n cleanup();\n this.modal?.hideLoading();\n }, 3000);\n }\n } catch {\n // Cross-origin access error — popup still open\n }\n }, 500);\n\n // 4. Max timeout (3 minutes)\n const maxTimer = setTimeout(() => {\n if (resolved || cleaned) return;\n cleanup();\n this.modal?.hideLoading();\n }, 180_000);\n } catch (err) {\n this.modal?.hideLoading();\n this.emit('error', err instanceof Error ? err : new Error(String(err)));\n }\n }\n\n private async apiGet<T>(path: string): Promise<T> {\n const res = await fetch(`${this.config.apiUrl}${path}`, {\n headers: { 'x-api-key': this.publishableKey },\n credentials: 'include',\n });\n if (!res.ok) throw new Error(await this.parseApiError(res, path));\n return res.json();\n }\n\n private async apiPost<T>(path: string, body?: unknown): Promise<T> {\n const res = await fetch(`${this.config.apiUrl}${path}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': this.publishableKey,\n },\n credentials: 'include',\n body: body ? JSON.stringify(body) : undefined,\n });\n if (!res.ok) throw new Error(await this.parseApiError(res, path));\n return res.json();\n }\n\n private async parseApiError(res: Response, path: string): Promise<string> {\n try {\n const body = await res.json();\n if (Array.isArray(body.message) && body.message.length > 0) {\n return body.message[0];\n }\n if (typeof body.message === 'string' && body.message !== 'Bad Request') {\n return body.message;\n }\n } catch { /* ignore */ }\n return `API ${path}: ${res.status}`;\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/modal.ts","../src/providers.ts","../src/session.ts","../src/authon.ts"],"sourcesContent":["import type { BrandingConfig, OAuthProviderType } from '@authon/shared';\nimport { DEFAULT_BRANDING } from '@authon/shared';\nimport { getProviderButtonConfig } from './providers';\n\nexport class ModalRenderer {\n private shadowRoot: ShadowRoot | null = null;\n private hostElement: HTMLDivElement | null = null;\n private containerElement: HTMLElement | null = null;\n private mode: 'popup' | 'embedded';\n private theme: 'light' | 'dark' | 'auto';\n private branding: BrandingConfig;\n private enabledProviders: OAuthProviderType[] = [];\n private currentView: 'signIn' | 'signUp' = 'signIn';\n private onProviderClick: (provider: OAuthProviderType) => void;\n private onEmailSubmit: (email: string, password: string, isSignUp: boolean) => void;\n private onClose: () => void;\n private escHandler: ((e: KeyboardEvent) => void) | null = null;\n\n constructor(options: {\n mode: 'popup' | 'embedded';\n theme?: 'light' | 'dark' | 'auto';\n containerId?: string;\n branding?: BrandingConfig;\n onProviderClick: (provider: OAuthProviderType) => void;\n onEmailSubmit: (email: string, password: string, isSignUp: boolean) => void;\n onClose: () => void;\n }) {\n this.mode = options.mode;\n this.theme = options.theme || 'auto';\n this.branding = { ...DEFAULT_BRANDING, ...options.branding };\n this.onProviderClick = options.onProviderClick;\n this.onEmailSubmit = options.onEmailSubmit;\n this.onClose = options.onClose;\n\n if (options.mode === 'embedded' && options.containerId) {\n this.containerElement = document.getElementById(options.containerId);\n }\n }\n\n setProviders(providers: OAuthProviderType[]): void {\n this.enabledProviders = providers;\n }\n\n setBranding(branding: BrandingConfig): void {\n this.branding = { ...DEFAULT_BRANDING, ...branding };\n }\n\n open(view: 'signIn' | 'signUp' = 'signIn'): void {\n if (this.shadowRoot && this.hostElement) {\n // Modal already open — smooth in-place view switch\n this.switchView(view);\n } else {\n this.currentView = view;\n this.render(view);\n }\n }\n\n close(): void {\n if (this.escHandler) {\n document.removeEventListener('keydown', this.escHandler);\n this.escHandler = null;\n }\n if (this.hostElement) {\n this.hostElement.remove();\n this.hostElement = null;\n this.shadowRoot = null;\n }\n if (this.containerElement) {\n this.containerElement.innerHTML = '';\n }\n }\n\n showError(message: string): void {\n if (!this.shadowRoot) return;\n this.clearError();\n const errorEl = this.shadowRoot.getElementById('email-form');\n if (errorEl) {\n const errDiv = document.createElement('div');\n errDiv.id = 'authon-error-msg';\n errDiv.className = 'error-msg';\n errDiv.textContent = message;\n errorEl.appendChild(errDiv);\n }\n }\n\n showBanner(message: string, type: 'error' | 'warning' = 'error'): void {\n if (!this.shadowRoot) return;\n this.clearBanner();\n const inner = this.shadowRoot.getElementById('modal-inner');\n if (!inner) return;\n const banner = document.createElement('div');\n banner.id = 'authon-banner';\n banner.className = type === 'warning' ? 'banner-warning' : 'error-msg';\n banner.textContent = message;\n inner.insertBefore(banner, inner.firstChild);\n }\n\n clearBanner(): void {\n if (!this.shadowRoot) return;\n this.shadowRoot.getElementById('authon-banner')?.remove();\n }\n\n clearError(): void {\n if (!this.shadowRoot) return;\n this.shadowRoot.getElementById('authon-error-msg')?.remove();\n }\n\n showLoading(): void {\n if (!this.shadowRoot) return;\n this.hideLoading();\n const overlay = document.createElement('div');\n overlay.id = 'authon-loading-overlay';\n overlay.innerHTML = `\n <div class=\"loading-spinner\">\n <div class=\"loading-ring\"></div>\n <div class=\"loading-ring\"></div>\n <div class=\"loading-ring\"></div>\n </div>\n <div class=\"loading-text\">Signing in<span class=\"loading-dots\"><span></span><span></span><span></span></span></div>\n `;\n this.shadowRoot.querySelector('.modal-container')?.appendChild(overlay);\n }\n\n hideLoading(): void {\n if (!this.shadowRoot) return;\n this.shadowRoot.getElementById('authon-loading-overlay')?.remove();\n }\n\n // ── Smooth view switch (no flicker) ──\n\n private switchView(view: 'signIn' | 'signUp'): void {\n if (!this.shadowRoot || view === this.currentView) return;\n this.currentView = view;\n\n const inner = this.shadowRoot.getElementById('modal-inner');\n if (!inner) return;\n\n // Cross-fade: fade out → update → fade in\n inner.style.opacity = '0';\n inner.style.transform = 'translateY(-4px)';\n\n setTimeout(() => {\n inner.innerHTML = this.buildInnerContent(view);\n this.attachInnerEvents(view);\n // Trigger reflow, then animate in\n void inner.offsetHeight;\n inner.style.opacity = '1';\n inner.style.transform = 'translateY(0)';\n }, 140);\n }\n\n // ── Render ──\n\n private render(view: 'signIn' | 'signUp'): void {\n const host = document.createElement('div');\n host.setAttribute('data-authon-modal', '');\n this.hostElement = host;\n\n if (this.mode === 'popup') {\n document.body.appendChild(host);\n } else if (this.containerElement) {\n this.containerElement.appendChild(host);\n }\n\n this.shadowRoot = host.attachShadow({ mode: 'open' });\n this.shadowRoot.innerHTML = this.buildShell(view);\n this.attachInnerEvents(view);\n this.attachShellEvents();\n }\n\n // ── HTML builders ──\n\n /** Shell = style + backdrop + modal-container (stable across view switches) */\n private buildShell(view: 'signIn' | 'signUp'): string {\n const popupWrapper =\n this.mode === 'popup'\n ? `<div class=\"backdrop\" id=\"backdrop\"></div>`\n : '';\n\n return `\n <style>${this.buildCSS()}</style>\n ${popupWrapper}\n <div class=\"modal-container\" role=\"dialog\" aria-modal=\"true\">\n <div id=\"modal-inner\" class=\"modal-inner\">\n ${this.buildInnerContent(view)}\n </div>\n </div>\n `;\n }\n\n /** Inner content = everything inside the modal that changes per view */\n private buildInnerContent(view: 'signIn' | 'signUp'): string {\n const b = this.branding;\n const isSignUp = view === 'signUp';\n const title = isSignUp ? 'Create your account' : 'Welcome back';\n const subtitle = isSignUp ? 'Already have an account?' : \"Don't have an account?\";\n const subtitleLink = isSignUp ? 'Sign in' : 'Sign up';\n\n const dark = this.isDark();\n\n // SignUp view: hide providers, show only email form\n const showProviders = !isSignUp;\n\n const providerButtons = showProviders\n ? this.enabledProviders\n .filter((p) => !b.hiddenProviders?.includes(p))\n .map((p) => {\n const config = getProviderButtonConfig(p);\n const isWhiteBg = config.bgColor === '#ffffff';\n const btnBg = dark && isWhiteBg ? '#f8fafc' : config.bgColor;\n const btnBorder = isWhiteBg ? (dark ? '#475569' : '#e5e7eb') : config.bgColor;\n return `<button class=\"provider-btn\" data-provider=\"${p}\" style=\"background:${btnBg};color:${config.textColor};border:1px solid ${btnBorder}\">\n <span class=\"provider-icon\">${config.iconSvg}</span>\n <span>${config.label}</span>\n </button>`;\n })\n .join('')\n : '';\n\n const divider =\n showProviders && b.showDivider !== false && b.showEmailPassword !== false\n ? `<div class=\"divider\"><span>or</span></div>`\n : '';\n\n const emailForm =\n b.showEmailPassword !== false\n ? `<form class=\"email-form\" id=\"email-form\">\n <input type=\"email\" placeholder=\"Email address\" name=\"email\" required class=\"input\" autocomplete=\"email\" />\n <input type=\"password\" placeholder=\"Password\" name=\"password\" required class=\"input\" autocomplete=\"${isSignUp ? 'new-password' : 'current-password'}\" />\n ${isSignUp ? '<p class=\"password-hint\">Must contain uppercase, lowercase, and a number (min 8 chars)</p>' : ''}\n <button type=\"submit\" class=\"submit-btn\">${isSignUp ? 'Sign up' : 'Sign in'}</button>\n </form>`\n : '';\n\n const footer =\n b.termsUrl || b.privacyUrl\n ? `<div class=\"footer\">\n ${b.termsUrl ? `<a href=\"${b.termsUrl}\" target=\"_blank\">Terms of Service</a>` : ''}\n ${b.termsUrl && b.privacyUrl ? ' · ' : ''}\n ${b.privacyUrl ? `<a href=\"${b.privacyUrl}\" target=\"_blank\">Privacy Policy</a>` : ''}\n </div>`\n : '';\n\n const titleHtml = isSignUp\n ? `<div class=\"title-row\">\n <button class=\"back-btn\" id=\"back-btn\" type=\"button\" aria-label=\"Back to sign in\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M19 12H5\"/><path d=\"m12 19-7-7 7-7\"/></svg>\n </button>\n <h2 class=\"title\">${title}</h2>\n </div>`\n : `<h2 class=\"title\">${title}</h2>`;\n\n return `\n ${b.logoDataUrl ? `<img src=\"${b.logoDataUrl}\" alt=\"Logo\" class=\"logo\" />` : ''}\n ${titleHtml}\n ${b.brandName ? `<p class=\"brand-name\">${b.brandName}</p>` : ''}\n ${showProviders ? `<div class=\"providers\">${providerButtons}</div>` : ''}\n ${divider}\n ${emailForm}\n <p class=\"switch-view\">${subtitle} <a href=\"#\" id=\"switch-link\">${subtitleLink}</a></p>\n ${footer}\n ${b.showSecuredBy !== false ? `<div class=\"secured-by\">Secured by <a href=\"https://authon.dev\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"secured-link\">Authon</a></div>` : ''}\n `;\n }\n\n private isDark(): boolean {\n if (this.theme === 'dark') return true;\n if (this.theme === 'light') return false;\n return typeof window !== 'undefined' && window.matchMedia('(prefers-color-scheme: dark)').matches;\n }\n\n private buildCSS(): string {\n const b = this.branding;\n const dark = this.isDark();\n const bg = dark ? (b.darkBg || '#0f172a') : (b.lightBg || '#ffffff');\n const text = dark ? (b.darkText || '#f1f5f9') : (b.lightText || '#111827');\n const mutedText = dark ? '#94a3b8' : '#6b7280';\n const dimText = dark ? '#64748b' : '#9ca3af';\n const borderColor = dark ? '#334155' : '#d1d5db';\n const dividerColor = dark ? '#334155' : '#e5e7eb';\n const inputBg = dark ? '#1e293b' : '#ffffff';\n\n return `\n :host {\n --authon-primary-start: ${b.primaryColorStart || '#7c3aed'};\n --authon-primary-end: ${b.primaryColorEnd || '#4f46e5'};\n --authon-bg: ${bg};\n --authon-text: ${text};\n --authon-muted: ${mutedText};\n --authon-dim: ${dimText};\n --authon-border: ${borderColor};\n --authon-divider: ${dividerColor};\n --authon-input-bg: ${inputBg};\n --authon-radius: ${b.borderRadius ?? 12}px;\n --authon-font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n font-family: var(--authon-font);\n color: var(--authon-text);\n }\n * { box-sizing: border-box; margin: 0; padding: 0; }\n .backdrop {\n position: fixed; inset: 0; z-index: 99998;\n background: rgba(0,0,0,${dark ? '0.7' : '0.5'}); backdrop-filter: blur(4px);\n animation: fadeIn 0.2s ease;\n }\n .modal-container {\n ${this.mode === 'popup' ? 'position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 99999; max-height: 90vh; overflow-y: auto;' : ''}\n background: var(--authon-bg);\n color: var(--authon-text);\n border: 1px solid var(--authon-border);\n border-radius: var(--authon-radius);\n padding: 32px;\n width: 400px; max-width: 100%;\n position: ${this.mode === 'popup' ? 'fixed' : 'relative'};\n ${this.mode === 'popup' ? `box-shadow: 0 25px 50px -12px rgba(0,0,0,${dark ? '0.5' : '0.25'}); animation: slideIn 0.3s ease;` : ''}\n }\n .modal-inner {\n transition: opacity 0.14s ease, transform 0.14s ease;\n }\n .logo { display: block; margin: 0 auto 16px; max-height: 48px; }\n .title-row { display: flex; align-items: center; position: relative; margin-bottom: 8px; }\n .title-row .title { flex: 1; margin-bottom: 0; }\n .back-btn {\n position: absolute; left: 0; top: 50%; transform: translateY(-50%);\n background: none; border: none; color: var(--authon-muted);\n cursor: pointer; padding: 4px; border-radius: 6px; display: flex; align-items: center; justify-content: center;\n transition: color 0.15s, background 0.15s;\n }\n .back-btn:hover { color: var(--authon-text); background: var(--authon-divider); }\n .password-hint { font-size: 11px; color: var(--authon-dim); margin: -4px 0 2px; }\n .title { text-align: center; font-size: 24px; font-weight: 700; margin-bottom: 8px; color: var(--authon-text); }\n .brand-name { text-align: center; font-size: 14px; color: var(--authon-muted); margin-bottom: 24px; }\n .providers { display: flex; flex-direction: column; gap: 8px; margin-bottom: 16px; }\n .provider-btn {\n display: flex; align-items: center; gap: 12px;\n width: 100%; padding: 10px 16px; border-radius: calc(var(--authon-radius) * 0.67);\n font-size: 14px; font-weight: 500; cursor: pointer;\n transition: opacity 0.15s, transform 0.1s;\n font-family: var(--authon-font);\n }\n .provider-btn:hover { opacity: 0.9; }\n .provider-btn:active { transform: scale(0.98); }\n .provider-icon { display: flex; align-items: center; flex-shrink: 0; }\n .divider {\n display: flex; align-items: center; gap: 12px;\n margin: 16px 0; color: var(--authon-dim); font-size: 13px;\n }\n .divider::before, .divider::after {\n content: ''; flex: 1; height: 1px; background: var(--authon-divider);\n }\n .email-form { display: flex; flex-direction: column; gap: 10px; }\n .input {\n width: 100%; padding: 10px 14px;\n background: var(--authon-input-bg);\n color: var(--authon-text);\n border: 1px solid var(--authon-border); border-radius: calc(var(--authon-radius) * 0.5);\n font-size: 14px; font-family: var(--authon-font);\n outline: none; transition: border-color 0.15s;\n }\n .input::placeholder { color: var(--authon-dim); }\n .input:focus { border-color: var(--authon-primary-start); box-shadow: 0 0 0 3px rgba(124,58,237,0.15); }\n .submit-btn {\n width: 100%; padding: 10px;\n background: linear-gradient(135deg, var(--authon-primary-start), var(--authon-primary-end));\n color: #fff; border: none; border-radius: calc(var(--authon-radius) * 0.5);\n font-size: 14px; font-weight: 600; cursor: pointer;\n font-family: var(--authon-font); transition: opacity 0.15s;\n }\n .submit-btn:hover { opacity: 0.9; }\n .submit-btn:disabled { opacity: 0.6; cursor: not-allowed; }\n .error-msg {\n margin-top: 8px; padding: 8px 12px;\n background: rgba(239,68,68,0.1); border: 1px solid rgba(239,68,68,0.3);\n border-radius: calc(var(--authon-radius) * 0.33);\n font-size: 13px; color: #ef4444; text-align: center;\n animation: fadeIn 0.15s ease;\n }\n .banner-warning {\n margin-bottom: 16px; padding: 10px 14px;\n background: rgba(245,158,11,0.1); border: 1px solid rgba(245,158,11,0.3);\n border-radius: calc(var(--authon-radius) * 0.33);\n font-size: 13px; color: #f59e0b; text-align: center;\n animation: fadeIn 0.15s ease;\n }\n .switch-view { text-align: center; margin-top: 16px; font-size: 13px; color: var(--authon-muted); }\n .switch-view a { color: var(--authon-primary-start); text-decoration: none; font-weight: 500; }\n .switch-view a:hover { text-decoration: underline; }\n .footer { text-align: center; margin-top: 12px; font-size: 12px; color: var(--authon-dim); }\n .footer a { color: var(--authon-dim); text-decoration: none; }\n .footer a:hover { text-decoration: underline; }\n .secured-by {\n text-align: center; margin-top: 16px;\n font-size: 11px; color: var(--authon-dim);\n }\n .secured-link { font-weight: 600; color: var(--authon-muted); text-decoration: none; }\n .secured-link:hover { text-decoration: underline; }\n /* Loading overlay */\n #authon-loading-overlay {\n position: absolute; inset: 0; z-index: 10;\n background: ${dark ? 'rgba(15,23,42,0.92)' : 'rgba(255,255,255,0.92)'};\n backdrop-filter: blur(2px);\n border-radius: var(--authon-radius);\n display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 20px;\n animation: fadeIn 0.15s ease;\n }\n .loading-spinner { position: relative; width: 48px; height: 48px; }\n .loading-ring {\n position: absolute; inset: 0;\n border: 2.5px solid transparent; border-top-color: var(--authon-primary-start);\n border-radius: 50%; animation: spin 1s cubic-bezier(.55,.15,.45,.85) infinite;\n }\n .loading-ring:nth-child(2) {\n inset: 5px; border-top-color: transparent; border-right-color: var(--authon-primary-end);\n animation-duration: 1.2s; animation-direction: reverse; opacity: .7;\n }\n .loading-ring:nth-child(3) {\n inset: 10px; border-top-color: transparent; border-bottom-color: var(--authon-primary-start);\n animation-duration: .8s; opacity: .4;\n }\n .loading-text { font-size: 14px; font-weight: 500; color: var(--authon-muted); }\n .loading-dots { display: inline-flex; gap: 2px; margin-left: 2px; }\n .loading-dots span {\n width: 3px; height: 3px; border-radius: 50%;\n background: var(--authon-muted); animation: blink 1.4s infinite both;\n }\n .loading-dots span:nth-child(2) { animation-delay: .2s; }\n .loading-dots span:nth-child(3) { animation-delay: .4s; }\n @keyframes spin { to { transform: rotate(360deg); } }\n @keyframes blink { 0%,80%,100% { opacity: .2; } 40% { opacity: 1; } }\n @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }\n @keyframes slideIn { from { opacity: 0; transform: translate(-50%, -48%); } to { opacity: 1; transform: translate(-50%, -50%); } }\n ${b.customCss || ''}\n `;\n }\n\n // ── Event binding ──\n\n /** Attach events to shell elements (backdrop, ESC) — called once */\n private attachShellEvents(): void {\n if (!this.shadowRoot) return;\n\n const backdrop = this.shadowRoot.getElementById('backdrop');\n if (backdrop) {\n backdrop.addEventListener('click', () => this.onClose());\n }\n\n if (this.escHandler) {\n document.removeEventListener('keydown', this.escHandler);\n }\n if (this.mode === 'popup') {\n this.escHandler = (e: KeyboardEvent) => {\n if (e.key === 'Escape') this.onClose();\n };\n document.addEventListener('keydown', this.escHandler);\n }\n }\n\n /** Attach events to inner content (buttons, form, switch link) — called on each view */\n private attachInnerEvents(view: 'signIn' | 'signUp'): void {\n if (!this.shadowRoot) return;\n\n // Provider buttons\n this.shadowRoot.querySelectorAll('.provider-btn').forEach((btn) => {\n btn.addEventListener('click', () => {\n const provider = (btn as HTMLElement).dataset.provider as OAuthProviderType;\n this.onProviderClick(provider);\n });\n });\n\n // Email form\n const form = this.shadowRoot.getElementById('email-form') as HTMLFormElement | null;\n if (form) {\n form.addEventListener('submit', (e) => {\n e.preventDefault();\n const formData = new FormData(form);\n this.onEmailSubmit(\n formData.get('email') as string,\n formData.get('password') as string,\n view === 'signUp',\n );\n });\n }\n\n // Back button (signUp → signIn)\n const backBtn = this.shadowRoot.getElementById('back-btn');\n if (backBtn) {\n backBtn.addEventListener('click', () => {\n this.open('signIn');\n });\n }\n\n // Switch view link\n const switchLink = this.shadowRoot.getElementById('switch-link');\n if (switchLink) {\n switchLink.addEventListener('click', (e) => {\n e.preventDefault();\n this.open(view === 'signIn' ? 'signUp' : 'signIn');\n });\n }\n }\n}\n","import { PROVIDER_COLORS, PROVIDER_DISPLAY_NAMES, type OAuthProviderType } from '@authon/shared';\n\nexport interface ProviderButtonConfig {\n provider: OAuthProviderType;\n label: string;\n bgColor: string;\n textColor: string;\n iconSvg: string;\n}\n\nconst PROVIDER_ICONS: Record<OAuthProviderType, string> = {\n google: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\"><path fill=\"#4285F4\" d=\"M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 01-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z\"/><path fill=\"#34A853\" d=\"M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z\"/><path fill=\"#FBBC05\" d=\"M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z\"/><path fill=\"#EA4335\" d=\"M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z\"/></svg>`,\n apple: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"currentColor\"><path d=\"M17.05 20.28c-.98.95-2.05.88-3.08.4-1.09-.5-2.08-.48-3.24 0-1.44.62-2.2.44-3.06-.4C2.79 15.25 3.51 7.59 9.05 7.31c1.35.07 2.29.74 3.08.8 1.18-.24 2.31-.93 3.57-.84 1.51.12 2.65.72 3.4 1.8-3.12 1.87-2.38 5.98.48 7.13-.57 1.5-1.31 2.99-2.54 4.09zM12.03 7.25c-.15-2.23 1.66-4.07 3.74-4.25.29 2.58-2.34 4.5-3.74 4.25z\"/></svg>`,\n kakao: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\"><path fill=\"#191919\" d=\"M12 3C6.48 3 2 6.36 2 10.43c0 2.62 1.75 4.93 4.37 6.23l-1.12 4.14c-.1.36.31.65.62.44l4.93-3.26c.39.04.79.06 1.2.06 5.52 0 10-3.36 10-7.61C22 6.36 17.52 3 12 3z\"/></svg>`,\n naver: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\"><path fill=\"#fff\" d=\"M16.27 3H7.73A4.73 4.73 0 003 7.73v8.54A4.73 4.73 0 007.73 21h8.54A4.73 4.73 0 0021 16.27V7.73A4.73 4.73 0 0016.27 3zm-1.84 12.44h-2.1l-2.86-4.15v4.15H7.38V8.56h2.1l2.86 4.15V8.56h2.09v6.88z\"/></svg>`,\n facebook: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\"><path fill=\"#fff\" d=\"M24 12.07C24 5.41 18.63 0 12 0S0 5.4 0 12.07C0 18.1 4.39 23.1 10.13 24v-8.44H7.08v-3.49h3.04V9.41c0-3.02 1.8-4.7 4.54-4.7 1.31 0 2.68.24 2.68.24v2.97h-1.5c-1.5 0-1.96.93-1.96 1.89v2.26h3.33l-.53 3.49h-2.8V24C19.62 23.1 24 18.1 24 12.07z\"/></svg>`,\n github: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"#fff\"><path d=\"M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z\"/></svg>`,\n discord: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"#fff\"><path d=\"M20.32 4.37a19.8 19.8 0 00-4.89-1.52.07.07 0 00-.08.04c-.21.38-.44.87-.61 1.26a18.27 18.27 0 00-5.49 0 12.64 12.64 0 00-.62-1.26.07.07 0 00-.08-.04 19.74 19.74 0 00-4.89 1.52.07.07 0 00-.03.03C1.11 8.39.34 12.28.73 16.12a.08.08 0 00.03.06 19.9 19.9 0 005.99 3.03.08.08 0 00.08-.03c.46-.63.87-1.3 1.22-2a.08.08 0 00-.04-.11 13.1 13.1 0 01-1.87-.9.08.08 0 01-.01-.13c.13-.09.25-.19.37-.29a.07.07 0 01.08-.01c3.93 1.8 8.18 1.8 12.07 0a.07.07 0 01.08 0c.12.1.25.2.37.3a.08.08 0 01-.01.12c-.6.35-1.22.65-1.87.9a.08.08 0 00-.04.1c.36.7.77 1.37 1.22 2a.08.08 0 00.08.03 19.83 19.83 0 006-3.03.08.08 0 00.03-.05c.47-4.87-.78-9.09-3.3-12.84a.06.06 0 00-.03-.03zM8.02 13.62c-1.11 0-2.03-1.02-2.03-2.28 0-1.26.9-2.28 2.03-2.28 1.14 0 2.04 1.03 2.03 2.28 0 1.26-.9 2.28-2.03 2.28zm7.5 0c-1.11 0-2.03-1.02-2.03-2.28 0-1.26.9-2.28 2.03-2.28 1.14 0 2.04 1.03 2.03 2.28 0 1.26-.89 2.28-2.03 2.28z\"/></svg>`,\n x: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"#fff\"><path d=\"M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z\"/></svg>`,\n line: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"#fff\"><path d=\"M19.365 9.863c.349 0 .63.285.63.631 0 .345-.281.63-.63.63H17.61v1.125h1.755c.349 0 .63.283.63.63 0 .344-.281.629-.63.629h-2.386c-.345 0-.627-.285-.627-.629V8.108c0-.345.282-.63.63-.63h2.386c.346 0 .627.285.627.63 0 .349-.281.63-.63.63H17.61v1.125h1.755zm-3.855 3.016c0 .27-.174.51-.432.596-.064.021-.133.031-.199.031-.211 0-.391-.09-.51-.25l-2.443-3.317v2.94c0 .344-.279.629-.631.629-.346 0-.626-.285-.626-.629V8.108c0-.27.173-.51.43-.595.06-.023.136-.033.194-.033.195 0 .375.104.495.254l2.462 3.33V8.108c0-.345.282-.63.63-.63.345 0 .63.285.63.63v4.771zm-5.741 0c0 .344-.282.629-.631.629-.345 0-.627-.285-.627-.629V8.108c0-.345.282-.63.63-.63.346 0 .628.285.628.63v4.771zm-2.466.629H4.917c-.345 0-.63-.285-.63-.629V8.108c0-.345.285-.63.63-.63.348 0 .63.285.63.63v4.141h1.756c.348 0 .629.283.629.63 0 .344-.282.629-.629.629M24 10.314C24 4.943 18.615.572 12 .572S0 4.943 0 10.314c0 4.811 4.27 8.842 10.035 9.608.391.082.923.258 1.058.59.12.301.079.766.038 1.08l-.164 1.02c-.045.301-.24 1.186 1.049.645 1.291-.539 6.916-4.078 9.436-6.975C23.176 14.393 24 12.458 24 10.314\"/></svg>`,\n microsoft: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\"><rect fill=\"#F25022\" x=\"1\" y=\"1\" width=\"10\" height=\"10\"/><rect fill=\"#7FBA00\" x=\"13\" y=\"1\" width=\"10\" height=\"10\"/><rect fill=\"#00A4EF\" x=\"1\" y=\"13\" width=\"10\" height=\"10\"/><rect fill=\"#FFB900\" x=\"13\" y=\"13\" width=\"10\" height=\"10\"/></svg>`,\n};\n\nexport function getProviderButtonConfig(provider: OAuthProviderType): ProviderButtonConfig {\n const colors = PROVIDER_COLORS[provider];\n return {\n provider,\n label: `Continue with ${PROVIDER_DISPLAY_NAMES[provider]}`,\n bgColor: colors.bg,\n textColor: colors.text,\n iconSvg: PROVIDER_ICONS[provider],\n };\n}\n","import type { AuthonUser, AuthTokens } from '@authon/shared';\n\nexport class SessionManager {\n private accessToken: string | null = null;\n private refreshToken: string | null = null;\n private user: AuthonUser | null = null;\n private refreshTimer: ReturnType<typeof setTimeout> | null = null;\n private apiUrl: string;\n private publishableKey: string;\n\n constructor(publishableKey: string, apiUrl: string) {\n this.publishableKey = publishableKey;\n this.apiUrl = apiUrl;\n }\n\n getToken(): string | null {\n return this.accessToken;\n }\n\n getUser(): AuthonUser | null {\n return this.user;\n }\n\n setSession(tokens: AuthTokens): void {\n this.accessToken = tokens.accessToken;\n this.refreshToken = tokens.refreshToken;\n this.user = tokens.user;\n if (tokens.expiresIn && tokens.expiresIn > 0) {\n this.scheduleRefresh(tokens.expiresIn);\n }\n }\n\n clearSession(): void {\n this.accessToken = null;\n this.refreshToken = null;\n this.user = null;\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n this.refreshTimer = null;\n }\n }\n\n private scheduleRefresh(expiresIn: number): void {\n if (this.refreshTimer) clearTimeout(this.refreshTimer);\n // Refresh 60 seconds before expiry\n const refreshIn = Math.max((expiresIn - 60) * 1000, 30000);\n this.refreshTimer = setTimeout(() => this.refresh(), refreshIn);\n }\n\n async refresh(): Promise<AuthTokens | null> {\n if (!this.refreshToken) {\n this.clearSession();\n return null;\n }\n try {\n const res = await fetch(`${this.apiUrl}/v1/auth/token/refresh`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': this.publishableKey,\n },\n credentials: 'include',\n body: JSON.stringify({ refreshToken: this.refreshToken }),\n });\n if (!res.ok) {\n this.clearSession();\n return null;\n }\n const tokens: AuthTokens = await res.json();\n this.setSession(tokens);\n return tokens;\n } catch {\n this.clearSession();\n return null;\n }\n }\n\n async signOut(): Promise<void> {\n try {\n await fetch(`${this.apiUrl}/v1/auth/signout`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': this.publishableKey,\n ...(this.accessToken ? { Authorization: `Bearer ${this.accessToken}` } : {}),\n },\n credentials: 'include',\n });\n } catch {\n // ignore\n }\n this.clearSession();\n }\n\n destroy(): void {\n this.clearSession();\n }\n}\n","import type { AuthonUser, AuthTokens, BrandingConfig, OAuthProviderType } from '@authon/shared';\nimport type { AuthonConfig, AuthonEventType, AuthonEvents } from './types';\nimport { ModalRenderer } from './modal';\nimport { SessionManager } from './session';\n\nexport class Authon {\n private publishableKey: string;\n private config: Required<Omit<AuthonConfig, 'containerId' | 'appearance'>> & {\n containerId?: string;\n appearance?: Partial<BrandingConfig>;\n };\n private session: SessionManager;\n private modal: ModalRenderer | null = null;\n private listeners: Map<string, Set<(...args: unknown[]) => void>> = new Map();\n private branding: BrandingConfig | null = null;\n private providers: OAuthProviderType[] = [];\n private initialized = false;\n\n constructor(publishableKey: string, config?: AuthonConfig) {\n this.publishableKey = publishableKey;\n this.config = {\n apiUrl: config?.apiUrl || 'https://api.authon.dev',\n mode: config?.mode || 'popup',\n theme: config?.theme || 'auto',\n locale: config?.locale || 'en',\n containerId: config?.containerId,\n appearance: config?.appearance,\n };\n this.session = new SessionManager(publishableKey, this.config.apiUrl);\n }\n\n // ── Public API ──\n\n async openSignIn(): Promise<void> {\n await this.ensureInitialized();\n this.getModal().open('signIn');\n }\n\n async openSignUp(): Promise<void> {\n await this.ensureInitialized();\n this.getModal().open('signUp');\n }\n\n async signInWithOAuth(provider: OAuthProviderType): Promise<void> {\n await this.ensureInitialized();\n await this.startOAuthFlow(provider);\n }\n\n async signInWithEmail(email: string, password: string): Promise<AuthonUser> {\n const tokens = await this.apiPost<AuthTokens>('/v1/auth/signin', { email, password });\n this.session.setSession(tokens);\n this.emit('signedIn', tokens.user);\n return tokens.user;\n }\n\n async signUpWithEmail(\n email: string,\n password: string,\n meta?: { displayName?: string },\n ): Promise<AuthonUser> {\n const tokens = await this.apiPost<AuthTokens>('/v1/auth/signup', {\n email,\n password,\n ...meta,\n });\n this.session.setSession(tokens);\n this.emit('signedIn', tokens.user);\n return tokens.user;\n }\n\n async signOut(): Promise<void> {\n await this.session.signOut();\n this.emit('signedOut');\n }\n\n getUser(): AuthonUser | null {\n return this.session.getUser();\n }\n\n getToken(): string | null {\n return this.session.getToken();\n }\n\n on<K extends AuthonEventType>(event: K, listener: AuthonEvents[K]): () => void {\n if (!this.listeners.has(event)) this.listeners.set(event, new Set());\n const set = this.listeners.get(event)!;\n set.add(listener as (...args: unknown[]) => void);\n return () => set.delete(listener as (...args: unknown[]) => void);\n }\n\n destroy(): void {\n this.modal?.close();\n this.session.destroy();\n this.listeners.clear();\n }\n\n // ── Internal ──\n\n private emit(event: string, ...args: unknown[]): void {\n this.listeners.get(event)?.forEach((fn) => fn(...args));\n }\n\n private async ensureInitialized(): Promise<void> {\n if (this.initialized) return;\n try {\n const [branding, providersRes] = await Promise.all([\n this.apiGet<BrandingConfig>('/v1/auth/branding'),\n this.apiGet<{ providers: OAuthProviderType[] }>('/v1/auth/providers'),\n ]);\n this.branding = { ...branding, ...this.config.appearance };\n this.providers = providersRes.providers;\n this.initialized = true;\n } catch (err) {\n this.emit('error', err instanceof Error ? err : new Error(String(err)));\n throw err;\n }\n }\n\n private getModal(): ModalRenderer {\n if (!this.modal) {\n this.modal = new ModalRenderer({\n mode: this.config.mode,\n theme: this.config.theme,\n containerId: this.config.containerId,\n branding: this.branding || undefined,\n onProviderClick: (provider) => this.startOAuthFlow(provider),\n onEmailSubmit: (email, password, isSignUp) => {\n this.modal?.clearError();\n const promise = isSignUp\n ? this.signUpWithEmail(email, password)\n : this.signInWithEmail(email, password);\n promise\n .then(() => this.modal?.close())\n .catch((err) => {\n const msg = err instanceof Error ? err.message : String(err);\n this.modal?.showError(msg || 'Authentication failed');\n this.emit('error', err instanceof Error ? err : new Error(msg));\n });\n },\n onClose: () => this.modal?.close(),\n });\n }\n if (this.branding) this.modal.setBranding(this.branding);\n this.modal.setProviders(this.providers);\n return this.modal;\n }\n\n private async startOAuthFlow(provider: OAuthProviderType): Promise<void> {\n try {\n const redirectUri = `${this.config.apiUrl}/v1/auth/oauth/redirect`;\n const { url, state } = await this.apiGet<{ url: string; state: string }>(\n `/v1/auth/oauth/${provider}/url?redirectUri=${encodeURIComponent(redirectUri)}`,\n );\n\n this.modal?.showLoading();\n\n // Open popup\n const width = 500;\n const height = 700;\n const left = window.screenX + (window.outerWidth - width) / 2;\n const top = window.screenY + (window.outerHeight - height) / 2;\n const popup = window.open(\n url,\n 'authon-oauth',\n `width=${width},height=${height},left=${left},top=${top},toolbar=no,menubar=no`,\n );\n\n if (!popup || popup.closed) {\n this.modal?.hideLoading();\n this.modal?.showBanner(\n 'Pop-up blocked. Please allow pop-ups for this site and try again.',\n 'warning',\n );\n this.emit('error', new Error('Popup was blocked by the browser'));\n return;\n }\n\n let resolved = false;\n let cleaned = false;\n const storageKey = `authon-oauth-${state}`;\n\n const resolve = (tokens: AuthTokens) => {\n if (resolved) return;\n resolved = true;\n cleanup();\n try { if (popup && !popup.closed) popup.close(); } catch { /* ignore */ }\n try { localStorage.removeItem(storageKey); } catch { /* ignore */ }\n this.session.setSession(tokens);\n this.modal?.close();\n this.emit('signedIn', tokens.user);\n };\n\n const handleError = (msg: string) => {\n if (resolved) return;\n cleanup();\n this.modal?.hideLoading();\n this.modal?.showError(msg);\n this.emit('error', new Error(msg));\n };\n\n const pollApi = async () => {\n if (resolved || cleaned) return;\n try {\n const result = await this.apiGet<{ status: string; accessToken?: string; refreshToken?: string; expiresIn?: number; user?: AuthonUser; message?: string }>(\n `/v1/auth/oauth/poll?state=${encodeURIComponent(state)}`,\n );\n if (result.status === 'completed' && result.accessToken) {\n resolve({\n accessToken: result.accessToken,\n refreshToken: result.refreshToken!,\n expiresIn: result.expiresIn!,\n user: result.user!,\n });\n } else if (result.status === 'error') {\n handleError(result.message || 'Authentication failed');\n }\n } catch {\n // Network error — keep polling\n }\n };\n\n const cleanup = () => {\n if (cleaned) return;\n cleaned = true;\n window.removeEventListener('message', messageHandler);\n window.removeEventListener('storage', storageHandler);\n document.removeEventListener('visibilitychange', visibilityHandler);\n if (apiPollTimer) clearInterval(apiPollTimer);\n if (closePollTimer) clearInterval(closePollTimer);\n if (maxTimer) clearTimeout(maxTimer);\n };\n\n // 1. postMessage handler (fast path — Chrome/Firefox desktop)\n const messageHandler = (e: MessageEvent) => {\n if (e.data?.type !== 'authon-oauth-callback') return;\n if (e.data.tokens) {\n resolve(e.data.tokens as AuthTokens);\n }\n };\n window.addEventListener('message', messageHandler);\n\n // 2. localStorage handler (mobile fallback — cross-tab communication)\n const storageHandler = (e: StorageEvent) => {\n if (e.key !== storageKey || !e.newValue) return;\n try {\n const data = JSON.parse(e.newValue);\n if (data.tokens) resolve(data.tokens as AuthTokens);\n else if (data.error) handleError(data.error);\n } catch { /* ignore */ }\n };\n window.addEventListener('storage', storageHandler);\n\n // Also check localStorage immediately in case it was set before listener\n try {\n const existing = localStorage.getItem(storageKey);\n if (existing) {\n const data = JSON.parse(existing);\n if (data.tokens) { resolve(data.tokens as AuthTokens); return; }\n }\n } catch { /* ignore */ }\n\n // 3. API polling (fallback for all browsers)\n const apiPollTimer = setInterval(pollApi, 1500);\n\n // 4. visibilitychange — poll immediately when tab regains focus (mobile)\n const visibilityHandler = () => {\n if (document.visibilityState === 'visible' && !resolved && !cleaned) {\n pollApi();\n }\n };\n document.addEventListener('visibilitychange', visibilityHandler);\n\n // 5. Popup close detection\n const closePollTimer = setInterval(() => {\n if (resolved || cleaned) return;\n try {\n if (popup && popup.closed) {\n clearInterval(closePollTimer);\n // Poll immediately + give a few more seconds\n pollApi();\n setTimeout(() => {\n if (resolved || cleaned) return;\n pollApi().then(() => {\n if (resolved || cleaned) return;\n cleanup();\n this.modal?.hideLoading();\n });\n }, 3000);\n }\n } catch {\n // Cross-origin access error — popup still open\n }\n }, 500);\n\n // 6. Max timeout (3 minutes)\n const maxTimer = setTimeout(() => {\n if (resolved || cleaned) return;\n cleanup();\n this.modal?.hideLoading();\n }, 180_000);\n } catch (err) {\n this.modal?.hideLoading();\n this.emit('error', err instanceof Error ? err : new Error(String(err)));\n }\n }\n\n private async apiGet<T>(path: string): Promise<T> {\n const res = await fetch(`${this.config.apiUrl}${path}`, {\n headers: { 'x-api-key': this.publishableKey },\n credentials: 'include',\n });\n if (!res.ok) throw new Error(await this.parseApiError(res, path));\n return res.json();\n }\n\n private async apiPost<T>(path: string, body?: unknown): Promise<T> {\n const res = await fetch(`${this.config.apiUrl}${path}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': this.publishableKey,\n },\n credentials: 'include',\n body: body ? JSON.stringify(body) : undefined,\n });\n if (!res.ok) throw new Error(await this.parseApiError(res, path));\n return res.json();\n }\n\n private async parseApiError(res: Response, path: string): Promise<string> {\n try {\n const body = await res.json();\n if (Array.isArray(body.message) && body.message.length > 0) {\n return body.message[0];\n }\n if (typeof body.message === 'string' && body.message !== 'Bad Request') {\n return body.message;\n }\n } catch { /* ignore */ }\n return `API ${path}: ${res.status}`;\n }\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@authon/js",
3
- "version": "0.1.14",
3
+ "version": "0.1.15",
4
4
  "description": "Authon core browser SDK — ShadowDOM login modal, OAuth, session management",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",