@authrobo/react 0.5.0 → 0.5.1

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/README.md CHANGED
@@ -1,9 +1,23 @@
1
- # @authrobo/react
2
-
3
- Drop-in React sign-in for [AuthRobo](https://authrobo.com). Renders exactly the
4
- methods you've enabled in your dashboard — social providers (Google, LinkedIn,
5
- GitHub, Apple) plus an email switcher (**Magic Link · Register · Login**) — or
6
- compose your own UI from a single configurable button.
1
+ <p align="center">
2
+ <a href="https://authrobo.com"><img src="https://cdn.jsdelivr.net/npm/@authrobo/react/assets/hero.png" alt="AuthRobo — drop-in React sign-in" width="100%"></a>
3
+ </p>
4
+
5
+ <h1 align="center">@authrobo/react</h1>
6
+
7
+ <p align="center">
8
+ <a href="https://www.npmjs.com/package/@authrobo/react"><img src="https://img.shields.io/npm/v/@authrobo/react?logo=npm&color=4f46e5&labelColor=0b1526" alt="npm version"></a>
9
+ <a href="https://www.npmjs.com/package/@authrobo/react"><img src="https://img.shields.io/npm/dm/@authrobo/react?color=4f46e5&labelColor=0b1526" alt="npm downloads"></a>
10
+ <img src="https://img.shields.io/bundlejs/size/@authrobo/react?label=min%2Bgzip&color=4f46e5&labelColor=0b1526" alt="min+gzip size">
11
+ <img src="https://img.shields.io/badge/types-included-4f46e5?labelColor=0b1526&logo=typescript&logoColor=white" alt="TypeScript types included">
12
+ <img src="https://img.shields.io/npm/l/@authrobo/react?color=4f46e5&labelColor=0b1526" alt="MIT license">
13
+ </p>
14
+
15
+ <p align="center">
16
+ <b>Drop-in React sign-in for <a href="https://authrobo.com">AuthRobo</a>.</b><br>
17
+ Renders exactly the methods you've enabled in your dashboard — social (Google, LinkedIn,
18
+ GitHub, Apple, Facebook) plus an email switcher (<b>Magic Link · Register · Login</b>) —
19
+ or compose your own UI from a single configurable button.
20
+ </p>
7
21
 
8
22
  ```bash
9
23
  npm i @authrobo/react
Binary file
package/dist/index.cjs CHANGED
@@ -177,7 +177,7 @@ function prefetchAppConfig(config) {
177
177
  const base = config.issuerUrl.replace(/\/$/, "");
178
178
  e.promise = fetch(`${base}/api/v1/config?client_id=${encodeURIComponent(config.clientId)}`).then((r) => r.ok ? r.json() : Promise.reject(new Error(`config ${r.status}`))).then((j) => {
179
179
  e.state = {
180
- data: { name: j.name, brandColor: j.brand_color, logoUrl: j.logo_url, methods: j.methods },
180
+ data: { name: j.name, brandColor: j.brand_color, logoUrl: j.logo_url, methods: j.methods, poweredBy: j.powered_by !== false },
181
181
  loading: false,
182
182
  error: null
183
183
  };
@@ -250,6 +250,10 @@ ${scoped('[data-theme="dark"] ', TOKENS_DARK)}
250
250
  .authrobo-title{font:700 16px system-ui,sans-serif;color:var(--authrobo-title-fg);}
251
251
  .authrobo-muted{color:var(--authrobo-muted);font:14px system-ui,sans-serif;margin:0;}
252
252
  .authrobo-error{color:var(--authrobo-error);font:14px system-ui,sans-serif;margin:0;}
253
+ .authrobo-powered{display:block;margin:2px 0 -2px;text-align:center;text-decoration:none;
254
+ font:500 11.5px system-ui,sans-serif;color:var(--authrobo-muted);opacity:.85;transition:opacity .15s ease;}
255
+ .authrobo-powered:hover{opacity:1;}
256
+ .authrobo-powered b{font-weight:700;color:var(--authrobo-title-fg);}
253
257
  .authrobo-divider{display:flex;align-items:center;gap:10px;color:var(--authrobo-divider-fg);font:500 12px system-ui,sans-serif;}
254
258
  .authrobo-divider::before,.authrobo-divider::after{content:"";height:1px;flex:1;background:var(--authrobo-divider-line);}
255
259
  .authrobo-tabs{display:flex;gap:4px;padding:4px;border:1px solid var(--authrobo-btn-border);
@@ -276,7 +280,7 @@ ${scoped('[data-theme="dark"] ', TOKENS_DARK)}
276
280
  .authrobo-spinner{display:inline-block;width:1.15em;height:1.15em;vertical-align:-0.2em;border-radius:50%;
277
281
  border:2px solid color-mix(in srgb, currentColor 24%, transparent);border-top-color:currentColor;
278
282
  animation:authrobo-spin .7s linear infinite;}
279
- .authrobo-loading{display:flex;align-items:center;gap:10px;padding:4px 0;}
283
+ .authrobo-loading{display:flex;align-items:center;justify-content:center;gap:10px;padding:20px 0;}
280
284
  @keyframes authrobo-spin{to{transform:rotate(360deg)}}
281
285
  @media (prefers-reduced-motion: reduce){.authrobo-spinner{animation-duration:1.4s}}
282
286
  .authrobo-overlay{position:fixed;inset:0;z-index:2147483000;display:flex;align-items:center;
@@ -570,7 +574,11 @@ function AuthRoboAuth({
570
574
  )),
571
575
  email.length > 0 && social.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "authrobo-divider", children: "or" }),
572
576
  email.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(EmailSwitcher, { config: c, methods: email, startPath, onSuccess }),
573
- !loading && !error && shown.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "authrobo-muted", children: "No sign-in methods are enabled for this app." })
577
+ !loading && !error && shown.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "authrobo-muted", children: "No sign-in methods are enabled for this app." }),
578
+ !loading && !error && data?.poweredBy && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("a", { className: "authrobo-powered", href: "https://authrobo.com", target: "_blank", rel: "noreferrer", children: [
579
+ "Authentication provided by ",
580
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("b", { children: "AuthRobo" })
581
+ ] })
574
582
  ] });
575
583
  if (mode === "inline") return panel;
576
584
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "authrobo-overlay", onClick: () => onClose?.(), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "authrobo-card", role: "dialog", "aria-modal": "true", onClick: (e) => e.stopPropagation(), children: [
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.tsx","../src/icons.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n} from \"react\";\nimport { BRAND_STYLE, PROVIDER_META, WHITE_MARKS, type Method } from \"./icons\";\n\nexport type { Method } from \"./icons\";\nexport { PROVIDER_META, BRAND_STYLE } from \"./icons\";\n\n/** Which hosted screen an email flow should open. */\nexport type Screen = \"login\" | \"register\" | \"magic\";\n\n/**\n * How to render social provider buttons.\n * - \"neutral\" (default): one consistent button chrome (themeable), brand-coloured icon.\n * - \"branded\": each button wears its provider's colours — LinkedIn blue, GitHub\n * black, Google white, Facebook blue, Apple black — with a legible glyph.\n */\nexport type ButtonStyle = \"neutral\" | \"branded\";\n\nexport interface AuthRoboConfig {\n /** Your AuthRobo instance, e.g. \"https://authrobo.com\". */\n issuerUrl: string;\n /** Your app's client_id (arc_...). */\n clientId: string;\n /** Where AuthRobo returns the one-time `code` after sign-in. */\n redirectUri: string;\n}\n\n/** Shape returned by GET /api/v1/config. */\nexport interface AppConfig {\n name: string;\n brandColor: string | null;\n logoUrl: string | null;\n methods: Method[];\n}\n\nconst ConfigContext = createContext<AuthRoboConfig | null>(null);\n\nexport function AuthRoboProvider({\n config,\n children,\n}: {\n config: AuthRoboConfig;\n children: React.ReactNode;\n}) {\n // Warm the app-config cache as soon as the provider mounts (i.e. on app start),\n // so the enabled sign-in methods are already resolved by the time a login modal\n // or page is opened — no request-on-open, no loading flash.\n useEffect(() => {\n prefetchAppConfig(config);\n }, [config.issuerUrl, config.clientId]);\n return <ConfigContext.Provider value={config}>{children}</ConfigContext.Provider>;\n}\n\nfunction useResolvedConfig(override?: AuthRoboConfig): AuthRoboConfig {\n const ctx = useContext(ConfigContext);\n const c = override ?? ctx;\n if (!c) {\n throw new Error(\n \"@authrobo/react: wrap your app in <AuthRoboProvider config={...}> or pass a `config` prop.\",\n );\n }\n return c;\n}\n\nfunction randomState(): string {\n const b = new Uint8Array(16);\n (globalThis.crypto ?? (globalThis as { crypto: Crypto }).crypto).getRandomValues(b);\n return Array.from(b, (x) => x.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\n// Email-based methods open a hosted page (which collects the address + password\n// or mails a link); social providers redirect straight into their OAuth start.\nconst EMAIL_METHODS: readonly Method[] = [\"password\", \"magic_link\"];\n\n/** Options accepted by startSignIn and the button/panel components. */\nexport interface StartOptions {\n state?: string;\n /** Prefill the email on the hosted page. */\n loginHint?: string;\n /** For email flows: which hosted screen to open (login / register / magic). */\n screen?: Screen;\n /**\n * Route the redirect through YOUR server instead of straight to AuthRobo.\n * When set, the browser navigates to `${startPath}/<method>/start` — your\n * route sets a first-party CSRF state cookie + the real redirect_uri, then\n * bounces to AuthRobo. This is the right choice for apps that keep the session\n * in httpOnly cookies (the code exchange happens server-side with your\n * client_secret). Leave unset to redirect to AuthRobo directly.\n */\n startPath?: string;\n}\n\n/**\n * Begin sign-in: navigate the browser to the hosted flow for `method`.\n *\n * - Social methods hit /api/v1/auth/<provider>/start.\n * - \"password\" opens the hosted /login (or /register when `screen: \"register\"`).\n * - \"magic_link\" opens /login?screen=magic (the passwordless view).\n *\n * With `startPath`, all of the above are proxied through your own server route\n * (`${startPath}/<method>/start`) so the flow stays first-party. Either way,\n * AuthRobo returns to your callback with a one-time `code` your backend\n * exchanges (with your client_secret) for tokens.\n */\nexport function startSignIn(config: AuthRoboConfig, method: Method, opts?: StartOptions): void {\n // Remember the method so we can badge it \"Last used\" next time (per client_id).\n try {\n localStorage.setItem(lastMethodKey(config.clientId), method);\n } catch {\n /* storage unavailable — badge just won't show next time */\n }\n\n // App-proxied: hand off to the consumer's own server, which owns state +\n // redirect_uri. Nothing sensitive is decided client-side here.\n if (opts?.startPath) {\n const p = new URLSearchParams();\n if (opts.loginHint) p.set(\"login_hint\", opts.loginHint);\n if (opts.screen) p.set(\"screen\", opts.screen);\n const qs = p.toString();\n window.location.assign(`${opts.startPath.replace(/\\/$/, \"\")}/${method}/start${qs ? `?${qs}` : \"\"}`);\n return;\n }\n\n const base = config.issuerUrl.replace(/\\/$/, \"\");\n const state = opts?.state ?? randomState();\n try {\n sessionStorage.setItem(\"authrobo:state\", state);\n } catch {\n /* storage unavailable — state is still sent, just not persisted for a check */\n }\n const params = new URLSearchParams({\n client_id: config.clientId,\n redirect_uri: config.redirectUri,\n state,\n });\n if (opts?.loginHint) params.set(\"login_hint\", opts.loginHint);\n\n let path: string;\n if (method === \"magic_link\") {\n params.set(\"screen\", \"magic\");\n path = \"/login\";\n } else if (method === \"password\") {\n path = opts?.screen === \"register\" ? \"/register\" : \"/login\";\n } else {\n path = `/api/v1/auth/${method}/start`;\n }\n window.location.assign(`${base}${path}?${params.toString()}`);\n}\n\nconst lastMethodKey = (clientId: string) => `authrobo:last-method:${clientId}`;\n\n/** The method last used to sign in for this client (from a prior startSignIn). */\nexport function useLastMethod(clientId: string): Method | null {\n const [last, setLast] = useState<Method | null>(null);\n useEffect(() => {\n try {\n setLast((localStorage.getItem(lastMethodKey(clientId)) as Method | null) ?? null);\n } catch {\n /* storage unavailable */\n }\n }, [clientId]);\n return last;\n}\n\n/* ------------------------- App-config cache ----------------------------- */\n// A tiny module-level store so the app's public config (branding + enabled\n// methods) is fetched at most once per (issuer, clientId) and shared across every\n// hook/component. Prefetched on provider mount; read synchronously thereafter.\n\ntype ConfigState = { data: AppConfig | null; loading: boolean; error: string | null };\n\nconst LOADING_STATE: ConfigState = { data: null, loading: true, error: null };\n\ntype ConfigEntry = { state: ConfigState; promise?: Promise<void>; listeners: Set<() => void> };\n\nconst configStore = new Map<string, ConfigEntry>();\nconst configKey = (c: AuthRoboConfig) => `${c.issuerUrl.replace(/\\/$/, \"\")}|${c.clientId}`;\n\nfunction configEntry(key: string): ConfigEntry {\n let e = configStore.get(key);\n if (!e) {\n e = { state: LOADING_STATE, listeners: new Set() };\n configStore.set(key, e);\n }\n return e;\n}\n\n/**\n * Fetch (once) and cache an app's public config. Safe to call eagerly on app\n * start — concurrent calls dedupe onto the same in-flight request, and a resolved\n * entry returns immediately. Returns the in-flight promise (or a resolved one).\n */\nexport function prefetchAppConfig(config: AuthRoboConfig): Promise<void> {\n if (typeof window === \"undefined\") return Promise.resolve(); // no-op during SSR\n const key = configKey(config);\n const e = configEntry(key);\n if (e.state.data || e.promise) return e.promise ?? Promise.resolve();\n const base = config.issuerUrl.replace(/\\/$/, \"\");\n e.promise = fetch(`${base}/api/v1/config?client_id=${encodeURIComponent(config.clientId)}`)\n .then((r) => (r.ok ? r.json() : Promise.reject(new Error(`config ${r.status}`))))\n .then((j) => {\n e.state = {\n data: { name: j.name, brandColor: j.brand_color, logoUrl: j.logo_url, methods: j.methods },\n loading: false,\n error: null,\n };\n })\n .catch((err) => {\n e.state = { data: null, loading: false, error: String(err?.message ?? err) };\n })\n .finally(() => {\n e.promise = undefined;\n e.listeners.forEach((l) => l());\n });\n return e.promise;\n}\n\n/** Fetch an app's public config (branding + enabled methods) for `clientId`. */\nexport function useAppConfig(config?: AuthRoboConfig): ConfigState {\n const c = useResolvedConfig(config);\n const key = configKey(c);\n\n const subscribe = useCallback(\n (cb: () => void) => {\n const e = configEntry(key);\n e.listeners.add(cb);\n return () => {\n e.listeners.delete(cb);\n };\n },\n [key],\n );\n const getSnapshot = useCallback(() => configEntry(key).state, [key]);\n const state = useSyncExternalStore(subscribe, getSnapshot, () => LOADING_STATE);\n\n // Kick off the fetch if the provider didn't already (e.g. no <AuthRoboProvider>).\n useEffect(() => {\n prefetchAppConfig(c);\n }, [c.issuerUrl, c.clientId]);\n\n return state;\n}\n\n/* ----------------------------- Styling ---------------------------------- */\n\nconst STYLE_ID = \"authrobo-react-styles\";\n\n// Theme-aware: tokens default to a soft light palette, flip to dark on the OS\n// preference, and can be forced either way by a `data-theme` attribute on any\n// ancestor (`<html data-theme=\"dark\">`). A host app can also override any single\n// token inline (e.g. `--authrobo-accent`) to brand the injected widgets.\nconst TOKENS_LIGHT = `\n --authrobo-btn-bg:#fff;--authrobo-btn-fg:#111827;--authrobo-btn-border:#d1d5db;\n --authrobo-btn-hover-bg:#f8fafc;--authrobo-btn-hover-border:#9ca3af;\n --authrobo-card-bg:#fff;--authrobo-title-fg:#0f172a;--authrobo-muted:#64748b;\n --authrobo-error:#b91c1c;--authrobo-divider-fg:#9ca3af;--authrobo-divider-line:#e5e7eb;\n --authrobo-overlay:rgba(2,6,23,.55);--authrobo-close:#94a3b8;--authrobo-close-hover:#334155;\n --authrobo-focus:#2b8aff;--authrobo-card-shadow:rgba(2,6,23,.4);\n --authrobo-last-bg:#e7efff;--authrobo-last-fg:#2563eb;\n --authrobo-input-bg:#fff;--authrobo-input-fg:#111827;\n --authrobo-tabs-bg:#f1f5f9;--authrobo-accent:#4338ca;--authrobo-accent-fg:#fff;`;\nconst TOKENS_DARK = `\n --authrobo-btn-bg:#0e1626;--authrobo-btn-fg:#e6edf8;--authrobo-btn-border:#28374f;\n --authrobo-btn-hover-bg:#16233a;--authrobo-btn-hover-border:#3a4d6b;\n --authrobo-card-bg:#0b1424;--authrobo-title-fg:#f1f5fb;--authrobo-muted:#93a4bd;\n --authrobo-error:#f87171;--authrobo-divider-fg:#64748b;--authrobo-divider-line:#223049;\n --authrobo-overlay:rgba(2,6,23,.72);--authrobo-close:#64748b;--authrobo-close-hover:#cbd5e1;\n --authrobo-focus:#46c8ff;--authrobo-card-shadow:rgba(0,0,0,.6);\n --authrobo-last-bg:rgba(70,160,255,.18);--authrobo-last-fg:#8fc4ff;\n --authrobo-input-bg:#0e1626;--authrobo-input-fg:#e6edf8;\n --authrobo-tabs-bg:#0e1626;--authrobo-accent:#4338ca;--authrobo-accent-fg:#fff;`;\n// Elements that either read tokens directly or need them for their descendants.\nconst TOKEN_ROOTS =\n \".authrobo-btn,.authrobo-stack,.authrobo-card,.authrobo-overlay,.authrobo-divider,.authrobo-title\";\nconst scoped = (prefix: string, tokens: string) =>\n TOKEN_ROOTS.split(\",\")\n .map((s) => `${prefix}${s.trim()}`)\n .join(\",\") + `{${tokens}}`;\n\nconst CSS = `\n${scoped(\"\", TOKENS_LIGHT)}\n@media (prefers-color-scheme:dark){${scoped(\"\", TOKENS_DARK)}}\n${scoped('[data-theme=\"light\"] ', TOKENS_LIGHT)}\n${scoped('[data-theme=\"dark\"] ', TOKENS_DARK)}\n.authrobo-btn{position:relative;display:flex;width:100%;align-items:center;justify-content:center;gap:10px;\n border:1px solid var(--authrobo-btn-border);background:var(--authrobo-btn-bg);color:var(--authrobo-btn-fg);border-radius:10px;padding:10px 14px;\n font:600 14px/1.2 system-ui,-apple-system,Segoe UI,Roboto,sans-serif;cursor:pointer;\n transition:background .15s ease,border-color .15s ease,box-shadow .15s ease;}\n.authrobo-btn:hover{background:var(--authrobo-btn-hover-bg);border-color:var(--authrobo-btn-hover-border);}\n.authrobo-btn:focus-visible{outline:2px solid var(--authrobo-focus);outline-offset:2px;}\n.authrobo-last{position:absolute;right:8px;top:50%;transform:translateY(-50%);pointer-events:none;\n font:600 10px/1 system-ui,sans-serif;letter-spacing:.02em;padding:3px 7px;border-radius:999px;\n background:var(--authrobo-last-bg);color:var(--authrobo-last-fg);}\n.authrobo-stack{display:flex;flex-direction:column;gap:10px;}\n.authrobo-title{font:700 16px system-ui,sans-serif;color:var(--authrobo-title-fg);}\n.authrobo-muted{color:var(--authrobo-muted);font:14px system-ui,sans-serif;margin:0;}\n.authrobo-error{color:var(--authrobo-error);font:14px system-ui,sans-serif;margin:0;}\n.authrobo-divider{display:flex;align-items:center;gap:10px;color:var(--authrobo-divider-fg);font:500 12px system-ui,sans-serif;}\n.authrobo-divider::before,.authrobo-divider::after{content:\"\";height:1px;flex:1;background:var(--authrobo-divider-line);}\n.authrobo-tabs{display:flex;gap:4px;padding:4px;border:1px solid var(--authrobo-btn-border);\n background:var(--authrobo-tabs-bg);border-radius:10px;}\n.authrobo-tab{flex:1;border:0;background:transparent;border-radius:7px;padding:8px 0;cursor:pointer;\n font:600 13px system-ui,sans-serif;color:var(--authrobo-muted);transition:background .15s ease,color .15s ease;}\n.authrobo-tab:hover{color:var(--authrobo-title-fg);}\n.authrobo-tab[aria-selected=\"true\"]{background:var(--authrobo-accent);color:var(--authrobo-accent-fg);}\n.authrobo-tab:focus-visible{outline:2px solid var(--authrobo-focus);outline-offset:2px;}\n.authrobo-form{display:flex;flex-direction:column;gap:10px;}\n.authrobo-label{font:500 12.5px system-ui,sans-serif;color:var(--authrobo-muted);}\n.authrobo-input{width:100%;box-sizing:border-box;margin-top:6px;border:1px solid var(--authrobo-btn-border);\n background:var(--authrobo-input-bg);color:var(--authrobo-input-fg);border-radius:10px;padding:10px 12px;\n font:14px system-ui,sans-serif;}\n.authrobo-input:focus{outline:none;border-color:var(--authrobo-accent);}\n.authrobo-primary{display:flex;width:100%;align-items:center;justify-content:center;gap:8px;border:0;\n background:var(--authrobo-accent);color:var(--authrobo-accent-fg);border-radius:10px;padding:11px 14px;\n font:700 14px system-ui,sans-serif;cursor:pointer;transition:filter .15s ease;}\n.authrobo-primary:hover{filter:brightness(.96);}\n.authrobo-primary:focus-visible{outline:2px solid var(--authrobo-focus);outline-offset:2px;}\n.authrobo-primary:disabled{opacity:.7;cursor:default;}\n.authrobo-btn-brand{transition:filter .15s ease,box-shadow .15s ease;}\n.authrobo-btn-brand:hover{filter:brightness(.96);}\n.authrobo-spinner{display:inline-block;width:1.15em;height:1.15em;vertical-align:-0.2em;border-radius:50%;\n border:2px solid color-mix(in srgb, currentColor 24%, transparent);border-top-color:currentColor;\n animation:authrobo-spin .7s linear infinite;}\n.authrobo-loading{display:flex;align-items:center;gap:10px;padding:4px 0;}\n@keyframes authrobo-spin{to{transform:rotate(360deg)}}\n@media (prefers-reduced-motion: reduce){.authrobo-spinner{animation-duration:1.4s}}\n.authrobo-overlay{position:fixed;inset:0;z-index:2147483000;display:flex;align-items:center;\n justify-content:center;padding:16px;background:var(--authrobo-overlay);backdrop-filter:blur(2px);\n animation:authrobo-fade .16s ease-out both;}\n.authrobo-card{position:relative;width:100%;max-width:360px;background:var(--authrobo-card-bg);border-radius:16px;\n padding:24px;box-shadow:0 20px 60px -12px var(--authrobo-card-shadow);animation:authrobo-pop .2s cubic-bezier(.16,1,.3,1) both;}\n.authrobo-close{position:absolute;top:12px;right:12px;border:0;background:transparent;cursor:pointer;\n color:var(--authrobo-close);font-size:18px;line-height:1;padding:4px;}\n.authrobo-close:hover{color:var(--authrobo-close-hover);}\n@keyframes authrobo-fade{from{opacity:0}to{opacity:1}}\n@keyframes authrobo-pop{from{opacity:0;transform:translateY(8px) scale(.97)}to{opacity:1;transform:none}}\n@media (prefers-reduced-motion: reduce){.authrobo-overlay,.authrobo-card{animation:none}}\n`;\n\nfunction useInjectStyles() {\n useEffect(() => {\n if (typeof document === \"undefined\" || document.getElementById(STYLE_ID)) return;\n const el = document.createElement(\"style\");\n el.id = STYLE_ID;\n el.textContent = CSS;\n document.head.appendChild(el);\n }, []);\n}\n\n/** A theme-aware loading spinner. Colour follows the surrounding text (currentColor). */\nexport function Spinner({ style, className }: { style?: React.CSSProperties; className?: string }) {\n return (\n <span\n className={className ? `authrobo-spinner ${className}` : \"authrobo-spinner\"}\n role=\"status\"\n aria-label=\"Loading\"\n style={style}\n />\n );\n}\n\n/* ----------------------------- Button ----------------------------------- */\n\nexport function AuthRoboButton({\n provider,\n config,\n label,\n className,\n style,\n onClick,\n lastUsed,\n startPath,\n buttonStyle = \"neutral\",\n}: {\n provider: Method;\n config?: AuthRoboConfig;\n label?: string;\n className?: string;\n style?: React.CSSProperties;\n onClick?: () => void;\n /** Show a \"Last used\" badge (the method the visitor signed in with before). */\n lastUsed?: boolean;\n /** Proxy the redirect through your own server (see StartOptions.startPath). */\n startPath?: string;\n /** \"neutral\" (default) or \"branded\" (provider-coloured button). */\n buttonStyle?: ButtonStyle;\n}) {\n useInjectStyles();\n const c = useResolvedConfig(config);\n const meta = PROVIDER_META[provider];\n const brand = buttonStyle === \"branded\" ? BRAND_STYLE[provider] : undefined;\n const icon = brand?.whiteIcon ? WHITE_MARKS[provider] ?? meta.icon : meta.icon;\n\n const classes = [\"authrobo-btn\", brand ? \"authrobo-btn-brand\" : \"\", className]\n .filter(Boolean)\n .join(\" \");\n const brandStyle: React.CSSProperties | undefined = brand\n ? { background: brand.bg, color: brand.fg, borderColor: brand.border }\n : undefined;\n\n return (\n <button\n type=\"button\"\n className={classes}\n style={{ ...brandStyle, ...style }}\n onClick={() => {\n onClick?.();\n startSignIn(c, provider, { startPath });\n }}\n >\n <span style={{ display: \"inline-flex\", alignItems: \"center\" }}>{icon}</span>\n {label ?? `Continue with ${meta.label}`}\n {lastUsed && <span className=\"authrobo-last\">Last used</span>}\n </button>\n );\n}\n\n/* ---------------------- Email switcher (tabs) --------------------------- */\n\n// Tab order is fixed: Magic Link first, then Register, then Login. Each tab is\n// filtered in only if its underlying method is enabled for the app. Every tab\n// collects exactly the fields that flow needs:\n// • Magic Link → email (a one-time link is emailed)\n// • Register → name + email + password (creates the account)\n// • Login → email + password\nconst EMAIL_TABS: {\n key: Screen;\n method: Method;\n label: string;\n cta: string;\n requires: Method;\n fields: { name: boolean; password: boolean };\n /** Server endpoint (relative to startPath) for the proxied JSON POST. */\n proxyPath: string;\n}[] = [\n { key: \"magic\", method: \"magic_link\", label: \"Magic Link\", cta: \"Email me a link\", requires: \"magic_link\", fields: { name: false, password: false }, proxyPath: \"magic\" },\n { key: \"register\", method: \"password\", label: \"Register\", cta: \"Create account\", requires: \"password\", fields: { name: true, password: true }, proxyPath: \"register\" },\n { key: \"login\", method: \"password\", label: \"Login\", cta: \"Sign in\", requires: \"password\", fields: { name: false, password: true }, proxyPath: \"login\" },\n];\n\n/**\n * The email tabs (Magic Link / Register / Login).\n *\n * Two submission modes:\n * - **Direct** (no `startPath`): a native cross-origin form POST straight to\n * AuthRobo — `authorize` for password login/register (→ returns to your\n * `redirectUri` with a one-time code your backend exchanges), or `magic/start`\n * for the link. Credentials go to AuthRobo, never to your own server.\n * - **Proxied** (`startPath` set): a same-origin JSON POST to\n * `${startPath}/{login|register|magic}` on YOUR server, which forwards to\n * AuthRobo and sets your httpOnly session cookies. On success `onSuccess()`\n * fires (no full-page redirect), so it slots into an existing modal.\n */\nfunction EmailSwitcher({\n config,\n methods,\n startPath,\n onSuccess,\n}: {\n config: AuthRoboConfig;\n methods: Method[];\n startPath?: string;\n onSuccess?: () => void;\n}) {\n const tabs = useMemo(() => EMAIL_TABS.filter((t) => methods.includes(t.requires)), [methods]);\n const [active, setActive] = useState<Screen>(tabs[0]?.key ?? \"login\");\n const [name, setName] = useState(\"\");\n const [email, setEmail] = useState(\"\");\n const [password, setPassword] = useState(\"\");\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [sent, setSent] = useState(false);\n const stateRef = useRef<HTMLInputElement>(null);\n const proxy = !!startPath;\n\n // Keep the active tab valid if the enabled set changes under us.\n useEffect(() => {\n if (tabs.length && !tabs.some((t) => t.key === active)) setActive(tabs[0].key);\n }, [tabs, active]);\n\n if (!tabs.length) return null;\n const current = tabs.find((t) => t.key === active) ?? tabs[0];\n const base = config.issuerUrl.replace(/\\/$/, \"\");\n const directAction =\n current.key === \"magic\" ? `${base}/api/v1/auth/magic/start` : `${base}/api/v1/auth/authorize`;\n\n const selectTab = (key: Screen) => {\n setActive(key);\n setError(null);\n setSent(false);\n };\n\n // Proxied mode: JSON POST to the app's own route, then hand back to the host.\n async function proxySubmit(e: React.FormEvent) {\n e.preventDefault();\n setError(null);\n setLoading(true);\n try {\n const body: Record<string, string> = { email: email.trim() };\n if (current.fields.password) body.password = password;\n if (current.fields.name && name.trim()) body.name = name.trim();\n const res = await fetch(`${startPath!.replace(/\\/$/, \"\")}/${current.proxyPath}`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n if (!res.ok) {\n const d = (await res.json().catch(() => ({}))) as { error?: string };\n throw new Error(d?.error || \"Something went wrong. Please try again.\");\n }\n try {\n localStorage.setItem(lastMethodKey(config.clientId), current.method);\n } catch {\n /* ignore */\n }\n if (current.key === \"magic\") setSent(true);\n else onSuccess?.();\n } catch (err) {\n setError(err instanceof Error ? err.message : \"Something went wrong.\");\n } finally {\n setLoading(false);\n }\n }\n\n // Direct mode: stamp a fresh CSRF state into the hidden field + sessionStorage,\n // then let the browser perform the native cross-origin form POST to AuthRobo.\n function directSubmit() {\n const s = randomState();\n try {\n sessionStorage.setItem(\"authrobo:state\", s);\n } catch {\n /* storage unavailable */\n }\n if (stateRef.current) stateRef.current.value = s;\n try {\n localStorage.setItem(lastMethodKey(config.clientId), current.method);\n } catch {\n /* ignore */\n }\n setLoading(true); // page is about to navigate away\n }\n\n if (sent) {\n return (\n <div className=\"authrobo-stack\" role=\"status\">\n <p className=\"authrobo-title\">Check your email</p>\n <p className=\"authrobo-muted\">\n We sent a sign-in link to <b>{email.trim()}</b>. It works once and expires shortly.\n </p>\n </div>\n );\n }\n\n return (\n <div className=\"authrobo-stack\">\n {tabs.length > 1 && (\n <div className=\"authrobo-tabs\" role=\"tablist\" aria-label=\"Sign-in method\">\n {tabs.map((t) => (\n <button\n key={t.key}\n type=\"button\"\n role=\"tab\"\n aria-selected={current.key === t.key}\n className=\"authrobo-tab\"\n onClick={() => selectTab(t.key)}\n >\n {t.label}\n </button>\n ))}\n </div>\n )}\n <form\n className=\"authrobo-form\"\n method={proxy ? undefined : \"post\"}\n action={proxy ? undefined : directAction}\n onSubmit={proxy ? proxySubmit : directSubmit}\n >\n {!proxy && (\n <>\n <input type=\"hidden\" name=\"client_id\" value={config.clientId} />\n <input type=\"hidden\" name=\"redirect_uri\" value={config.redirectUri} />\n <input type=\"hidden\" name=\"state\" ref={stateRef} />\n {current.key !== \"magic\" && (\n <input type=\"hidden\" name=\"mode\" value={current.key === \"register\" ? \"register\" : \"login\"} />\n )}\n </>\n )}\n\n {current.fields.name && (\n <label className=\"authrobo-label\">\n Name\n <input\n className=\"authrobo-input\"\n name=\"name\"\n type=\"text\"\n autoComplete=\"name\"\n placeholder=\"Your name\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n />\n </label>\n )}\n <label className=\"authrobo-label\">\n Email\n <input\n className=\"authrobo-input\"\n name=\"email\"\n type=\"email\"\n required\n autoComplete=\"email\"\n placeholder=\"you@example.com\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n />\n </label>\n {current.fields.password && (\n <label className=\"authrobo-label\">\n Password\n <input\n className=\"authrobo-input\"\n name=\"password\"\n type=\"password\"\n required\n minLength={current.key === \"register\" ? 8 : undefined}\n autoComplete={current.key === \"register\" ? \"new-password\" : \"current-password\"}\n placeholder={current.key === \"register\" ? \"At least 8 characters\" : \"Your password\"}\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n />\n </label>\n )}\n\n {error && <p className=\"authrobo-error\">{error}</p>}\n\n <button type=\"submit\" className=\"authrobo-primary\" disabled={loading}>\n {loading ? (\n <>\n <Spinner /> Please wait…\n </>\n ) : (\n current.cta\n )}\n </button>\n </form>\n </div>\n );\n}\n\n/* ---------------------- Auth modal / inline panel ----------------------- */\n\nexport function AuthRoboAuth({\n config,\n mode = \"inline\",\n open = true,\n onClose,\n onSuccess,\n title,\n showHeader = true,\n methods: only,\n startPath,\n buttonStyle = \"neutral\",\n}: {\n config?: AuthRoboConfig;\n /** \"inline\" renders in place; \"modal\" renders a centered overlay. */\n mode?: \"inline\" | \"modal\";\n /** Only used in modal mode. */\n open?: boolean;\n onClose?: () => void;\n /**\n * Fires after a successful proxied (startPath) password login/register — the\n * session cookies are set and no page redirect happened, so refresh your auth\n * state and close the modal here. Not called for social/magic or direct mode\n * (those navigate the page).\n */\n onSuccess?: () => void;\n /** Heading; defaults to \"Sign in to <app name>\". */\n title?: string;\n /** Render the logo + title row. Set false when the host supplies its own heading. */\n showHeader?: boolean;\n /** Restrict/reorder which methods to show (defaults to all enabled ones). */\n methods?: Method[];\n /** Proxy every redirect through your own server (see StartOptions.startPath). */\n startPath?: string;\n /** \"neutral\" (default) or \"branded\" social buttons. */\n buttonStyle?: ButtonStyle;\n}) {\n useInjectStyles();\n const c = useResolvedConfig(config);\n const { data, loading, error } = useAppConfig(c);\n const lastMethod = useLastMethod(c.clientId);\n\n useEffect(() => {\n if (mode !== \"modal\" || !open) return;\n const onKey = (e: KeyboardEvent) => e.key === \"Escape\" && onClose?.();\n document.addEventListener(\"keydown\", onKey);\n return () => document.removeEventListener(\"keydown\", onKey);\n }, [mode, open, onClose]);\n\n if (mode === \"modal\" && !open) return null;\n\n const available = data?.methods ?? [];\n const shown = (only ? only.filter((m) => available.includes(m)) : available).filter(\n (m) => m in PROVIDER_META,\n );\n const social = shown.filter((m) => !EMAIL_METHODS.includes(m));\n const email = shown.filter((m) => EMAIL_METHODS.includes(m));\n // Only worth pointing out the last-used method when there's a choice to make.\n const badge = (m: Method) => shown.length > 1 && m === lastMethod;\n\n const panel = (\n <div className=\"authrobo-stack\">\n {showHeader && (data?.logoUrl || data?.name) && (\n <div style={{ display: \"flex\", alignItems: \"center\", gap: 10, marginBottom: 4 }}>\n {data?.logoUrl && (\n <img src={data.logoUrl} alt=\"\" width={28} height={28} style={{ borderRadius: 6 }} />\n )}\n <span className=\"authrobo-title\">\n {title ?? `Sign in${data?.name ? ` to ${data.name}` : \"\"}`}\n </span>\n </div>\n )}\n\n {loading && (\n <div className=\"authrobo-loading\">\n <Spinner style={{ color: \"var(--authrobo-accent)\" }} />\n <span className=\"authrobo-muted\">Loading sign-in options…</span>\n </div>\n )}\n {error && <p className=\"authrobo-error\">Couldn&apos;t load sign-in options.</p>}\n\n {social.map((m) => (\n <AuthRoboButton\n key={m}\n provider={m}\n config={c}\n lastUsed={badge(m)}\n startPath={startPath}\n buttonStyle={buttonStyle}\n />\n ))}\n\n {email.length > 0 && social.length > 0 && <div className=\"authrobo-divider\">or</div>}\n\n {email.length > 0 && (\n <EmailSwitcher config={c} methods={email} startPath={startPath} onSuccess={onSuccess} />\n )}\n\n {!loading && !error && shown.length === 0 && (\n <p className=\"authrobo-muted\">No sign-in methods are enabled for this app.</p>\n )}\n </div>\n );\n\n if (mode === \"inline\") return panel;\n\n return (\n <div className=\"authrobo-overlay\" onClick={() => onClose?.()}>\n <div className=\"authrobo-card\" role=\"dialog\" aria-modal=\"true\" onClick={(e) => e.stopPropagation()}>\n <button type=\"button\" className=\"authrobo-close\" aria-label=\"Close\" onClick={() => onClose?.()}>\n ✕\n </button>\n {panel}\n </div>\n </div>\n );\n}\n","import * as React from \"react\";\n\n// Sign-in methods AuthRobo can surface. \"password\" and \"magic_link\" route to\n// the hosted email login page; the rest are social OAuth providers.\nexport type Method =\n | \"google\"\n | \"linkedin\"\n | \"github\"\n | \"apple\"\n | \"facebook\"\n | \"password\"\n | \"magic_link\";\n\nconst sz = { width: 18, height: 18, \"aria-hidden\": true } as const;\n\n// Single-colour brand glyphs share one path so we can also render a white\n// variant (for branded buttons whose background is the brand colour).\nconst LINKEDIN_PATH =\n \"M20.45 20.45h-3.56v-5.57c0-1.33-.02-3.04-1.85-3.04-1.85 0-2.13 1.45-2.13 2.94v5.67H9.35V9h3.41v1.56h.05c.48-.9 1.64-1.85 3.37-1.85 3.6 0 4.27 2.37 4.27 5.45v6.29zM5.34 7.43a2.06 2.06 0 1 1 0-4.13 2.06 2.06 0 0 1 0 4.13zM7.12 20.45H3.56V9h3.56v11.45zM22.22 0H1.77C.79 0 0 .77 0 1.72v20.56C0 23.23.79 24 1.77 24h20.45c.98 0 1.78-.77 1.78-1.72V1.72C24 .77 23.2 0 22.22 0z\";\nconst GITHUB_PATH =\n \"M12 .3a12 12 0 0 0-3.8 23.4c.6.1.8-.3.8-.6v-2c-3.3.7-4-1.6-4-1.6-.6-1.4-1.3-1.8-1.3-1.8-1.1-.7.1-.7.1-.7 1.2.1 1.8 1.2 1.8 1.2 1.1 1.8 2.8 1.3 3.5 1 .1-.8.4-1.3.8-1.6-2.7-.3-5.5-1.3-5.5-6a4.7 4.7 0 0 1 1.2-3.2c-.1-.3-.5-1.5.1-3.2 0 0 1-.3 3.3 1.2a11.5 11.5 0 0 1 6 0c2.3-1.5 3.3-1.2 3.3-1.2.6 1.7.2 2.9.1 3.2a4.7 4.7 0 0 1 1.2 3.2c0 4.7-2.8 5.7-5.5 6 .4.4.8 1.1.8 2.2v3.3c0 .3.2.7.8.6A12 12 0 0 0 12 .3\";\nconst APPLE_PATH =\n \"M17.05 12.04c-.03-2.7 2.2-4 2.3-4.06-1.25-1.84-3.2-2.09-3.9-2.12-1.66-.17-3.24.98-4.08.98-.84 0-2.14-.96-3.52-.93-1.81.03-3.48 1.05-4.41 2.67-1.88 3.27-.48 8.1 1.35 10.76.9 1.3 1.97 2.76 3.38 2.71 1.36-.05 1.87-.88 3.51-.88 1.64 0 2.1.88 3.53.85 1.46-.03 2.38-1.33 3.27-2.63 1.03-1.51 1.46-2.97 1.48-3.05-.03-.01-2.84-1.09-2.87-4.32M14.4 4.2c.74-.9 1.24-2.15 1.1-3.4-1.07.04-2.36.71-3.13 1.61-.69.8-1.29 2.07-1.13 3.29 1.19.09 2.41-.61 3.16-1.5\";\nconst FACEBOOK_PATH =\n \"M24 12.07C24 5.4 18.63 0 12 0S0 5.4 0 12.07C0 18.1 4.39 23.1 10.13 24v-8.44H7.08v-3.49h3.05V9.41c0-3.02 1.79-4.69 4.53-4.69 1.31 0 2.68.24 2.68.24v2.97h-1.51c-1.49 0-1.95.93-1.95 1.88v2.26h3.32l-.53 3.49h-2.79V24C19.61 23.1 24 18.1 24 12.07\";\n\nfunction Glyph({ d, fill }: { d: string; fill: string }) {\n return (\n <svg viewBox=\"0 0 24 24\" {...sz} fill={fill}>\n <path d={d} />\n </svg>\n );\n}\n\nfunction GoogleIcon() {\n return (\n <svg viewBox=\"0 0 48 48\" {...sz}>\n <path fill=\"#FFC107\" d=\"M43.6 20.5H42V20H24v8h11.3C33.7 32.9 29.3 36 24 36c-6.6 0-12-5.4-12-12s5.4-12 12-12c3.1 0 5.9 1.2 8 3.1l5.7-5.7C34.6 6.1 29.6 4 24 4 12.9 4 4 12.9 4 24s8.9 20 20 20 20-8.9 20-20c0-1.3-.1-2.3-.4-3.5z\" />\n <path fill=\"#FF3D00\" d=\"M6.3 14.7l6.6 4.8C14.7 16 19 13 24 13c3.1 0 5.9 1.2 8 3.1l5.7-5.7C34.6 6.1 29.6 4 24 4 16.3 4 9.7 8.3 6.3 14.7z\" />\n <path fill=\"#4CAF50\" d=\"M24 44c5.2 0 10-2 13.6-5.2l-6.3-5.2C29.2 35 26.7 36 24 36c-5.3 0-9.7-3.4-11.3-8.1l-6.5 5C9.5 39.6 16.2 44 24 44z\" />\n <path fill=\"#1976D2\" d=\"M43.6 20.5H42V20H24v8h11.3c-.8 2.2-2.2 4.1-4.1 5.6l6.3 5.2C41.9 36 44 30.5 44 24c0-1.3-.1-2.3-.4-3.5z\" />\n </svg>\n );\n}\n\nfunction MailIcon() {\n return (\n <svg viewBox=\"0 0 24 24\" {...sz} fill=\"none\" stroke=\"#334155\" strokeWidth={2} strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"5\" width=\"18\" height=\"14\" rx=\"2\" />\n <path d=\"m3 7 9 6 9-6\" />\n </svg>\n );\n}\n\nexport const PROVIDER_META: Record<Method, { label: string; icon: React.ReactNode }> = {\n google: { label: \"Google\", icon: <GoogleIcon /> },\n linkedin: { label: \"LinkedIn\", icon: <Glyph d={LINKEDIN_PATH} fill=\"#0A66C2\" /> },\n github: { label: \"GitHub\", icon: <Glyph d={GITHUB_PATH} fill=\"#181717\" /> },\n apple: { label: \"Apple\", icon: <Glyph d={APPLE_PATH} fill=\"#000\" /> },\n facebook: { label: \"Facebook\", icon: <Glyph d={FACEBOOK_PATH} fill=\"#1877F2\" /> },\n password: { label: \"email\", icon: <MailIcon /> },\n magic_link: { label: \"magic link\", icon: <MailIcon /> },\n};\n\n// White glyph variants — used by branded buttons whose background is the brand\n// colour (so a monochrome mark stays legible). Google keeps its multicolour mark.\nexport const WHITE_MARKS: Partial<Record<Method, React.ReactNode>> = {\n linkedin: <Glyph d={LINKEDIN_PATH} fill=\"#fff\" />,\n github: <Glyph d={GITHUB_PATH} fill=\"#fff\" />,\n apple: <Glyph d={APPLE_PATH} fill=\"#fff\" />,\n facebook: <Glyph d={FACEBOOK_PATH} fill=\"#fff\" />,\n};\n\n// Fully-branded button palette: background / text / border per provider. Used\n// when <AuthRoboAuth buttonStyle=\"branded\"> (or <AuthRoboButton buttonStyle=…>).\nexport const BRAND_STYLE: Partial<Record<Method, { bg: string; fg: string; border: string; whiteIcon?: boolean }>> = {\n google: { bg: \"#ffffff\", fg: \"#1a73e8\", border: \"#dadce0\" },\n linkedin: { bg: \"#0a66c2\", fg: \"#ffffff\", border: \"#0a66c2\", whiteIcon: true },\n github: { bg: \"#181717\", fg: \"#ffffff\", border: \"#181717\", whiteIcon: true },\n apple: { bg: \"#000000\", fg: \"#ffffff\", border: \"#000000\", whiteIcon: true },\n facebook: { bg: \"#1877f2\", fg: \"#ffffff\", border: \"#1877f2\", whiteIcon: true },\n};\n"],"mappings":"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","names":["import_jsx_runtime"]}
1
+ {"version":3,"sources":["../src/index.tsx","../src/icons.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n} from \"react\";\nimport { BRAND_STYLE, PROVIDER_META, WHITE_MARKS, type Method } from \"./icons\";\n\nexport type { Method } from \"./icons\";\nexport { PROVIDER_META, BRAND_STYLE } from \"./icons\";\n\n/** Which hosted screen an email flow should open. */\nexport type Screen = \"login\" | \"register\" | \"magic\";\n\n/**\n * How to render social provider buttons.\n * - \"neutral\" (default): one consistent button chrome (themeable), brand-coloured icon.\n * - \"branded\": each button wears its provider's colours — LinkedIn blue, GitHub\n * black, Google white, Facebook blue, Apple black — with a legible glyph.\n */\nexport type ButtonStyle = \"neutral\" | \"branded\";\n\nexport interface AuthRoboConfig {\n /** Your AuthRobo instance, e.g. \"https://authrobo.com\". */\n issuerUrl: string;\n /** Your app's client_id (arc_...). */\n clientId: string;\n /** Where AuthRobo returns the one-time `code` after sign-in. */\n redirectUri: string;\n}\n\n/** Shape returned by GET /api/v1/config. */\nexport interface AppConfig {\n name: string;\n brandColor: string | null;\n logoUrl: string | null;\n methods: Method[];\n /** Show the \"Authentication provided by AuthRobo\" attribution. True on Free\n * plans; drops to false for Pro and above (white-label). */\n poweredBy: boolean;\n}\n\nconst ConfigContext = createContext<AuthRoboConfig | null>(null);\n\nexport function AuthRoboProvider({\n config,\n children,\n}: {\n config: AuthRoboConfig;\n children: React.ReactNode;\n}) {\n // Warm the app-config cache as soon as the provider mounts (i.e. on app start),\n // so the enabled sign-in methods are already resolved by the time a login modal\n // or page is opened — no request-on-open, no loading flash.\n useEffect(() => {\n prefetchAppConfig(config);\n }, [config.issuerUrl, config.clientId]);\n return <ConfigContext.Provider value={config}>{children}</ConfigContext.Provider>;\n}\n\nfunction useResolvedConfig(override?: AuthRoboConfig): AuthRoboConfig {\n const ctx = useContext(ConfigContext);\n const c = override ?? ctx;\n if (!c) {\n throw new Error(\n \"@authrobo/react: wrap your app in <AuthRoboProvider config={...}> or pass a `config` prop.\",\n );\n }\n return c;\n}\n\nfunction randomState(): string {\n const b = new Uint8Array(16);\n (globalThis.crypto ?? (globalThis as { crypto: Crypto }).crypto).getRandomValues(b);\n return Array.from(b, (x) => x.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\n// Email-based methods open a hosted page (which collects the address + password\n// or mails a link); social providers redirect straight into their OAuth start.\nconst EMAIL_METHODS: readonly Method[] = [\"password\", \"magic_link\"];\n\n/** Options accepted by startSignIn and the button/panel components. */\nexport interface StartOptions {\n state?: string;\n /** Prefill the email on the hosted page. */\n loginHint?: string;\n /** For email flows: which hosted screen to open (login / register / magic). */\n screen?: Screen;\n /**\n * Route the redirect through YOUR server instead of straight to AuthRobo.\n * When set, the browser navigates to `${startPath}/<method>/start` — your\n * route sets a first-party CSRF state cookie + the real redirect_uri, then\n * bounces to AuthRobo. This is the right choice for apps that keep the session\n * in httpOnly cookies (the code exchange happens server-side with your\n * client_secret). Leave unset to redirect to AuthRobo directly.\n */\n startPath?: string;\n}\n\n/**\n * Begin sign-in: navigate the browser to the hosted flow for `method`.\n *\n * - Social methods hit /api/v1/auth/<provider>/start.\n * - \"password\" opens the hosted /login (or /register when `screen: \"register\"`).\n * - \"magic_link\" opens /login?screen=magic (the passwordless view).\n *\n * With `startPath`, all of the above are proxied through your own server route\n * (`${startPath}/<method>/start`) so the flow stays first-party. Either way,\n * AuthRobo returns to your callback with a one-time `code` your backend\n * exchanges (with your client_secret) for tokens.\n */\nexport function startSignIn(config: AuthRoboConfig, method: Method, opts?: StartOptions): void {\n // Remember the method so we can badge it \"Last used\" next time (per client_id).\n try {\n localStorage.setItem(lastMethodKey(config.clientId), method);\n } catch {\n /* storage unavailable — badge just won't show next time */\n }\n\n // App-proxied: hand off to the consumer's own server, which owns state +\n // redirect_uri. Nothing sensitive is decided client-side here.\n if (opts?.startPath) {\n const p = new URLSearchParams();\n if (opts.loginHint) p.set(\"login_hint\", opts.loginHint);\n if (opts.screen) p.set(\"screen\", opts.screen);\n const qs = p.toString();\n window.location.assign(`${opts.startPath.replace(/\\/$/, \"\")}/${method}/start${qs ? `?${qs}` : \"\"}`);\n return;\n }\n\n const base = config.issuerUrl.replace(/\\/$/, \"\");\n const state = opts?.state ?? randomState();\n try {\n sessionStorage.setItem(\"authrobo:state\", state);\n } catch {\n /* storage unavailable — state is still sent, just not persisted for a check */\n }\n const params = new URLSearchParams({\n client_id: config.clientId,\n redirect_uri: config.redirectUri,\n state,\n });\n if (opts?.loginHint) params.set(\"login_hint\", opts.loginHint);\n\n let path: string;\n if (method === \"magic_link\") {\n params.set(\"screen\", \"magic\");\n path = \"/login\";\n } else if (method === \"password\") {\n path = opts?.screen === \"register\" ? \"/register\" : \"/login\";\n } else {\n path = `/api/v1/auth/${method}/start`;\n }\n window.location.assign(`${base}${path}?${params.toString()}`);\n}\n\nconst lastMethodKey = (clientId: string) => `authrobo:last-method:${clientId}`;\n\n/** The method last used to sign in for this client (from a prior startSignIn). */\nexport function useLastMethod(clientId: string): Method | null {\n const [last, setLast] = useState<Method | null>(null);\n useEffect(() => {\n try {\n setLast((localStorage.getItem(lastMethodKey(clientId)) as Method | null) ?? null);\n } catch {\n /* storage unavailable */\n }\n }, [clientId]);\n return last;\n}\n\n/* ------------------------- App-config cache ----------------------------- */\n// A tiny module-level store so the app's public config (branding + enabled\n// methods) is fetched at most once per (issuer, clientId) and shared across every\n// hook/component. Prefetched on provider mount; read synchronously thereafter.\n\ntype ConfigState = { data: AppConfig | null; loading: boolean; error: string | null };\n\nconst LOADING_STATE: ConfigState = { data: null, loading: true, error: null };\n\ntype ConfigEntry = { state: ConfigState; promise?: Promise<void>; listeners: Set<() => void> };\n\nconst configStore = new Map<string, ConfigEntry>();\nconst configKey = (c: AuthRoboConfig) => `${c.issuerUrl.replace(/\\/$/, \"\")}|${c.clientId}`;\n\nfunction configEntry(key: string): ConfigEntry {\n let e = configStore.get(key);\n if (!e) {\n e = { state: LOADING_STATE, listeners: new Set() };\n configStore.set(key, e);\n }\n return e;\n}\n\n/**\n * Fetch (once) and cache an app's public config. Safe to call eagerly on app\n * start — concurrent calls dedupe onto the same in-flight request, and a resolved\n * entry returns immediately. Returns the in-flight promise (or a resolved one).\n */\nexport function prefetchAppConfig(config: AuthRoboConfig): Promise<void> {\n if (typeof window === \"undefined\") return Promise.resolve(); // no-op during SSR\n const key = configKey(config);\n const e = configEntry(key);\n if (e.state.data || e.promise) return e.promise ?? Promise.resolve();\n const base = config.issuerUrl.replace(/\\/$/, \"\");\n e.promise = fetch(`${base}/api/v1/config?client_id=${encodeURIComponent(config.clientId)}`)\n .then((r) => (r.ok ? r.json() : Promise.reject(new Error(`config ${r.status}`))))\n .then((j) => {\n e.state = {\n data: { name: j.name, brandColor: j.brand_color, logoUrl: j.logo_url, methods: j.methods, poweredBy: j.powered_by !== false },\n loading: false,\n error: null,\n };\n })\n .catch((err) => {\n e.state = { data: null, loading: false, error: String(err?.message ?? err) };\n })\n .finally(() => {\n e.promise = undefined;\n e.listeners.forEach((l) => l());\n });\n return e.promise;\n}\n\n/** Fetch an app's public config (branding + enabled methods) for `clientId`. */\nexport function useAppConfig(config?: AuthRoboConfig): ConfigState {\n const c = useResolvedConfig(config);\n const key = configKey(c);\n\n const subscribe = useCallback(\n (cb: () => void) => {\n const e = configEntry(key);\n e.listeners.add(cb);\n return () => {\n e.listeners.delete(cb);\n };\n },\n [key],\n );\n const getSnapshot = useCallback(() => configEntry(key).state, [key]);\n const state = useSyncExternalStore(subscribe, getSnapshot, () => LOADING_STATE);\n\n // Kick off the fetch if the provider didn't already (e.g. no <AuthRoboProvider>).\n useEffect(() => {\n prefetchAppConfig(c);\n }, [c.issuerUrl, c.clientId]);\n\n return state;\n}\n\n/* ----------------------------- Styling ---------------------------------- */\n\nconst STYLE_ID = \"authrobo-react-styles\";\n\n// Theme-aware: tokens default to a soft light palette, flip to dark on the OS\n// preference, and can be forced either way by a `data-theme` attribute on any\n// ancestor (`<html data-theme=\"dark\">`). A host app can also override any single\n// token inline (e.g. `--authrobo-accent`) to brand the injected widgets.\nconst TOKENS_LIGHT = `\n --authrobo-btn-bg:#fff;--authrobo-btn-fg:#111827;--authrobo-btn-border:#d1d5db;\n --authrobo-btn-hover-bg:#f8fafc;--authrobo-btn-hover-border:#9ca3af;\n --authrobo-card-bg:#fff;--authrobo-title-fg:#0f172a;--authrobo-muted:#64748b;\n --authrobo-error:#b91c1c;--authrobo-divider-fg:#9ca3af;--authrobo-divider-line:#e5e7eb;\n --authrobo-overlay:rgba(2,6,23,.55);--authrobo-close:#94a3b8;--authrobo-close-hover:#334155;\n --authrobo-focus:#2b8aff;--authrobo-card-shadow:rgba(2,6,23,.4);\n --authrobo-last-bg:#e7efff;--authrobo-last-fg:#2563eb;\n --authrobo-input-bg:#fff;--authrobo-input-fg:#111827;\n --authrobo-tabs-bg:#f1f5f9;--authrobo-accent:#4338ca;--authrobo-accent-fg:#fff;`;\nconst TOKENS_DARK = `\n --authrobo-btn-bg:#0e1626;--authrobo-btn-fg:#e6edf8;--authrobo-btn-border:#28374f;\n --authrobo-btn-hover-bg:#16233a;--authrobo-btn-hover-border:#3a4d6b;\n --authrobo-card-bg:#0b1424;--authrobo-title-fg:#f1f5fb;--authrobo-muted:#93a4bd;\n --authrobo-error:#f87171;--authrobo-divider-fg:#64748b;--authrobo-divider-line:#223049;\n --authrobo-overlay:rgba(2,6,23,.72);--authrobo-close:#64748b;--authrobo-close-hover:#cbd5e1;\n --authrobo-focus:#46c8ff;--authrobo-card-shadow:rgba(0,0,0,.6);\n --authrobo-last-bg:rgba(70,160,255,.18);--authrobo-last-fg:#8fc4ff;\n --authrobo-input-bg:#0e1626;--authrobo-input-fg:#e6edf8;\n --authrobo-tabs-bg:#0e1626;--authrobo-accent:#4338ca;--authrobo-accent-fg:#fff;`;\n// Elements that either read tokens directly or need them for their descendants.\nconst TOKEN_ROOTS =\n \".authrobo-btn,.authrobo-stack,.authrobo-card,.authrobo-overlay,.authrobo-divider,.authrobo-title\";\nconst scoped = (prefix: string, tokens: string) =>\n TOKEN_ROOTS.split(\",\")\n .map((s) => `${prefix}${s.trim()}`)\n .join(\",\") + `{${tokens}}`;\n\nconst CSS = `\n${scoped(\"\", TOKENS_LIGHT)}\n@media (prefers-color-scheme:dark){${scoped(\"\", TOKENS_DARK)}}\n${scoped('[data-theme=\"light\"] ', TOKENS_LIGHT)}\n${scoped('[data-theme=\"dark\"] ', TOKENS_DARK)}\n.authrobo-btn{position:relative;display:flex;width:100%;align-items:center;justify-content:center;gap:10px;\n border:1px solid var(--authrobo-btn-border);background:var(--authrobo-btn-bg);color:var(--authrobo-btn-fg);border-radius:10px;padding:10px 14px;\n font:600 14px/1.2 system-ui,-apple-system,Segoe UI,Roboto,sans-serif;cursor:pointer;\n transition:background .15s ease,border-color .15s ease,box-shadow .15s ease;}\n.authrobo-btn:hover{background:var(--authrobo-btn-hover-bg);border-color:var(--authrobo-btn-hover-border);}\n.authrobo-btn:focus-visible{outline:2px solid var(--authrobo-focus);outline-offset:2px;}\n.authrobo-last{position:absolute;right:8px;top:50%;transform:translateY(-50%);pointer-events:none;\n font:600 10px/1 system-ui,sans-serif;letter-spacing:.02em;padding:3px 7px;border-radius:999px;\n background:var(--authrobo-last-bg);color:var(--authrobo-last-fg);}\n.authrobo-stack{display:flex;flex-direction:column;gap:10px;}\n.authrobo-title{font:700 16px system-ui,sans-serif;color:var(--authrobo-title-fg);}\n.authrobo-muted{color:var(--authrobo-muted);font:14px system-ui,sans-serif;margin:0;}\n.authrobo-error{color:var(--authrobo-error);font:14px system-ui,sans-serif;margin:0;}\n.authrobo-powered{display:block;margin:2px 0 -2px;text-align:center;text-decoration:none;\n font:500 11.5px system-ui,sans-serif;color:var(--authrobo-muted);opacity:.85;transition:opacity .15s ease;}\n.authrobo-powered:hover{opacity:1;}\n.authrobo-powered b{font-weight:700;color:var(--authrobo-title-fg);}\n.authrobo-divider{display:flex;align-items:center;gap:10px;color:var(--authrobo-divider-fg);font:500 12px system-ui,sans-serif;}\n.authrobo-divider::before,.authrobo-divider::after{content:\"\";height:1px;flex:1;background:var(--authrobo-divider-line);}\n.authrobo-tabs{display:flex;gap:4px;padding:4px;border:1px solid var(--authrobo-btn-border);\n background:var(--authrobo-tabs-bg);border-radius:10px;}\n.authrobo-tab{flex:1;border:0;background:transparent;border-radius:7px;padding:8px 0;cursor:pointer;\n font:600 13px system-ui,sans-serif;color:var(--authrobo-muted);transition:background .15s ease,color .15s ease;}\n.authrobo-tab:hover{color:var(--authrobo-title-fg);}\n.authrobo-tab[aria-selected=\"true\"]{background:var(--authrobo-accent);color:var(--authrobo-accent-fg);}\n.authrobo-tab:focus-visible{outline:2px solid var(--authrobo-focus);outline-offset:2px;}\n.authrobo-form{display:flex;flex-direction:column;gap:10px;}\n.authrobo-label{font:500 12.5px system-ui,sans-serif;color:var(--authrobo-muted);}\n.authrobo-input{width:100%;box-sizing:border-box;margin-top:6px;border:1px solid var(--authrobo-btn-border);\n background:var(--authrobo-input-bg);color:var(--authrobo-input-fg);border-radius:10px;padding:10px 12px;\n font:14px system-ui,sans-serif;}\n.authrobo-input:focus{outline:none;border-color:var(--authrobo-accent);}\n.authrobo-primary{display:flex;width:100%;align-items:center;justify-content:center;gap:8px;border:0;\n background:var(--authrobo-accent);color:var(--authrobo-accent-fg);border-radius:10px;padding:11px 14px;\n font:700 14px system-ui,sans-serif;cursor:pointer;transition:filter .15s ease;}\n.authrobo-primary:hover{filter:brightness(.96);}\n.authrobo-primary:focus-visible{outline:2px solid var(--authrobo-focus);outline-offset:2px;}\n.authrobo-primary:disabled{opacity:.7;cursor:default;}\n.authrobo-btn-brand{transition:filter .15s ease,box-shadow .15s ease;}\n.authrobo-btn-brand:hover{filter:brightness(.96);}\n.authrobo-spinner{display:inline-block;width:1.15em;height:1.15em;vertical-align:-0.2em;border-radius:50%;\n border:2px solid color-mix(in srgb, currentColor 24%, transparent);border-top-color:currentColor;\n animation:authrobo-spin .7s linear infinite;}\n.authrobo-loading{display:flex;align-items:center;justify-content:center;gap:10px;padding:20px 0;}\n@keyframes authrobo-spin{to{transform:rotate(360deg)}}\n@media (prefers-reduced-motion: reduce){.authrobo-spinner{animation-duration:1.4s}}\n.authrobo-overlay{position:fixed;inset:0;z-index:2147483000;display:flex;align-items:center;\n justify-content:center;padding:16px;background:var(--authrobo-overlay);backdrop-filter:blur(2px);\n animation:authrobo-fade .16s ease-out both;}\n.authrobo-card{position:relative;width:100%;max-width:360px;background:var(--authrobo-card-bg);border-radius:16px;\n padding:24px;box-shadow:0 20px 60px -12px var(--authrobo-card-shadow);animation:authrobo-pop .2s cubic-bezier(.16,1,.3,1) both;}\n.authrobo-close{position:absolute;top:12px;right:12px;border:0;background:transparent;cursor:pointer;\n color:var(--authrobo-close);font-size:18px;line-height:1;padding:4px;}\n.authrobo-close:hover{color:var(--authrobo-close-hover);}\n@keyframes authrobo-fade{from{opacity:0}to{opacity:1}}\n@keyframes authrobo-pop{from{opacity:0;transform:translateY(8px) scale(.97)}to{opacity:1;transform:none}}\n@media (prefers-reduced-motion: reduce){.authrobo-overlay,.authrobo-card{animation:none}}\n`;\n\nfunction useInjectStyles() {\n useEffect(() => {\n if (typeof document === \"undefined\" || document.getElementById(STYLE_ID)) return;\n const el = document.createElement(\"style\");\n el.id = STYLE_ID;\n el.textContent = CSS;\n document.head.appendChild(el);\n }, []);\n}\n\n/** A theme-aware loading spinner. Colour follows the surrounding text (currentColor). */\nexport function Spinner({ style, className }: { style?: React.CSSProperties; className?: string }) {\n return (\n <span\n className={className ? `authrobo-spinner ${className}` : \"authrobo-spinner\"}\n role=\"status\"\n aria-label=\"Loading\"\n style={style}\n />\n );\n}\n\n/* ----------------------------- Button ----------------------------------- */\n\nexport function AuthRoboButton({\n provider,\n config,\n label,\n className,\n style,\n onClick,\n lastUsed,\n startPath,\n buttonStyle = \"neutral\",\n}: {\n provider: Method;\n config?: AuthRoboConfig;\n label?: string;\n className?: string;\n style?: React.CSSProperties;\n onClick?: () => void;\n /** Show a \"Last used\" badge (the method the visitor signed in with before). */\n lastUsed?: boolean;\n /** Proxy the redirect through your own server (see StartOptions.startPath). */\n startPath?: string;\n /** \"neutral\" (default) or \"branded\" (provider-coloured button). */\n buttonStyle?: ButtonStyle;\n}) {\n useInjectStyles();\n const c = useResolvedConfig(config);\n const meta = PROVIDER_META[provider];\n const brand = buttonStyle === \"branded\" ? BRAND_STYLE[provider] : undefined;\n const icon = brand?.whiteIcon ? WHITE_MARKS[provider] ?? meta.icon : meta.icon;\n\n const classes = [\"authrobo-btn\", brand ? \"authrobo-btn-brand\" : \"\", className]\n .filter(Boolean)\n .join(\" \");\n const brandStyle: React.CSSProperties | undefined = brand\n ? { background: brand.bg, color: brand.fg, borderColor: brand.border }\n : undefined;\n\n return (\n <button\n type=\"button\"\n className={classes}\n style={{ ...brandStyle, ...style }}\n onClick={() => {\n onClick?.();\n startSignIn(c, provider, { startPath });\n }}\n >\n <span style={{ display: \"inline-flex\", alignItems: \"center\" }}>{icon}</span>\n {label ?? `Continue with ${meta.label}`}\n {lastUsed && <span className=\"authrobo-last\">Last used</span>}\n </button>\n );\n}\n\n/* ---------------------- Email switcher (tabs) --------------------------- */\n\n// Tab order is fixed: Magic Link first, then Register, then Login. Each tab is\n// filtered in only if its underlying method is enabled for the app. Every tab\n// collects exactly the fields that flow needs:\n// • Magic Link → email (a one-time link is emailed)\n// • Register → name + email + password (creates the account)\n// • Login → email + password\nconst EMAIL_TABS: {\n key: Screen;\n method: Method;\n label: string;\n cta: string;\n requires: Method;\n fields: { name: boolean; password: boolean };\n /** Server endpoint (relative to startPath) for the proxied JSON POST. */\n proxyPath: string;\n}[] = [\n { key: \"magic\", method: \"magic_link\", label: \"Magic Link\", cta: \"Email me a link\", requires: \"magic_link\", fields: { name: false, password: false }, proxyPath: \"magic\" },\n { key: \"register\", method: \"password\", label: \"Register\", cta: \"Create account\", requires: \"password\", fields: { name: true, password: true }, proxyPath: \"register\" },\n { key: \"login\", method: \"password\", label: \"Login\", cta: \"Sign in\", requires: \"password\", fields: { name: false, password: true }, proxyPath: \"login\" },\n];\n\n/**\n * The email tabs (Magic Link / Register / Login).\n *\n * Two submission modes:\n * - **Direct** (no `startPath`): a native cross-origin form POST straight to\n * AuthRobo — `authorize` for password login/register (→ returns to your\n * `redirectUri` with a one-time code your backend exchanges), or `magic/start`\n * for the link. Credentials go to AuthRobo, never to your own server.\n * - **Proxied** (`startPath` set): a same-origin JSON POST to\n * `${startPath}/{login|register|magic}` on YOUR server, which forwards to\n * AuthRobo and sets your httpOnly session cookies. On success `onSuccess()`\n * fires (no full-page redirect), so it slots into an existing modal.\n */\nfunction EmailSwitcher({\n config,\n methods,\n startPath,\n onSuccess,\n}: {\n config: AuthRoboConfig;\n methods: Method[];\n startPath?: string;\n onSuccess?: () => void;\n}) {\n const tabs = useMemo(() => EMAIL_TABS.filter((t) => methods.includes(t.requires)), [methods]);\n const [active, setActive] = useState<Screen>(tabs[0]?.key ?? \"login\");\n const [name, setName] = useState(\"\");\n const [email, setEmail] = useState(\"\");\n const [password, setPassword] = useState(\"\");\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [sent, setSent] = useState(false);\n const stateRef = useRef<HTMLInputElement>(null);\n const proxy = !!startPath;\n\n // Keep the active tab valid if the enabled set changes under us.\n useEffect(() => {\n if (tabs.length && !tabs.some((t) => t.key === active)) setActive(tabs[0].key);\n }, [tabs, active]);\n\n if (!tabs.length) return null;\n const current = tabs.find((t) => t.key === active) ?? tabs[0];\n const base = config.issuerUrl.replace(/\\/$/, \"\");\n const directAction =\n current.key === \"magic\" ? `${base}/api/v1/auth/magic/start` : `${base}/api/v1/auth/authorize`;\n\n const selectTab = (key: Screen) => {\n setActive(key);\n setError(null);\n setSent(false);\n };\n\n // Proxied mode: JSON POST to the app's own route, then hand back to the host.\n async function proxySubmit(e: React.FormEvent) {\n e.preventDefault();\n setError(null);\n setLoading(true);\n try {\n const body: Record<string, string> = { email: email.trim() };\n if (current.fields.password) body.password = password;\n if (current.fields.name && name.trim()) body.name = name.trim();\n const res = await fetch(`${startPath!.replace(/\\/$/, \"\")}/${current.proxyPath}`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n if (!res.ok) {\n const d = (await res.json().catch(() => ({}))) as { error?: string };\n throw new Error(d?.error || \"Something went wrong. Please try again.\");\n }\n try {\n localStorage.setItem(lastMethodKey(config.clientId), current.method);\n } catch {\n /* ignore */\n }\n if (current.key === \"magic\") setSent(true);\n else onSuccess?.();\n } catch (err) {\n setError(err instanceof Error ? err.message : \"Something went wrong.\");\n } finally {\n setLoading(false);\n }\n }\n\n // Direct mode: stamp a fresh CSRF state into the hidden field + sessionStorage,\n // then let the browser perform the native cross-origin form POST to AuthRobo.\n function directSubmit() {\n const s = randomState();\n try {\n sessionStorage.setItem(\"authrobo:state\", s);\n } catch {\n /* storage unavailable */\n }\n if (stateRef.current) stateRef.current.value = s;\n try {\n localStorage.setItem(lastMethodKey(config.clientId), current.method);\n } catch {\n /* ignore */\n }\n setLoading(true); // page is about to navigate away\n }\n\n if (sent) {\n return (\n <div className=\"authrobo-stack\" role=\"status\">\n <p className=\"authrobo-title\">Check your email</p>\n <p className=\"authrobo-muted\">\n We sent a sign-in link to <b>{email.trim()}</b>. It works once and expires shortly.\n </p>\n </div>\n );\n }\n\n return (\n <div className=\"authrobo-stack\">\n {tabs.length > 1 && (\n <div className=\"authrobo-tabs\" role=\"tablist\" aria-label=\"Sign-in method\">\n {tabs.map((t) => (\n <button\n key={t.key}\n type=\"button\"\n role=\"tab\"\n aria-selected={current.key === t.key}\n className=\"authrobo-tab\"\n onClick={() => selectTab(t.key)}\n >\n {t.label}\n </button>\n ))}\n </div>\n )}\n <form\n className=\"authrobo-form\"\n method={proxy ? undefined : \"post\"}\n action={proxy ? undefined : directAction}\n onSubmit={proxy ? proxySubmit : directSubmit}\n >\n {!proxy && (\n <>\n <input type=\"hidden\" name=\"client_id\" value={config.clientId} />\n <input type=\"hidden\" name=\"redirect_uri\" value={config.redirectUri} />\n <input type=\"hidden\" name=\"state\" ref={stateRef} />\n {current.key !== \"magic\" && (\n <input type=\"hidden\" name=\"mode\" value={current.key === \"register\" ? \"register\" : \"login\"} />\n )}\n </>\n )}\n\n {current.fields.name && (\n <label className=\"authrobo-label\">\n Name\n <input\n className=\"authrobo-input\"\n name=\"name\"\n type=\"text\"\n autoComplete=\"name\"\n placeholder=\"Your name\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n />\n </label>\n )}\n <label className=\"authrobo-label\">\n Email\n <input\n className=\"authrobo-input\"\n name=\"email\"\n type=\"email\"\n required\n autoComplete=\"email\"\n placeholder=\"you@example.com\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n />\n </label>\n {current.fields.password && (\n <label className=\"authrobo-label\">\n Password\n <input\n className=\"authrobo-input\"\n name=\"password\"\n type=\"password\"\n required\n minLength={current.key === \"register\" ? 8 : undefined}\n autoComplete={current.key === \"register\" ? \"new-password\" : \"current-password\"}\n placeholder={current.key === \"register\" ? \"At least 8 characters\" : \"Your password\"}\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n />\n </label>\n )}\n\n {error && <p className=\"authrobo-error\">{error}</p>}\n\n <button type=\"submit\" className=\"authrobo-primary\" disabled={loading}>\n {loading ? (\n <>\n <Spinner /> Please wait…\n </>\n ) : (\n current.cta\n )}\n </button>\n </form>\n </div>\n );\n}\n\n/* ---------------------- Auth modal / inline panel ----------------------- */\n\nexport function AuthRoboAuth({\n config,\n mode = \"inline\",\n open = true,\n onClose,\n onSuccess,\n title,\n showHeader = true,\n methods: only,\n startPath,\n buttonStyle = \"neutral\",\n}: {\n config?: AuthRoboConfig;\n /** \"inline\" renders in place; \"modal\" renders a centered overlay. */\n mode?: \"inline\" | \"modal\";\n /** Only used in modal mode. */\n open?: boolean;\n onClose?: () => void;\n /**\n * Fires after a successful proxied (startPath) password login/register — the\n * session cookies are set and no page redirect happened, so refresh your auth\n * state and close the modal here. Not called for social/magic or direct mode\n * (those navigate the page).\n */\n onSuccess?: () => void;\n /** Heading; defaults to \"Sign in to <app name>\". */\n title?: string;\n /** Render the logo + title row. Set false when the host supplies its own heading. */\n showHeader?: boolean;\n /** Restrict/reorder which methods to show (defaults to all enabled ones). */\n methods?: Method[];\n /** Proxy every redirect through your own server (see StartOptions.startPath). */\n startPath?: string;\n /** \"neutral\" (default) or \"branded\" social buttons. */\n buttonStyle?: ButtonStyle;\n}) {\n useInjectStyles();\n const c = useResolvedConfig(config);\n const { data, loading, error } = useAppConfig(c);\n const lastMethod = useLastMethod(c.clientId);\n\n useEffect(() => {\n if (mode !== \"modal\" || !open) return;\n const onKey = (e: KeyboardEvent) => e.key === \"Escape\" && onClose?.();\n document.addEventListener(\"keydown\", onKey);\n return () => document.removeEventListener(\"keydown\", onKey);\n }, [mode, open, onClose]);\n\n if (mode === \"modal\" && !open) return null;\n\n const available = data?.methods ?? [];\n const shown = (only ? only.filter((m) => available.includes(m)) : available).filter(\n (m) => m in PROVIDER_META,\n );\n const social = shown.filter((m) => !EMAIL_METHODS.includes(m));\n const email = shown.filter((m) => EMAIL_METHODS.includes(m));\n // Only worth pointing out the last-used method when there's a choice to make.\n const badge = (m: Method) => shown.length > 1 && m === lastMethod;\n\n const panel = (\n <div className=\"authrobo-stack\">\n {showHeader && (data?.logoUrl || data?.name) && (\n <div style={{ display: \"flex\", alignItems: \"center\", gap: 10, marginBottom: 4 }}>\n {data?.logoUrl && (\n <img src={data.logoUrl} alt=\"\" width={28} height={28} style={{ borderRadius: 6 }} />\n )}\n <span className=\"authrobo-title\">\n {title ?? `Sign in${data?.name ? ` to ${data.name}` : \"\"}`}\n </span>\n </div>\n )}\n\n {loading && (\n <div className=\"authrobo-loading\">\n <Spinner style={{ color: \"var(--authrobo-accent)\" }} />\n <span className=\"authrobo-muted\">Loading sign-in options…</span>\n </div>\n )}\n {error && <p className=\"authrobo-error\">Couldn&apos;t load sign-in options.</p>}\n\n {social.map((m) => (\n <AuthRoboButton\n key={m}\n provider={m}\n config={c}\n lastUsed={badge(m)}\n startPath={startPath}\n buttonStyle={buttonStyle}\n />\n ))}\n\n {email.length > 0 && social.length > 0 && <div className=\"authrobo-divider\">or</div>}\n\n {email.length > 0 && (\n <EmailSwitcher config={c} methods={email} startPath={startPath} onSuccess={onSuccess} />\n )}\n\n {!loading && !error && shown.length === 0 && (\n <p className=\"authrobo-muted\">No sign-in methods are enabled for this app.</p>\n )}\n\n {!loading && !error && data?.poweredBy && (\n <a className=\"authrobo-powered\" href=\"https://authrobo.com\" target=\"_blank\" rel=\"noreferrer\">\n Authentication provided by <b>AuthRobo</b>\n </a>\n )}\n </div>\n );\n\n if (mode === \"inline\") return panel;\n\n return (\n <div className=\"authrobo-overlay\" onClick={() => onClose?.()}>\n <div className=\"authrobo-card\" role=\"dialog\" aria-modal=\"true\" onClick={(e) => e.stopPropagation()}>\n <button type=\"button\" className=\"authrobo-close\" aria-label=\"Close\" onClick={() => onClose?.()}>\n ✕\n </button>\n {panel}\n </div>\n </div>\n );\n}\n","import * as React from \"react\";\n\n// Sign-in methods AuthRobo can surface. \"password\" and \"magic_link\" route to\n// the hosted email login page; the rest are social OAuth providers.\nexport type Method =\n | \"google\"\n | \"linkedin\"\n | \"github\"\n | \"apple\"\n | \"facebook\"\n | \"password\"\n | \"magic_link\";\n\nconst sz = { width: 18, height: 18, \"aria-hidden\": true } as const;\n\n// Single-colour brand glyphs share one path so we can also render a white\n// variant (for branded buttons whose background is the brand colour).\nconst LINKEDIN_PATH =\n \"M20.45 20.45h-3.56v-5.57c0-1.33-.02-3.04-1.85-3.04-1.85 0-2.13 1.45-2.13 2.94v5.67H9.35V9h3.41v1.56h.05c.48-.9 1.64-1.85 3.37-1.85 3.6 0 4.27 2.37 4.27 5.45v6.29zM5.34 7.43a2.06 2.06 0 1 1 0-4.13 2.06 2.06 0 0 1 0 4.13zM7.12 20.45H3.56V9h3.56v11.45zM22.22 0H1.77C.79 0 0 .77 0 1.72v20.56C0 23.23.79 24 1.77 24h20.45c.98 0 1.78-.77 1.78-1.72V1.72C24 .77 23.2 0 22.22 0z\";\nconst GITHUB_PATH =\n \"M12 .3a12 12 0 0 0-3.8 23.4c.6.1.8-.3.8-.6v-2c-3.3.7-4-1.6-4-1.6-.6-1.4-1.3-1.8-1.3-1.8-1.1-.7.1-.7.1-.7 1.2.1 1.8 1.2 1.8 1.2 1.1 1.8 2.8 1.3 3.5 1 .1-.8.4-1.3.8-1.6-2.7-.3-5.5-1.3-5.5-6a4.7 4.7 0 0 1 1.2-3.2c-.1-.3-.5-1.5.1-3.2 0 0 1-.3 3.3 1.2a11.5 11.5 0 0 1 6 0c2.3-1.5 3.3-1.2 3.3-1.2.6 1.7.2 2.9.1 3.2a4.7 4.7 0 0 1 1.2 3.2c0 4.7-2.8 5.7-5.5 6 .4.4.8 1.1.8 2.2v3.3c0 .3.2.7.8.6A12 12 0 0 0 12 .3\";\nconst APPLE_PATH =\n \"M17.05 12.04c-.03-2.7 2.2-4 2.3-4.06-1.25-1.84-3.2-2.09-3.9-2.12-1.66-.17-3.24.98-4.08.98-.84 0-2.14-.96-3.52-.93-1.81.03-3.48 1.05-4.41 2.67-1.88 3.27-.48 8.1 1.35 10.76.9 1.3 1.97 2.76 3.38 2.71 1.36-.05 1.87-.88 3.51-.88 1.64 0 2.1.88 3.53.85 1.46-.03 2.38-1.33 3.27-2.63 1.03-1.51 1.46-2.97 1.48-3.05-.03-.01-2.84-1.09-2.87-4.32M14.4 4.2c.74-.9 1.24-2.15 1.1-3.4-1.07.04-2.36.71-3.13 1.61-.69.8-1.29 2.07-1.13 3.29 1.19.09 2.41-.61 3.16-1.5\";\nconst FACEBOOK_PATH =\n \"M24 12.07C24 5.4 18.63 0 12 0S0 5.4 0 12.07C0 18.1 4.39 23.1 10.13 24v-8.44H7.08v-3.49h3.05V9.41c0-3.02 1.79-4.69 4.53-4.69 1.31 0 2.68.24 2.68.24v2.97h-1.51c-1.49 0-1.95.93-1.95 1.88v2.26h3.32l-.53 3.49h-2.79V24C19.61 23.1 24 18.1 24 12.07\";\n\nfunction Glyph({ d, fill }: { d: string; fill: string }) {\n return (\n <svg viewBox=\"0 0 24 24\" {...sz} fill={fill}>\n <path d={d} />\n </svg>\n );\n}\n\nfunction GoogleIcon() {\n return (\n <svg viewBox=\"0 0 48 48\" {...sz}>\n <path fill=\"#FFC107\" d=\"M43.6 20.5H42V20H24v8h11.3C33.7 32.9 29.3 36 24 36c-6.6 0-12-5.4-12-12s5.4-12 12-12c3.1 0 5.9 1.2 8 3.1l5.7-5.7C34.6 6.1 29.6 4 24 4 12.9 4 4 12.9 4 24s8.9 20 20 20 20-8.9 20-20c0-1.3-.1-2.3-.4-3.5z\" />\n <path fill=\"#FF3D00\" d=\"M6.3 14.7l6.6 4.8C14.7 16 19 13 24 13c3.1 0 5.9 1.2 8 3.1l5.7-5.7C34.6 6.1 29.6 4 24 4 16.3 4 9.7 8.3 6.3 14.7z\" />\n <path fill=\"#4CAF50\" d=\"M24 44c5.2 0 10-2 13.6-5.2l-6.3-5.2C29.2 35 26.7 36 24 36c-5.3 0-9.7-3.4-11.3-8.1l-6.5 5C9.5 39.6 16.2 44 24 44z\" />\n <path fill=\"#1976D2\" d=\"M43.6 20.5H42V20H24v8h11.3c-.8 2.2-2.2 4.1-4.1 5.6l6.3 5.2C41.9 36 44 30.5 44 24c0-1.3-.1-2.3-.4-3.5z\" />\n </svg>\n );\n}\n\nfunction MailIcon() {\n return (\n <svg viewBox=\"0 0 24 24\" {...sz} fill=\"none\" stroke=\"#334155\" strokeWidth={2} strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"5\" width=\"18\" height=\"14\" rx=\"2\" />\n <path d=\"m3 7 9 6 9-6\" />\n </svg>\n );\n}\n\nexport const PROVIDER_META: Record<Method, { label: string; icon: React.ReactNode }> = {\n google: { label: \"Google\", icon: <GoogleIcon /> },\n linkedin: { label: \"LinkedIn\", icon: <Glyph d={LINKEDIN_PATH} fill=\"#0A66C2\" /> },\n github: { label: \"GitHub\", icon: <Glyph d={GITHUB_PATH} fill=\"#181717\" /> },\n apple: { label: \"Apple\", icon: <Glyph d={APPLE_PATH} fill=\"#000\" /> },\n facebook: { label: \"Facebook\", icon: <Glyph d={FACEBOOK_PATH} fill=\"#1877F2\" /> },\n password: { label: \"email\", icon: <MailIcon /> },\n magic_link: { label: \"magic link\", icon: <MailIcon /> },\n};\n\n// White glyph variants — used by branded buttons whose background is the brand\n// colour (so a monochrome mark stays legible). Google keeps its multicolour mark.\nexport const WHITE_MARKS: Partial<Record<Method, React.ReactNode>> = {\n linkedin: <Glyph d={LINKEDIN_PATH} fill=\"#fff\" />,\n github: <Glyph d={GITHUB_PATH} fill=\"#fff\" />,\n apple: <Glyph d={APPLE_PATH} fill=\"#fff\" />,\n facebook: <Glyph d={FACEBOOK_PATH} fill=\"#fff\" />,\n};\n\n// Fully-branded button palette: background / text / border per provider. Used\n// when <AuthRoboAuth buttonStyle=\"branded\"> (or <AuthRoboButton buttonStyle=…>).\nexport const BRAND_STYLE: Partial<Record<Method, { bg: string; fg: string; border: string; whiteIcon?: boolean }>> = {\n google: { bg: \"#ffffff\", fg: \"#1a73e8\", border: \"#dadce0\" },\n linkedin: { bg: \"#0a66c2\", fg: \"#ffffff\", border: \"#0a66c2\", whiteIcon: true },\n github: { bg: \"#181717\", fg: \"#ffffff\", border: \"#181717\", whiteIcon: true },\n apple: { bg: \"#000000\", fg: \"#ffffff\", border: \"#000000\", whiteIcon: true },\n facebook: { bg: \"#1877f2\", fg: \"#ffffff\", border: \"#1877f2\", whiteIcon: true },\n};\n"],"mappings":"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","names":["import_jsx_runtime"]}
package/dist/index.d.cts CHANGED
@@ -35,6 +35,9 @@ interface AppConfig {
35
35
  brandColor: string | null;
36
36
  logoUrl: string | null;
37
37
  methods: Method[];
38
+ /** Show the "Authentication provided by AuthRobo" attribution. True on Free
39
+ * plans; drops to false for Pro and above (white-label). */
40
+ poweredBy: boolean;
38
41
  }
39
42
  declare function AuthRoboProvider({ config, children, }: {
40
43
  config: AuthRoboConfig;
package/dist/index.d.ts CHANGED
@@ -35,6 +35,9 @@ interface AppConfig {
35
35
  brandColor: string | null;
36
36
  logoUrl: string | null;
37
37
  methods: Method[];
38
+ /** Show the "Authentication provided by AuthRobo" attribution. True on Free
39
+ * plans; drops to false for Pro and above (white-label). */
40
+ poweredBy: boolean;
38
41
  }
39
42
  declare function AuthRoboProvider({ config, children, }: {
40
43
  config: AuthRoboConfig;
package/dist/index.js CHANGED
@@ -154,7 +154,7 @@ function prefetchAppConfig(config) {
154
154
  const base = config.issuerUrl.replace(/\/$/, "");
155
155
  e.promise = fetch(`${base}/api/v1/config?client_id=${encodeURIComponent(config.clientId)}`).then((r) => r.ok ? r.json() : Promise.reject(new Error(`config ${r.status}`))).then((j) => {
156
156
  e.state = {
157
- data: { name: j.name, brandColor: j.brand_color, logoUrl: j.logo_url, methods: j.methods },
157
+ data: { name: j.name, brandColor: j.brand_color, logoUrl: j.logo_url, methods: j.methods, poweredBy: j.powered_by !== false },
158
158
  loading: false,
159
159
  error: null
160
160
  };
@@ -227,6 +227,10 @@ ${scoped('[data-theme="dark"] ', TOKENS_DARK)}
227
227
  .authrobo-title{font:700 16px system-ui,sans-serif;color:var(--authrobo-title-fg);}
228
228
  .authrobo-muted{color:var(--authrobo-muted);font:14px system-ui,sans-serif;margin:0;}
229
229
  .authrobo-error{color:var(--authrobo-error);font:14px system-ui,sans-serif;margin:0;}
230
+ .authrobo-powered{display:block;margin:2px 0 -2px;text-align:center;text-decoration:none;
231
+ font:500 11.5px system-ui,sans-serif;color:var(--authrobo-muted);opacity:.85;transition:opacity .15s ease;}
232
+ .authrobo-powered:hover{opacity:1;}
233
+ .authrobo-powered b{font-weight:700;color:var(--authrobo-title-fg);}
230
234
  .authrobo-divider{display:flex;align-items:center;gap:10px;color:var(--authrobo-divider-fg);font:500 12px system-ui,sans-serif;}
231
235
  .authrobo-divider::before,.authrobo-divider::after{content:"";height:1px;flex:1;background:var(--authrobo-divider-line);}
232
236
  .authrobo-tabs{display:flex;gap:4px;padding:4px;border:1px solid var(--authrobo-btn-border);
@@ -253,7 +257,7 @@ ${scoped('[data-theme="dark"] ', TOKENS_DARK)}
253
257
  .authrobo-spinner{display:inline-block;width:1.15em;height:1.15em;vertical-align:-0.2em;border-radius:50%;
254
258
  border:2px solid color-mix(in srgb, currentColor 24%, transparent);border-top-color:currentColor;
255
259
  animation:authrobo-spin .7s linear infinite;}
256
- .authrobo-loading{display:flex;align-items:center;gap:10px;padding:4px 0;}
260
+ .authrobo-loading{display:flex;align-items:center;justify-content:center;gap:10px;padding:20px 0;}
257
261
  @keyframes authrobo-spin{to{transform:rotate(360deg)}}
258
262
  @media (prefers-reduced-motion: reduce){.authrobo-spinner{animation-duration:1.4s}}
259
263
  .authrobo-overlay{position:fixed;inset:0;z-index:2147483000;display:flex;align-items:center;
@@ -547,7 +551,11 @@ function AuthRoboAuth({
547
551
  )),
548
552
  email.length > 0 && social.length > 0 && /* @__PURE__ */ jsx2("div", { className: "authrobo-divider", children: "or" }),
549
553
  email.length > 0 && /* @__PURE__ */ jsx2(EmailSwitcher, { config: c, methods: email, startPath, onSuccess }),
550
- !loading && !error && shown.length === 0 && /* @__PURE__ */ jsx2("p", { className: "authrobo-muted", children: "No sign-in methods are enabled for this app." })
554
+ !loading && !error && shown.length === 0 && /* @__PURE__ */ jsx2("p", { className: "authrobo-muted", children: "No sign-in methods are enabled for this app." }),
555
+ !loading && !error && data?.poweredBy && /* @__PURE__ */ jsxs2("a", { className: "authrobo-powered", href: "https://authrobo.com", target: "_blank", rel: "noreferrer", children: [
556
+ "Authentication provided by ",
557
+ /* @__PURE__ */ jsx2("b", { children: "AuthRobo" })
558
+ ] })
551
559
  ] });
552
560
  if (mode === "inline") return panel;
553
561
  return /* @__PURE__ */ jsx2("div", { className: "authrobo-overlay", onClick: () => onClose?.(), children: /* @__PURE__ */ jsxs2("div", { className: "authrobo-card", role: "dialog", "aria-modal": "true", onClick: (e) => e.stopPropagation(), children: [
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.tsx","../src/icons.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n} from \"react\";\nimport { BRAND_STYLE, PROVIDER_META, WHITE_MARKS, type Method } from \"./icons\";\n\nexport type { Method } from \"./icons\";\nexport { PROVIDER_META, BRAND_STYLE } from \"./icons\";\n\n/** Which hosted screen an email flow should open. */\nexport type Screen = \"login\" | \"register\" | \"magic\";\n\n/**\n * How to render social provider buttons.\n * - \"neutral\" (default): one consistent button chrome (themeable), brand-coloured icon.\n * - \"branded\": each button wears its provider's colours — LinkedIn blue, GitHub\n * black, Google white, Facebook blue, Apple black — with a legible glyph.\n */\nexport type ButtonStyle = \"neutral\" | \"branded\";\n\nexport interface AuthRoboConfig {\n /** Your AuthRobo instance, e.g. \"https://authrobo.com\". */\n issuerUrl: string;\n /** Your app's client_id (arc_...). */\n clientId: string;\n /** Where AuthRobo returns the one-time `code` after sign-in. */\n redirectUri: string;\n}\n\n/** Shape returned by GET /api/v1/config. */\nexport interface AppConfig {\n name: string;\n brandColor: string | null;\n logoUrl: string | null;\n methods: Method[];\n}\n\nconst ConfigContext = createContext<AuthRoboConfig | null>(null);\n\nexport function AuthRoboProvider({\n config,\n children,\n}: {\n config: AuthRoboConfig;\n children: React.ReactNode;\n}) {\n // Warm the app-config cache as soon as the provider mounts (i.e. on app start),\n // so the enabled sign-in methods are already resolved by the time a login modal\n // or page is opened — no request-on-open, no loading flash.\n useEffect(() => {\n prefetchAppConfig(config);\n }, [config.issuerUrl, config.clientId]);\n return <ConfigContext.Provider value={config}>{children}</ConfigContext.Provider>;\n}\n\nfunction useResolvedConfig(override?: AuthRoboConfig): AuthRoboConfig {\n const ctx = useContext(ConfigContext);\n const c = override ?? ctx;\n if (!c) {\n throw new Error(\n \"@authrobo/react: wrap your app in <AuthRoboProvider config={...}> or pass a `config` prop.\",\n );\n }\n return c;\n}\n\nfunction randomState(): string {\n const b = new Uint8Array(16);\n (globalThis.crypto ?? (globalThis as { crypto: Crypto }).crypto).getRandomValues(b);\n return Array.from(b, (x) => x.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\n// Email-based methods open a hosted page (which collects the address + password\n// or mails a link); social providers redirect straight into their OAuth start.\nconst EMAIL_METHODS: readonly Method[] = [\"password\", \"magic_link\"];\n\n/** Options accepted by startSignIn and the button/panel components. */\nexport interface StartOptions {\n state?: string;\n /** Prefill the email on the hosted page. */\n loginHint?: string;\n /** For email flows: which hosted screen to open (login / register / magic). */\n screen?: Screen;\n /**\n * Route the redirect through YOUR server instead of straight to AuthRobo.\n * When set, the browser navigates to `${startPath}/<method>/start` — your\n * route sets a first-party CSRF state cookie + the real redirect_uri, then\n * bounces to AuthRobo. This is the right choice for apps that keep the session\n * in httpOnly cookies (the code exchange happens server-side with your\n * client_secret). Leave unset to redirect to AuthRobo directly.\n */\n startPath?: string;\n}\n\n/**\n * Begin sign-in: navigate the browser to the hosted flow for `method`.\n *\n * - Social methods hit /api/v1/auth/<provider>/start.\n * - \"password\" opens the hosted /login (or /register when `screen: \"register\"`).\n * - \"magic_link\" opens /login?screen=magic (the passwordless view).\n *\n * With `startPath`, all of the above are proxied through your own server route\n * (`${startPath}/<method>/start`) so the flow stays first-party. Either way,\n * AuthRobo returns to your callback with a one-time `code` your backend\n * exchanges (with your client_secret) for tokens.\n */\nexport function startSignIn(config: AuthRoboConfig, method: Method, opts?: StartOptions): void {\n // Remember the method so we can badge it \"Last used\" next time (per client_id).\n try {\n localStorage.setItem(lastMethodKey(config.clientId), method);\n } catch {\n /* storage unavailable — badge just won't show next time */\n }\n\n // App-proxied: hand off to the consumer's own server, which owns state +\n // redirect_uri. Nothing sensitive is decided client-side here.\n if (opts?.startPath) {\n const p = new URLSearchParams();\n if (opts.loginHint) p.set(\"login_hint\", opts.loginHint);\n if (opts.screen) p.set(\"screen\", opts.screen);\n const qs = p.toString();\n window.location.assign(`${opts.startPath.replace(/\\/$/, \"\")}/${method}/start${qs ? `?${qs}` : \"\"}`);\n return;\n }\n\n const base = config.issuerUrl.replace(/\\/$/, \"\");\n const state = opts?.state ?? randomState();\n try {\n sessionStorage.setItem(\"authrobo:state\", state);\n } catch {\n /* storage unavailable — state is still sent, just not persisted for a check */\n }\n const params = new URLSearchParams({\n client_id: config.clientId,\n redirect_uri: config.redirectUri,\n state,\n });\n if (opts?.loginHint) params.set(\"login_hint\", opts.loginHint);\n\n let path: string;\n if (method === \"magic_link\") {\n params.set(\"screen\", \"magic\");\n path = \"/login\";\n } else if (method === \"password\") {\n path = opts?.screen === \"register\" ? \"/register\" : \"/login\";\n } else {\n path = `/api/v1/auth/${method}/start`;\n }\n window.location.assign(`${base}${path}?${params.toString()}`);\n}\n\nconst lastMethodKey = (clientId: string) => `authrobo:last-method:${clientId}`;\n\n/** The method last used to sign in for this client (from a prior startSignIn). */\nexport function useLastMethod(clientId: string): Method | null {\n const [last, setLast] = useState<Method | null>(null);\n useEffect(() => {\n try {\n setLast((localStorage.getItem(lastMethodKey(clientId)) as Method | null) ?? null);\n } catch {\n /* storage unavailable */\n }\n }, [clientId]);\n return last;\n}\n\n/* ------------------------- App-config cache ----------------------------- */\n// A tiny module-level store so the app's public config (branding + enabled\n// methods) is fetched at most once per (issuer, clientId) and shared across every\n// hook/component. Prefetched on provider mount; read synchronously thereafter.\n\ntype ConfigState = { data: AppConfig | null; loading: boolean; error: string | null };\n\nconst LOADING_STATE: ConfigState = { data: null, loading: true, error: null };\n\ntype ConfigEntry = { state: ConfigState; promise?: Promise<void>; listeners: Set<() => void> };\n\nconst configStore = new Map<string, ConfigEntry>();\nconst configKey = (c: AuthRoboConfig) => `${c.issuerUrl.replace(/\\/$/, \"\")}|${c.clientId}`;\n\nfunction configEntry(key: string): ConfigEntry {\n let e = configStore.get(key);\n if (!e) {\n e = { state: LOADING_STATE, listeners: new Set() };\n configStore.set(key, e);\n }\n return e;\n}\n\n/**\n * Fetch (once) and cache an app's public config. Safe to call eagerly on app\n * start — concurrent calls dedupe onto the same in-flight request, and a resolved\n * entry returns immediately. Returns the in-flight promise (or a resolved one).\n */\nexport function prefetchAppConfig(config: AuthRoboConfig): Promise<void> {\n if (typeof window === \"undefined\") return Promise.resolve(); // no-op during SSR\n const key = configKey(config);\n const e = configEntry(key);\n if (e.state.data || e.promise) return e.promise ?? Promise.resolve();\n const base = config.issuerUrl.replace(/\\/$/, \"\");\n e.promise = fetch(`${base}/api/v1/config?client_id=${encodeURIComponent(config.clientId)}`)\n .then((r) => (r.ok ? r.json() : Promise.reject(new Error(`config ${r.status}`))))\n .then((j) => {\n e.state = {\n data: { name: j.name, brandColor: j.brand_color, logoUrl: j.logo_url, methods: j.methods },\n loading: false,\n error: null,\n };\n })\n .catch((err) => {\n e.state = { data: null, loading: false, error: String(err?.message ?? err) };\n })\n .finally(() => {\n e.promise = undefined;\n e.listeners.forEach((l) => l());\n });\n return e.promise;\n}\n\n/** Fetch an app's public config (branding + enabled methods) for `clientId`. */\nexport function useAppConfig(config?: AuthRoboConfig): ConfigState {\n const c = useResolvedConfig(config);\n const key = configKey(c);\n\n const subscribe = useCallback(\n (cb: () => void) => {\n const e = configEntry(key);\n e.listeners.add(cb);\n return () => {\n e.listeners.delete(cb);\n };\n },\n [key],\n );\n const getSnapshot = useCallback(() => configEntry(key).state, [key]);\n const state = useSyncExternalStore(subscribe, getSnapshot, () => LOADING_STATE);\n\n // Kick off the fetch if the provider didn't already (e.g. no <AuthRoboProvider>).\n useEffect(() => {\n prefetchAppConfig(c);\n }, [c.issuerUrl, c.clientId]);\n\n return state;\n}\n\n/* ----------------------------- Styling ---------------------------------- */\n\nconst STYLE_ID = \"authrobo-react-styles\";\n\n// Theme-aware: tokens default to a soft light palette, flip to dark on the OS\n// preference, and can be forced either way by a `data-theme` attribute on any\n// ancestor (`<html data-theme=\"dark\">`). A host app can also override any single\n// token inline (e.g. `--authrobo-accent`) to brand the injected widgets.\nconst TOKENS_LIGHT = `\n --authrobo-btn-bg:#fff;--authrobo-btn-fg:#111827;--authrobo-btn-border:#d1d5db;\n --authrobo-btn-hover-bg:#f8fafc;--authrobo-btn-hover-border:#9ca3af;\n --authrobo-card-bg:#fff;--authrobo-title-fg:#0f172a;--authrobo-muted:#64748b;\n --authrobo-error:#b91c1c;--authrobo-divider-fg:#9ca3af;--authrobo-divider-line:#e5e7eb;\n --authrobo-overlay:rgba(2,6,23,.55);--authrobo-close:#94a3b8;--authrobo-close-hover:#334155;\n --authrobo-focus:#2b8aff;--authrobo-card-shadow:rgba(2,6,23,.4);\n --authrobo-last-bg:#e7efff;--authrobo-last-fg:#2563eb;\n --authrobo-input-bg:#fff;--authrobo-input-fg:#111827;\n --authrobo-tabs-bg:#f1f5f9;--authrobo-accent:#4338ca;--authrobo-accent-fg:#fff;`;\nconst TOKENS_DARK = `\n --authrobo-btn-bg:#0e1626;--authrobo-btn-fg:#e6edf8;--authrobo-btn-border:#28374f;\n --authrobo-btn-hover-bg:#16233a;--authrobo-btn-hover-border:#3a4d6b;\n --authrobo-card-bg:#0b1424;--authrobo-title-fg:#f1f5fb;--authrobo-muted:#93a4bd;\n --authrobo-error:#f87171;--authrobo-divider-fg:#64748b;--authrobo-divider-line:#223049;\n --authrobo-overlay:rgba(2,6,23,.72);--authrobo-close:#64748b;--authrobo-close-hover:#cbd5e1;\n --authrobo-focus:#46c8ff;--authrobo-card-shadow:rgba(0,0,0,.6);\n --authrobo-last-bg:rgba(70,160,255,.18);--authrobo-last-fg:#8fc4ff;\n --authrobo-input-bg:#0e1626;--authrobo-input-fg:#e6edf8;\n --authrobo-tabs-bg:#0e1626;--authrobo-accent:#4338ca;--authrobo-accent-fg:#fff;`;\n// Elements that either read tokens directly or need them for their descendants.\nconst TOKEN_ROOTS =\n \".authrobo-btn,.authrobo-stack,.authrobo-card,.authrobo-overlay,.authrobo-divider,.authrobo-title\";\nconst scoped = (prefix: string, tokens: string) =>\n TOKEN_ROOTS.split(\",\")\n .map((s) => `${prefix}${s.trim()}`)\n .join(\",\") + `{${tokens}}`;\n\nconst CSS = `\n${scoped(\"\", TOKENS_LIGHT)}\n@media (prefers-color-scheme:dark){${scoped(\"\", TOKENS_DARK)}}\n${scoped('[data-theme=\"light\"] ', TOKENS_LIGHT)}\n${scoped('[data-theme=\"dark\"] ', TOKENS_DARK)}\n.authrobo-btn{position:relative;display:flex;width:100%;align-items:center;justify-content:center;gap:10px;\n border:1px solid var(--authrobo-btn-border);background:var(--authrobo-btn-bg);color:var(--authrobo-btn-fg);border-radius:10px;padding:10px 14px;\n font:600 14px/1.2 system-ui,-apple-system,Segoe UI,Roboto,sans-serif;cursor:pointer;\n transition:background .15s ease,border-color .15s ease,box-shadow .15s ease;}\n.authrobo-btn:hover{background:var(--authrobo-btn-hover-bg);border-color:var(--authrobo-btn-hover-border);}\n.authrobo-btn:focus-visible{outline:2px solid var(--authrobo-focus);outline-offset:2px;}\n.authrobo-last{position:absolute;right:8px;top:50%;transform:translateY(-50%);pointer-events:none;\n font:600 10px/1 system-ui,sans-serif;letter-spacing:.02em;padding:3px 7px;border-radius:999px;\n background:var(--authrobo-last-bg);color:var(--authrobo-last-fg);}\n.authrobo-stack{display:flex;flex-direction:column;gap:10px;}\n.authrobo-title{font:700 16px system-ui,sans-serif;color:var(--authrobo-title-fg);}\n.authrobo-muted{color:var(--authrobo-muted);font:14px system-ui,sans-serif;margin:0;}\n.authrobo-error{color:var(--authrobo-error);font:14px system-ui,sans-serif;margin:0;}\n.authrobo-divider{display:flex;align-items:center;gap:10px;color:var(--authrobo-divider-fg);font:500 12px system-ui,sans-serif;}\n.authrobo-divider::before,.authrobo-divider::after{content:\"\";height:1px;flex:1;background:var(--authrobo-divider-line);}\n.authrobo-tabs{display:flex;gap:4px;padding:4px;border:1px solid var(--authrobo-btn-border);\n background:var(--authrobo-tabs-bg);border-radius:10px;}\n.authrobo-tab{flex:1;border:0;background:transparent;border-radius:7px;padding:8px 0;cursor:pointer;\n font:600 13px system-ui,sans-serif;color:var(--authrobo-muted);transition:background .15s ease,color .15s ease;}\n.authrobo-tab:hover{color:var(--authrobo-title-fg);}\n.authrobo-tab[aria-selected=\"true\"]{background:var(--authrobo-accent);color:var(--authrobo-accent-fg);}\n.authrobo-tab:focus-visible{outline:2px solid var(--authrobo-focus);outline-offset:2px;}\n.authrobo-form{display:flex;flex-direction:column;gap:10px;}\n.authrobo-label{font:500 12.5px system-ui,sans-serif;color:var(--authrobo-muted);}\n.authrobo-input{width:100%;box-sizing:border-box;margin-top:6px;border:1px solid var(--authrobo-btn-border);\n background:var(--authrobo-input-bg);color:var(--authrobo-input-fg);border-radius:10px;padding:10px 12px;\n font:14px system-ui,sans-serif;}\n.authrobo-input:focus{outline:none;border-color:var(--authrobo-accent);}\n.authrobo-primary{display:flex;width:100%;align-items:center;justify-content:center;gap:8px;border:0;\n background:var(--authrobo-accent);color:var(--authrobo-accent-fg);border-radius:10px;padding:11px 14px;\n font:700 14px system-ui,sans-serif;cursor:pointer;transition:filter .15s ease;}\n.authrobo-primary:hover{filter:brightness(.96);}\n.authrobo-primary:focus-visible{outline:2px solid var(--authrobo-focus);outline-offset:2px;}\n.authrobo-primary:disabled{opacity:.7;cursor:default;}\n.authrobo-btn-brand{transition:filter .15s ease,box-shadow .15s ease;}\n.authrobo-btn-brand:hover{filter:brightness(.96);}\n.authrobo-spinner{display:inline-block;width:1.15em;height:1.15em;vertical-align:-0.2em;border-radius:50%;\n border:2px solid color-mix(in srgb, currentColor 24%, transparent);border-top-color:currentColor;\n animation:authrobo-spin .7s linear infinite;}\n.authrobo-loading{display:flex;align-items:center;gap:10px;padding:4px 0;}\n@keyframes authrobo-spin{to{transform:rotate(360deg)}}\n@media (prefers-reduced-motion: reduce){.authrobo-spinner{animation-duration:1.4s}}\n.authrobo-overlay{position:fixed;inset:0;z-index:2147483000;display:flex;align-items:center;\n justify-content:center;padding:16px;background:var(--authrobo-overlay);backdrop-filter:blur(2px);\n animation:authrobo-fade .16s ease-out both;}\n.authrobo-card{position:relative;width:100%;max-width:360px;background:var(--authrobo-card-bg);border-radius:16px;\n padding:24px;box-shadow:0 20px 60px -12px var(--authrobo-card-shadow);animation:authrobo-pop .2s cubic-bezier(.16,1,.3,1) both;}\n.authrobo-close{position:absolute;top:12px;right:12px;border:0;background:transparent;cursor:pointer;\n color:var(--authrobo-close);font-size:18px;line-height:1;padding:4px;}\n.authrobo-close:hover{color:var(--authrobo-close-hover);}\n@keyframes authrobo-fade{from{opacity:0}to{opacity:1}}\n@keyframes authrobo-pop{from{opacity:0;transform:translateY(8px) scale(.97)}to{opacity:1;transform:none}}\n@media (prefers-reduced-motion: reduce){.authrobo-overlay,.authrobo-card{animation:none}}\n`;\n\nfunction useInjectStyles() {\n useEffect(() => {\n if (typeof document === \"undefined\" || document.getElementById(STYLE_ID)) return;\n const el = document.createElement(\"style\");\n el.id = STYLE_ID;\n el.textContent = CSS;\n document.head.appendChild(el);\n }, []);\n}\n\n/** A theme-aware loading spinner. Colour follows the surrounding text (currentColor). */\nexport function Spinner({ style, className }: { style?: React.CSSProperties; className?: string }) {\n return (\n <span\n className={className ? `authrobo-spinner ${className}` : \"authrobo-spinner\"}\n role=\"status\"\n aria-label=\"Loading\"\n style={style}\n />\n );\n}\n\n/* ----------------------------- Button ----------------------------------- */\n\nexport function AuthRoboButton({\n provider,\n config,\n label,\n className,\n style,\n onClick,\n lastUsed,\n startPath,\n buttonStyle = \"neutral\",\n}: {\n provider: Method;\n config?: AuthRoboConfig;\n label?: string;\n className?: string;\n style?: React.CSSProperties;\n onClick?: () => void;\n /** Show a \"Last used\" badge (the method the visitor signed in with before). */\n lastUsed?: boolean;\n /** Proxy the redirect through your own server (see StartOptions.startPath). */\n startPath?: string;\n /** \"neutral\" (default) or \"branded\" (provider-coloured button). */\n buttonStyle?: ButtonStyle;\n}) {\n useInjectStyles();\n const c = useResolvedConfig(config);\n const meta = PROVIDER_META[provider];\n const brand = buttonStyle === \"branded\" ? BRAND_STYLE[provider] : undefined;\n const icon = brand?.whiteIcon ? WHITE_MARKS[provider] ?? meta.icon : meta.icon;\n\n const classes = [\"authrobo-btn\", brand ? \"authrobo-btn-brand\" : \"\", className]\n .filter(Boolean)\n .join(\" \");\n const brandStyle: React.CSSProperties | undefined = brand\n ? { background: brand.bg, color: brand.fg, borderColor: brand.border }\n : undefined;\n\n return (\n <button\n type=\"button\"\n className={classes}\n style={{ ...brandStyle, ...style }}\n onClick={() => {\n onClick?.();\n startSignIn(c, provider, { startPath });\n }}\n >\n <span style={{ display: \"inline-flex\", alignItems: \"center\" }}>{icon}</span>\n {label ?? `Continue with ${meta.label}`}\n {lastUsed && <span className=\"authrobo-last\">Last used</span>}\n </button>\n );\n}\n\n/* ---------------------- Email switcher (tabs) --------------------------- */\n\n// Tab order is fixed: Magic Link first, then Register, then Login. Each tab is\n// filtered in only if its underlying method is enabled for the app. Every tab\n// collects exactly the fields that flow needs:\n// • Magic Link → email (a one-time link is emailed)\n// • Register → name + email + password (creates the account)\n// • Login → email + password\nconst EMAIL_TABS: {\n key: Screen;\n method: Method;\n label: string;\n cta: string;\n requires: Method;\n fields: { name: boolean; password: boolean };\n /** Server endpoint (relative to startPath) for the proxied JSON POST. */\n proxyPath: string;\n}[] = [\n { key: \"magic\", method: \"magic_link\", label: \"Magic Link\", cta: \"Email me a link\", requires: \"magic_link\", fields: { name: false, password: false }, proxyPath: \"magic\" },\n { key: \"register\", method: \"password\", label: \"Register\", cta: \"Create account\", requires: \"password\", fields: { name: true, password: true }, proxyPath: \"register\" },\n { key: \"login\", method: \"password\", label: \"Login\", cta: \"Sign in\", requires: \"password\", fields: { name: false, password: true }, proxyPath: \"login\" },\n];\n\n/**\n * The email tabs (Magic Link / Register / Login).\n *\n * Two submission modes:\n * - **Direct** (no `startPath`): a native cross-origin form POST straight to\n * AuthRobo — `authorize` for password login/register (→ returns to your\n * `redirectUri` with a one-time code your backend exchanges), or `magic/start`\n * for the link. Credentials go to AuthRobo, never to your own server.\n * - **Proxied** (`startPath` set): a same-origin JSON POST to\n * `${startPath}/{login|register|magic}` on YOUR server, which forwards to\n * AuthRobo and sets your httpOnly session cookies. On success `onSuccess()`\n * fires (no full-page redirect), so it slots into an existing modal.\n */\nfunction EmailSwitcher({\n config,\n methods,\n startPath,\n onSuccess,\n}: {\n config: AuthRoboConfig;\n methods: Method[];\n startPath?: string;\n onSuccess?: () => void;\n}) {\n const tabs = useMemo(() => EMAIL_TABS.filter((t) => methods.includes(t.requires)), [methods]);\n const [active, setActive] = useState<Screen>(tabs[0]?.key ?? \"login\");\n const [name, setName] = useState(\"\");\n const [email, setEmail] = useState(\"\");\n const [password, setPassword] = useState(\"\");\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [sent, setSent] = useState(false);\n const stateRef = useRef<HTMLInputElement>(null);\n const proxy = !!startPath;\n\n // Keep the active tab valid if the enabled set changes under us.\n useEffect(() => {\n if (tabs.length && !tabs.some((t) => t.key === active)) setActive(tabs[0].key);\n }, [tabs, active]);\n\n if (!tabs.length) return null;\n const current = tabs.find((t) => t.key === active) ?? tabs[0];\n const base = config.issuerUrl.replace(/\\/$/, \"\");\n const directAction =\n current.key === \"magic\" ? `${base}/api/v1/auth/magic/start` : `${base}/api/v1/auth/authorize`;\n\n const selectTab = (key: Screen) => {\n setActive(key);\n setError(null);\n setSent(false);\n };\n\n // Proxied mode: JSON POST to the app's own route, then hand back to the host.\n async function proxySubmit(e: React.FormEvent) {\n e.preventDefault();\n setError(null);\n setLoading(true);\n try {\n const body: Record<string, string> = { email: email.trim() };\n if (current.fields.password) body.password = password;\n if (current.fields.name && name.trim()) body.name = name.trim();\n const res = await fetch(`${startPath!.replace(/\\/$/, \"\")}/${current.proxyPath}`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n if (!res.ok) {\n const d = (await res.json().catch(() => ({}))) as { error?: string };\n throw new Error(d?.error || \"Something went wrong. Please try again.\");\n }\n try {\n localStorage.setItem(lastMethodKey(config.clientId), current.method);\n } catch {\n /* ignore */\n }\n if (current.key === \"magic\") setSent(true);\n else onSuccess?.();\n } catch (err) {\n setError(err instanceof Error ? err.message : \"Something went wrong.\");\n } finally {\n setLoading(false);\n }\n }\n\n // Direct mode: stamp a fresh CSRF state into the hidden field + sessionStorage,\n // then let the browser perform the native cross-origin form POST to AuthRobo.\n function directSubmit() {\n const s = randomState();\n try {\n sessionStorage.setItem(\"authrobo:state\", s);\n } catch {\n /* storage unavailable */\n }\n if (stateRef.current) stateRef.current.value = s;\n try {\n localStorage.setItem(lastMethodKey(config.clientId), current.method);\n } catch {\n /* ignore */\n }\n setLoading(true); // page is about to navigate away\n }\n\n if (sent) {\n return (\n <div className=\"authrobo-stack\" role=\"status\">\n <p className=\"authrobo-title\">Check your email</p>\n <p className=\"authrobo-muted\">\n We sent a sign-in link to <b>{email.trim()}</b>. It works once and expires shortly.\n </p>\n </div>\n );\n }\n\n return (\n <div className=\"authrobo-stack\">\n {tabs.length > 1 && (\n <div className=\"authrobo-tabs\" role=\"tablist\" aria-label=\"Sign-in method\">\n {tabs.map((t) => (\n <button\n key={t.key}\n type=\"button\"\n role=\"tab\"\n aria-selected={current.key === t.key}\n className=\"authrobo-tab\"\n onClick={() => selectTab(t.key)}\n >\n {t.label}\n </button>\n ))}\n </div>\n )}\n <form\n className=\"authrobo-form\"\n method={proxy ? undefined : \"post\"}\n action={proxy ? undefined : directAction}\n onSubmit={proxy ? proxySubmit : directSubmit}\n >\n {!proxy && (\n <>\n <input type=\"hidden\" name=\"client_id\" value={config.clientId} />\n <input type=\"hidden\" name=\"redirect_uri\" value={config.redirectUri} />\n <input type=\"hidden\" name=\"state\" ref={stateRef} />\n {current.key !== \"magic\" && (\n <input type=\"hidden\" name=\"mode\" value={current.key === \"register\" ? \"register\" : \"login\"} />\n )}\n </>\n )}\n\n {current.fields.name && (\n <label className=\"authrobo-label\">\n Name\n <input\n className=\"authrobo-input\"\n name=\"name\"\n type=\"text\"\n autoComplete=\"name\"\n placeholder=\"Your name\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n />\n </label>\n )}\n <label className=\"authrobo-label\">\n Email\n <input\n className=\"authrobo-input\"\n name=\"email\"\n type=\"email\"\n required\n autoComplete=\"email\"\n placeholder=\"you@example.com\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n />\n </label>\n {current.fields.password && (\n <label className=\"authrobo-label\">\n Password\n <input\n className=\"authrobo-input\"\n name=\"password\"\n type=\"password\"\n required\n minLength={current.key === \"register\" ? 8 : undefined}\n autoComplete={current.key === \"register\" ? \"new-password\" : \"current-password\"}\n placeholder={current.key === \"register\" ? \"At least 8 characters\" : \"Your password\"}\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n />\n </label>\n )}\n\n {error && <p className=\"authrobo-error\">{error}</p>}\n\n <button type=\"submit\" className=\"authrobo-primary\" disabled={loading}>\n {loading ? (\n <>\n <Spinner /> Please wait…\n </>\n ) : (\n current.cta\n )}\n </button>\n </form>\n </div>\n );\n}\n\n/* ---------------------- Auth modal / inline panel ----------------------- */\n\nexport function AuthRoboAuth({\n config,\n mode = \"inline\",\n open = true,\n onClose,\n onSuccess,\n title,\n showHeader = true,\n methods: only,\n startPath,\n buttonStyle = \"neutral\",\n}: {\n config?: AuthRoboConfig;\n /** \"inline\" renders in place; \"modal\" renders a centered overlay. */\n mode?: \"inline\" | \"modal\";\n /** Only used in modal mode. */\n open?: boolean;\n onClose?: () => void;\n /**\n * Fires after a successful proxied (startPath) password login/register — the\n * session cookies are set and no page redirect happened, so refresh your auth\n * state and close the modal here. Not called for social/magic or direct mode\n * (those navigate the page).\n */\n onSuccess?: () => void;\n /** Heading; defaults to \"Sign in to <app name>\". */\n title?: string;\n /** Render the logo + title row. Set false when the host supplies its own heading. */\n showHeader?: boolean;\n /** Restrict/reorder which methods to show (defaults to all enabled ones). */\n methods?: Method[];\n /** Proxy every redirect through your own server (see StartOptions.startPath). */\n startPath?: string;\n /** \"neutral\" (default) or \"branded\" social buttons. */\n buttonStyle?: ButtonStyle;\n}) {\n useInjectStyles();\n const c = useResolvedConfig(config);\n const { data, loading, error } = useAppConfig(c);\n const lastMethod = useLastMethod(c.clientId);\n\n useEffect(() => {\n if (mode !== \"modal\" || !open) return;\n const onKey = (e: KeyboardEvent) => e.key === \"Escape\" && onClose?.();\n document.addEventListener(\"keydown\", onKey);\n return () => document.removeEventListener(\"keydown\", onKey);\n }, [mode, open, onClose]);\n\n if (mode === \"modal\" && !open) return null;\n\n const available = data?.methods ?? [];\n const shown = (only ? only.filter((m) => available.includes(m)) : available).filter(\n (m) => m in PROVIDER_META,\n );\n const social = shown.filter((m) => !EMAIL_METHODS.includes(m));\n const email = shown.filter((m) => EMAIL_METHODS.includes(m));\n // Only worth pointing out the last-used method when there's a choice to make.\n const badge = (m: Method) => shown.length > 1 && m === lastMethod;\n\n const panel = (\n <div className=\"authrobo-stack\">\n {showHeader && (data?.logoUrl || data?.name) && (\n <div style={{ display: \"flex\", alignItems: \"center\", gap: 10, marginBottom: 4 }}>\n {data?.logoUrl && (\n <img src={data.logoUrl} alt=\"\" width={28} height={28} style={{ borderRadius: 6 }} />\n )}\n <span className=\"authrobo-title\">\n {title ?? `Sign in${data?.name ? ` to ${data.name}` : \"\"}`}\n </span>\n </div>\n )}\n\n {loading && (\n <div className=\"authrobo-loading\">\n <Spinner style={{ color: \"var(--authrobo-accent)\" }} />\n <span className=\"authrobo-muted\">Loading sign-in options…</span>\n </div>\n )}\n {error && <p className=\"authrobo-error\">Couldn&apos;t load sign-in options.</p>}\n\n {social.map((m) => (\n <AuthRoboButton\n key={m}\n provider={m}\n config={c}\n lastUsed={badge(m)}\n startPath={startPath}\n buttonStyle={buttonStyle}\n />\n ))}\n\n {email.length > 0 && social.length > 0 && <div className=\"authrobo-divider\">or</div>}\n\n {email.length > 0 && (\n <EmailSwitcher config={c} methods={email} startPath={startPath} onSuccess={onSuccess} />\n )}\n\n {!loading && !error && shown.length === 0 && (\n <p className=\"authrobo-muted\">No sign-in methods are enabled for this app.</p>\n )}\n </div>\n );\n\n if (mode === \"inline\") return panel;\n\n return (\n <div className=\"authrobo-overlay\" onClick={() => onClose?.()}>\n <div className=\"authrobo-card\" role=\"dialog\" aria-modal=\"true\" onClick={(e) => e.stopPropagation()}>\n <button type=\"button\" className=\"authrobo-close\" aria-label=\"Close\" onClick={() => onClose?.()}>\n ✕\n </button>\n {panel}\n </div>\n </div>\n );\n}\n","import * as React from \"react\";\n\n// Sign-in methods AuthRobo can surface. \"password\" and \"magic_link\" route to\n// the hosted email login page; the rest are social OAuth providers.\nexport type Method =\n | \"google\"\n | \"linkedin\"\n | \"github\"\n | \"apple\"\n | \"facebook\"\n | \"password\"\n | \"magic_link\";\n\nconst sz = { width: 18, height: 18, \"aria-hidden\": true } as const;\n\n// Single-colour brand glyphs share one path so we can also render a white\n// variant (for branded buttons whose background is the brand colour).\nconst LINKEDIN_PATH =\n \"M20.45 20.45h-3.56v-5.57c0-1.33-.02-3.04-1.85-3.04-1.85 0-2.13 1.45-2.13 2.94v5.67H9.35V9h3.41v1.56h.05c.48-.9 1.64-1.85 3.37-1.85 3.6 0 4.27 2.37 4.27 5.45v6.29zM5.34 7.43a2.06 2.06 0 1 1 0-4.13 2.06 2.06 0 0 1 0 4.13zM7.12 20.45H3.56V9h3.56v11.45zM22.22 0H1.77C.79 0 0 .77 0 1.72v20.56C0 23.23.79 24 1.77 24h20.45c.98 0 1.78-.77 1.78-1.72V1.72C24 .77 23.2 0 22.22 0z\";\nconst GITHUB_PATH =\n \"M12 .3a12 12 0 0 0-3.8 23.4c.6.1.8-.3.8-.6v-2c-3.3.7-4-1.6-4-1.6-.6-1.4-1.3-1.8-1.3-1.8-1.1-.7.1-.7.1-.7 1.2.1 1.8 1.2 1.8 1.2 1.1 1.8 2.8 1.3 3.5 1 .1-.8.4-1.3.8-1.6-2.7-.3-5.5-1.3-5.5-6a4.7 4.7 0 0 1 1.2-3.2c-.1-.3-.5-1.5.1-3.2 0 0 1-.3 3.3 1.2a11.5 11.5 0 0 1 6 0c2.3-1.5 3.3-1.2 3.3-1.2.6 1.7.2 2.9.1 3.2a4.7 4.7 0 0 1 1.2 3.2c0 4.7-2.8 5.7-5.5 6 .4.4.8 1.1.8 2.2v3.3c0 .3.2.7.8.6A12 12 0 0 0 12 .3\";\nconst APPLE_PATH =\n \"M17.05 12.04c-.03-2.7 2.2-4 2.3-4.06-1.25-1.84-3.2-2.09-3.9-2.12-1.66-.17-3.24.98-4.08.98-.84 0-2.14-.96-3.52-.93-1.81.03-3.48 1.05-4.41 2.67-1.88 3.27-.48 8.1 1.35 10.76.9 1.3 1.97 2.76 3.38 2.71 1.36-.05 1.87-.88 3.51-.88 1.64 0 2.1.88 3.53.85 1.46-.03 2.38-1.33 3.27-2.63 1.03-1.51 1.46-2.97 1.48-3.05-.03-.01-2.84-1.09-2.87-4.32M14.4 4.2c.74-.9 1.24-2.15 1.1-3.4-1.07.04-2.36.71-3.13 1.61-.69.8-1.29 2.07-1.13 3.29 1.19.09 2.41-.61 3.16-1.5\";\nconst FACEBOOK_PATH =\n \"M24 12.07C24 5.4 18.63 0 12 0S0 5.4 0 12.07C0 18.1 4.39 23.1 10.13 24v-8.44H7.08v-3.49h3.05V9.41c0-3.02 1.79-4.69 4.53-4.69 1.31 0 2.68.24 2.68.24v2.97h-1.51c-1.49 0-1.95.93-1.95 1.88v2.26h3.32l-.53 3.49h-2.79V24C19.61 23.1 24 18.1 24 12.07\";\n\nfunction Glyph({ d, fill }: { d: string; fill: string }) {\n return (\n <svg viewBox=\"0 0 24 24\" {...sz} fill={fill}>\n <path d={d} />\n </svg>\n );\n}\n\nfunction GoogleIcon() {\n return (\n <svg viewBox=\"0 0 48 48\" {...sz}>\n <path fill=\"#FFC107\" d=\"M43.6 20.5H42V20H24v8h11.3C33.7 32.9 29.3 36 24 36c-6.6 0-12-5.4-12-12s5.4-12 12-12c3.1 0 5.9 1.2 8 3.1l5.7-5.7C34.6 6.1 29.6 4 24 4 12.9 4 4 12.9 4 24s8.9 20 20 20 20-8.9 20-20c0-1.3-.1-2.3-.4-3.5z\" />\n <path fill=\"#FF3D00\" d=\"M6.3 14.7l6.6 4.8C14.7 16 19 13 24 13c3.1 0 5.9 1.2 8 3.1l5.7-5.7C34.6 6.1 29.6 4 24 4 16.3 4 9.7 8.3 6.3 14.7z\" />\n <path fill=\"#4CAF50\" d=\"M24 44c5.2 0 10-2 13.6-5.2l-6.3-5.2C29.2 35 26.7 36 24 36c-5.3 0-9.7-3.4-11.3-8.1l-6.5 5C9.5 39.6 16.2 44 24 44z\" />\n <path fill=\"#1976D2\" d=\"M43.6 20.5H42V20H24v8h11.3c-.8 2.2-2.2 4.1-4.1 5.6l6.3 5.2C41.9 36 44 30.5 44 24c0-1.3-.1-2.3-.4-3.5z\" />\n </svg>\n );\n}\n\nfunction MailIcon() {\n return (\n <svg viewBox=\"0 0 24 24\" {...sz} fill=\"none\" stroke=\"#334155\" strokeWidth={2} strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"5\" width=\"18\" height=\"14\" rx=\"2\" />\n <path d=\"m3 7 9 6 9-6\" />\n </svg>\n );\n}\n\nexport const PROVIDER_META: Record<Method, { label: string; icon: React.ReactNode }> = {\n google: { label: \"Google\", icon: <GoogleIcon /> },\n linkedin: { label: \"LinkedIn\", icon: <Glyph d={LINKEDIN_PATH} fill=\"#0A66C2\" /> },\n github: { label: \"GitHub\", icon: <Glyph d={GITHUB_PATH} fill=\"#181717\" /> },\n apple: { label: \"Apple\", icon: <Glyph d={APPLE_PATH} fill=\"#000\" /> },\n facebook: { label: \"Facebook\", icon: <Glyph d={FACEBOOK_PATH} fill=\"#1877F2\" /> },\n password: { label: \"email\", icon: <MailIcon /> },\n magic_link: { label: \"magic link\", icon: <MailIcon /> },\n};\n\n// White glyph variants — used by branded buttons whose background is the brand\n// colour (so a monochrome mark stays legible). Google keeps its multicolour mark.\nexport const WHITE_MARKS: Partial<Record<Method, React.ReactNode>> = {\n linkedin: <Glyph d={LINKEDIN_PATH} fill=\"#fff\" />,\n github: <Glyph d={GITHUB_PATH} fill=\"#fff\" />,\n apple: <Glyph d={APPLE_PATH} fill=\"#fff\" />,\n facebook: <Glyph d={FACEBOOK_PATH} fill=\"#fff\" />,\n};\n\n// Fully-branded button palette: background / text / border per provider. Used\n// when <AuthRoboAuth buttonStyle=\"branded\"> (or <AuthRoboButton buttonStyle=…>).\nexport const BRAND_STYLE: Partial<Record<Method, { bg: string; fg: string; border: string; whiteIcon?: boolean }>> = {\n google: { bg: \"#ffffff\", fg: \"#1a73e8\", border: \"#dadce0\" },\n linkedin: { bg: \"#0a66c2\", fg: \"#ffffff\", border: \"#0a66c2\", whiteIcon: true },\n github: { bg: \"#181717\", fg: \"#ffffff\", border: \"#181717\", whiteIcon: true },\n apple: { bg: \"#000000\", fg: \"#ffffff\", border: \"#000000\", whiteIcon: true },\n facebook: { bg: \"#1877f2\", fg: \"#ffffff\", border: \"#1877f2\", whiteIcon: true },\n};\n"],"mappings":"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","names":["jsx","jsxs"]}
1
+ {"version":3,"sources":["../src/index.tsx","../src/icons.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n} from \"react\";\nimport { BRAND_STYLE, PROVIDER_META, WHITE_MARKS, type Method } from \"./icons\";\n\nexport type { Method } from \"./icons\";\nexport { PROVIDER_META, BRAND_STYLE } from \"./icons\";\n\n/** Which hosted screen an email flow should open. */\nexport type Screen = \"login\" | \"register\" | \"magic\";\n\n/**\n * How to render social provider buttons.\n * - \"neutral\" (default): one consistent button chrome (themeable), brand-coloured icon.\n * - \"branded\": each button wears its provider's colours — LinkedIn blue, GitHub\n * black, Google white, Facebook blue, Apple black — with a legible glyph.\n */\nexport type ButtonStyle = \"neutral\" | \"branded\";\n\nexport interface AuthRoboConfig {\n /** Your AuthRobo instance, e.g. \"https://authrobo.com\". */\n issuerUrl: string;\n /** Your app's client_id (arc_...). */\n clientId: string;\n /** Where AuthRobo returns the one-time `code` after sign-in. */\n redirectUri: string;\n}\n\n/** Shape returned by GET /api/v1/config. */\nexport interface AppConfig {\n name: string;\n brandColor: string | null;\n logoUrl: string | null;\n methods: Method[];\n /** Show the \"Authentication provided by AuthRobo\" attribution. True on Free\n * plans; drops to false for Pro and above (white-label). */\n poweredBy: boolean;\n}\n\nconst ConfigContext = createContext<AuthRoboConfig | null>(null);\n\nexport function AuthRoboProvider({\n config,\n children,\n}: {\n config: AuthRoboConfig;\n children: React.ReactNode;\n}) {\n // Warm the app-config cache as soon as the provider mounts (i.e. on app start),\n // so the enabled sign-in methods are already resolved by the time a login modal\n // or page is opened — no request-on-open, no loading flash.\n useEffect(() => {\n prefetchAppConfig(config);\n }, [config.issuerUrl, config.clientId]);\n return <ConfigContext.Provider value={config}>{children}</ConfigContext.Provider>;\n}\n\nfunction useResolvedConfig(override?: AuthRoboConfig): AuthRoboConfig {\n const ctx = useContext(ConfigContext);\n const c = override ?? ctx;\n if (!c) {\n throw new Error(\n \"@authrobo/react: wrap your app in <AuthRoboProvider config={...}> or pass a `config` prop.\",\n );\n }\n return c;\n}\n\nfunction randomState(): string {\n const b = new Uint8Array(16);\n (globalThis.crypto ?? (globalThis as { crypto: Crypto }).crypto).getRandomValues(b);\n return Array.from(b, (x) => x.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\n// Email-based methods open a hosted page (which collects the address + password\n// or mails a link); social providers redirect straight into their OAuth start.\nconst EMAIL_METHODS: readonly Method[] = [\"password\", \"magic_link\"];\n\n/** Options accepted by startSignIn and the button/panel components. */\nexport interface StartOptions {\n state?: string;\n /** Prefill the email on the hosted page. */\n loginHint?: string;\n /** For email flows: which hosted screen to open (login / register / magic). */\n screen?: Screen;\n /**\n * Route the redirect through YOUR server instead of straight to AuthRobo.\n * When set, the browser navigates to `${startPath}/<method>/start` — your\n * route sets a first-party CSRF state cookie + the real redirect_uri, then\n * bounces to AuthRobo. This is the right choice for apps that keep the session\n * in httpOnly cookies (the code exchange happens server-side with your\n * client_secret). Leave unset to redirect to AuthRobo directly.\n */\n startPath?: string;\n}\n\n/**\n * Begin sign-in: navigate the browser to the hosted flow for `method`.\n *\n * - Social methods hit /api/v1/auth/<provider>/start.\n * - \"password\" opens the hosted /login (or /register when `screen: \"register\"`).\n * - \"magic_link\" opens /login?screen=magic (the passwordless view).\n *\n * With `startPath`, all of the above are proxied through your own server route\n * (`${startPath}/<method>/start`) so the flow stays first-party. Either way,\n * AuthRobo returns to your callback with a one-time `code` your backend\n * exchanges (with your client_secret) for tokens.\n */\nexport function startSignIn(config: AuthRoboConfig, method: Method, opts?: StartOptions): void {\n // Remember the method so we can badge it \"Last used\" next time (per client_id).\n try {\n localStorage.setItem(lastMethodKey(config.clientId), method);\n } catch {\n /* storage unavailable — badge just won't show next time */\n }\n\n // App-proxied: hand off to the consumer's own server, which owns state +\n // redirect_uri. Nothing sensitive is decided client-side here.\n if (opts?.startPath) {\n const p = new URLSearchParams();\n if (opts.loginHint) p.set(\"login_hint\", opts.loginHint);\n if (opts.screen) p.set(\"screen\", opts.screen);\n const qs = p.toString();\n window.location.assign(`${opts.startPath.replace(/\\/$/, \"\")}/${method}/start${qs ? `?${qs}` : \"\"}`);\n return;\n }\n\n const base = config.issuerUrl.replace(/\\/$/, \"\");\n const state = opts?.state ?? randomState();\n try {\n sessionStorage.setItem(\"authrobo:state\", state);\n } catch {\n /* storage unavailable — state is still sent, just not persisted for a check */\n }\n const params = new URLSearchParams({\n client_id: config.clientId,\n redirect_uri: config.redirectUri,\n state,\n });\n if (opts?.loginHint) params.set(\"login_hint\", opts.loginHint);\n\n let path: string;\n if (method === \"magic_link\") {\n params.set(\"screen\", \"magic\");\n path = \"/login\";\n } else if (method === \"password\") {\n path = opts?.screen === \"register\" ? \"/register\" : \"/login\";\n } else {\n path = `/api/v1/auth/${method}/start`;\n }\n window.location.assign(`${base}${path}?${params.toString()}`);\n}\n\nconst lastMethodKey = (clientId: string) => `authrobo:last-method:${clientId}`;\n\n/** The method last used to sign in for this client (from a prior startSignIn). */\nexport function useLastMethod(clientId: string): Method | null {\n const [last, setLast] = useState<Method | null>(null);\n useEffect(() => {\n try {\n setLast((localStorage.getItem(lastMethodKey(clientId)) as Method | null) ?? null);\n } catch {\n /* storage unavailable */\n }\n }, [clientId]);\n return last;\n}\n\n/* ------------------------- App-config cache ----------------------------- */\n// A tiny module-level store so the app's public config (branding + enabled\n// methods) is fetched at most once per (issuer, clientId) and shared across every\n// hook/component. Prefetched on provider mount; read synchronously thereafter.\n\ntype ConfigState = { data: AppConfig | null; loading: boolean; error: string | null };\n\nconst LOADING_STATE: ConfigState = { data: null, loading: true, error: null };\n\ntype ConfigEntry = { state: ConfigState; promise?: Promise<void>; listeners: Set<() => void> };\n\nconst configStore = new Map<string, ConfigEntry>();\nconst configKey = (c: AuthRoboConfig) => `${c.issuerUrl.replace(/\\/$/, \"\")}|${c.clientId}`;\n\nfunction configEntry(key: string): ConfigEntry {\n let e = configStore.get(key);\n if (!e) {\n e = { state: LOADING_STATE, listeners: new Set() };\n configStore.set(key, e);\n }\n return e;\n}\n\n/**\n * Fetch (once) and cache an app's public config. Safe to call eagerly on app\n * start — concurrent calls dedupe onto the same in-flight request, and a resolved\n * entry returns immediately. Returns the in-flight promise (or a resolved one).\n */\nexport function prefetchAppConfig(config: AuthRoboConfig): Promise<void> {\n if (typeof window === \"undefined\") return Promise.resolve(); // no-op during SSR\n const key = configKey(config);\n const e = configEntry(key);\n if (e.state.data || e.promise) return e.promise ?? Promise.resolve();\n const base = config.issuerUrl.replace(/\\/$/, \"\");\n e.promise = fetch(`${base}/api/v1/config?client_id=${encodeURIComponent(config.clientId)}`)\n .then((r) => (r.ok ? r.json() : Promise.reject(new Error(`config ${r.status}`))))\n .then((j) => {\n e.state = {\n data: { name: j.name, brandColor: j.brand_color, logoUrl: j.logo_url, methods: j.methods, poweredBy: j.powered_by !== false },\n loading: false,\n error: null,\n };\n })\n .catch((err) => {\n e.state = { data: null, loading: false, error: String(err?.message ?? err) };\n })\n .finally(() => {\n e.promise = undefined;\n e.listeners.forEach((l) => l());\n });\n return e.promise;\n}\n\n/** Fetch an app's public config (branding + enabled methods) for `clientId`. */\nexport function useAppConfig(config?: AuthRoboConfig): ConfigState {\n const c = useResolvedConfig(config);\n const key = configKey(c);\n\n const subscribe = useCallback(\n (cb: () => void) => {\n const e = configEntry(key);\n e.listeners.add(cb);\n return () => {\n e.listeners.delete(cb);\n };\n },\n [key],\n );\n const getSnapshot = useCallback(() => configEntry(key).state, [key]);\n const state = useSyncExternalStore(subscribe, getSnapshot, () => LOADING_STATE);\n\n // Kick off the fetch if the provider didn't already (e.g. no <AuthRoboProvider>).\n useEffect(() => {\n prefetchAppConfig(c);\n }, [c.issuerUrl, c.clientId]);\n\n return state;\n}\n\n/* ----------------------------- Styling ---------------------------------- */\n\nconst STYLE_ID = \"authrobo-react-styles\";\n\n// Theme-aware: tokens default to a soft light palette, flip to dark on the OS\n// preference, and can be forced either way by a `data-theme` attribute on any\n// ancestor (`<html data-theme=\"dark\">`). A host app can also override any single\n// token inline (e.g. `--authrobo-accent`) to brand the injected widgets.\nconst TOKENS_LIGHT = `\n --authrobo-btn-bg:#fff;--authrobo-btn-fg:#111827;--authrobo-btn-border:#d1d5db;\n --authrobo-btn-hover-bg:#f8fafc;--authrobo-btn-hover-border:#9ca3af;\n --authrobo-card-bg:#fff;--authrobo-title-fg:#0f172a;--authrobo-muted:#64748b;\n --authrobo-error:#b91c1c;--authrobo-divider-fg:#9ca3af;--authrobo-divider-line:#e5e7eb;\n --authrobo-overlay:rgba(2,6,23,.55);--authrobo-close:#94a3b8;--authrobo-close-hover:#334155;\n --authrobo-focus:#2b8aff;--authrobo-card-shadow:rgba(2,6,23,.4);\n --authrobo-last-bg:#e7efff;--authrobo-last-fg:#2563eb;\n --authrobo-input-bg:#fff;--authrobo-input-fg:#111827;\n --authrobo-tabs-bg:#f1f5f9;--authrobo-accent:#4338ca;--authrobo-accent-fg:#fff;`;\nconst TOKENS_DARK = `\n --authrobo-btn-bg:#0e1626;--authrobo-btn-fg:#e6edf8;--authrobo-btn-border:#28374f;\n --authrobo-btn-hover-bg:#16233a;--authrobo-btn-hover-border:#3a4d6b;\n --authrobo-card-bg:#0b1424;--authrobo-title-fg:#f1f5fb;--authrobo-muted:#93a4bd;\n --authrobo-error:#f87171;--authrobo-divider-fg:#64748b;--authrobo-divider-line:#223049;\n --authrobo-overlay:rgba(2,6,23,.72);--authrobo-close:#64748b;--authrobo-close-hover:#cbd5e1;\n --authrobo-focus:#46c8ff;--authrobo-card-shadow:rgba(0,0,0,.6);\n --authrobo-last-bg:rgba(70,160,255,.18);--authrobo-last-fg:#8fc4ff;\n --authrobo-input-bg:#0e1626;--authrobo-input-fg:#e6edf8;\n --authrobo-tabs-bg:#0e1626;--authrobo-accent:#4338ca;--authrobo-accent-fg:#fff;`;\n// Elements that either read tokens directly or need them for their descendants.\nconst TOKEN_ROOTS =\n \".authrobo-btn,.authrobo-stack,.authrobo-card,.authrobo-overlay,.authrobo-divider,.authrobo-title\";\nconst scoped = (prefix: string, tokens: string) =>\n TOKEN_ROOTS.split(\",\")\n .map((s) => `${prefix}${s.trim()}`)\n .join(\",\") + `{${tokens}}`;\n\nconst CSS = `\n${scoped(\"\", TOKENS_LIGHT)}\n@media (prefers-color-scheme:dark){${scoped(\"\", TOKENS_DARK)}}\n${scoped('[data-theme=\"light\"] ', TOKENS_LIGHT)}\n${scoped('[data-theme=\"dark\"] ', TOKENS_DARK)}\n.authrobo-btn{position:relative;display:flex;width:100%;align-items:center;justify-content:center;gap:10px;\n border:1px solid var(--authrobo-btn-border);background:var(--authrobo-btn-bg);color:var(--authrobo-btn-fg);border-radius:10px;padding:10px 14px;\n font:600 14px/1.2 system-ui,-apple-system,Segoe UI,Roboto,sans-serif;cursor:pointer;\n transition:background .15s ease,border-color .15s ease,box-shadow .15s ease;}\n.authrobo-btn:hover{background:var(--authrobo-btn-hover-bg);border-color:var(--authrobo-btn-hover-border);}\n.authrobo-btn:focus-visible{outline:2px solid var(--authrobo-focus);outline-offset:2px;}\n.authrobo-last{position:absolute;right:8px;top:50%;transform:translateY(-50%);pointer-events:none;\n font:600 10px/1 system-ui,sans-serif;letter-spacing:.02em;padding:3px 7px;border-radius:999px;\n background:var(--authrobo-last-bg);color:var(--authrobo-last-fg);}\n.authrobo-stack{display:flex;flex-direction:column;gap:10px;}\n.authrobo-title{font:700 16px system-ui,sans-serif;color:var(--authrobo-title-fg);}\n.authrobo-muted{color:var(--authrobo-muted);font:14px system-ui,sans-serif;margin:0;}\n.authrobo-error{color:var(--authrobo-error);font:14px system-ui,sans-serif;margin:0;}\n.authrobo-powered{display:block;margin:2px 0 -2px;text-align:center;text-decoration:none;\n font:500 11.5px system-ui,sans-serif;color:var(--authrobo-muted);opacity:.85;transition:opacity .15s ease;}\n.authrobo-powered:hover{opacity:1;}\n.authrobo-powered b{font-weight:700;color:var(--authrobo-title-fg);}\n.authrobo-divider{display:flex;align-items:center;gap:10px;color:var(--authrobo-divider-fg);font:500 12px system-ui,sans-serif;}\n.authrobo-divider::before,.authrobo-divider::after{content:\"\";height:1px;flex:1;background:var(--authrobo-divider-line);}\n.authrobo-tabs{display:flex;gap:4px;padding:4px;border:1px solid var(--authrobo-btn-border);\n background:var(--authrobo-tabs-bg);border-radius:10px;}\n.authrobo-tab{flex:1;border:0;background:transparent;border-radius:7px;padding:8px 0;cursor:pointer;\n font:600 13px system-ui,sans-serif;color:var(--authrobo-muted);transition:background .15s ease,color .15s ease;}\n.authrobo-tab:hover{color:var(--authrobo-title-fg);}\n.authrobo-tab[aria-selected=\"true\"]{background:var(--authrobo-accent);color:var(--authrobo-accent-fg);}\n.authrobo-tab:focus-visible{outline:2px solid var(--authrobo-focus);outline-offset:2px;}\n.authrobo-form{display:flex;flex-direction:column;gap:10px;}\n.authrobo-label{font:500 12.5px system-ui,sans-serif;color:var(--authrobo-muted);}\n.authrobo-input{width:100%;box-sizing:border-box;margin-top:6px;border:1px solid var(--authrobo-btn-border);\n background:var(--authrobo-input-bg);color:var(--authrobo-input-fg);border-radius:10px;padding:10px 12px;\n font:14px system-ui,sans-serif;}\n.authrobo-input:focus{outline:none;border-color:var(--authrobo-accent);}\n.authrobo-primary{display:flex;width:100%;align-items:center;justify-content:center;gap:8px;border:0;\n background:var(--authrobo-accent);color:var(--authrobo-accent-fg);border-radius:10px;padding:11px 14px;\n font:700 14px system-ui,sans-serif;cursor:pointer;transition:filter .15s ease;}\n.authrobo-primary:hover{filter:brightness(.96);}\n.authrobo-primary:focus-visible{outline:2px solid var(--authrobo-focus);outline-offset:2px;}\n.authrobo-primary:disabled{opacity:.7;cursor:default;}\n.authrobo-btn-brand{transition:filter .15s ease,box-shadow .15s ease;}\n.authrobo-btn-brand:hover{filter:brightness(.96);}\n.authrobo-spinner{display:inline-block;width:1.15em;height:1.15em;vertical-align:-0.2em;border-radius:50%;\n border:2px solid color-mix(in srgb, currentColor 24%, transparent);border-top-color:currentColor;\n animation:authrobo-spin .7s linear infinite;}\n.authrobo-loading{display:flex;align-items:center;justify-content:center;gap:10px;padding:20px 0;}\n@keyframes authrobo-spin{to{transform:rotate(360deg)}}\n@media (prefers-reduced-motion: reduce){.authrobo-spinner{animation-duration:1.4s}}\n.authrobo-overlay{position:fixed;inset:0;z-index:2147483000;display:flex;align-items:center;\n justify-content:center;padding:16px;background:var(--authrobo-overlay);backdrop-filter:blur(2px);\n animation:authrobo-fade .16s ease-out both;}\n.authrobo-card{position:relative;width:100%;max-width:360px;background:var(--authrobo-card-bg);border-radius:16px;\n padding:24px;box-shadow:0 20px 60px -12px var(--authrobo-card-shadow);animation:authrobo-pop .2s cubic-bezier(.16,1,.3,1) both;}\n.authrobo-close{position:absolute;top:12px;right:12px;border:0;background:transparent;cursor:pointer;\n color:var(--authrobo-close);font-size:18px;line-height:1;padding:4px;}\n.authrobo-close:hover{color:var(--authrobo-close-hover);}\n@keyframes authrobo-fade{from{opacity:0}to{opacity:1}}\n@keyframes authrobo-pop{from{opacity:0;transform:translateY(8px) scale(.97)}to{opacity:1;transform:none}}\n@media (prefers-reduced-motion: reduce){.authrobo-overlay,.authrobo-card{animation:none}}\n`;\n\nfunction useInjectStyles() {\n useEffect(() => {\n if (typeof document === \"undefined\" || document.getElementById(STYLE_ID)) return;\n const el = document.createElement(\"style\");\n el.id = STYLE_ID;\n el.textContent = CSS;\n document.head.appendChild(el);\n }, []);\n}\n\n/** A theme-aware loading spinner. Colour follows the surrounding text (currentColor). */\nexport function Spinner({ style, className }: { style?: React.CSSProperties; className?: string }) {\n return (\n <span\n className={className ? `authrobo-spinner ${className}` : \"authrobo-spinner\"}\n role=\"status\"\n aria-label=\"Loading\"\n style={style}\n />\n );\n}\n\n/* ----------------------------- Button ----------------------------------- */\n\nexport function AuthRoboButton({\n provider,\n config,\n label,\n className,\n style,\n onClick,\n lastUsed,\n startPath,\n buttonStyle = \"neutral\",\n}: {\n provider: Method;\n config?: AuthRoboConfig;\n label?: string;\n className?: string;\n style?: React.CSSProperties;\n onClick?: () => void;\n /** Show a \"Last used\" badge (the method the visitor signed in with before). */\n lastUsed?: boolean;\n /** Proxy the redirect through your own server (see StartOptions.startPath). */\n startPath?: string;\n /** \"neutral\" (default) or \"branded\" (provider-coloured button). */\n buttonStyle?: ButtonStyle;\n}) {\n useInjectStyles();\n const c = useResolvedConfig(config);\n const meta = PROVIDER_META[provider];\n const brand = buttonStyle === \"branded\" ? BRAND_STYLE[provider] : undefined;\n const icon = brand?.whiteIcon ? WHITE_MARKS[provider] ?? meta.icon : meta.icon;\n\n const classes = [\"authrobo-btn\", brand ? \"authrobo-btn-brand\" : \"\", className]\n .filter(Boolean)\n .join(\" \");\n const brandStyle: React.CSSProperties | undefined = brand\n ? { background: brand.bg, color: brand.fg, borderColor: brand.border }\n : undefined;\n\n return (\n <button\n type=\"button\"\n className={classes}\n style={{ ...brandStyle, ...style }}\n onClick={() => {\n onClick?.();\n startSignIn(c, provider, { startPath });\n }}\n >\n <span style={{ display: \"inline-flex\", alignItems: \"center\" }}>{icon}</span>\n {label ?? `Continue with ${meta.label}`}\n {lastUsed && <span className=\"authrobo-last\">Last used</span>}\n </button>\n );\n}\n\n/* ---------------------- Email switcher (tabs) --------------------------- */\n\n// Tab order is fixed: Magic Link first, then Register, then Login. Each tab is\n// filtered in only if its underlying method is enabled for the app. Every tab\n// collects exactly the fields that flow needs:\n// • Magic Link → email (a one-time link is emailed)\n// • Register → name + email + password (creates the account)\n// • Login → email + password\nconst EMAIL_TABS: {\n key: Screen;\n method: Method;\n label: string;\n cta: string;\n requires: Method;\n fields: { name: boolean; password: boolean };\n /** Server endpoint (relative to startPath) for the proxied JSON POST. */\n proxyPath: string;\n}[] = [\n { key: \"magic\", method: \"magic_link\", label: \"Magic Link\", cta: \"Email me a link\", requires: \"magic_link\", fields: { name: false, password: false }, proxyPath: \"magic\" },\n { key: \"register\", method: \"password\", label: \"Register\", cta: \"Create account\", requires: \"password\", fields: { name: true, password: true }, proxyPath: \"register\" },\n { key: \"login\", method: \"password\", label: \"Login\", cta: \"Sign in\", requires: \"password\", fields: { name: false, password: true }, proxyPath: \"login\" },\n];\n\n/**\n * The email tabs (Magic Link / Register / Login).\n *\n * Two submission modes:\n * - **Direct** (no `startPath`): a native cross-origin form POST straight to\n * AuthRobo — `authorize` for password login/register (→ returns to your\n * `redirectUri` with a one-time code your backend exchanges), or `magic/start`\n * for the link. Credentials go to AuthRobo, never to your own server.\n * - **Proxied** (`startPath` set): a same-origin JSON POST to\n * `${startPath}/{login|register|magic}` on YOUR server, which forwards to\n * AuthRobo and sets your httpOnly session cookies. On success `onSuccess()`\n * fires (no full-page redirect), so it slots into an existing modal.\n */\nfunction EmailSwitcher({\n config,\n methods,\n startPath,\n onSuccess,\n}: {\n config: AuthRoboConfig;\n methods: Method[];\n startPath?: string;\n onSuccess?: () => void;\n}) {\n const tabs = useMemo(() => EMAIL_TABS.filter((t) => methods.includes(t.requires)), [methods]);\n const [active, setActive] = useState<Screen>(tabs[0]?.key ?? \"login\");\n const [name, setName] = useState(\"\");\n const [email, setEmail] = useState(\"\");\n const [password, setPassword] = useState(\"\");\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [sent, setSent] = useState(false);\n const stateRef = useRef<HTMLInputElement>(null);\n const proxy = !!startPath;\n\n // Keep the active tab valid if the enabled set changes under us.\n useEffect(() => {\n if (tabs.length && !tabs.some((t) => t.key === active)) setActive(tabs[0].key);\n }, [tabs, active]);\n\n if (!tabs.length) return null;\n const current = tabs.find((t) => t.key === active) ?? tabs[0];\n const base = config.issuerUrl.replace(/\\/$/, \"\");\n const directAction =\n current.key === \"magic\" ? `${base}/api/v1/auth/magic/start` : `${base}/api/v1/auth/authorize`;\n\n const selectTab = (key: Screen) => {\n setActive(key);\n setError(null);\n setSent(false);\n };\n\n // Proxied mode: JSON POST to the app's own route, then hand back to the host.\n async function proxySubmit(e: React.FormEvent) {\n e.preventDefault();\n setError(null);\n setLoading(true);\n try {\n const body: Record<string, string> = { email: email.trim() };\n if (current.fields.password) body.password = password;\n if (current.fields.name && name.trim()) body.name = name.trim();\n const res = await fetch(`${startPath!.replace(/\\/$/, \"\")}/${current.proxyPath}`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n if (!res.ok) {\n const d = (await res.json().catch(() => ({}))) as { error?: string };\n throw new Error(d?.error || \"Something went wrong. Please try again.\");\n }\n try {\n localStorage.setItem(lastMethodKey(config.clientId), current.method);\n } catch {\n /* ignore */\n }\n if (current.key === \"magic\") setSent(true);\n else onSuccess?.();\n } catch (err) {\n setError(err instanceof Error ? err.message : \"Something went wrong.\");\n } finally {\n setLoading(false);\n }\n }\n\n // Direct mode: stamp a fresh CSRF state into the hidden field + sessionStorage,\n // then let the browser perform the native cross-origin form POST to AuthRobo.\n function directSubmit() {\n const s = randomState();\n try {\n sessionStorage.setItem(\"authrobo:state\", s);\n } catch {\n /* storage unavailable */\n }\n if (stateRef.current) stateRef.current.value = s;\n try {\n localStorage.setItem(lastMethodKey(config.clientId), current.method);\n } catch {\n /* ignore */\n }\n setLoading(true); // page is about to navigate away\n }\n\n if (sent) {\n return (\n <div className=\"authrobo-stack\" role=\"status\">\n <p className=\"authrobo-title\">Check your email</p>\n <p className=\"authrobo-muted\">\n We sent a sign-in link to <b>{email.trim()}</b>. It works once and expires shortly.\n </p>\n </div>\n );\n }\n\n return (\n <div className=\"authrobo-stack\">\n {tabs.length > 1 && (\n <div className=\"authrobo-tabs\" role=\"tablist\" aria-label=\"Sign-in method\">\n {tabs.map((t) => (\n <button\n key={t.key}\n type=\"button\"\n role=\"tab\"\n aria-selected={current.key === t.key}\n className=\"authrobo-tab\"\n onClick={() => selectTab(t.key)}\n >\n {t.label}\n </button>\n ))}\n </div>\n )}\n <form\n className=\"authrobo-form\"\n method={proxy ? undefined : \"post\"}\n action={proxy ? undefined : directAction}\n onSubmit={proxy ? proxySubmit : directSubmit}\n >\n {!proxy && (\n <>\n <input type=\"hidden\" name=\"client_id\" value={config.clientId} />\n <input type=\"hidden\" name=\"redirect_uri\" value={config.redirectUri} />\n <input type=\"hidden\" name=\"state\" ref={stateRef} />\n {current.key !== \"magic\" && (\n <input type=\"hidden\" name=\"mode\" value={current.key === \"register\" ? \"register\" : \"login\"} />\n )}\n </>\n )}\n\n {current.fields.name && (\n <label className=\"authrobo-label\">\n Name\n <input\n className=\"authrobo-input\"\n name=\"name\"\n type=\"text\"\n autoComplete=\"name\"\n placeholder=\"Your name\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n />\n </label>\n )}\n <label className=\"authrobo-label\">\n Email\n <input\n className=\"authrobo-input\"\n name=\"email\"\n type=\"email\"\n required\n autoComplete=\"email\"\n placeholder=\"you@example.com\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n />\n </label>\n {current.fields.password && (\n <label className=\"authrobo-label\">\n Password\n <input\n className=\"authrobo-input\"\n name=\"password\"\n type=\"password\"\n required\n minLength={current.key === \"register\" ? 8 : undefined}\n autoComplete={current.key === \"register\" ? \"new-password\" : \"current-password\"}\n placeholder={current.key === \"register\" ? \"At least 8 characters\" : \"Your password\"}\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n />\n </label>\n )}\n\n {error && <p className=\"authrobo-error\">{error}</p>}\n\n <button type=\"submit\" className=\"authrobo-primary\" disabled={loading}>\n {loading ? (\n <>\n <Spinner /> Please wait…\n </>\n ) : (\n current.cta\n )}\n </button>\n </form>\n </div>\n );\n}\n\n/* ---------------------- Auth modal / inline panel ----------------------- */\n\nexport function AuthRoboAuth({\n config,\n mode = \"inline\",\n open = true,\n onClose,\n onSuccess,\n title,\n showHeader = true,\n methods: only,\n startPath,\n buttonStyle = \"neutral\",\n}: {\n config?: AuthRoboConfig;\n /** \"inline\" renders in place; \"modal\" renders a centered overlay. */\n mode?: \"inline\" | \"modal\";\n /** Only used in modal mode. */\n open?: boolean;\n onClose?: () => void;\n /**\n * Fires after a successful proxied (startPath) password login/register — the\n * session cookies are set and no page redirect happened, so refresh your auth\n * state and close the modal here. Not called for social/magic or direct mode\n * (those navigate the page).\n */\n onSuccess?: () => void;\n /** Heading; defaults to \"Sign in to <app name>\". */\n title?: string;\n /** Render the logo + title row. Set false when the host supplies its own heading. */\n showHeader?: boolean;\n /** Restrict/reorder which methods to show (defaults to all enabled ones). */\n methods?: Method[];\n /** Proxy every redirect through your own server (see StartOptions.startPath). */\n startPath?: string;\n /** \"neutral\" (default) or \"branded\" social buttons. */\n buttonStyle?: ButtonStyle;\n}) {\n useInjectStyles();\n const c = useResolvedConfig(config);\n const { data, loading, error } = useAppConfig(c);\n const lastMethod = useLastMethod(c.clientId);\n\n useEffect(() => {\n if (mode !== \"modal\" || !open) return;\n const onKey = (e: KeyboardEvent) => e.key === \"Escape\" && onClose?.();\n document.addEventListener(\"keydown\", onKey);\n return () => document.removeEventListener(\"keydown\", onKey);\n }, [mode, open, onClose]);\n\n if (mode === \"modal\" && !open) return null;\n\n const available = data?.methods ?? [];\n const shown = (only ? only.filter((m) => available.includes(m)) : available).filter(\n (m) => m in PROVIDER_META,\n );\n const social = shown.filter((m) => !EMAIL_METHODS.includes(m));\n const email = shown.filter((m) => EMAIL_METHODS.includes(m));\n // Only worth pointing out the last-used method when there's a choice to make.\n const badge = (m: Method) => shown.length > 1 && m === lastMethod;\n\n const panel = (\n <div className=\"authrobo-stack\">\n {showHeader && (data?.logoUrl || data?.name) && (\n <div style={{ display: \"flex\", alignItems: \"center\", gap: 10, marginBottom: 4 }}>\n {data?.logoUrl && (\n <img src={data.logoUrl} alt=\"\" width={28} height={28} style={{ borderRadius: 6 }} />\n )}\n <span className=\"authrobo-title\">\n {title ?? `Sign in${data?.name ? ` to ${data.name}` : \"\"}`}\n </span>\n </div>\n )}\n\n {loading && (\n <div className=\"authrobo-loading\">\n <Spinner style={{ color: \"var(--authrobo-accent)\" }} />\n <span className=\"authrobo-muted\">Loading sign-in options…</span>\n </div>\n )}\n {error && <p className=\"authrobo-error\">Couldn&apos;t load sign-in options.</p>}\n\n {social.map((m) => (\n <AuthRoboButton\n key={m}\n provider={m}\n config={c}\n lastUsed={badge(m)}\n startPath={startPath}\n buttonStyle={buttonStyle}\n />\n ))}\n\n {email.length > 0 && social.length > 0 && <div className=\"authrobo-divider\">or</div>}\n\n {email.length > 0 && (\n <EmailSwitcher config={c} methods={email} startPath={startPath} onSuccess={onSuccess} />\n )}\n\n {!loading && !error && shown.length === 0 && (\n <p className=\"authrobo-muted\">No sign-in methods are enabled for this app.</p>\n )}\n\n {!loading && !error && data?.poweredBy && (\n <a className=\"authrobo-powered\" href=\"https://authrobo.com\" target=\"_blank\" rel=\"noreferrer\">\n Authentication provided by <b>AuthRobo</b>\n </a>\n )}\n </div>\n );\n\n if (mode === \"inline\") return panel;\n\n return (\n <div className=\"authrobo-overlay\" onClick={() => onClose?.()}>\n <div className=\"authrobo-card\" role=\"dialog\" aria-modal=\"true\" onClick={(e) => e.stopPropagation()}>\n <button type=\"button\" className=\"authrobo-close\" aria-label=\"Close\" onClick={() => onClose?.()}>\n ✕\n </button>\n {panel}\n </div>\n </div>\n );\n}\n","import * as React from \"react\";\n\n// Sign-in methods AuthRobo can surface. \"password\" and \"magic_link\" route to\n// the hosted email login page; the rest are social OAuth providers.\nexport type Method =\n | \"google\"\n | \"linkedin\"\n | \"github\"\n | \"apple\"\n | \"facebook\"\n | \"password\"\n | \"magic_link\";\n\nconst sz = { width: 18, height: 18, \"aria-hidden\": true } as const;\n\n// Single-colour brand glyphs share one path so we can also render a white\n// variant (for branded buttons whose background is the brand colour).\nconst LINKEDIN_PATH =\n \"M20.45 20.45h-3.56v-5.57c0-1.33-.02-3.04-1.85-3.04-1.85 0-2.13 1.45-2.13 2.94v5.67H9.35V9h3.41v1.56h.05c.48-.9 1.64-1.85 3.37-1.85 3.6 0 4.27 2.37 4.27 5.45v6.29zM5.34 7.43a2.06 2.06 0 1 1 0-4.13 2.06 2.06 0 0 1 0 4.13zM7.12 20.45H3.56V9h3.56v11.45zM22.22 0H1.77C.79 0 0 .77 0 1.72v20.56C0 23.23.79 24 1.77 24h20.45c.98 0 1.78-.77 1.78-1.72V1.72C24 .77 23.2 0 22.22 0z\";\nconst GITHUB_PATH =\n \"M12 .3a12 12 0 0 0-3.8 23.4c.6.1.8-.3.8-.6v-2c-3.3.7-4-1.6-4-1.6-.6-1.4-1.3-1.8-1.3-1.8-1.1-.7.1-.7.1-.7 1.2.1 1.8 1.2 1.8 1.2 1.1 1.8 2.8 1.3 3.5 1 .1-.8.4-1.3.8-1.6-2.7-.3-5.5-1.3-5.5-6a4.7 4.7 0 0 1 1.2-3.2c-.1-.3-.5-1.5.1-3.2 0 0 1-.3 3.3 1.2a11.5 11.5 0 0 1 6 0c2.3-1.5 3.3-1.2 3.3-1.2.6 1.7.2 2.9.1 3.2a4.7 4.7 0 0 1 1.2 3.2c0 4.7-2.8 5.7-5.5 6 .4.4.8 1.1.8 2.2v3.3c0 .3.2.7.8.6A12 12 0 0 0 12 .3\";\nconst APPLE_PATH =\n \"M17.05 12.04c-.03-2.7 2.2-4 2.3-4.06-1.25-1.84-3.2-2.09-3.9-2.12-1.66-.17-3.24.98-4.08.98-.84 0-2.14-.96-3.52-.93-1.81.03-3.48 1.05-4.41 2.67-1.88 3.27-.48 8.1 1.35 10.76.9 1.3 1.97 2.76 3.38 2.71 1.36-.05 1.87-.88 3.51-.88 1.64 0 2.1.88 3.53.85 1.46-.03 2.38-1.33 3.27-2.63 1.03-1.51 1.46-2.97 1.48-3.05-.03-.01-2.84-1.09-2.87-4.32M14.4 4.2c.74-.9 1.24-2.15 1.1-3.4-1.07.04-2.36.71-3.13 1.61-.69.8-1.29 2.07-1.13 3.29 1.19.09 2.41-.61 3.16-1.5\";\nconst FACEBOOK_PATH =\n \"M24 12.07C24 5.4 18.63 0 12 0S0 5.4 0 12.07C0 18.1 4.39 23.1 10.13 24v-8.44H7.08v-3.49h3.05V9.41c0-3.02 1.79-4.69 4.53-4.69 1.31 0 2.68.24 2.68.24v2.97h-1.51c-1.49 0-1.95.93-1.95 1.88v2.26h3.32l-.53 3.49h-2.79V24C19.61 23.1 24 18.1 24 12.07\";\n\nfunction Glyph({ d, fill }: { d: string; fill: string }) {\n return (\n <svg viewBox=\"0 0 24 24\" {...sz} fill={fill}>\n <path d={d} />\n </svg>\n );\n}\n\nfunction GoogleIcon() {\n return (\n <svg viewBox=\"0 0 48 48\" {...sz}>\n <path fill=\"#FFC107\" d=\"M43.6 20.5H42V20H24v8h11.3C33.7 32.9 29.3 36 24 36c-6.6 0-12-5.4-12-12s5.4-12 12-12c3.1 0 5.9 1.2 8 3.1l5.7-5.7C34.6 6.1 29.6 4 24 4 12.9 4 4 12.9 4 24s8.9 20 20 20 20-8.9 20-20c0-1.3-.1-2.3-.4-3.5z\" />\n <path fill=\"#FF3D00\" d=\"M6.3 14.7l6.6 4.8C14.7 16 19 13 24 13c3.1 0 5.9 1.2 8 3.1l5.7-5.7C34.6 6.1 29.6 4 24 4 16.3 4 9.7 8.3 6.3 14.7z\" />\n <path fill=\"#4CAF50\" d=\"M24 44c5.2 0 10-2 13.6-5.2l-6.3-5.2C29.2 35 26.7 36 24 36c-5.3 0-9.7-3.4-11.3-8.1l-6.5 5C9.5 39.6 16.2 44 24 44z\" />\n <path fill=\"#1976D2\" d=\"M43.6 20.5H42V20H24v8h11.3c-.8 2.2-2.2 4.1-4.1 5.6l6.3 5.2C41.9 36 44 30.5 44 24c0-1.3-.1-2.3-.4-3.5z\" />\n </svg>\n );\n}\n\nfunction MailIcon() {\n return (\n <svg viewBox=\"0 0 24 24\" {...sz} fill=\"none\" stroke=\"#334155\" strokeWidth={2} strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"5\" width=\"18\" height=\"14\" rx=\"2\" />\n <path d=\"m3 7 9 6 9-6\" />\n </svg>\n );\n}\n\nexport const PROVIDER_META: Record<Method, { label: string; icon: React.ReactNode }> = {\n google: { label: \"Google\", icon: <GoogleIcon /> },\n linkedin: { label: \"LinkedIn\", icon: <Glyph d={LINKEDIN_PATH} fill=\"#0A66C2\" /> },\n github: { label: \"GitHub\", icon: <Glyph d={GITHUB_PATH} fill=\"#181717\" /> },\n apple: { label: \"Apple\", icon: <Glyph d={APPLE_PATH} fill=\"#000\" /> },\n facebook: { label: \"Facebook\", icon: <Glyph d={FACEBOOK_PATH} fill=\"#1877F2\" /> },\n password: { label: \"email\", icon: <MailIcon /> },\n magic_link: { label: \"magic link\", icon: <MailIcon /> },\n};\n\n// White glyph variants — used by branded buttons whose background is the brand\n// colour (so a monochrome mark stays legible). Google keeps its multicolour mark.\nexport const WHITE_MARKS: Partial<Record<Method, React.ReactNode>> = {\n linkedin: <Glyph d={LINKEDIN_PATH} fill=\"#fff\" />,\n github: <Glyph d={GITHUB_PATH} fill=\"#fff\" />,\n apple: <Glyph d={APPLE_PATH} fill=\"#fff\" />,\n facebook: <Glyph d={FACEBOOK_PATH} fill=\"#fff\" />,\n};\n\n// Fully-branded button palette: background / text / border per provider. Used\n// when <AuthRoboAuth buttonStyle=\"branded\"> (or <AuthRoboButton buttonStyle=…>).\nexport const BRAND_STYLE: Partial<Record<Method, { bg: string; fg: string; border: string; whiteIcon?: boolean }>> = {\n google: { bg: \"#ffffff\", fg: \"#1a73e8\", border: \"#dadce0\" },\n linkedin: { bg: \"#0a66c2\", fg: \"#ffffff\", border: \"#0a66c2\", whiteIcon: true },\n github: { bg: \"#181717\", fg: \"#ffffff\", border: \"#181717\", whiteIcon: true },\n apple: { bg: \"#000000\", fg: \"#ffffff\", border: \"#000000\", whiteIcon: true },\n facebook: { bg: \"#1877f2\", fg: \"#ffffff\", border: \"#1877f2\", whiteIcon: true },\n};\n"],"mappings":";;;;AAGA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;;;ACiBD,cAOF,YAPE;AAhBN,IAAM,KAAK,EAAE,OAAO,IAAI,QAAQ,IAAI,eAAe,KAAK;AAIxD,IAAM,gBACJ;AACF,IAAM,cACJ;AACF,IAAM,aACJ;AACF,IAAM,gBACJ;AAEF,SAAS,MAAM,EAAE,GAAG,KAAK,GAAgC;AACvD,SACE,oBAAC,SAAI,SAAQ,aAAa,GAAG,IAAI,MAC/B,8BAAC,UAAK,GAAM,GACd;AAEJ;AAEA,SAAS,aAAa;AACpB,SACE,qBAAC,SAAI,SAAQ,aAAa,GAAG,IAC3B;AAAA,wBAAC,UAAK,MAAK,WAAU,GAAE,0MAAyM;AAAA,IAChO,oBAAC,UAAK,MAAK,WAAU,GAAE,mHAAkH;AAAA,IACzI,oBAAC,UAAK,MAAK,WAAU,GAAE,oHAAmH;AAAA,IAC1I,oBAAC,UAAK,MAAK,WAAU,GAAE,yGAAwG;AAAA,KACjI;AAEJ;AAEA,SAAS,WAAW;AAClB,SACE,qBAAC,SAAI,SAAQ,aAAa,GAAG,IAAI,MAAK,QAAO,QAAO,WAAU,aAAa,GAAG,eAAc,SAAQ,gBAAe,SACjH;AAAA,wBAAC,UAAK,GAAE,KAAI,GAAE,KAAI,OAAM,MAAK,QAAO,MAAK,IAAG,KAAI;AAAA,IAChD,oBAAC,UAAK,GAAE,gBAAe;AAAA,KACzB;AAEJ;AAEO,IAAM,gBAA0E;AAAA,EACrF,QAAQ,EAAE,OAAO,UAAU,MAAM,oBAAC,cAAW,EAAG;AAAA,EAChD,UAAU,EAAE,OAAO,YAAY,MAAM,oBAAC,SAAM,GAAG,eAAe,MAAK,WAAU,EAAG;AAAA,EAChF,QAAQ,EAAE,OAAO,UAAU,MAAM,oBAAC,SAAM,GAAG,aAAa,MAAK,WAAU,EAAG;AAAA,EAC1E,OAAO,EAAE,OAAO,SAAS,MAAM,oBAAC,SAAM,GAAG,YAAY,MAAK,QAAO,EAAG;AAAA,EACpE,UAAU,EAAE,OAAO,YAAY,MAAM,oBAAC,SAAM,GAAG,eAAe,MAAK,WAAU,EAAG;AAAA,EAChF,UAAU,EAAE,OAAO,SAAS,MAAM,oBAAC,YAAS,EAAG;AAAA,EAC/C,YAAY,EAAE,OAAO,cAAc,MAAM,oBAAC,YAAS,EAAG;AACxD;AAIO,IAAM,cAAwD;AAAA,EACnE,UAAU,oBAAC,SAAM,GAAG,eAAe,MAAK,QAAO;AAAA,EAC/C,QAAQ,oBAAC,SAAM,GAAG,aAAa,MAAK,QAAO;AAAA,EAC3C,OAAO,oBAAC,SAAM,GAAG,YAAY,MAAK,QAAO;AAAA,EACzC,UAAU,oBAAC,SAAM,GAAG,eAAe,MAAK,QAAO;AACjD;AAIO,IAAM,cAAwG;AAAA,EACnH,QAAQ,EAAE,IAAI,WAAW,IAAI,WAAW,QAAQ,UAAU;AAAA,EAC1D,UAAU,EAAE,IAAI,WAAW,IAAI,WAAW,QAAQ,WAAW,WAAW,KAAK;AAAA,EAC7E,QAAQ,EAAE,IAAI,WAAW,IAAI,WAAW,QAAQ,WAAW,WAAW,KAAK;AAAA,EAC3E,OAAO,EAAE,IAAI,WAAW,IAAI,WAAW,QAAQ,WAAW,WAAW,KAAK;AAAA,EAC1E,UAAU,EAAE,IAAI,WAAW,IAAI,WAAW,QAAQ,WAAW,WAAW,KAAK;AAC/E;;;ADjBS,SAohBC,UAphBD,OAAAA,MAmWL,QAAAC,aAnWK;AAfT,IAAM,gBAAgB,cAAqC,IAAI;AAExD,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AACF,GAGG;AAID,YAAU,MAAM;AACd,sBAAkB,MAAM;AAAA,EAC1B,GAAG,CAAC,OAAO,WAAW,OAAO,QAAQ,CAAC;AACtC,SAAO,gBAAAD,KAAC,cAAc,UAAd,EAAuB,OAAO,QAAS,UAAS;AAC1D;AAEA,SAAS,kBAAkB,UAA2C;AACpE,QAAM,MAAM,WAAW,aAAa;AACpC,QAAM,IAAI,YAAY;AACtB,MAAI,CAAC,GAAG;AACN,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,cAAsB;AAC7B,QAAM,IAAI,IAAI,WAAW,EAAE;AAC3B,GAAC,WAAW,UAAW,WAAkC,QAAQ,gBAAgB,CAAC;AAClF,SAAO,MAAM,KAAK,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAAE,KAAK,EAAE;AACtE;AAIA,IAAM,gBAAmC,CAAC,YAAY,YAAY;AAgC3D,SAAS,YAAY,QAAwB,QAAgB,MAA2B;AAE7F,MAAI;AACF,iBAAa,QAAQ,cAAc,OAAO,QAAQ,GAAG,MAAM;AAAA,EAC7D,QAAQ;AAAA,EAER;AAIA,MAAI,MAAM,WAAW;AACnB,UAAM,IAAI,IAAI,gBAAgB;AAC9B,QAAI,KAAK,UAAW,GAAE,IAAI,cAAc,KAAK,SAAS;AACtD,QAAI,KAAK,OAAQ,GAAE,IAAI,UAAU,KAAK,MAAM;AAC5C,UAAM,KAAK,EAAE,SAAS;AACtB,WAAO,SAAS,OAAO,GAAG,KAAK,UAAU,QAAQ,OAAO,EAAE,CAAC,IAAI,MAAM,SAAS,KAAK,IAAI,EAAE,KAAK,EAAE,EAAE;AAClG;AAAA,EACF;AAEA,QAAM,OAAO,OAAO,UAAU,QAAQ,OAAO,EAAE;AAC/C,QAAM,QAAQ,MAAM,SAAS,YAAY;AACzC,MAAI;AACF,mBAAe,QAAQ,kBAAkB,KAAK;AAAA,EAChD,QAAQ;AAAA,EAER;AACA,QAAM,SAAS,IAAI,gBAAgB;AAAA,IACjC,WAAW,OAAO;AAAA,IAClB,cAAc,OAAO;AAAA,IACrB;AAAA,EACF,CAAC;AACD,MAAI,MAAM,UAAW,QAAO,IAAI,cAAc,KAAK,SAAS;AAE5D,MAAI;AACJ,MAAI,WAAW,cAAc;AAC3B,WAAO,IAAI,UAAU,OAAO;AAC5B,WAAO;AAAA,EACT,WAAW,WAAW,YAAY;AAChC,WAAO,MAAM,WAAW,aAAa,cAAc;AAAA,EACrD,OAAO;AACL,WAAO,gBAAgB,MAAM;AAAA,EAC/B;AACA,SAAO,SAAS,OAAO,GAAG,IAAI,GAAG,IAAI,IAAI,OAAO,SAAS,CAAC,EAAE;AAC9D;AAEA,IAAM,gBAAgB,CAAC,aAAqB,wBAAwB,QAAQ;AAGrE,SAAS,cAAc,UAAiC;AAC7D,QAAM,CAAC,MAAM,OAAO,IAAI,SAAwB,IAAI;AACpD,YAAU,MAAM;AACd,QAAI;AACF,cAAS,aAAa,QAAQ,cAAc,QAAQ,CAAC,KAAuB,IAAI;AAAA,IAClF,QAAQ;AAAA,IAER;AAAA,EACF,GAAG,CAAC,QAAQ,CAAC;AACb,SAAO;AACT;AASA,IAAM,gBAA6B,EAAE,MAAM,MAAM,SAAS,MAAM,OAAO,KAAK;AAI5E,IAAM,cAAc,oBAAI,IAAyB;AACjD,IAAM,YAAY,CAAC,MAAsB,GAAG,EAAE,UAAU,QAAQ,OAAO,EAAE,CAAC,IAAI,EAAE,QAAQ;AAExF,SAAS,YAAY,KAA0B;AAC7C,MAAI,IAAI,YAAY,IAAI,GAAG;AAC3B,MAAI,CAAC,GAAG;AACN,QAAI,EAAE,OAAO,eAAe,WAAW,oBAAI,IAAI,EAAE;AACjD,gBAAY,IAAI,KAAK,CAAC;AAAA,EACxB;AACA,SAAO;AACT;AAOO,SAAS,kBAAkB,QAAuC;AACvE,MAAI,OAAO,WAAW,YAAa,QAAO,QAAQ,QAAQ;AAC1D,QAAM,MAAM,UAAU,MAAM;AAC5B,QAAM,IAAI,YAAY,GAAG;AACzB,MAAI,EAAE,MAAM,QAAQ,EAAE,QAAS,QAAO,EAAE,WAAW,QAAQ,QAAQ;AACnE,QAAM,OAAO,OAAO,UAAU,QAAQ,OAAO,EAAE;AAC/C,IAAE,UAAU,MAAM,GAAG,IAAI,4BAA4B,mBAAmB,OAAO,QAAQ,CAAC,EAAE,EACvF,KAAK,CAAC,MAAO,EAAE,KAAK,EAAE,KAAK,IAAI,QAAQ,OAAO,IAAI,MAAM,UAAU,EAAE,MAAM,EAAE,CAAC,CAAE,EAC/E,KAAK,CAAC,MAAM;AACX,MAAE,QAAQ;AAAA,MACR,MAAM,EAAE,MAAM,EAAE,MAAM,YAAY,EAAE,aAAa,SAAS,EAAE,UAAU,SAAS,EAAE,SAAS,WAAW,EAAE,eAAe,MAAM;AAAA,MAC5H,SAAS;AAAA,MACT,OAAO;AAAA,IACT;AAAA,EACF,CAAC,EACA,MAAM,CAAC,QAAQ;AACd,MAAE,QAAQ,EAAE,MAAM,MAAM,SAAS,OAAO,OAAO,OAAO,KAAK,WAAW,GAAG,EAAE;AAAA,EAC7E,CAAC,EACA,QAAQ,MAAM;AACb,MAAE,UAAU;AACZ,MAAE,UAAU,QAAQ,CAAC,MAAM,EAAE,CAAC;AAAA,EAChC,CAAC;AACH,SAAO,EAAE;AACX;AAGO,SAAS,aAAa,QAAsC;AACjE,QAAM,IAAI,kBAAkB,MAAM;AAClC,QAAM,MAAM,UAAU,CAAC;AAEvB,QAAM,YAAY;AAAA,IAChB,CAAC,OAAmB;AAClB,YAAM,IAAI,YAAY,GAAG;AACzB,QAAE,UAAU,IAAI,EAAE;AAClB,aAAO,MAAM;AACX,UAAE,UAAU,OAAO,EAAE;AAAA,MACvB;AAAA,IACF;AAAA,IACA,CAAC,GAAG;AAAA,EACN;AACA,QAAM,cAAc,YAAY,MAAM,YAAY,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC;AACnE,QAAM,QAAQ,qBAAqB,WAAW,aAAa,MAAM,aAAa;AAG9E,YAAU,MAAM;AACd,sBAAkB,CAAC;AAAA,EACrB,GAAG,CAAC,EAAE,WAAW,EAAE,QAAQ,CAAC;AAE5B,SAAO;AACT;AAIA,IAAM,WAAW;AAMjB,IAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUrB,IAAM,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWpB,IAAM,cACJ;AACF,IAAM,SAAS,CAAC,QAAgB,WAC9B,YAAY,MAAM,GAAG,EAClB,IAAI,CAAC,MAAM,GAAG,MAAM,GAAG,EAAE,KAAK,CAAC,EAAE,EACjC,KAAK,GAAG,IAAI,IAAI,MAAM;AAE3B,IAAM,MAAM;AAAA,EACV,OAAO,IAAI,YAAY,CAAC;AAAA,qCACW,OAAO,IAAI,WAAW,CAAC;AAAA,EAC1D,OAAO,yBAAyB,YAAY,CAAC;AAAA,EAC7C,OAAO,wBAAwB,WAAW,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4D7C,SAAS,kBAAkB;AACzB,YAAU,MAAM;AACd,QAAI,OAAO,aAAa,eAAe,SAAS,eAAe,QAAQ,EAAG;AAC1E,UAAM,KAAK,SAAS,cAAc,OAAO;AACzC,OAAG,KAAK;AACR,OAAG,cAAc;AACjB,aAAS,KAAK,YAAY,EAAE;AAAA,EAC9B,GAAG,CAAC,CAAC;AACP;AAGO,SAAS,QAAQ,EAAE,OAAO,UAAU,GAAwD;AACjG,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,YAAY,oBAAoB,SAAS,KAAK;AAAA,MACzD,MAAK;AAAA,MACL,cAAW;AAAA,MACX;AAAA;AAAA,EACF;AAEJ;AAIO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAChB,GAaG;AACD,kBAAgB;AAChB,QAAM,IAAI,kBAAkB,MAAM;AAClC,QAAM,OAAO,cAAc,QAAQ;AACnC,QAAM,QAAQ,gBAAgB,YAAY,YAAY,QAAQ,IAAI;AAClE,QAAM,OAAO,OAAO,YAAY,YAAY,QAAQ,KAAK,KAAK,OAAO,KAAK;AAE1E,QAAM,UAAU,CAAC,gBAAgB,QAAQ,uBAAuB,IAAI,SAAS,EAC1E,OAAO,OAAO,EACd,KAAK,GAAG;AACX,QAAM,aAA8C,QAChD,EAAE,YAAY,MAAM,IAAI,OAAO,MAAM,IAAI,aAAa,MAAM,OAAO,IACnE;AAEJ,SACE,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,WAAW;AAAA,MACX,OAAO,EAAE,GAAG,YAAY,GAAG,MAAM;AAAA,MACjC,SAAS,MAAM;AACb,kBAAU;AACV,oBAAY,GAAG,UAAU,EAAE,UAAU,CAAC;AAAA,MACxC;AAAA,MAEA;AAAA,wBAAAD,KAAC,UAAK,OAAO,EAAE,SAAS,eAAe,YAAY,SAAS,GAAI,gBAAK;AAAA,QACpE,SAAS,iBAAiB,KAAK,KAAK;AAAA,QACpC,YAAY,gBAAAA,KAAC,UAAK,WAAU,iBAAgB,uBAAS;AAAA;AAAA;AAAA,EACxD;AAEJ;AAUA,IAAM,aASA;AAAA,EACJ,EAAE,KAAK,SAAS,QAAQ,cAAc,OAAO,cAAc,KAAK,mBAAmB,UAAU,cAAc,QAAQ,EAAE,MAAM,OAAO,UAAU,MAAM,GAAG,WAAW,QAAQ;AAAA,EACxK,EAAE,KAAK,YAAY,QAAQ,YAAY,OAAO,YAAY,KAAK,kBAAkB,UAAU,YAAY,QAAQ,EAAE,MAAM,MAAM,UAAU,KAAK,GAAG,WAAW,WAAW;AAAA,EACrK,EAAE,KAAK,SAAS,QAAQ,YAAY,OAAO,SAAS,KAAK,WAAW,UAAU,YAAY,QAAQ,EAAE,MAAM,OAAO,UAAU,KAAK,GAAG,WAAW,QAAQ;AACxJ;AAeA,SAAS,cAAc;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,QAAM,OAAO,QAAQ,MAAM,WAAW,OAAO,CAAC,MAAM,QAAQ,SAAS,EAAE,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC;AAC5F,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAiB,KAAK,CAAC,GAAG,OAAO,OAAO;AACpE,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,EAAE;AACnC,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,EAAE;AACrC,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,EAAE;AAC3C,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,KAAK;AAC5C,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAwB,IAAI;AACtD,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,KAAK;AACtC,QAAM,WAAW,OAAyB,IAAI;AAC9C,QAAM,QAAQ,CAAC,CAAC;AAGhB,YAAU,MAAM;AACd,QAAI,KAAK,UAAU,CAAC,KAAK,KAAK,CAAC,MAAM,EAAE,QAAQ,MAAM,EAAG,WAAU,KAAK,CAAC,EAAE,GAAG;AAAA,EAC/E,GAAG,CAAC,MAAM,MAAM,CAAC;AAEjB,MAAI,CAAC,KAAK,OAAQ,QAAO;AACzB,QAAM,UAAU,KAAK,KAAK,CAAC,MAAM,EAAE,QAAQ,MAAM,KAAK,KAAK,CAAC;AAC5D,QAAM,OAAO,OAAO,UAAU,QAAQ,OAAO,EAAE;AAC/C,QAAM,eACJ,QAAQ,QAAQ,UAAU,GAAG,IAAI,6BAA6B,GAAG,IAAI;AAEvE,QAAM,YAAY,CAAC,QAAgB;AACjC,cAAU,GAAG;AACb,aAAS,IAAI;AACb,YAAQ,KAAK;AAAA,EACf;AAGA,iBAAe,YAAY,GAAoB;AAC7C,MAAE,eAAe;AACjB,aAAS,IAAI;AACb,eAAW,IAAI;AACf,QAAI;AACF,YAAM,OAA+B,EAAE,OAAO,MAAM,KAAK,EAAE;AAC3D,UAAI,QAAQ,OAAO,SAAU,MAAK,WAAW;AAC7C,UAAI,QAAQ,OAAO,QAAQ,KAAK,KAAK,EAAG,MAAK,OAAO,KAAK,KAAK;AAC9D,YAAM,MAAM,MAAM,MAAM,GAAG,UAAW,QAAQ,OAAO,EAAE,CAAC,IAAI,QAAQ,SAAS,IAAI;AAAA,QAC/E,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,IAAI;AAAA,MAC3B,CAAC;AACD,UAAI,CAAC,IAAI,IAAI;AACX,cAAM,IAAK,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AAC5C,cAAM,IAAI,MAAM,GAAG,SAAS,yCAAyC;AAAA,MACvE;AACA,UAAI;AACF,qBAAa,QAAQ,cAAc,OAAO,QAAQ,GAAG,QAAQ,MAAM;AAAA,MACrE,QAAQ;AAAA,MAER;AACA,UAAI,QAAQ,QAAQ,QAAS,SAAQ,IAAI;AAAA,UACpC,aAAY;AAAA,IACnB,SAAS,KAAK;AACZ,eAAS,eAAe,QAAQ,IAAI,UAAU,uBAAuB;AAAA,IACvE,UAAE;AACA,iBAAW,KAAK;AAAA,IAClB;AAAA,EACF;AAIA,WAAS,eAAe;AACtB,UAAM,IAAI,YAAY;AACtB,QAAI;AACF,qBAAe,QAAQ,kBAAkB,CAAC;AAAA,IAC5C,QAAQ;AAAA,IAER;AACA,QAAI,SAAS,QAAS,UAAS,QAAQ,QAAQ;AAC/C,QAAI;AACF,mBAAa,QAAQ,cAAc,OAAO,QAAQ,GAAG,QAAQ,MAAM;AAAA,IACrE,QAAQ;AAAA,IAER;AACA,eAAW,IAAI;AAAA,EACjB;AAEA,MAAI,MAAM;AACR,WACE,gBAAAC,MAAC,SAAI,WAAU,kBAAiB,MAAK,UACnC;AAAA,sBAAAD,KAAC,OAAE,WAAU,kBAAiB,8BAAgB;AAAA,MAC9C,gBAAAC,MAAC,OAAE,WAAU,kBAAiB;AAAA;AAAA,QACF,gBAAAD,KAAC,OAAG,gBAAM,KAAK,GAAE;AAAA,QAAI;AAAA,SACjD;AAAA,OACF;AAAA,EAEJ;AAEA,SACE,gBAAAC,MAAC,SAAI,WAAU,kBACZ;AAAA,SAAK,SAAS,KACb,gBAAAD,KAAC,SAAI,WAAU,iBAAgB,MAAK,WAAU,cAAW,kBACtD,eAAK,IAAI,CAAC,MACT,gBAAAA;AAAA,MAAC;AAAA;AAAA,QAEC,MAAK;AAAA,QACL,MAAK;AAAA,QACL,iBAAe,QAAQ,QAAQ,EAAE;AAAA,QACjC,WAAU;AAAA,QACV,SAAS,MAAM,UAAU,EAAE,GAAG;AAAA,QAE7B,YAAE;AAAA;AAAA,MAPE,EAAE;AAAA,IAQT,CACD,GACH;AAAA,IAEF,gBAAAC;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,QAAQ,QAAQ,SAAY;AAAA,QAC5B,QAAQ,QAAQ,SAAY;AAAA,QAC5B,UAAU,QAAQ,cAAc;AAAA,QAE/B;AAAA,WAAC,SACA,gBAAAA,MAAA,YACE;AAAA,4BAAAD,KAAC,WAAM,MAAK,UAAS,MAAK,aAAY,OAAO,OAAO,UAAU;AAAA,YAC9D,gBAAAA,KAAC,WAAM,MAAK,UAAS,MAAK,gBAAe,OAAO,OAAO,aAAa;AAAA,YACpE,gBAAAA,KAAC,WAAM,MAAK,UAAS,MAAK,SAAQ,KAAK,UAAU;AAAA,YAChD,QAAQ,QAAQ,WACf,gBAAAA,KAAC,WAAM,MAAK,UAAS,MAAK,QAAO,OAAO,QAAQ,QAAQ,aAAa,aAAa,SAAS;AAAA,aAE/F;AAAA,UAGD,QAAQ,OAAO,QACd,gBAAAC,MAAC,WAAM,WAAU,kBAAiB;AAAA;AAAA,YAEhC,gBAAAD;AAAA,cAAC;AAAA;AAAA,gBACC,WAAU;AAAA,gBACV,MAAK;AAAA,gBACL,MAAK;AAAA,gBACL,cAAa;AAAA,gBACb,aAAY;AAAA,gBACZ,OAAO;AAAA,gBACP,UAAU,CAAC,MAAM,QAAQ,EAAE,OAAO,KAAK;AAAA;AAAA,YACzC;AAAA,aACF;AAAA,UAEF,gBAAAC,MAAC,WAAM,WAAU,kBAAiB;AAAA;AAAA,YAEhC,gBAAAD;AAAA,cAAC;AAAA;AAAA,gBACC,WAAU;AAAA,gBACV,MAAK;AAAA,gBACL,MAAK;AAAA,gBACL,UAAQ;AAAA,gBACR,cAAa;AAAA,gBACb,aAAY;AAAA,gBACZ,OAAO;AAAA,gBACP,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,KAAK;AAAA;AAAA,YAC1C;AAAA,aACF;AAAA,UACC,QAAQ,OAAO,YACd,gBAAAC,MAAC,WAAM,WAAU,kBAAiB;AAAA;AAAA,YAEhC,gBAAAD;AAAA,cAAC;AAAA;AAAA,gBACC,WAAU;AAAA,gBACV,MAAK;AAAA,gBACL,MAAK;AAAA,gBACL,UAAQ;AAAA,gBACR,WAAW,QAAQ,QAAQ,aAAa,IAAI;AAAA,gBAC5C,cAAc,QAAQ,QAAQ,aAAa,iBAAiB;AAAA,gBAC5D,aAAa,QAAQ,QAAQ,aAAa,0BAA0B;AAAA,gBACpE,OAAO;AAAA,gBACP,UAAU,CAAC,MAAM,YAAY,EAAE,OAAO,KAAK;AAAA;AAAA,YAC7C;AAAA,aACF;AAAA,UAGD,SAAS,gBAAAA,KAAC,OAAE,WAAU,kBAAkB,iBAAM;AAAA,UAE/C,gBAAAA,KAAC,YAAO,MAAK,UAAS,WAAU,oBAAmB,UAAU,SAC1D,oBACC,gBAAAC,MAAA,YACE;AAAA,4BAAAD,KAAC,WAAQ;AAAA,YAAE;AAAA,aACb,IAEA,QAAQ,KAEZ;AAAA;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;AAIO,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA,OAAO;AAAA,EACP,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACb,SAAS;AAAA,EACT;AAAA,EACA,cAAc;AAChB,GAwBG;AACD,kBAAgB;AAChB,QAAM,IAAI,kBAAkB,MAAM;AAClC,QAAM,EAAE,MAAM,SAAS,MAAM,IAAI,aAAa,CAAC;AAC/C,QAAM,aAAa,cAAc,EAAE,QAAQ;AAE3C,YAAU,MAAM;AACd,QAAI,SAAS,WAAW,CAAC,KAAM;AAC/B,UAAM,QAAQ,CAAC,MAAqB,EAAE,QAAQ,YAAY,UAAU;AACpE,aAAS,iBAAiB,WAAW,KAAK;AAC1C,WAAO,MAAM,SAAS,oBAAoB,WAAW,KAAK;AAAA,EAC5D,GAAG,CAAC,MAAM,MAAM,OAAO,CAAC;AAExB,MAAI,SAAS,WAAW,CAAC,KAAM,QAAO;AAEtC,QAAM,YAAY,MAAM,WAAW,CAAC;AACpC,QAAM,SAAS,OAAO,KAAK,OAAO,CAAC,MAAM,UAAU,SAAS,CAAC,CAAC,IAAI,WAAW;AAAA,IAC3E,CAAC,MAAM,KAAK;AAAA,EACd;AACA,QAAM,SAAS,MAAM,OAAO,CAAC,MAAM,CAAC,cAAc,SAAS,CAAC,CAAC;AAC7D,QAAM,QAAQ,MAAM,OAAO,CAAC,MAAM,cAAc,SAAS,CAAC,CAAC;AAE3D,QAAM,QAAQ,CAAC,MAAc,MAAM,SAAS,KAAK,MAAM;AAEvD,QAAM,QACJ,gBAAAC,MAAC,SAAI,WAAU,kBACZ;AAAA,mBAAe,MAAM,WAAW,MAAM,SACrC,gBAAAA,MAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,YAAY,UAAU,KAAK,IAAI,cAAc,EAAE,GAC3E;AAAA,YAAM,WACL,gBAAAD,KAAC,SAAI,KAAK,KAAK,SAAS,KAAI,IAAG,OAAO,IAAI,QAAQ,IAAI,OAAO,EAAE,cAAc,EAAE,GAAG;AAAA,MAEpF,gBAAAA,KAAC,UAAK,WAAU,kBACb,mBAAS,UAAU,MAAM,OAAO,OAAO,KAAK,IAAI,KAAK,EAAE,IAC1D;AAAA,OACF;AAAA,IAGD,WACC,gBAAAC,MAAC,SAAI,WAAU,oBACb;AAAA,sBAAAD,KAAC,WAAQ,OAAO,EAAE,OAAO,yBAAyB,GAAG;AAAA,MACrD,gBAAAA,KAAC,UAAK,WAAU,kBAAiB,2CAAwB;AAAA,OAC3D;AAAA,IAED,SAAS,gBAAAA,KAAC,OAAE,WAAU,kBAAiB,4CAAmC;AAAA,IAE1E,OAAO,IAAI,CAAC,MACX,gBAAAA;AAAA,MAAC;AAAA;AAAA,QAEC,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,UAAU,MAAM,CAAC;AAAA,QACjB;AAAA,QACA;AAAA;AAAA,MALK;AAAA,IAMP,CACD;AAAA,IAEA,MAAM,SAAS,KAAK,OAAO,SAAS,KAAK,gBAAAA,KAAC,SAAI,WAAU,oBAAmB,gBAAE;AAAA,IAE7E,MAAM,SAAS,KACd,gBAAAA,KAAC,iBAAc,QAAQ,GAAG,SAAS,OAAO,WAAsB,WAAsB;AAAA,IAGvF,CAAC,WAAW,CAAC,SAAS,MAAM,WAAW,KACtC,gBAAAA,KAAC,OAAE,WAAU,kBAAiB,0DAA4C;AAAA,IAG3E,CAAC,WAAW,CAAC,SAAS,MAAM,aAC3B,gBAAAC,MAAC,OAAE,WAAU,oBAAmB,MAAK,wBAAuB,QAAO,UAAS,KAAI,cAAa;AAAA;AAAA,MAChE,gBAAAD,KAAC,OAAE,sBAAQ;AAAA,OACxC;AAAA,KAEJ;AAGF,MAAI,SAAS,SAAU,QAAO;AAE9B,SACE,gBAAAA,KAAC,SAAI,WAAU,oBAAmB,SAAS,MAAM,UAAU,GACzD,0BAAAC,MAAC,SAAI,WAAU,iBAAgB,MAAK,UAAS,cAAW,QAAO,SAAS,CAAC,MAAM,EAAE,gBAAgB,GAC/F;AAAA,oBAAAD,KAAC,YAAO,MAAK,UAAS,WAAU,kBAAiB,cAAW,SAAQ,SAAS,MAAM,UAAU,GAAG,oBAEhG;AAAA,IACC;AAAA,KACH,GACF;AAEJ;","names":["jsx","jsxs"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@authrobo/react",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "React sign-in buttons and a configurable auth modal for AuthRobo — Google, LinkedIn, GitHub, Apple, Facebook, and email.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -21,7 +21,11 @@
21
21
  },
22
22
  "./package.json": "./package.json"
23
23
  },
24
- "files": ["dist", "README.md"],
24
+ "files": [
25
+ "dist",
26
+ "assets",
27
+ "README.md"
28
+ ],
25
29
  "scripts": {
26
30
  "build": "tsup",
27
31
  "typecheck": "tsc --noEmit",